Commit d14693e1 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #1785 from ethereum-optimism/bugfix/fix-deadlock-2

l2geth: fix deadlock on invalid txs
parents fc631b53 7f2898ba
---
'@eth-optimism/l2geth': patch
---
Fixes deadlock
...@@ -22,7 +22,10 @@ import ( ...@@ -22,7 +22,10 @@ import (
) )
// NewTxsEvent is posted when a batch of transactions enter the transaction pool. // NewTxsEvent is posted when a batch of transactions enter the transaction pool.
type NewTxsEvent struct{ Txs []*types.Transaction } type NewTxsEvent struct {
Txs []*types.Transaction
ErrCh chan error
}
// NewMinedBlockEvent is posted when a block has been imported. // NewMinedBlockEvent is posted when a block has been imported.
type NewMinedBlockEvent struct{ Block *types.Block } type NewMinedBlockEvent struct{ Block *types.Block }
......
...@@ -1090,7 +1090,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt ...@@ -1090,7 +1090,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
for _, set := range events { for _, set := range events {
txs = append(txs, set.Flatten()...) txs = append(txs, set.Flatten()...)
} }
pool.txFeed.Send(NewTxsEvent{txs}) pool.txFeed.Send(NewTxsEvent{Txs: txs})
} }
} }
......
...@@ -506,7 +506,10 @@ func (w *worker) mainLoop() { ...@@ -506,7 +506,10 @@ func (w *worker) mainLoop() {
} }
w.pendingMu.Unlock() w.pendingMu.Unlock()
} else { } else {
log.Debug("Problem committing transaction", "msg", err) log.Error("Problem committing transaction", "msg", err)
if ev.ErrCh != nil {
ev.ErrCh <- err
}
} }
case ev := <-w.txsCh: case ev := <-w.txsCh:
...@@ -781,6 +784,11 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin ...@@ -781,6 +784,11 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
} }
var coalescedLogs []*types.Log var coalescedLogs []*types.Log
// UsingOVM
// Keep track of the number of transactions being added to the block.
// Blocks should only have a single transaction. This value is used to
// compute a success return value
var txCount int
for { for {
// In the following three cases, we will interrupt the execution of the transaction. // In the following three cases, we will interrupt the execution of the transaction.
...@@ -814,6 +822,8 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin ...@@ -814,6 +822,8 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
break break
} }
txCount++
// Error may be ignored here. The error has already been checked // Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool. // during transaction acceptance is the transaction pool.
// //
...@@ -881,7 +891,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin ...@@ -881,7 +891,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
if interrupt != nil { if interrupt != nil {
w.resubmitAdjustCh <- &intervalAdjust{inc: false} w.resubmitAdjustCh <- &intervalAdjust{inc: false}
} }
return false return txCount == 0
} }
// commitNewTx is an OVM addition that mines a block with a single tx in it. // commitNewTx is an OVM addition that mines a block with a single tx in it.
......
...@@ -806,9 +806,9 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error { ...@@ -806,9 +806,9 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
// Note that Ethereum Layer one consensus rules dictate that the timestamp // Note that Ethereum Layer one consensus rules dictate that the timestamp
// must be strictly increasing between blocks, so no need to check both the // must be strictly increasing between blocks, so no need to check both the
// timestamp and the blocknumber. // timestamp and the blocknumber.
ts := s.GetLatestL1Timestamp()
bn := s.GetLatestL1BlockNumber()
if tx.L1Timestamp() == 0 { if tx.L1Timestamp() == 0 {
ts := s.GetLatestL1Timestamp()
bn := s.GetLatestL1BlockNumber()
tx.SetL1Timestamp(ts) tx.SetL1Timestamp(ts)
tx.SetL1BlockNumber(bn) tx.SetL1BlockNumber(bn)
} else if tx.L1Timestamp() > s.GetLatestL1Timestamp() { } else if tx.L1Timestamp() > s.GetLatestL1Timestamp() {
...@@ -816,17 +816,15 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error { ...@@ -816,17 +816,15 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
// service's locally maintained timestamp, update the timestamp and // service's locally maintained timestamp, update the timestamp and
// blocknumber to equal that of the transaction's. This should happen // blocknumber to equal that of the transaction's. This should happen
// with `enqueue` transactions. // with `enqueue` transactions.
ts := tx.L1Timestamp() s.SetLatestL1Timestamp(tx.L1Timestamp())
bn := tx.L1BlockNumber() s.SetLatestL1BlockNumber(tx.L1BlockNumber().Uint64())
s.SetLatestL1Timestamp(ts) log.Debug("Updating OVM context based on new transaction", "timestamp", ts, "blocknumber", tx.L1BlockNumber().Uint64(), "queue-origin", tx.QueueOrigin())
s.SetLatestL1BlockNumber(bn.Uint64())
log.Debug("Updating OVM context based on new transaction", "timestamp", ts, "blocknumber", bn.Uint64(), "queue-origin", tx.QueueOrigin())
} else if tx.L1Timestamp() < s.GetLatestL1Timestamp() { } else if tx.L1Timestamp() < s.GetLatestL1Timestamp() {
log.Error("Timestamp monotonicity violation", "hash", tx.Hash().Hex()) log.Error("Timestamp monotonicity violation", "hash", tx.Hash().Hex())
} }
index := s.GetLatestIndex()
if tx.GetMeta().Index == nil { if tx.GetMeta().Index == nil {
index := s.GetLatestIndex()
if index == nil { if index == nil {
tx.SetIndex(0) tx.SetIndex(0)
} else { } else {
...@@ -846,21 +844,36 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error { ...@@ -846,21 +844,36 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
log.Debug("Applying transaction to tip", "index", *tx.GetMeta().Index, "hash", tx.Hash().Hex(), "origin", tx.QueueOrigin().String()) log.Debug("Applying transaction to tip", "index", *tx.GetMeta().Index, "hash", tx.Hash().Hex(), "origin", tx.QueueOrigin().String())
txs := types.Transactions{tx} txs := types.Transactions{tx}
s.txFeed.Send(core.NewTxsEvent{Txs: txs}) errCh := make(chan error, 1)
s.txFeed.Send(core.NewTxsEvent{
Txs: txs,
ErrCh: errCh,
})
// Block until the transaction has been added to the chain // Block until the transaction has been added to the chain
log.Trace("Waiting for transaction to be added to chain", "hash", tx.Hash().Hex()) log.Trace("Waiting for transaction to be added to chain", "hash", tx.Hash().Hex())
<-s.chainHeadCh
select {
// Update the cache when the transaction is from the owner case err := <-errCh:
// of the gas price oracle log.Error("Got error waiting for transaction to be added to chain", "msg", err)
sender, _ := types.Sender(s.signer, tx) s.SetLatestL1Timestamp(ts)
owner := s.GasPriceOracleOwnerAddress() s.SetLatestL1BlockNumber(bn)
if owner != nil && sender == *owner { s.SetLatestIndex(index)
if err := s.updateGasPriceOracleCache(nil); err != nil { return err
return err case <-s.chainHeadCh:
// Update the cache when the transaction is from the owner
// of the gas price oracle
sender, _ := types.Sender(s.signer, tx)
owner := s.GasPriceOracleOwnerAddress()
if owner != nil && sender == *owner {
if err := s.updateGasPriceOracleCache(nil); err != nil {
s.SetLatestL1Timestamp(ts)
s.SetLatestL1BlockNumber(bn)
s.SetLatestIndex(index)
return err
}
} }
return nil
} }
return nil
} }
// applyBatchedTransaction applies transactions that were batched to layer one. // applyBatchedTransaction applies transactions that were batched to layer one.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment