Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect L2 reorgs by counting number of reorgs #1688

Merged
merged 1 commit into from
Feb 23, 2023
Merged
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
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 @@ -2199,6 +2199,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