Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/spicy-spoons-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/l2geth': minor
---

Fixes deadlock
5 changes: 4 additions & 1 deletion l2geth/core/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import (
)

// 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.
type NewMinedBlockEvent struct{ Block *types.Block }
Expand Down
2 changes: 1 addition & 1 deletion l2geth/core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
for _, set := range events {
txs = append(txs, set.Flatten()...)
}
pool.txFeed.Send(NewTxsEvent{txs})
pool.txFeed.Send(NewTxsEvent{Txs: txs})
}
}

Expand Down
10 changes: 8 additions & 2 deletions l2geth/miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,10 @@ func (w *worker) mainLoop() {
}
w.pendingMu.Unlock()
} 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:
Expand Down Expand Up @@ -781,6 +784,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
}

var coalescedLogs []*types.Log
var txCount int

for {
// In the following three cases, we will interrupt the execution of the transaction.
Expand Down Expand Up @@ -814,6 +818,8 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
break
}

txCount++

// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
//
Expand Down Expand Up @@ -881,7 +887,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
if interrupt != nil {
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.
Expand Down
51 changes: 32 additions & 19 deletions l2geth/rollup/sync_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -806,27 +806,25 @@ func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
// Note that Ethereum Layer one consensus rules dictate that the timestamp
// must be strictly increasing between blocks, so no need to check both the
// timestamp and the blocknumber.
ts := s.GetLatestL1Timestamp()
bn := s.GetLatestL1BlockNumber()
if tx.L1Timestamp() == 0 {
ts := s.GetLatestL1Timestamp()
bn := s.GetLatestL1BlockNumber()
tx.SetL1Timestamp(ts)
tx.SetL1BlockNumber(bn)
} else if tx.L1Timestamp() > s.GetLatestL1Timestamp() {
// If the timestamp of the transaction is greater than the sync
// service's locally maintained timestamp, update the timestamp and
// blocknumber to equal that of the transaction's. This should happen
// with `enqueue` transactions.
ts := tx.L1Timestamp()
bn := tx.L1BlockNumber()
s.SetLatestL1Timestamp(ts)
s.SetLatestL1BlockNumber(bn.Uint64())
log.Debug("Updating OVM context based on new transaction", "timestamp", ts, "blocknumber", bn.Uint64(), "queue-origin", tx.QueueOrigin())
s.SetLatestL1Timestamp(tx.L1Timestamp())
s.SetLatestL1BlockNumber(tx.L1BlockNumber().Uint64())
log.Debug("Updating OVM context based on new transaction", "timestamp", ts, "blocknumber", tx.L1BlockNumber().Uint64(), "queue-origin", tx.QueueOrigin())
} else if tx.L1Timestamp() < s.GetLatestL1Timestamp() {
log.Error("Timestamp monotonicity violation", "hash", tx.Hash().Hex())
}

index := s.GetLatestIndex()
if tx.GetMeta().Index == nil {
index := s.GetLatestIndex()
if index == nil {
tx.SetIndex(0)
} else {
Expand All @@ -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())

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
log.Trace("Waiting for transaction to be added to chain", "hash", tx.Hash().Hex())
<-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 {
return err

select {
case err := <-errCh:
log.Error("Got error waiting for transaction to be added to chain", "msg", err)
s.SetLatestL1Timestamp(ts)
s.SetLatestL1BlockNumber(bn)
s.SetLatestIndex(index)
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.
Expand Down