Transactions

替換交易時的競速條件

  • January 21, 2021

我正在編寫一個監控 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);
 }
}

上面的方法在大多數情況下都很好用,但有一個例外:

  1. 送出交易0x123
  2. 等待 15 秒,檢查我們是否收到了乙太坊的收據。
  3. 如果我們沒有,請重新計算 gas 價格並發送替換 tx 0xabc
  4. 當替換 tx0xabc被廣播到乙太坊網路時,0x123就會被開採。
  5. 機器人將嘗試0xabc永遠替換 tx,因為收據始終null0xabc.

當我更新數組中的 tx 時,我還覆蓋了之前的 tx 雜湊(這使得實現變得簡單)。換句話說,一旦腳本廣播了一個替換的 tx,它就不再知道過去的 tx 雜湊,這會在發生競爭情況時導致無限回歸。

問題是有沒有辦法避免這種情況?我只在 Rinkeby 上針對 Infura 節點執行我的機器人。也許這是在測試網上經常發生但在主網上很少發生的事情?

我知道一種解決方案是修改程式碼以跟踪每個清算機會的多個 tx 雜湊,但這會大大增加實現的複雜性(我正在使用 Rust)。

您可以使用 nonce 和事務計數來驗證 nonce 是否被探勘。

if (tx.nonce < getTransactionCount(sender)) {
 drop transaction
}

我認為這種情況並不是測試網所特有的。我想說在短鏈重組很常見的主網中情況更糟。

引用自:https://ethereum.stackexchange.com/questions/92627