Skip to content

Commit

Permalink
Detect L2 reorgs by counting number of reorgs (#1688)
Browse files Browse the repository at this point in the history
  • Loading branch information
ToniRamirezM authored Feb 23, 2023
1 parent 27b65d9 commit 5994a08
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 36 deletions.
59 changes: 23 additions & 36 deletions sequencer/dbmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type dbManager struct {
l2ReorgCh chan L2ReorgEvent
ctx context.Context
batchConstraints batchConstraints
numberOfReorgs uint64
}

func (d *dbManager) GetBatchByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.Batch, error) {
Expand All @@ -45,7 +46,12 @@ type ClosingBatchParameters struct {
}

func newDBManager(ctx context.Context, txPool txPool, state dbManagerStateInterface, worker *Worker, closingSignalCh ClosingSignalCh, txsStore TxsStore, batchConstraints batchConstraints) *dbManager {
return &dbManager{ctx: ctx, txPool: txPool, state: state, worker: worker, txsStore: txsStore, l2ReorgCh: closingSignalCh.L2ReorgCh, batchConstraints: batchConstraints}
numberOfReorgs, err := state.CountReorgs(ctx, nil)
if err != nil {
log.Error("failed to get number of reorgs: %v", err)
}

return &dbManager{ctx: ctx, txPool: txPool, state: state, worker: worker, txsStore: txsStore, l2ReorgCh: closingSignalCh.L2ReorgCh, batchConstraints: batchConstraints, numberOfReorgs: numberOfReorgs}
}

// Start stars the dbManager routines
Expand Down Expand Up @@ -162,41 +168,17 @@ func (d *dbManager) storeProcessedTxAndDeleteFromPool() {
log.Errorf("StoreProcessedTxAndDeleteFromPool: %v", err)
}

// // Check if the Tx is still valid in the state to detect reorgs
// lastStateRoot, err := d.state.GetLastStateRoot(d.ctx, dbTx)
// if err != nil {
// err = dbTx.Rollback(d.ctx)
// if err != nil {
// log.Errorf("StoreProcessedTxAndDeleteFromPool: %v", err)
// }
// d.txsStore.Wg.Done()
// continue
// }

// if txToStore.previousL2BlockStateRoot != state.ZeroHash && lastStateRoot != txToStore.previousL2BlockStateRoot {
// // We may have closed the batch because of a new GER without transactions
// // If there are no transactions in the batch when closing it, we can not base our check in l2 blocks
// // so we will check against the latest closed batch

// lastBatch, err := d.state.GetLastClosedBatch(d.ctx, dbTx)
// if err != nil {
// err = dbTx.Rollback(d.ctx)
// if err != nil {
// log.Errorf("StoreProcessedTxAndDeleteFromPool: %v", err)
// }
// d.txsStore.Wg.Done()
// continue
// }

// lastStateRoot = lastBatch.StateRoot

// if lastStateRoot != txToStore.previousL2BlockStateRoot {
// log.Warnf("L2 reorg detected. Expected OldStateRoot: %v actual OldStateRoot: %v", lastStateRoot, txToStore.previousL2BlockStateRoot)
// d.l2ReorgCh <- L2ReorgEvent{}
// d.txsStore.Wg.Done()
// continue
// }
// }
numberOfReorgs, err := d.state.CountReorgs(d.ctx, nil)
if err != nil {
log.Error("failed to get number of reorgs: %v", err)
}

if numberOfReorgs != d.numberOfReorgs {
log.Warnf("New L2 reorg detected")
d.l2ReorgCh <- L2ReorgEvent{}
d.txsStore.Wg.Done()
continue
}

err = d.StoreProcessedTransaction(d.ctx, txToStore.batchNumber, txToStore.txResponse, txToStore.coinbase, txToStore.timestamp, dbTx)
if err != nil {
Expand Down Expand Up @@ -587,3 +569,8 @@ func (d *dbManager) UpdateTxStatus(ctx context.Context, hash common.Hash, newSta
func (d *dbManager) GetLatestVirtualBatchTimestamp(ctx context.Context, dbTx pgx.Tx) (time.Time, error) {
return d.state.GetLatestVirtualBatchTimestamp(ctx, dbTx)
}

// CountReorgs returns the number of reorgs
func (d *dbManager) CountReorgs(ctx context.Context, dbTx pgx.Tx) (uint64, error) {
return d.state.CountReorgs(ctx, dbTx)
}
3 changes: 3 additions & 0 deletions sequencer/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type stateInterface interface {
GetForcedBatchesSince(ctx context.Context, forcedBatchNumber, maxBlockNumber uint64, dbTx pgx.Tx) ([]*state.ForcedBatch, error)
GetLastTrustedForcedBatchNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error)
GetLatestVirtualBatchTimestamp(ctx context.Context, dbTx pgx.Tx) (time.Time, error)
CountReorgs(ctx context.Context, dbTx pgx.Tx) (uint64, error)
}

type workerInterface interface {
Expand Down Expand Up @@ -109,6 +110,7 @@ type dbManagerInterface interface {
GetBalanceByStateRoot(ctx context.Context, address common.Address, root common.Hash) (*big.Int, error)
UpdateTxStatus(ctx context.Context, hash common.Hash, newStatus pool.TxStatus) error
GetLatestVirtualBatchTimestamp(ctx context.Context, dbTx pgx.Tx) (time.Time, error)
CountReorgs(ctx context.Context, dbTx pgx.Tx) (uint64, error)
}

type dbManagerStateInterface interface {
Expand Down Expand Up @@ -136,6 +138,7 @@ type dbManagerStateInterface interface {
GetLastTrustedForcedBatchNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error)
GetBalanceByStateRoot(ctx context.Context, address common.Address, root common.Hash) (*big.Int, error)
GetLatestVirtualBatchTimestamp(ctx context.Context, dbTx pgx.Tx) (time.Time, error)
CountReorgs(ctx context.Context, dbTx pgx.Tx) (uint64, error)
}

type ethTxManager interface {
Expand Down
21 changes: 21 additions & 0 deletions sequencer/mock_db_manager.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions sequencer/mock_state.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions state/pgstatestorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -2210,6 +2210,19 @@ func (p *PostgresStorage) AddTrustedReorg(ctx context.Context, reorg *TrustedReo
return err
}

// CountReorgs returns the number of reorgs
func (p *PostgresStorage) CountReorgs(ctx context.Context, dbTx pgx.Tx) (uint64, error) {
const countReorgsSQL = "SELECT COUNT(*) FROM state.trusted_reorg"

var count uint64
q := p.getExecQuerier(dbTx)
err := q.QueryRow(ctx, countReorgsSQL).Scan(&count)
if err != nil {
return 0, err
}
return count, nil
}

// GetReorgedTransactions returns the transactions that were reorged
func (p *PostgresStorage) GetReorgedTransactions(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (txs []*types.Transaction, err error) {
const getReorgedTransactionsSql = "SELECT encoded FROM state.transaction t INNER JOIN state.l2block b ON t.l2_block_num = b.block_num WHERE b.batch_num >= $1 ORDER BY l2_block_num ASC"
Expand Down

0 comments on commit 5994a08

Please sign in to comment.