diff --git a/db/migrations/state/0003.sql b/db/migrations/state/0003.sql new file mode 100644 index 0000000000..6f9d31420a --- /dev/null +++ b/db/migrations/state/0003.sql @@ -0,0 +1,15 @@ +-- +migrate Up +ALTER TABLE state.forced_batch +DROP COLUMN IF EXISTS batch_num; + +ALTER TABLE state.batch +ADD COLUMN forced_batch_num BIGINT; +ALTER TABLE state.batch +ADD FOREIGN KEY (forced_batch_num) REFERENCES state.forced_batch(forced_batch_num); + +-- +migrate Down +ALTER TABLE state.batch +DROP COLUMN IF EXISTS forced_batch_num; + +ALTER TABLE state.forced_batch +ADD COLUMN batch_num BIGINT; \ No newline at end of file diff --git a/sequencer/broadcast/interfaces.go b/sequencer/broadcast/interfaces.go index 035eef3164..c0f3c267de 100644 --- a/sequencer/broadcast/interfaces.go +++ b/sequencer/broadcast/interfaces.go @@ -14,6 +14,5 @@ type stateInterface interface { GetLastBatch(ctx context.Context, dbTx pgx.Tx) (*state.Batch, error) GetBatchByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.Batch, error) GetEncodedTransactionsByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (encoded []string, err error) - GetForcedBatchByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.ForcedBatch, error) GetExitRootByGlobalExitRoot(ctx context.Context, ger common.Hash, dbTx pgx.Tx) (*state.GlobalExitRoot, error) } diff --git a/sequencer/broadcast/mocks/mock_state.go b/sequencer/broadcast/mocks/mock_state.go index 028d2a82d3..96f6ae2b32 100644 --- a/sequencer/broadcast/mocks/mock_state.go +++ b/sequencer/broadcast/mocks/mock_state.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.14.0. DO NOT EDIT. package mocks @@ -88,29 +88,6 @@ func (_m *StateMock) GetExitRootByGlobalExitRoot(ctx context.Context, ger common return r0, r1 } -// GetForcedBatchByBatchNumber provides a mock function with given fields: ctx, batchNumber, dbTx -func (_m *StateMock) GetForcedBatchByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.ForcedBatch, error) { - ret := _m.Called(ctx, batchNumber, dbTx) - - var r0 *state.ForcedBatch - if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) *state.ForcedBatch); ok { - r0 = rf(ctx, batchNumber, dbTx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*state.ForcedBatch) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { - r1 = rf(ctx, batchNumber, dbTx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // GetLastBatch provides a mock function with given fields: ctx, dbTx func (_m *StateMock) GetLastBatch(ctx context.Context, dbTx pgx.Tx) (*state.Batch, error) { ret := _m.Called(ctx, dbTx) diff --git a/sequencer/broadcast/server.go b/sequencer/broadcast/server.go index c0e747f138..6e53f69c4d 100644 --- a/sequencer/broadcast/server.go +++ b/sequencer/broadcast/server.go @@ -92,14 +92,6 @@ func (s *Server) genericGetBatch(ctx context.Context, batch *state.Batch) (*pb.G } } - var forcedBatchNum uint64 - forcedBatch, err := s.state.GetForcedBatchByBatchNumber(ctx, batch.BatchNumber, nil) - if err == nil { - forcedBatchNum = forcedBatch.ForcedBatchNumber - } else if err != state.ErrNotFound { - return nil, err - } - var mainnetExitRoot, rollupExitRoot string ger, err := s.state.GetExitRootByGlobalExitRoot(ctx, batch.GlobalExitRoot, nil) if err == nil { @@ -108,6 +100,10 @@ func (s *Server) genericGetBatch(ctx context.Context, batch *state.Batch) (*pb.G } else if err != state.ErrNotFound { return nil, err } + var fb uint64 + if batch.ForcedBatchNum != nil { + fb = *batch.ForcedBatchNum + } return &pb.GetBatchResponse{ BatchNumber: batch.BatchNumber, @@ -119,7 +115,7 @@ func (s *Server) genericGetBatch(ctx context.Context, batch *state.Batch) (*pb.G RollupExitRoot: rollupExitRoot, Timestamp: uint64(batch.Timestamp.Unix()), Transactions: transactions, - ForcedBatchNumber: forcedBatchNum, + ForcedBatchNumber: fb, }, nil } diff --git a/sequencer/broadcast/server_test.go b/sequencer/broadcast/server_test.go index c9d02b3e4d..71d2d8c276 100644 --- a/sequencer/broadcast/server_test.go +++ b/sequencer/broadcast/server_test.go @@ -145,7 +145,6 @@ func TestBroadcastServerGetBatch(t *testing.T) { } st.On("GetBatchByNumber", mock.AnythingOfType("*context.valueCtx"), tc.inputBatchNumber, nil).Return(tc.expectedBatch, err) st.On("GetEncodedTransactionsByBatchNumber", mock.AnythingOfType("*context.valueCtx"), tc.inputBatchNumber, nil).Return(tc.expectedEncodedTxs, err) - st.On("GetForcedBatchByBatchNumber", mock.AnythingOfType("*context.valueCtx"), tc.inputBatchNumber, nil).Return(tc.expectedForcedBatch, err) if tc.expectedBatch != nil { st.On("GetExitRootByGlobalExitRoot", mock.AnythingOfType("*context.valueCtx"), tc.expectedBatch.GlobalExitRoot, nil).Return(tc.expectedGER, err) } @@ -217,7 +216,6 @@ func TestBroadcastServerGetLastBatch(t *testing.T) { st.On("GetLastBatch", mock.AnythingOfType("*context.valueCtx"), nil).Return(tc.expectedBatch, err) if tc.expectedBatch != nil { st.On("GetEncodedTransactionsByBatchNumber", mock.AnythingOfType("*context.valueCtx"), tc.expectedBatch.BatchNumber, nil).Return(tc.expectedEncodedTxs, err) - st.On("GetForcedBatchByBatchNumber", mock.AnythingOfType("*context.valueCtx"), tc.expectedBatch.BatchNumber, nil).Return(tc.expectedForcedBatch, err) st.On("GetExitRootByGlobalExitRoot", mock.AnythingOfType("*context.valueCtx"), tc.expectedBatch.GlobalExitRoot, nil).Return(tc.expectedGER, err) } diff --git a/state/batch.go b/state/batch.go index 5b9eb8db32..af45b7a089 100644 --- a/state/batch.go +++ b/state/batch.go @@ -18,6 +18,7 @@ type Batch struct { Timestamp time.Time Transactions []types.Transaction GlobalExitRoot common.Hash + ForcedBatchNum *uint64 } // ProcessingContext is the necessary data that a batch needs to provide to the runtime, @@ -27,6 +28,7 @@ type ProcessingContext struct { Coinbase common.Address Timestamp time.Time GlobalExitRoot common.Hash + ForcedBatchNum *uint64 } // ProcessingReceipt indicates the outcome (StateRoot, AccInputHash) of processing a batch diff --git a/state/forcedbatch.go b/state/forcedbatch.go index 3e54e808fb..3170e9bf5f 100644 --- a/state/forcedbatch.go +++ b/state/forcedbatch.go @@ -9,7 +9,6 @@ import ( // ForcedBatch represents a ForcedBatch type ForcedBatch struct { BlockNumber uint64 - BatchNumber *uint64 ForcedBatchNumber uint64 Sequencer common.Address GlobalExitRoot common.Hash diff --git a/state/pgstatestorage.go b/state/pgstatestorage.go index 2ec3d70995..242b083092 100644 --- a/state/pgstatestorage.go +++ b/state/pgstatestorage.go @@ -21,36 +21,28 @@ const ( addGlobalExitRootSQL = "INSERT INTO state.exit_root (block_num, mainnet_exit_root, rollup_exit_root, global_exit_root) VALUES ($1, $2, $3, $4)" getLatestExitRootBlockNumSQL = "SELECT block_num FROM state.exit_root ORDER BY id DESC LIMIT 1" addVirtualBatchSQL = "INSERT INTO state.virtual_batch (batch_num, tx_hash, coinbase, block_num) VALUES ($1, $2, $3, $4)" - addForcedBatchSQL = "INSERT INTO state.forced_batch (forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, batch_num, block_num) VALUES ($1, $2, $3, $4, $5, $6, $7)" - getForcedBatchSQL = "SELECT forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, batch_num, block_num FROM state.forced_batch WHERE forced_batch_num = $1" addBlockSQL = "INSERT INTO state.block (block_num, block_hash, parent_hash, received_at) VALUES ($1, $2, $3, $4)" getLastBlockSQL = "SELECT block_num, block_hash, parent_hash, received_at FROM state.block ORDER BY block_num DESC LIMIT 1" getPreviousBlockSQL = "SELECT block_num, block_hash, parent_hash, received_at FROM state.block ORDER BY block_num DESC LIMIT 1 OFFSET $1" - resetSQL = "DELETE FROM state.block WHERE block_num > $1" - resetTrustedStateSQL = "DELETE FROM state.batch WHERE batch_num > $1" addVerifiedBatchSQL = "INSERT INTO state.verified_batch (block_num, batch_num, tx_hash, aggregator, state_root) VALUES ($1, $2, $3, $4, $5)" getVerifiedBatchSQL = "SELECT block_num, batch_num, tx_hash, aggregator, state_root FROM state.verified_batch WHERE batch_num = $1" getLastBatchNumberSQL = "SELECT batch_num FROM state.batch ORDER BY batch_num DESC LIMIT 1" - getLastNBatchesSQL = "SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data from state.batch ORDER BY batch_num DESC LIMIT $1" + getLastNBatchesSQL = "SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num from state.batch ORDER BY batch_num DESC LIMIT $1" getLastBatchTimeSQL = "SELECT timestamp FROM state.batch ORDER BY batch_num DESC LIMIT 1" getLastVirtualBatchNumSQL = "SELECT COALESCE(MAX(batch_num), 0) FROM state.virtual_batch" getLastVirtualBatchBlockNumSQL = "SELECT block_num FROM state.virtual_batch ORDER BY batch_num DESC LIMIT 1" getLastBlockNumSQL = "SELECT block_num FROM state.block ORDER BY block_num DESC LIMIT 1" getLastL2BlockNumber = "SELECT block_num FROM state.l2block ORDER BY block_num DESC LIMIT 1" getBlockTimeByNumSQL = "SELECT received_at FROM state.block WHERE block_num = $1" - getForcedBatchByBatchNumSQL = "SELECT forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, batch_num, block_num from state.forced_batch WHERE batch_num = $1" - getProcessingContextSQL = "SELECT batch_num, global_exit_root, timestamp, coinbase from state.batch WHERE batch_num = $1" + getProcessingContextSQL = "SELECT batch_num, global_exit_root, timestamp, coinbase, forced_batch_num from state.batch WHERE batch_num = $1" getEncodedTransactionsByBatchNumberSQL = "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" getTransactionHashesByBatchNumberSQL = "SELECT hash 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" getLastBatchSeenSQL = "SELECT last_batch_num_seen FROM state.sync_info LIMIT 1" updateLastBatchSeenSQL = "UPDATE state.sync_info SET last_batch_num_seen = $1" - resetTrustedBatchSQL = "DELETE FROM state.batch WHERE batch_num > $1" isBatchClosedSQL = "SELECT global_exit_root IS NOT NULL AND state_root IS NOT NULL FROM state.batch WHERE batch_num = $1 LIMIT 1" - addGenesisBatchSQL = "INSERT INTO state.batch (batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)" - openBatchSQL = "INSERT INTO state.batch (batch_num, global_exit_root, timestamp, coinbase) VALUES ($1, $2, $3, $4)" + addGenesisBatchSQL = "INSERT INTO state.batch (batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)" + openBatchSQL = "INSERT INTO state.batch (batch_num, global_exit_root, timestamp, coinbase, forced_batch_num) VALUES ($1, $2, $3, $4, $5)" closeBatchSQL = "UPDATE state.batch SET state_root = $1, local_exit_root = $2, acc_input_hash = $3, raw_txs_data = $4 WHERE batch_num = $5" - getNextForcedBatchesSQL = "SELECT forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, batch_num, block_num FROM state.forced_batch WHERE batch_num IS NULL ORDER BY forced_batch_num ASC LIMIT $1" - addBatchNumberInForcedBatchSQL = "UPDATE state.forced_batch SET batch_num = $2 WHERE forced_batch_num = $1" getL2BlockByNumberSQL = "SELECT header, uncles, received_at FROM state.l2block b WHERE b.block_num = $1" getL2BlockHeaderByNumberSQL = "SELECT header FROM state.l2block b WHERE b.block_num = $1" getTransactionByHashSQL = "SELECT transaction.encoded FROM state.transaction WHERE hash = $1" @@ -112,21 +104,23 @@ func (p *PostgresStorage) getExecQuerier(dbTx pgx.Tx) execQuerier { // Reset resets the state to a block for the given DB tx func (p *PostgresStorage) Reset(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) error { e := p.getExecQuerier(dbTx) + const resetSQL = "DELETE FROM state.block WHERE block_num > $1" if _, err := e.Exec(ctx, resetSQL, blockNumber); err != nil { return err } - // TODO: Remove consolidations + return nil } // ResetTrustedState removes the batches with number greater than the given one // from the database. func (p *PostgresStorage) ResetTrustedState(ctx context.Context, batchNum uint64, dbTx pgx.Tx) error { + const resetTrustedStateSQL = "DELETE FROM state.batch WHERE batch_num > $1" e := p.getExecQuerier(dbTx) if _, err := e.Exec(ctx, resetTrustedStateSQL, batchNum); err != nil { return err } - // TODO: Remove consolidations + // TODO Find a way to put txs in the pool again return nil } @@ -322,7 +316,8 @@ func (p *PostgresStorage) GetTimeForLatestBatchVirtualization(ctx context.Contex // AddForcedBatch adds a new ForcedBatch to the db func (p *PostgresStorage) AddForcedBatch(ctx context.Context, forcedBatch *ForcedBatch, tx pgx.Tx) error { - _, err := tx.Exec(ctx, addForcedBatchSQL, forcedBatch.ForcedBatchNumber, forcedBatch.GlobalExitRoot.String(), forcedBatch.ForcedAt, forcedBatch.RawTxsData, forcedBatch.Sequencer.String(), forcedBatch.BatchNumber, forcedBatch.BlockNumber) + const addForcedBatchSQL = "INSERT INTO state.forced_batch (forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, block_num) VALUES ($1, $2, $3, $4, $5, $6)" + _, err := tx.Exec(ctx, addForcedBatchSQL, forcedBatch.ForcedBatchNumber, forcedBatch.GlobalExitRoot.String(), forcedBatch.ForcedAt, forcedBatch.RawTxsData, forcedBatch.Sequencer.String(), forcedBatch.BlockNumber) return err } @@ -334,32 +329,9 @@ func (p *PostgresStorage) GetForcedBatch(ctx context.Context, forcedBatchNumber rawTxs string seq string ) + const getForcedBatchSQL = "SELECT forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, block_num FROM state.forced_batch WHERE forced_batch_num = $1" e := p.getExecQuerier(dbTx) - err := e.QueryRow(ctx, getForcedBatchSQL, forcedBatchNumber).Scan(&forcedBatch.ForcedBatchNumber, &globalExitRoot, &forcedBatch.ForcedAt, &rawTxs, &seq, &forcedBatch.BatchNumber, &forcedBatch.BlockNumber) - if errors.Is(err, pgx.ErrNoRows) { - return nil, ErrNotFound - } else if err != nil { - return nil, err - } - forcedBatch.RawTxsData, err = hex.DecodeString(rawTxs) - if err != nil { - return nil, err - } - forcedBatch.Sequencer = common.HexToAddress(seq) - forcedBatch.GlobalExitRoot = common.HexToHash(globalExitRoot) - return &forcedBatch, nil -} - -// GetForcedBatchByBatchNumber gets an L1 forcedBatch by batch number. -func (p *PostgresStorage) GetForcedBatchByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*ForcedBatch, error) { - var ( - forcedBatch ForcedBatch - globalExitRoot string - rawTxs string - seq string - ) - e := p.getExecQuerier(dbTx) - err := e.QueryRow(ctx, getForcedBatchByBatchNumSQL, batchNumber).Scan(&forcedBatch.ForcedBatchNumber, &globalExitRoot, &forcedBatch.ForcedAt, &rawTxs, &seq, &forcedBatch.BatchNumber, &forcedBatch.BlockNumber) + err := e.QueryRow(ctx, getForcedBatchSQL, forcedBatchNumber).Scan(&forcedBatch.ForcedBatchNumber, &globalExitRoot, &forcedBatch.ForcedAt, &rawTxs, &seq, &forcedBatch.BlockNumber) if errors.Is(err, pgx.ErrNoRows) { return nil, ErrNotFound } else if err != nil { @@ -557,7 +529,7 @@ func (p *PostgresStorage) GetLastBatchNumberSeenOnEthereum(ctx context.Context, // GetBatchByNumber returns the batch with the given number. func (p *PostgresStorage) GetBatchByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*Batch, error) { const getBatchByNumberSQL = ` - SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data + SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num FROM state.batch WHERE batch_num = $1` @@ -576,7 +548,7 @@ func (p *PostgresStorage) GetBatchByNumber(ctx context.Context, batchNumber uint // GetBatchByTxHash returns the batch including the given tx func (p *PostgresStorage) GetBatchByTxHash(ctx context.Context, transactionHash common.Hash, dbTx pgx.Tx) (*Batch, error) { const getBatchByTxHashSQL = ` - SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data + SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data, b.forced_batch_num FROM state.transaction t, state.batch b, state.l2block l WHERE t.hash = $1 AND l.block_num = t.l2_block_num AND b.batch_num = l.batch_num` @@ -595,7 +567,7 @@ func (p *PostgresStorage) GetBatchByTxHash(ctx context.Context, transactionHash // GetBatchByL2BlockNumber returns the batch related to the l2 block accordingly to the provided l2 block number. func (p *PostgresStorage) GetBatchByL2BlockNumber(ctx context.Context, l2BlockNumber uint64, dbTx pgx.Tx) (*Batch, error) { const getBatchByL2BlockNumberSQL = ` - SELECT bt.batch_num, bt.global_exit_root, bt.local_exit_root, bt.acc_input_hash, bt.state_root, bt.timestamp, bt.coinbase, bt.raw_txs_data + SELECT bt.batch_num, bt.global_exit_root, bt.local_exit_root, bt.acc_input_hash, bt.state_root, bt.timestamp, bt.coinbase, bt.raw_txs_data, bt.forced_batch_num FROM state.batch bt INNER JOIN state.l2block bl ON bt.batch_num = bl.batch_num @@ -625,7 +597,8 @@ func (p *PostgresStorage) GetVirtualBatchByNumber(ctx context.Context, batchNumb state_root, timestamp, coinbase, - raw_txs_data + raw_txs_data, + forced_batch_num FROM state.batch WHERE @@ -682,6 +655,7 @@ func (p *PostgresStorage) GetProcessingContext(ctx context.Context, batchNumber &gerStr, &processingContext.Timestamp, &coinbaseStr, + &processingContext.ForcedBatchNum, ); errors.Is(err, pgx.ErrNoRows) { return nil, ErrStateNotSynchronized } else if err != nil { @@ -711,6 +685,7 @@ func scanBatch(row pgx.Row) (Batch, error) { &batch.Timestamp, &coinbaseStr, &batch.BatchL2Data, + &batch.ForcedBatchNum, ); err != nil { return batch, err } @@ -836,13 +811,6 @@ func (p *PostgresStorage) GetTxsHashesByBatchNumber(ctx context.Context, batchNu return txs, nil } -// ResetTrustedBatch resets the batches which the batch number is higher than the input. -func (p *PostgresStorage) ResetTrustedBatch(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) error { - e := p.getExecQuerier(dbTx) - _, err := e.Exec(ctx, resetTrustedBatchSQL, batchNumber) - return err -} - // AddVirtualBatch adds a new virtual batch to the storage. func (p *PostgresStorage) AddVirtualBatch(ctx context.Context, virtualBatch *VirtualBatch, dbTx pgx.Tx) error { e := p.getExecQuerier(dbTx) @@ -866,6 +834,7 @@ func (p *PostgresStorage) storeGenesisBatch(ctx context.Context, batch Batch, db batch.Timestamp.UTC(), batch.Coinbase.String(), batch.BatchL2Data, + batch.ForcedBatchNum, ) return err @@ -883,6 +852,7 @@ func (p *PostgresStorage) openBatch(ctx context.Context, batchContext Processing batchContext.GlobalExitRoot.String(), batchContext.Timestamp.UTC(), batchContext.Coinbase.String(), + batchContext.ForcedBatchNum, ) return err } @@ -939,6 +909,12 @@ func (p *PostgresStorage) IsBatchClosed(ctx context.Context, batchNum uint64, db // GetNextForcedBatches gets the next forced batches from the queue. func (p *PostgresStorage) GetNextForcedBatches(ctx context.Context, nextForcedBatches int, dbTx pgx.Tx) ([]ForcedBatch, error) { + const getNextForcedBatchesSQL = ` + SELECT forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, block_num + FROM state.forced_batch + WHERE forced_batch_num > (Select coalesce(max(forced_batch_num),0) as forced_batch_num from state.batch INNER JOIN state.virtual_batch ON state.virtual_batch.batch_num = state.batch.batch_num) + ORDER BY forced_batch_num ASC LIMIT $1; + ` q := p.getExecQuerier(dbTx) // Get the next forced batches rows, err := q.Query(ctx, getNextForcedBatchesSQL, nextForcedBatches) @@ -959,7 +935,7 @@ func (p *PostgresStorage) GetNextForcedBatches(ctx context.Context, nextForcedBa rawTxs string seq string ) - err := rows.Scan(&forcedBatch.ForcedBatchNumber, &globalExitRoot, &forcedBatch.ForcedAt, &rawTxs, &seq, &forcedBatch.BatchNumber, &forcedBatch.BlockNumber) + err := rows.Scan(&forcedBatch.ForcedBatchNumber, &globalExitRoot, &forcedBatch.ForcedAt, &rawTxs, &seq, &forcedBatch.BlockNumber) if err != nil { return nil, err } @@ -975,13 +951,6 @@ func (p *PostgresStorage) GetNextForcedBatches(ctx context.Context, nextForcedBa return batches, nil } -// AddBatchNumberInForcedBatch updates the forced_batch table with the batchNumber. -func (p *PostgresStorage) AddBatchNumberInForcedBatch(ctx context.Context, forceBatchNumber, batchNumber uint64, dbTx pgx.Tx) error { - e := p.getExecQuerier(dbTx) - _, err := e.Exec(ctx, addBatchNumberInForcedBatchSQL, forceBatchNumber, batchNumber) - return err -} - // GetBatchNumberOfL2Block gets a batch number for l2 block by its number func (p *PostgresStorage) GetBatchNumberOfL2Block(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (uint64, error) { getBatchNumByBlockNum := "SELECT batch_num FROM state.l2block WHERE block_num = $1" @@ -1803,7 +1772,8 @@ func (p *PostgresStorage) GetVirtualBatchToProve(ctx context.Context, lastVerfie b.state_root, b.timestamp, b.coinbase, - b.raw_txs_data + b.raw_txs_data, + b.forced_batch_num FROM state.batch b, state.virtual_batch v diff --git a/state/state.go b/state/state.go index fcb8ca9ab6..ec6299660a 100644 --- a/state/state.go +++ b/state/state.go @@ -1281,6 +1281,7 @@ func (s *State) SetGenesis(ctx context.Context, block Block, genesis Genesis, db Timestamp: block.ReceivedAt, Transactions: []types.Transaction{}, GlobalExitRoot: ZeroHash, + ForcedBatchNum: nil, } err = s.storeGenesisBatch(ctx, batch, dbTx) diff --git a/state/state_test.go b/state/state_test.go index 81293001a3..6d8567b94c 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -278,11 +278,9 @@ func TestAddForcedBatch(t *testing.T) { assert.NoError(t, err) b := common.Hex2Bytes("0x617b3a3528F9") assert.NoError(t, err) - var bN uint64 = 3 forcedBatch := state.ForcedBatch{ BlockNumber: 1, ForcedBatchNumber: 2, - BatchNumber: &bN, GlobalExitRoot: common.HexToHash("0x29e885edaf8e4b51e1d2e05f9da28161d2fb4f6b1d53827d9b80a23cf2d7d9f1"), Sequencer: common.HexToAddress("0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D"), RawTxsData: b, @@ -295,7 +293,6 @@ func TestAddForcedBatch(t *testing.T) { err = tx.Commit(ctx) require.NoError(t, err) assert.Equal(t, forcedBatch.BlockNumber, fb.BlockNumber) - assert.Equal(t, forcedBatch.BatchNumber, fb.BatchNumber) assert.Equal(t, forcedBatch.ForcedBatchNumber, fb.ForcedBatchNumber) assert.NotEqual(t, time.Time{}, fb.ForcedAt) assert.Equal(t, forcedBatch.GlobalExitRoot, fb.GlobalExitRoot) @@ -306,7 +303,6 @@ func TestAddForcedBatch(t *testing.T) { forcedBatch = state.ForcedBatch{ BlockNumber: 1, ForcedBatchNumber: 3, - BatchNumber: nil, GlobalExitRoot: common.HexToHash("0x29e885edaf8e4b51e1d2e05f9da28161d2fb4f6b1d53827d9b80a23cf2d7d9f1"), Sequencer: common.HexToAddress("0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D"), RawTxsData: b, @@ -314,23 +310,25 @@ func TestAddForcedBatch(t *testing.T) { } err = testState.AddForcedBatch(ctx, &forcedBatch, tx) require.NoError(t, err) + + _, err = testState.PostgresStorage.Exec(ctx, "INSERT INTO state.batch (batch_num, forced_batch_num) VALUES (2, 2)") + assert.NoError(t, err) + virtualBatch := state.VirtualBatch{ + BlockNumber: 1, + BatchNumber: 2, + TxHash: common.HexToHash("0x29e885edaf8e4b51e1d2e05f9da28161d2fb4f6b1d53827d9b80a23cf2d7d9f1"), + Coinbase: common.HexToAddress("0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D"), + } + err = testState.AddVirtualBatch(ctx, &virtualBatch, tx) + require.NoError(t, err) + batches, err := testState.GetNextForcedBatches(ctx, 1, tx) require.NoError(t, err) - require.NoError(t, tx.Commit(ctx)) assert.Equal(t, forcedBatch.BlockNumber, batches[0].BlockNumber) - assert.Equal(t, forcedBatch.BatchNumber, batches[0].BatchNumber) assert.Equal(t, forcedBatch.ForcedBatchNumber, batches[0].ForcedBatchNumber) assert.NotEqual(t, time.Time{}, batches[0].ForcedAt) assert.Equal(t, forcedBatch.GlobalExitRoot, batches[0].GlobalExitRoot) assert.Equal(t, forcedBatch.RawTxsData, batches[0].RawTxsData) - // Test AddBatchNumberInForcedBatch - tx, err = testState.BeginStateTransaction(ctx) - require.NoError(t, err) - err = testState.AddBatchNumberInForcedBatch(ctx, 3, 2, tx) - require.NoError(t, err) - fb, err = testState.GetForcedBatch(ctx, 3, tx) - require.NoError(t, err) - assert.Equal(t, uint64(2), *fb.BatchNumber) require.NoError(t, tx.Commit(ctx)) } diff --git a/synchronizer/interfaces.go b/synchronizer/interfaces.go index 7eef8b46ca..273a7b5141 100644 --- a/synchronizer/interfaces.go +++ b/synchronizer/interfaces.go @@ -35,7 +35,6 @@ type stateInterface interface { AddVirtualBatch(ctx context.Context, virtualBatch *state.VirtualBatch, dbTx pgx.Tx) error // GetNextForcedBatches returns the next forcedBatches in FIFO order GetNextForcedBatches(ctx context.Context, nextForcedBatches int, dbTx pgx.Tx) ([]state.ForcedBatch, error) - AddBatchNumberInForcedBatch(ctx context.Context, forceBatchNumber, batchNumber uint64, dbTx pgx.Tx) error AddVerifiedBatch(ctx context.Context, verifiedBatch *state.VerifiedBatch, dbTx pgx.Tx) error ProcessAndStoreClosedBatch(ctx context.Context, processingCtx state.ProcessingContext, encodedTxs []byte, dbTx pgx.Tx, caller state.CallerLabel) error SetGenesis(ctx context.Context, block state.Block, genesis state.Genesis, dbTx pgx.Tx) ([]byte, error) diff --git a/synchronizer/mock_state.go b/synchronizer/mock_state.go index 5611d60248..a12d15e234 100644 --- a/synchronizer/mock_state.go +++ b/synchronizer/mock_state.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.14.0. DO NOT EDIT. package synchronizer @@ -23,20 +23,6 @@ type stateMock struct { mock.Mock } -// AddBatchNumberInForcedBatch provides a mock function with given fields: ctx, forceBatchNumber, batchNumber, dbTx -func (_m *stateMock) AddBatchNumberInForcedBatch(ctx context.Context, forceBatchNumber uint64, batchNumber uint64, dbTx pgx.Tx) error { - ret := _m.Called(ctx, forceBatchNumber, batchNumber, dbTx) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, pgx.Tx) error); ok { - r0 = rf(ctx, forceBatchNumber, batchNumber, dbTx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // AddBlock provides a mock function with given fields: ctx, block, dbTx func (_m *stateMock) AddBlock(ctx context.Context, block *state.Block, dbTx pgx.Tx) error { ret := _m.Called(ctx, block, dbTx) diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 6044fde5bc..76778e20ed 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -562,7 +562,7 @@ func (s *ClientSynchronizer) processSequenceBatches(sequencedBatches []etherman. BatchL2Data: sbatch.Transactions, } // ForcedBatch must be processed - if sbatch.MinForcedTimestamp > 0 { + if sbatch.MinForcedTimestamp > 0 { // If this is true means that the batch is forced // Read forcedBatches from db forcedBatches, err := s.state.GetNextForcedBatches(s.ctx, 1, dbTx) if err != nil { @@ -581,34 +581,22 @@ func (s *ClientSynchronizer) processSequenceBatches(sequencedBatches []etherman. log.Errorf("error rolling back state. BatchNumber: %d, BlockNumber: %d, rollbackErr: %w", sbatch.BatchNumber, blockNumber, rollbackErr) return rollbackErr } - log.Errorf("error: empty forcedBatches array read from db. BatchNumber: %d", sbatch.BatchNumber) return fmt.Errorf("error: empty forcedBatches array read from db. BatchNumber: %d", sbatch.BatchNumber) } if uint64(forcedBatches[0].ForcedAt.Unix()) != sbatch.MinForcedTimestamp || forcedBatches[0].GlobalExitRoot != sbatch.GlobalExitRoot || - common.Bytes2Hex(forcedBatches[0].RawTxsData) != common.Bytes2Hex(sbatch.Transactions) || - forcedBatches[0].Sequencer != sbatch.Coinbase { + common.Bytes2Hex(forcedBatches[0].RawTxsData) != common.Bytes2Hex(sbatch.Transactions) { + log.Warnf("ForcedBatch stored: %+v", forcedBatches) + log.Warnf("ForcedBatch sequenced received: %+v", sbatch) log.Errorf("error: forcedBatch received doesn't match with the next expected forcedBatch stored in db. Expected: %+v, Synced: %+v", forcedBatches, sbatch) rollbackErr := dbTx.Rollback(s.ctx) if rollbackErr != nil { log.Errorf("error rolling back state. BatchNumber: %d, BlockNumber: %d, rollbackErr: %w", virtualBatch.BatchNumber, blockNumber, rollbackErr) return rollbackErr } - log.Errorf("error: forcedBatch received doesn't match with the next expected forcedBatch stored in db. Expected: %+v, Synced: %+v", forcedBatches, sbatch) return fmt.Errorf("error: forcedBatch received doesn't match with the next expected forcedBatch stored in db. Expected: %+v, Synced: %+v", forcedBatches, sbatch) } - // Store batchNumber in forced_batch table - err = s.state.AddBatchNumberInForcedBatch(s.ctx, forcedBatches[0].ForcedBatchNumber, sbatch.BatchNumber, dbTx) - if err != nil { - log.Errorf("error adding the batchNumber to forcedBatch in processSequenceBatches. BlockNumber: %d", blockNumber) - rollbackErr := dbTx.Rollback(s.ctx) - if rollbackErr != nil { - log.Errorf("error rolling back state. BlockNumber: %d, rollbackErr: %s, error : %w", blockNumber, rollbackErr.Error(), err) - return rollbackErr - } - log.Errorf("error adding the batchNumber to forcedBatch in processSequenceBatches. BlockNumber: %d, error: %w", blockNumber, err) - return err - } + batch.ForcedBatchNum = &forcedBatches[0].ForcedBatchNumber } // Now we need to check the batch. ForcedBatches should be already stored in the batch table because this is done by the sequencer @@ -617,6 +605,7 @@ func (s *ClientSynchronizer) processSequenceBatches(sequencedBatches []etherman. Coinbase: batch.Coinbase, Timestamp: batch.Timestamp, GlobalExitRoot: batch.GlobalExitRoot, + ForcedBatchNum: batch.ForcedBatchNum, } // Call the check trusted state method to compare trusted and virtual state status, err := s.checkTrustedState(batch, dbTx) @@ -758,15 +747,15 @@ func (s *ClientSynchronizer) processSequenceForceBatch(sequenceForceBatch []ethe for i, fbatch := range sequenceForceBatch { if uint64(forcedBatches[i].ForcedAt.Unix()) != fbatch.MinForcedTimestamp || forcedBatches[i].GlobalExitRoot != fbatch.GlobalExitRoot || - common.Bytes2Hex(forcedBatches[i].RawTxsData) != common.Bytes2Hex(fbatch.Transactions) || - forcedBatches[i].Sequencer != fbatch.Coinbase { + common.Bytes2Hex(forcedBatches[i].RawTxsData) != common.Bytes2Hex(fbatch.Transactions) { + log.Warnf("ForcedBatch stored: %+v", forcedBatches) + log.Warnf("ForcedBatch sequenced received: %+v", fbatch) log.Errorf("error: forcedBatch received doesn't match with the next expected forcedBatch stored in db. Expected: %+v, Synced: %+v", forcedBatches[i], fbatch) rollbackErr := dbTx.Rollback(s.ctx) if rollbackErr != nil { log.Errorf("error rolling back state. BatchNumber: %d, BlockNumber: %d, rollbackErr: %w", fbatch.BatchNumber, block.BlockNumber, rollbackErr) return rollbackErr } - log.Errorf("error: forcedBatch received doesn't match with the next expected forcedBatch stored in db. Expected: %+v, Synced: %+v", forcedBatches[i], fbatch) return fmt.Errorf("error: forcedBatch received doesn't match with the next expected forcedBatch stored in db. Expected: %+v, Synced: %+v", forcedBatches[i], fbatch) } virtualBatch := state.VirtualBatch{ @@ -780,6 +769,7 @@ func (s *ClientSynchronizer) processSequenceForceBatch(sequenceForceBatch []ethe GlobalExitRoot: fbatch.GlobalExitRoot, Timestamp: block.ReceivedAt, Coinbase: fbatch.Coinbase, + ForcedBatchNum: &forcedBatches[i].ForcedBatchNumber, } // Process batch err := s.state.ProcessAndStoreClosedBatch(s.ctx, batch, forcedBatches[i].RawTxsData, dbTx, state.SynchronizerCallerLabel) @@ -805,18 +795,6 @@ func (s *ClientSynchronizer) processSequenceForceBatch(sequenceForceBatch []ethe log.Errorf("error storing virtualBatch in processSequenceForceBatch. BatchNumber: %d, BlockNumber: %d, error: %w", virtualBatch.BatchNumber, block.BlockNumber, err) return err } - // Store batchNumber in forced_batch table - err = s.state.AddBatchNumberInForcedBatch(s.ctx, forcedBatches[i].ForcedBatchNumber, virtualBatch.BatchNumber, dbTx) - if err != nil { - log.Errorf("error adding the batchNumber to forcedBatch in processSequenceForceBatch. BlockNumber: %d", block.BlockNumber) - rollbackErr := dbTx.Rollback(s.ctx) - if rollbackErr != nil { - log.Errorf("error rolling back state. BlockNumber: %d, rollbackErr: %s, error : %w", block.BlockNumber, rollbackErr.Error(), err) - return rollbackErr - } - log.Errorf("error adding the batchNumber to forcedBatch in processSequenceForceBatch. BlockNumber: %d, error: %w", block.BlockNumber, err) - return err - } } // Insert the sequence to allow the aggregator verify the sequence batches seq := state.Sequence{ @@ -841,7 +819,6 @@ func (s *ClientSynchronizer) processForcedBatch(forcedBatch etherman.ForcedBatch // Store forced batch into the db forcedB := state.ForcedBatch{ BlockNumber: forcedBatch.BlockNumber, - BatchNumber: nil, ForcedBatchNumber: forcedBatch.ForcedBatchNumber, Sequencer: forcedBatch.Sequencer, GlobalExitRoot: forcedBatch.GlobalExitRoot, @@ -1036,14 +1013,6 @@ func (s *ClientSynchronizer) processTrustedBatch(trustedBatch *pb.GetBatchRespon } } - if trustedBatch.ForcedBatchNumber > 0 { - log.Debugf("adding batch num %v for forced batch %v", trustedBatch.BatchNumber, trustedBatch.ForcedBatchNumber) - if err := s.state.AddBatchNumberInForcedBatch(s.ctx, trustedBatch.ForcedBatchNumber, trustedBatch.BatchNumber, dbTx); err != nil { - log.Errorf("error adding batch %v for forced batch %v", trustedBatch.BatchNumber, trustedBatch.ForcedBatchNumber) - return err - } - } - log.Infof("batch %v synchronized", trustedBatch.BatchNumber) return nil } diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index 1dfb3a121f..12a134eaaa 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -259,3 +259,399 @@ func TestTrustedStateReorg(t *testing.T) { }) } } + +func TestForcedBatch(t *testing.T) { + genesis := state.Genesis{} + cfg := Config{ + SyncInterval: cfgTypes.Duration{Duration: 1 * time.Second}, + SyncChunkSize: 10, + GenBlockNumber: uint64(123456), + } + + m := mocks{ + Etherman: newEthermanMock(t), + State: newStateMock(t), + DbTx: newDbTxMock(t), + } + + sync, err := NewSynchronizer(true, m.Etherman, m.State, genesis, cfg) + require.NoError(t, err) + + // state preparation + ctxMatchBy := mock.MatchedBy(func(ctx context.Context) bool { return ctx != nil }) + m.State. + On("BeginStateTransaction", ctxMatchBy). + Run(func(args mock.Arguments) { + ctx := args[0].(context.Context) + parentHash := common.HexToHash("0x111") + ethHeader := &types.Header{Number: big.NewInt(1), ParentHash: parentHash} + ethBlock := types.NewBlockWithHeader(ethHeader) + lastBlock := &state.Block{BlockHash: ethBlock.Hash(), BlockNumber: ethBlock.Number().Uint64()} + + m.State. + On("GetLastBlock", ctx, m.DbTx). + Return(lastBlock, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock.BlockNumber). + Return(ethBlock, nil). + Once() + + var n *big.Int + m.Etherman. + On("HeaderByNumber", ctx, n). + Return(ethHeader, nil). + Once() + + sequencedBatch := etherman.SequencedBatch{ + BatchNumber: uint64(2), + Coinbase: common.HexToAddress("0x222"), + TxHash: common.HexToHash("0x333"), + ProofOfEfficiencyBatchData: proofofefficiency.ProofOfEfficiencyBatchData{ + Transactions: []byte{}, + GlobalExitRoot: [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, + Timestamp: uint64(time.Now().Unix()), + MinForcedTimestamp: 1000, //ForcedBatch + }, + } + + forceb := []etherman.ForcedBatch{{ + BlockNumber: lastBlock.BlockNumber, + ForcedBatchNumber: 1, + Sequencer: sequencedBatch.Coinbase, + GlobalExitRoot: sequencedBatch.GlobalExitRoot, + RawTxsData: sequencedBatch.Transactions, + ForcedAt: time.Unix(int64(sequencedBatch.MinForcedTimestamp), 0), + }} + + ethermanBlock := etherman.Block{ + BlockHash: ethBlock.Hash(), + SequencedBatches: [][]etherman.SequencedBatch{{sequencedBatch}}, + ForcedBatches: forceb, + } + blocks := []etherman.Block{ethermanBlock} + order := map[common.Hash][]etherman.Order{ + ethBlock.Hash(): { + { + Name: etherman.ForcedBatchesOrder, + Pos: 0, + }, + { + Name: etherman.SequenceBatchesOrder, + Pos: 0, + }, + }, + } + + fromBlock := ethBlock.NumberU64() + 1 + toBlock := fromBlock + cfg.SyncChunkSize + + m.Etherman. + On("GetRollupInfoByBlockRange", ctx, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock := &state.Block{ + BlockNumber: ethermanBlock.BlockNumber, + BlockHash: ethermanBlock.BlockHash, + ParentHash: ethermanBlock.ParentHash, + ReceivedAt: ethermanBlock.ReceivedAt, + } + + m.State. + On("AddBlock", ctx, stateBlock, m.DbTx). + Return(nil). + Once() + + fb := []state.ForcedBatch{{ + BlockNumber: lastBlock.BlockNumber, + ForcedBatchNumber: 1, + Sequencer: sequencedBatch.Coinbase, + GlobalExitRoot: sequencedBatch.GlobalExitRoot, + RawTxsData: sequencedBatch.Transactions, + ForcedAt: time.Unix(int64(sequencedBatch.MinForcedTimestamp), 0), + }} + + m.State. + On("AddForcedBatch", ctx, &fb[0], m.DbTx). + Return(nil). + Once() + + m.State. + On("GetNextForcedBatches", ctx, 1, m.DbTx). + Return(fb, nil). + Once() + + trustedBatch := &state.Batch{ + BatchL2Data: sequencedBatch.Transactions, + GlobalExitRoot: sequencedBatch.GlobalExitRoot, + Timestamp: time.Unix(int64(sequencedBatch.Timestamp), 0), + Coinbase: sequencedBatch.Coinbase, + } + + m.State. + On("GetBatchByNumber", ctx, sequencedBatch.BatchNumber, m.DbTx). + Return(trustedBatch, nil). + Once() + + m.State. //ExecuteBatch(s.ctx, batch.BatchNumber, batch.BatchL2Data, dbTx + On("ExecuteBatch", ctx, sequencedBatch.BatchNumber, sequencedBatch.Transactions, m.DbTx). + Return(&pb.ProcessBatchResponse{NewStateRoot: trustedBatch.StateRoot.Bytes()}, nil). + Once() + + virtualBatch := &state.VirtualBatch{ + BatchNumber: sequencedBatch.BatchNumber, + TxHash: sequencedBatch.TxHash, + Coinbase: sequencedBatch.Coinbase, + BlockNumber: ethermanBlock.BlockNumber, + } + + m.State. + On("AddVirtualBatch", ctx, virtualBatch, m.DbTx). + Return(nil). + Once() + + seq := state.Sequence{ + FromBatchNumber: 2, + ToBatchNumber: 2, + } + m.State. + On("AddSequence", ctx, seq, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Run(func(args mock.Arguments) { sync.Stop() }). + Return(nil). + Once() + + m.Etherman. + On("GetLatestBatchNumber"). + Return(uint64(10), nil). + Once() + + var nilDbTx pgx.Tx + m.State. + On("GetLastBatchNumber", ctx, nilDbTx). + Return(uint64(10), nil). + Once() + }). + Return(m.DbTx, nil). + Once() + + err = sync.Sync() + require.NoError(t, err) +} + +func TestSequenceForcedBatch(t *testing.T) { + genesis := state.Genesis{} + cfg := Config{ + SyncInterval: cfgTypes.Duration{Duration: 1 * time.Second}, + SyncChunkSize: 10, + GenBlockNumber: uint64(123456), + } + + m := mocks{ + Etherman: newEthermanMock(t), + State: newStateMock(t), + DbTx: newDbTxMock(t), + } + + sync, err := NewSynchronizer(true, m.Etherman, m.State, genesis, cfg) + require.NoError(t, err) + + // state preparation + ctxMatchBy := mock.MatchedBy(func(ctx context.Context) bool { return ctx != nil }) + m.State. + On("BeginStateTransaction", ctxMatchBy). + Run(func(args mock.Arguments) { + ctx := args[0].(context.Context) + parentHash := common.HexToHash("0x111") + ethHeader := &types.Header{Number: big.NewInt(1), ParentHash: parentHash} + ethBlock := types.NewBlockWithHeader(ethHeader) + lastBlock := &state.Block{BlockHash: ethBlock.Hash(), BlockNumber: ethBlock.Number().Uint64()} + + m.State. + On("GetLastBlock", ctx, m.DbTx). + Return(lastBlock, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock.BlockNumber). + Return(ethBlock, nil). + Once() + + var n *big.Int + m.Etherman. + On("HeaderByNumber", ctx, n). + Return(ethHeader, nil). + Once() + + sequencedForceBatch := etherman.SequencedForceBatch{ + BatchNumber: uint64(2), + Coinbase: common.HexToAddress("0x222"), + TxHash: common.HexToHash("0x333"), + ProofOfEfficiencyForcedBatchData: proofofefficiency.ProofOfEfficiencyForcedBatchData{ + Transactions: []byte{}, + GlobalExitRoot: [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, + MinForcedTimestamp: 1000, //ForcedBatch + }, + } + + forceb := []etherman.ForcedBatch{{ + BlockNumber: lastBlock.BlockNumber, + ForcedBatchNumber: 1, + Sequencer: sequencedForceBatch.Coinbase, + GlobalExitRoot: sequencedForceBatch.GlobalExitRoot, + RawTxsData: sequencedForceBatch.Transactions, + ForcedAt: time.Unix(int64(sequencedForceBatch.MinForcedTimestamp), 0), + }} + + ethermanBlock := etherman.Block{ + BlockHash: ethBlock.Hash(), + SequencedForceBatches: [][]etherman.SequencedForceBatch{{sequencedForceBatch}}, + ForcedBatches: forceb, + } + blocks := []etherman.Block{ethermanBlock} + order := map[common.Hash][]etherman.Order{ + ethBlock.Hash(): { + { + Name: etherman.ForcedBatchesOrder, + Pos: 0, + }, + { + Name: etherman.SequenceForceBatchesOrder, + Pos: 0, + }, + }, + } + + fromBlock := ethBlock.NumberU64() + 1 + toBlock := fromBlock + cfg.SyncChunkSize + + m.Etherman. + On("GetRollupInfoByBlockRange", ctx, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock := &state.Block{ + BlockNumber: ethermanBlock.BlockNumber, + BlockHash: ethermanBlock.BlockHash, + ParentHash: ethermanBlock.ParentHash, + ReceivedAt: ethermanBlock.ReceivedAt, + } + + m.State. + On("AddBlock", ctx, stateBlock, m.DbTx). + Return(nil). + Once() + + fb := []state.ForcedBatch{{ + BlockNumber: lastBlock.BlockNumber, + ForcedBatchNumber: 1, + Sequencer: sequencedForceBatch.Coinbase, + GlobalExitRoot: sequencedForceBatch.GlobalExitRoot, + RawTxsData: sequencedForceBatch.Transactions, + ForcedAt: time.Unix(int64(sequencedForceBatch.MinForcedTimestamp), 0), + }} + + m.State. + On("AddForcedBatch", ctx, &fb[0], m.DbTx). + Return(nil). + Once() + + m.State. + On("GetLastVirtualBatchNum", ctx, m.DbTx). + Return(uint64(1), nil). + Once() + + m.State. + On("ResetTrustedState", ctx, uint64(1), m.DbTx). + Return(nil). + Once() + + m.State. + On("GetNextForcedBatches", ctx, 1, m.DbTx). + Return(fb, nil). + Once() + + f := uint64(1) + processingContext := state.ProcessingContext{ + BatchNumber: sequencedForceBatch.BatchNumber, + Coinbase: sequencedForceBatch.Coinbase, + Timestamp: ethBlock.ReceivedAt, + GlobalExitRoot: sequencedForceBatch.GlobalExitRoot, + ForcedBatchNum: &f, + } + + m.State. + On("ProcessAndStoreClosedBatch", ctx, processingContext, sequencedForceBatch.Transactions, m.DbTx, state.SynchronizerCallerLabel). + Return(nil). + Once() + + virtualBatch := &state.VirtualBatch{ + BatchNumber: sequencedForceBatch.BatchNumber, + TxHash: sequencedForceBatch.TxHash, + Coinbase: sequencedForceBatch.Coinbase, + BlockNumber: ethermanBlock.BlockNumber, + } + + m.State. + On("AddVirtualBatch", ctx, virtualBatch, m.DbTx). + Return(nil). + Once() + + seq := state.Sequence{ + FromBatchNumber: 2, + ToBatchNumber: 2, + } + m.State. + On("AddSequence", ctx, seq, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Run(func(args mock.Arguments) { sync.Stop() }). + Return(nil). + Once() + + m.Etherman. + On("GetLatestBatchNumber"). + Return(uint64(10), nil). + Once() + + var nilDbTx pgx.Tx + m.State. + On("GetLastBatchNumber", ctx, nilDbTx). + Return(uint64(10), nil). + Once() + }). + Return(m.DbTx, nil). + Once() + + err = sync.Sync() + require.NoError(t, err) +} diff --git a/test/e2e/broadcast_test.go b/test/e2e/broadcast_test.go index da55412d6f..85730d4893 100644 --- a/test/e2e/broadcast_test.go +++ b/test/e2e/broadcast_test.go @@ -100,11 +100,22 @@ func populateDB(ctx context.Context, st *state.State) error { var parentHash common.Hash var l2Block types.Block - const addBatch = "INSERT INTO state.batch (batch_num, global_exit_root, timestamp, coinbase, local_exit_root, state_root) VALUES ($1, $2, $3, $4, $5, $6)" - for i := 1; i <= totalBatches; i++ { - if _, err := st.PostgresStorage.Exec(ctx, addBatch, i, ger.String(), time.Now(), common.HexToAddress("").String(), common.Hash{}.String(), common.Hash{}.String()); err != nil { - return err - } + const addBlock = "INSERT INTO state.block (block_num, received_at, block_hash) VALUES ($1, $2, $3)" + if _, err := st.PostgresStorage.Exec(ctx, addBlock, blockNumber, time.Now(), ""); err != nil { + return err + } + + const addForcedBatch = "INSERT INTO state.forced_batch (forced_batch_num, global_exit_root, raw_txs_data, coinbase, timestamp, block_num) VALUES ($1, $2, $3, $4, $5, $6)" + if _, err := st.PostgresStorage.Exec(ctx, addForcedBatch, forcedBatchNumber, ger.String(), "", common.HexToAddress("").String(), time.Now(), blockNumber); err != nil { + return err + } + + const addBatch = "INSERT INTO state.batch (batch_num, global_exit_root, timestamp, coinbase, local_exit_root, state_root, forced_batch_num) VALUES ($1, $2, $3, $4, $5, $6, $7)" + if _, err := st.PostgresStorage.Exec(ctx, addBatch, 1, ger.String(), time.Now(), common.HexToAddress("").String(), common.Hash{}.String(), common.Hash{}.String(), nil); err != nil { + return err + } + if _, err := st.PostgresStorage.Exec(ctx, addBatch, 2, ger.String(), time.Now(), common.HexToAddress("").String(), common.Hash{}.String(), common.Hash{}.String(), forcedBatchNumber); err != nil { + return err } for i := 1; i <= totalTxsLastBatch; i++ { @@ -134,16 +145,6 @@ func populateDB(ctx context.Context, st *state.State) error { } } - const addBlock = "INSERT INTO state.block (block_num, received_at, block_hash) VALUES ($1, $2, $3)" - if _, err := st.PostgresStorage.Exec(ctx, addBlock, blockNumber, time.Now(), ""); err != nil { - return err - } - - const addForcedBatch = "INSERT INTO state.forced_batch (forced_batch_num, global_exit_root, raw_txs_data, coinbase, timestamp, batch_num, block_num) VALUES ($1, $2, $3, $4, $5, $6, $7)" - if _, err := st.PostgresStorage.Exec(ctx, addForcedBatch, forcedBatchNumber, ger.String(), "", common.HexToAddress("").String(), time.Now(), totalBatches, blockNumber); err != nil { - return err - } - const addExitRoots = "INSERT INTO state.exit_root (block_num, global_exit_root, mainnet_exit_root, rollup_exit_root) VALUES ($1, $2, $3, $4)" _, err := st.PostgresStorage.Exec(ctx, addExitRoots, blockNumber, ger, mainnetExitRoot, rollupExitRoot) return err