Transactions
替換交易時的競速條件
我正在編寫一個監控 DeFi 協議以尋找清算機會的機器人。該機器人的行為類似於下面的虛擬碼:
let pending_txs: []; for every_new_block in Ethereum { // Check the state of pending txs. for pending_tx in pending_txs { let receipt = get_receipt(pending_tx); if receipt != null { // If we got a receipt from Ethereum, clear the tx from the local state. delete_tx_from_array(pending_tx); } else { // Otherwise, replace the tx and update it in the array. let new_gas_price = bump_gas_price(pending_tx.gas_price); let tx = send_tx(new_gas_price); update_tx_in_array(tx); } } ... // Search for new liquidation opportunities. if liquidation_opportunity and if !pending_tx_for_liquidation_opportunity { let tx = send_tx(initial_gas_price); add_tx_in_array(tx); } }
上面的方法在大多數情況下都很好用,但有一個例外:
- 送出交易
0x123
- 等待 15 秒,檢查我們是否收到了乙太坊的收據。
- 如果我們沒有,請重新計算 gas 價格並發送替換 tx
0xabc
。- 當替換 tx
0xabc
被廣播到乙太坊網路時,0x123
就會被開採。- 機器人將嘗試
0xabc
永遠替換 tx,因為收據始終null
是0xabc
.當我更新數組中的 tx 時,我還覆蓋了之前的 tx 雜湊(這使得實現變得簡單)。換句話說,一旦腳本廣播了一個替換的 tx,它就不再知道過去的 tx 雜湊,這會在發生競爭情況時導致無限回歸。
問題是有沒有辦法避免這種情況?我只在 Rinkeby 上針對 Infura 節點執行我的機器人。也許這是在測試網上經常發生但在主網上很少發生的事情?
我知道一種解決方案是修改程式碼以跟踪每個清算機會的多個 tx 雜湊,但這會大大增加實現的複雜性(我正在使用 Rust)。
您可以使用 nonce 和事務計數來驗證 nonce 是否被探勘。
if (tx.nonce < getTransactionCount(sender)) { drop transaction }
我認為這種情況並不是測試網所特有的。我想說在短鏈重組很常見的主網中情況更糟。