diff --git a/state/interfaces.go b/state/interfaces.go index 6b0cf82e68..3a0edec4be 100644 --- a/state/interfaces.go +++ b/state/interfaces.go @@ -60,6 +60,7 @@ type storage interface { GetBatchNumberOfL2Block(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (uint64, error) BatchNumberByL2BlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (uint64, error) GetL2BlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*L2Block, error) + GetL2BlockHashByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (common.Hash, error) GetL2BlocksByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) ([]L2Block, error) GetLastL2BlockCreatedAt(ctx context.Context, dbTx pgx.Tx) (*time.Time, error) GetTransactionByHash(ctx context.Context, transactionHash common.Hash, dbTx pgx.Tx) (*types.Transaction, error) diff --git a/state/mocks/mock_storage.go b/state/mocks/mock_storage.go index eac22d7cf5..5f943ec7d3 100644 --- a/state/mocks/mock_storage.go +++ b/state/mocks/mock_storage.go @@ -2888,6 +2888,66 @@ func (_c *StorageMock_GetL2BlockByNumber_Call) RunAndReturn(run func(context.Con return _c } +// GetL2BlockHashByNumber provides a mock function with given fields: ctx, blockNumber, dbTx +func (_m *StorageMock) GetL2BlockHashByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (common.Hash, error) { + ret := _m.Called(ctx, blockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetL2BlockHashByNumber") + } + + var r0 common.Hash + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) (common.Hash, error)); ok { + return rf(ctx, blockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) common.Hash); ok { + r0 = rf(ctx, blockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.Hash) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, blockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StorageMock_GetL2BlockHashByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL2BlockHashByNumber' +type StorageMock_GetL2BlockHashByNumber_Call struct { + *mock.Call +} + +// GetL2BlockHashByNumber is a helper method to define mock.On call +// - ctx context.Context +// - blockNumber uint64 +// - dbTx pgx.Tx +func (_e *StorageMock_Expecter) GetL2BlockHashByNumber(ctx interface{}, blockNumber interface{}, dbTx interface{}) *StorageMock_GetL2BlockHashByNumber_Call { + return &StorageMock_GetL2BlockHashByNumber_Call{Call: _e.mock.On("GetL2BlockHashByNumber", ctx, blockNumber, dbTx)} +} + +func (_c *StorageMock_GetL2BlockHashByNumber_Call) Run(run func(ctx context.Context, blockNumber uint64, dbTx pgx.Tx)) *StorageMock_GetL2BlockHashByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(pgx.Tx)) + }) + return _c +} + +func (_c *StorageMock_GetL2BlockHashByNumber_Call) Return(_a0 common.Hash, _a1 error) *StorageMock_GetL2BlockHashByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StorageMock_GetL2BlockHashByNumber_Call) RunAndReturn(run func(context.Context, uint64, pgx.Tx) (common.Hash, error)) *StorageMock_GetL2BlockHashByNumber_Call { + _c.Call.Return(run) + return _c +} + // GetL2BlockHashesSince provides a mock function with given fields: ctx, since, dbTx func (_m *StorageMock) GetL2BlockHashesSince(ctx context.Context, since time.Time, dbTx pgx.Tx) ([]common.Hash, error) { ret := _m.Called(ctx, since, dbTx) diff --git a/state/pgstatestorage/l2block.go b/state/pgstatestorage/l2block.go index a01853931d..fe68559387 100644 --- a/state/pgstatestorage/l2block.go +++ b/state/pgstatestorage/l2block.go @@ -424,6 +424,27 @@ func (p *PostgresStorage) GetL2BlockHeaderByNumber(ctx context.Context, blockNum return header, nil } +// GetL2BlockHashByNumber gets the block hash by block number +func (p *PostgresStorage) GetL2BlockHashByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (common.Hash, error) { + const getL2BlockHeaderByNumberSQL = "SELECT block_hash FROM state.l2block b WHERE b.block_num = $1" + + blockHash := state.ZeroHash + + var blockHashStr string + q := p.getExecQuerier(dbTx) + err := q.QueryRow(ctx, getL2BlockHeaderByNumberSQL, blockNumber).Scan(&blockHashStr) + + if errors.Is(err, pgx.ErrNoRows) { + return blockHash, state.ErrNotFound + } else if err != nil { + return blockHash, err + } + + blockHash = common.HexToHash(blockHashStr) + + return blockHash, nil +} + // GetL2BlockHashesSince gets the block hashes added since the provided date func (p *PostgresStorage) GetL2BlockHashesSince(ctx context.Context, since time.Time, dbTx pgx.Tx) ([]common.Hash, error) { const getL2BlockHashesSinceSQL = "SELECT block_hash FROM state.l2block WHERE created_at >= $1" diff --git a/state/transaction.go b/state/transaction.go index cca22989b6..083fd2e3be 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -203,11 +203,16 @@ func (s *State) StoreL2Block(ctx context.Context, batchNumber uint64, l2Block *P log.Debugf("storing l2 block %d, txs %d, hash %s", l2Block.BlockNumber, len(l2Block.TransactionResponses), l2Block.BlockHash.String()) start := time.Now() + prevL2BlockHash, err := s.GetL2BlockHashByNumber(ctx, l2Block.BlockNumber-1, dbTx) + if err != nil { + return err + } + header := &types.Header{ Number: new(big.Int).SetUint64(l2Block.BlockNumber), - ParentHash: l2Block.ParentHash, + ParentHash: prevL2BlockHash, Coinbase: l2Block.Coinbase, - Root: l2Block.BlockHash, //BlockHash is the StateRoot in Etrog + Root: l2Block.BlockHash, //BlockHash returned by the executor is the StateRoot in Etrog GasUsed: l2Block.GasUsed, GasLimit: s.cfg.MaxCumulativeGasUsed, Time: l2Block.Timestamp,