diff --git a/db/migrations/state/0017.sql b/db/migrations/state/0017.sql new file mode 100644 index 0000000000..1c06607dfe --- /dev/null +++ b/db/migrations/state/0017.sql @@ -0,0 +1,9 @@ +-- +migrate Up +ALTER TABLE state.receipt + ADD COLUMN IF NOT EXISTS im_state_root BYTEA; + +UPDATE state.receipt SET im_state_root = post_state WHERE block_num >= (SELECT MIN(block_num) FROM state.l2block WHERE batch_num >= (SELECT from_batch_num FROM state.fork_id WHERE fork_id = 7)); + +-- +migrate Down +ALTER TABLE state.receipt + DROP COLUMN IF EXISTS im_state_root; diff --git a/jsonrpc/endpoints_eth_test.go b/jsonrpc/endpoints_eth_test.go index 60067ab1b3..33f4b1ec9c 100644 --- a/jsonrpc/endpoints_eth_test.go +++ b/jsonrpc/endpoints_eth_test.go @@ -3311,7 +3311,7 @@ func TestGetTransactionReceipt(t *testing.T) { receipt.Bloom = ethTypes.CreateBloom(ethTypes.Receipts{receipt}) rpcReceipt := types.Receipt{ - Root: stateRoot, + Root: &stateRoot, CumulativeGasUsed: types.ArgUint64(receipt.CumulativeGasUsed), LogsBloom: receipt.Bloom, Logs: receipt.Logs, diff --git a/jsonrpc/endpoints_zkevm_test.go b/jsonrpc/endpoints_zkevm_test.go index 85db81328b..8c0090d1e2 100644 --- a/jsonrpc/endpoints_zkevm_test.go +++ b/jsonrpc/endpoints_zkevm_test.go @@ -2260,7 +2260,7 @@ func TestGetTransactionReceiptByL2Hash(t *testing.T) { receipt.Bloom = ethTypes.CreateBloom(ethTypes.Receipts{receipt}) rpcReceipt := types.Receipt{ - Root: stateRoot, + Root: &stateRoot, CumulativeGasUsed: types.ArgUint64(receipt.CumulativeGasUsed), LogsBloom: receipt.Bloom, Logs: receipt.Logs, diff --git a/jsonrpc/types/types.go b/jsonrpc/types/types.go index eec295f8ad..ec50389564 100644 --- a/jsonrpc/types/types.go +++ b/jsonrpc/types/types.go @@ -601,7 +601,7 @@ func NewTransaction( // Receipt structure type Receipt struct { - Root common.Hash `json:"root"` + Root *common.Hash `json:"root,omitempty"` CumulativeGasUsed ArgUint64 `json:"cumulativeGasUsed"` LogsBloom types.Bloom `json:"logsBloom"` Logs []*types.Log `json:"logs"` @@ -643,7 +643,6 @@ func NewReceipt(tx types.Transaction, r *types.Receipt, l2Hash *common.Hash) (Re return Receipt{}, err } receipt := Receipt{ - Root: common.BytesToHash(r.PostState), CumulativeGasUsed: ArgUint64(r.CumulativeGasUsed), LogsBloom: r.Bloom, Logs: logs, @@ -659,6 +658,11 @@ func NewReceipt(tx types.Transaction, r *types.Receipt, l2Hash *common.Hash) (Re Type: ArgUint64(r.Type), TxL2Hash: l2Hash, } + if common.BytesToHash(r.PostState).String() != state.ZeroHash.String() { + root := common.BytesToHash(r.PostState) + receipt.Root = &root + } + if r.EffectiveGasPrice != nil { egp := ArgBig(*r.EffectiveGasPrice) receipt.EffectiveGasPrice = &egp diff --git a/proto/src/proto/executor/v1/executor.proto b/proto/src/proto/executor/v1/executor.proto index e18008ba58..e79e52c7b0 100644 --- a/proto/src/proto/executor/v1/executor.proto +++ b/proto/src/proto/executor/v1/executor.proto @@ -872,4 +872,6 @@ enum ExecutorError { EXECUTOR_ERROR_INVALID_DATA_STREAM = 115; // EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE indicates that the provided update merkle tree is invalid, e.g. because the executor is configured not to write to database EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE = 116; + // EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR indicates that a TX has an invalid status-error combination + EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR = 117; } diff --git a/state/convertersV2.go b/state/convertersV2.go index c68d33db48..b445bad973 100644 --- a/state/convertersV2.go +++ b/state/convertersV2.go @@ -127,6 +127,7 @@ func (s *State) convertToProcessTransactionResponseV2(responses []*executor.Proc result.ReturnValue = response.ReturnValue result.GasLeft = response.GasLeft result.GasUsed = response.GasUsed + result.CumulativeGasUsed = response.CumulativeGasUsed result.GasRefunded = response.GasRefunded result.RomError = executor.RomErr(response.Error) result.CreateAddress = common.HexToAddress(response.CreateAddress) diff --git a/state/datastream.go b/state/datastream.go index 9bcd7fac58..d50c7adecf 100644 --- a/state/datastream.go +++ b/state/datastream.go @@ -118,6 +118,7 @@ func (b DSL2BlockStart) Decode(data []byte) DSL2BlockStart { // DSL2Transaction represents a data stream L2 transaction type DSL2Transaction struct { L2BlockNumber uint64 // Not included in the encoded data + ImStateRoot common.Hash // Not included in the encoded data EffectiveGasPricePercentage uint8 // 1 byte IsValid uint8 // 1 byte StateRoot common.Hash // 32 bytes @@ -553,6 +554,9 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St } for _, tx := range l2Block.Txs { + // < ETROG => IM State root is retrieved from the system SC (using cache is available) + // = ETROG => IM State root is retrieved from the receipt.post_state => Do nothing + // > ETROG => IM State root is retrieved from the receipt.im_state_root if l2Block.ForkID < FORKID_ETROG { // Populate intermediate state root with information from the system SC (or cache if available) if imStateRoots == nil || (*imStateRoots)[blockStart.L2BlockNumber] == nil { @@ -565,6 +569,8 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St } else { tx.StateRoot = common.BytesToHash((*imStateRoots)[blockStart.L2BlockNumber]) } + } else if l2Block.ForkID > FORKID_ETROG { + tx.StateRoot = tx.ImStateRoot } _, err = streamServer.AddStreamEntry(EntryTypeL2Tx, tx.Encode()) diff --git a/state/genesis.go b/state/genesis.go index 41c2424c56..50c4b5a950 100644 --- a/state/genesis.go +++ b/state/genesis.go @@ -204,7 +204,7 @@ func (s *State) SetGenesis(ctx context.Context, block Block, genesis Genesis, m storeTxsEGPData := []StoreTxEGPData{} txsL2Hash := []common.Hash{} - err = s.AddL2Block(ctx, batch.BatchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx) + err = s.AddL2Block(ctx, batch.BatchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, []common.Hash{}, dbTx) if err != nil { return common.Hash{}, err } diff --git a/state/helper.go b/state/helper.go index 473725b33d..4d074292bb 100644 --- a/state/helper.go +++ b/state/helper.go @@ -279,19 +279,23 @@ func DecodeTx(encodedTx string) (*types.Transaction, error) { } // GenerateReceipt generates a receipt from a processed transaction -func GenerateReceipt(blockNumber *big.Int, processedTx *ProcessTransactionResponse, txIndex uint) *types.Receipt { +func GenerateReceipt(blockNumber *big.Int, processedTx *ProcessTransactionResponse, txIndex uint, forkID uint64) *types.Receipt { receipt := &types.Receipt{ - Type: uint8(processedTx.Type), - PostState: processedTx.StateRoot.Bytes(), - CumulativeGasUsed: processedTx.GasUsed, - BlockNumber: blockNumber, - GasUsed: processedTx.GasUsed, - TxHash: processedTx.Tx.Hash(), - TransactionIndex: txIndex, - ContractAddress: processedTx.CreateAddress, - Logs: processedTx.Logs, + Type: uint8(processedTx.Type), + BlockNumber: blockNumber, + GasUsed: processedTx.GasUsed, + TxHash: processedTx.Tx.Hash(), + TransactionIndex: txIndex, + ContractAddress: processedTx.CreateAddress, + Logs: processedTx.Logs, + } + if forkID <= FORKID_ETROG { + receipt.PostState = processedTx.StateRoot.Bytes() + receipt.CumulativeGasUsed = processedTx.GasUsed + } else { + receipt.PostState = ZeroHash.Bytes() + receipt.CumulativeGasUsed = processedTx.CumulativeGasUsed } - if processedTx.EffectiveGasPrice != "" { effectiveGasPrice, ok := big.NewInt(0).SetString(processedTx.EffectiveGasPrice, 0) if !ok { @@ -309,10 +313,14 @@ func GenerateReceipt(blockNumber *big.Int, processedTx *ProcessTransactionRespon for i := 0; i < len(receipt.Logs); i++ { receipt.Logs[i].TxHash = processedTx.Tx.Hash() } - if processedTx.RomError == nil { - receipt.Status = types.ReceiptStatusSuccessful + if forkID <= FORKID_ETROG { + if processedTx.RomError == nil { + receipt.Status = types.ReceiptStatusSuccessful + } else { + receipt.Status = types.ReceiptStatusFailed + } } else { - receipt.Status = types.ReceiptStatusFailed + receipt.Status = uint64(processedTx.Status) } return receipt diff --git a/state/interfaces.go b/state/interfaces.go index daa38906fd..17264098be 100644 --- a/state/interfaces.go +++ b/state/interfaces.go @@ -72,7 +72,7 @@ type storage interface { GetL2BlockTransactionCountByHash(ctx context.Context, blockHash common.Hash, dbTx pgx.Tx) (uint64, error) GetL2BlockTransactionCountByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (uint64, error) GetTransactionEGPLogByHash(ctx context.Context, transactionHash common.Hash, dbTx pgx.Tx) (*EffectiveGasPriceLog, error) - AddL2Block(ctx context.Context, batchNumber uint64, l2Block *L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []StoreTxEGPData, dbTx pgx.Tx) error + AddL2Block(ctx context.Context, batchNumber uint64, l2Block *L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []StoreTxEGPData, imStateRoots []common.Hash, dbTx pgx.Tx) error GetLastVirtualizedL2BlockNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error) GetLastConsolidatedL2BlockNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error) GetLastVerifiedL2BlockNumberUntilL1Block(ctx context.Context, l1FinalizedBlockNumber uint64, dbTx pgx.Tx) (uint64, error) @@ -93,7 +93,7 @@ type storage interface { IsL2BlockConsolidated(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (bool, error) IsL2BlockVirtualized(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (bool, error) GetLogs(ctx context.Context, fromBlock uint64, toBlock uint64, addresses []common.Address, topics [][]common.Hash, blockHash *common.Hash, since *time.Time, dbTx pgx.Tx) ([]*types.Log, error) - AddReceipt(ctx context.Context, receipt *types.Receipt, dbTx pgx.Tx) error + AddReceipt(ctx context.Context, receipt *types.Receipt, imStateRoot common.Hash, dbTx pgx.Tx) error AddLog(ctx context.Context, l *types.Log, dbTx pgx.Tx) error GetExitRootByGlobalExitRoot(ctx context.Context, ger common.Hash, dbTx pgx.Tx) (*GlobalExitRoot, error) AddSequence(ctx context.Context, sequence Sequence, dbTx pgx.Tx) error diff --git a/state/mocks/mock_storage.go b/state/mocks/mock_storage.go index a2d06980c1..b07d5de4cc 100644 --- a/state/mocks/mock_storage.go +++ b/state/mocks/mock_storage.go @@ -418,17 +418,17 @@ func (_c *StorageMock_AddL1InfoRootToExitRoot_Call) RunAndReturn(run func(contex return _c } -// AddL2Block provides a mock function with given fields: ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, dbTx -func (_m *StorageMock) AddL2Block(ctx context.Context, batchNumber uint64, l2Block *state.L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []state.StoreTxEGPData, dbTx pgx.Tx) error { - ret := _m.Called(ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, dbTx) +// AddL2Block provides a mock function with given fields: ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, imStateRoots, dbTx +func (_m *StorageMock) AddL2Block(ctx context.Context, batchNumber uint64, l2Block *state.L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []state.StoreTxEGPData, imStateRoots []common.Hash, dbTx pgx.Tx) error { + ret := _m.Called(ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, imStateRoots, dbTx) if len(ret) == 0 { panic("no return value specified for AddL2Block") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, uint64, *state.L2Block, []*types.Receipt, []common.Hash, []state.StoreTxEGPData, pgx.Tx) error); ok { - r0 = rf(ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, dbTx) + if rf, ok := ret.Get(0).(func(context.Context, uint64, *state.L2Block, []*types.Receipt, []common.Hash, []state.StoreTxEGPData, []common.Hash, pgx.Tx) error); ok { + r0 = rf(ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, imStateRoots, dbTx) } else { r0 = ret.Error(0) } @@ -448,14 +448,15 @@ type StorageMock_AddL2Block_Call struct { // - receipts []*types.Receipt // - txsL2Hash []common.Hash // - txsEGPData []state.StoreTxEGPData +// - imStateRoots []common.Hash // - dbTx pgx.Tx -func (_e *StorageMock_Expecter) AddL2Block(ctx interface{}, batchNumber interface{}, l2Block interface{}, receipts interface{}, txsL2Hash interface{}, txsEGPData interface{}, dbTx interface{}) *StorageMock_AddL2Block_Call { - return &StorageMock_AddL2Block_Call{Call: _e.mock.On("AddL2Block", ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, dbTx)} +func (_e *StorageMock_Expecter) AddL2Block(ctx interface{}, batchNumber interface{}, l2Block interface{}, receipts interface{}, txsL2Hash interface{}, txsEGPData interface{}, imStateRoots interface{}, dbTx interface{}) *StorageMock_AddL2Block_Call { + return &StorageMock_AddL2Block_Call{Call: _e.mock.On("AddL2Block", ctx, batchNumber, l2Block, receipts, txsL2Hash, txsEGPData, imStateRoots, dbTx)} } -func (_c *StorageMock_AddL2Block_Call) Run(run func(ctx context.Context, batchNumber uint64, l2Block *state.L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []state.StoreTxEGPData, dbTx pgx.Tx)) *StorageMock_AddL2Block_Call { +func (_c *StorageMock_AddL2Block_Call) Run(run func(ctx context.Context, batchNumber uint64, l2Block *state.L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []state.StoreTxEGPData, imStateRoots []common.Hash, dbTx pgx.Tx)) *StorageMock_AddL2Block_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uint64), args[2].(*state.L2Block), args[3].([]*types.Receipt), args[4].([]common.Hash), args[5].([]state.StoreTxEGPData), args[6].(pgx.Tx)) + run(args[0].(context.Context), args[1].(uint64), args[2].(*state.L2Block), args[3].([]*types.Receipt), args[4].([]common.Hash), args[5].([]state.StoreTxEGPData), args[6].([]common.Hash), args[7].(pgx.Tx)) }) return _c } @@ -465,7 +466,7 @@ func (_c *StorageMock_AddL2Block_Call) Return(_a0 error) *StorageMock_AddL2Block return _c } -func (_c *StorageMock_AddL2Block_Call) RunAndReturn(run func(context.Context, uint64, *state.L2Block, []*types.Receipt, []common.Hash, []state.StoreTxEGPData, pgx.Tx) error) *StorageMock_AddL2Block_Call { +func (_c *StorageMock_AddL2Block_Call) RunAndReturn(run func(context.Context, uint64, *state.L2Block, []*types.Receipt, []common.Hash, []state.StoreTxEGPData, []common.Hash, pgx.Tx) error) *StorageMock_AddL2Block_Call { _c.Call.Return(run) return _c } @@ -518,17 +519,17 @@ func (_c *StorageMock_AddLog_Call) RunAndReturn(run func(context.Context, *types return _c } -// AddReceipt provides a mock function with given fields: ctx, receipt, dbTx -func (_m *StorageMock) AddReceipt(ctx context.Context, receipt *types.Receipt, dbTx pgx.Tx) error { - ret := _m.Called(ctx, receipt, dbTx) +// AddReceipt provides a mock function with given fields: ctx, receipt, imStateRoot, dbTx +func (_m *StorageMock) AddReceipt(ctx context.Context, receipt *types.Receipt, imStateRoot common.Hash, dbTx pgx.Tx) error { + ret := _m.Called(ctx, receipt, imStateRoot, dbTx) if len(ret) == 0 { panic("no return value specified for AddReceipt") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *types.Receipt, pgx.Tx) error); ok { - r0 = rf(ctx, receipt, dbTx) + if rf, ok := ret.Get(0).(func(context.Context, *types.Receipt, common.Hash, pgx.Tx) error); ok { + r0 = rf(ctx, receipt, imStateRoot, dbTx) } else { r0 = ret.Error(0) } @@ -544,14 +545,15 @@ type StorageMock_AddReceipt_Call struct { // AddReceipt is a helper method to define mock.On call // - ctx context.Context // - receipt *types.Receipt +// - imStateRoot common.Hash // - dbTx pgx.Tx -func (_e *StorageMock_Expecter) AddReceipt(ctx interface{}, receipt interface{}, dbTx interface{}) *StorageMock_AddReceipt_Call { - return &StorageMock_AddReceipt_Call{Call: _e.mock.On("AddReceipt", ctx, receipt, dbTx)} +func (_e *StorageMock_Expecter) AddReceipt(ctx interface{}, receipt interface{}, imStateRoot interface{}, dbTx interface{}) *StorageMock_AddReceipt_Call { + return &StorageMock_AddReceipt_Call{Call: _e.mock.On("AddReceipt", ctx, receipt, imStateRoot, dbTx)} } -func (_c *StorageMock_AddReceipt_Call) Run(run func(ctx context.Context, receipt *types.Receipt, dbTx pgx.Tx)) *StorageMock_AddReceipt_Call { +func (_c *StorageMock_AddReceipt_Call) Run(run func(ctx context.Context, receipt *types.Receipt, imStateRoot common.Hash, dbTx pgx.Tx)) *StorageMock_AddReceipt_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*types.Receipt), args[2].(pgx.Tx)) + run(args[0].(context.Context), args[1].(*types.Receipt), args[2].(common.Hash), args[3].(pgx.Tx)) }) return _c } @@ -561,7 +563,7 @@ func (_c *StorageMock_AddReceipt_Call) Return(_a0 error) *StorageMock_AddReceipt return _c } -func (_c *StorageMock_AddReceipt_Call) RunAndReturn(run func(context.Context, *types.Receipt, pgx.Tx) error) *StorageMock_AddReceipt_Call { +func (_c *StorageMock_AddReceipt_Call) RunAndReturn(run func(context.Context, *types.Receipt, common.Hash, pgx.Tx) error) *StorageMock_AddReceipt_Call { _c.Call.Return(run) return _c } diff --git a/state/pgstatestorage/datastream.go b/state/pgstatestorage/datastream.go index d94eb385d5..4b15000aeb 100644 --- a/state/pgstatestorage/datastream.go +++ b/state/pgstatestorage/datastream.go @@ -91,7 +91,7 @@ func scanL2Block(row pgx.Row) (*state.DSL2Block, error) { // GetDSL2Transactions returns the L2 transactions func (p *PostgresStorage) GetDSL2Transactions(ctx context.Context, firstL2Block, lastL2Block uint64, dbTx pgx.Tx) ([]*state.DSL2Transaction, error) { - const l2TxSQL = `SELECT l2_block_num, t.effective_percentage, t.encoded, r.post_state + const l2TxSQL = `SELECT l2_block_num, t.effective_percentage, t.encoded, r.post_state, r.im_state_root FROM state.transaction t, state.receipt r WHERE l2_block_num BETWEEN $1 AND $2 AND r.tx_hash = t.hash ORDER BY t.l2_block_num ASC, r.tx_index ASC` @@ -120,11 +120,13 @@ func scanDSL2Transaction(row pgx.Row) (*state.DSL2Transaction, error) { l2Transaction := state.DSL2Transaction{} encoded := []byte{} postState := []byte{} + imStateRoot := []byte{} if err := row.Scan( &l2Transaction.L2BlockNumber, &l2Transaction.EffectiveGasPricePercentage, &encoded, &postState, + &imStateRoot, ); err != nil { return nil, err } @@ -142,6 +144,7 @@ func scanDSL2Transaction(row pgx.Row) (*state.DSL2Transaction, error) { l2Transaction.EncodedLength = uint32(len(l2Transaction.Encoded)) l2Transaction.IsValid = 1 l2Transaction.StateRoot = common.BytesToHash(postState) + l2Transaction.ImStateRoot = common.BytesToHash(imStateRoot) return &l2Transaction, nil } diff --git a/state/pgstatestorage/l2block.go b/state/pgstatestorage/l2block.go index fac23ce6ce..8ea2870f3d 100644 --- a/state/pgstatestorage/l2block.go +++ b/state/pgstatestorage/l2block.go @@ -169,8 +169,8 @@ func (p *PostgresStorage) GetL2BlockTransactionCountByNumber(ctx context.Context } // AddL2Block adds a new L2 block to the State Store -func (p *PostgresStorage) AddL2Block(ctx context.Context, batchNumber uint64, l2Block *state.L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []state.StoreTxEGPData, dbTx pgx.Tx) error { - //TODO: Optmize this function using only one SQL (with several values) to insert all the txs, receips and logs +func (p *PostgresStorage) AddL2Block(ctx context.Context, batchNumber uint64, l2Block *state.L2Block, receipts []*types.Receipt, txsL2Hash []common.Hash, txsEGPData []state.StoreTxEGPData, imStateRoots []common.Hash, dbTx pgx.Tx) error { + // TODO: Optimize this function using only one SQL (with several values) to insert all the txs, receipts and logs log.Debugf("[AddL2Block] adding L2 block %d", l2Block.NumberU64()) start := time.Now() @@ -255,7 +255,7 @@ func (p *PostgresStorage) AddL2Block(ctx context.Context, batchNumber uint64, l2 } if len(receipts) > 0 { - p.AddReceipts(ctx, receipts, dbTx) + p.AddReceipts(ctx, receipts, imStateRoots, dbTx) var logs []*types.Log for _, receipt := range receipts { diff --git a/state/pgstatestorage/pgstatestorage_test.go b/state/pgstatestorage/pgstatestorage_test.go index 8c0b553514..08a9fe8a7a 100644 --- a/state/pgstatestorage/pgstatestorage_test.go +++ b/state/pgstatestorage/pgstatestorage_test.go @@ -188,6 +188,7 @@ func TestGetBatchByL2BlockNumber(t *testing.T) { transactions := []*types.Transaction{tx} receipts := []*types.Receipt{receipt} + imStateRoots := []common.Hash{state.ZeroHash} // Create block to be able to calculate its hash st := trie.NewStackTrie(nil) @@ -202,7 +203,7 @@ func TestGetBatchByL2BlockNumber(t *testing.T) { txsL2Hash[i] = common.HexToHash(fmt.Sprintf("0x%d", i)) } - err = pgStateStorage.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx) + err = pgStateStorage.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, imStateRoots, dbTx) require.NoError(t, err) result, err := pgStateStorage.BatchNumberByL2BlockNumber(ctx, l2Block.Number().Uint64(), dbTx) require.NoError(t, err) @@ -724,7 +725,7 @@ func TestGetLastVerifiedL2BlockNumberUntilL1Block(t *testing.T) { txsL2Hash[i] = common.HexToHash(fmt.Sprintf("0x%d", i)) } - err = testState.AddL2Block(ctx, batchNumber, l2Block, []*types.Receipt{}, txsL2Hash, storeTxsEGPData, dbTx) + err = testState.AddL2Block(ctx, batchNumber, l2Block, []*types.Receipt{}, txsL2Hash, storeTxsEGPData, []common.Hash{}, dbTx) require.NoError(t, err) virtualBatch := state.VirtualBatch{BlockNumber: blockNumber, BatchNumber: batchNumber, Coinbase: addr, SequencerAddr: addr, TxHash: hash} @@ -923,6 +924,7 @@ func TestGetLogs(t *testing.T) { transactions := []*types.Transaction{tx} receipts := []*types.Receipt{receipt} + stateRoots := []common.Hash{state.ZeroHash} header := state.NewL2Header(&types.Header{ Number: big.NewInt(int64(i) + 1), @@ -948,7 +950,7 @@ func TestGetLogs(t *testing.T) { txsL2Hash[i] = common.HexToHash(fmt.Sprintf("0x%d", i)) } - err = testState.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx) + err = testState.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, stateRoots, dbTx) require.NoError(t, err) } @@ -1054,6 +1056,7 @@ func TestGetNativeBlockHashesInRange(t *testing.T) { transactions := []*types.Transaction{tx} receipts := []*types.Receipt{receipt} + stateRoots := []common.Hash{state.ZeroHash} header := state.NewL2Header(&types.Header{ Number: big.NewInt(int64(i) + 1), @@ -1079,7 +1082,7 @@ func TestGetNativeBlockHashesInRange(t *testing.T) { txsL2Hash[i] = common.HexToHash(fmt.Sprintf("0x%d", i)) } - err = testState.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx) + err = testState.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, stateRoots, dbTx) require.NoError(t, err) nativeBlockHashes = append(nativeBlockHashes, l2Block.Header().Root) diff --git a/state/pgstatestorage/transaction.go b/state/pgstatestorage/transaction.go index b372b6b13d..f25554d44e 100644 --- a/state/pgstatestorage/transaction.go +++ b/state/pgstatestorage/transaction.go @@ -515,7 +515,7 @@ func (p *PostgresStorage) GetTxsByBatchNumber(ctx context.Context, batchNumber u } // AddReceipt adds a new receipt to the State Store -func (p *PostgresStorage) AddReceipt(ctx context.Context, receipt *types.Receipt, dbTx pgx.Tx) error { +func (p *PostgresStorage) AddReceipt(ctx context.Context, receipt *types.Receipt, imStateRoot common.Hash, dbTx pgx.Tx) error { e := p.getExecQuerier(dbTx) var effectiveGasPrice *uint64 @@ -526,31 +526,31 @@ func (p *PostgresStorage) AddReceipt(ctx context.Context, receipt *types.Receipt } const addReceiptSQL = ` - INSERT INTO state.receipt (tx_hash, type, post_state, status, cumulative_gas_used, gas_used, effective_gas_price, block_num, tx_index, contract_address) - VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)` - _, err := e.Exec(ctx, addReceiptSQL, receipt.TxHash.String(), receipt.Type, receipt.PostState, receipt.Status, receipt.CumulativeGasUsed, receipt.GasUsed, effectiveGasPrice, receipt.BlockNumber.Uint64(), receipt.TransactionIndex, receipt.ContractAddress.String()) + INSERT INTO state.receipt (tx_hash, type, post_state, status, cumulative_gas_used, gas_used, effective_gas_price, block_num, tx_index, contract_address, im_state_root) + VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)` + _, err := e.Exec(ctx, addReceiptSQL, receipt.TxHash.String(), receipt.Type, receipt.PostState, receipt.Status, receipt.CumulativeGasUsed, receipt.GasUsed, effectiveGasPrice, receipt.BlockNumber.Uint64(), receipt.TransactionIndex, receipt.ContractAddress.String(), imStateRoot.Bytes()) return err } // AddReceipts adds a list of receipts to the State Store -func (p *PostgresStorage) AddReceipts(ctx context.Context, receipts []*types.Receipt, dbTx pgx.Tx) error { +func (p *PostgresStorage) AddReceipts(ctx context.Context, receipts []*types.Receipt, imStateRoots []common.Hash, dbTx pgx.Tx) error { if len(receipts) == 0 { return nil } receiptRows := [][]interface{}{} - for _, receipt := range receipts { + for i, receipt := range receipts { var egp uint64 if receipt.EffectiveGasPrice != nil { egp = receipt.EffectiveGasPrice.Uint64() } - receiptRow := []interface{}{receipt.TxHash.String(), receipt.Type, receipt.PostState, receipt.Status, receipt.CumulativeGasUsed, receipt.GasUsed, egp, receipt.BlockNumber.Uint64(), receipt.TransactionIndex, receipt.ContractAddress.String()} + receiptRow := []interface{}{receipt.TxHash.String(), receipt.Type, receipt.PostState, receipt.Status, receipt.CumulativeGasUsed, receipt.GasUsed, egp, receipt.BlockNumber.Uint64(), receipt.TransactionIndex, receipt.ContractAddress.String(), imStateRoots[i].Bytes()} receiptRows = append(receiptRows, receiptRow) } _, err := dbTx.CopyFrom(ctx, pgx.Identifier{"state", "receipt"}, - []string{"tx_hash", "type", "post_state", "status", "cumulative_gas_used", "gas_used", "effective_gas_price", "block_num", "tx_index", "contract_address"}, + []string{"tx_hash", "type", "post_state", "status", "cumulative_gas_used", "gas_used", "effective_gas_price", "block_num", "tx_index", "contract_address", "im_state_root"}, pgx.CopyFromRows(receiptRows)) return err diff --git a/state/runtime/executor/errors.go b/state/runtime/executor/errors.go index a2e8f2d1d5..a0ca5782d6 100644 --- a/state/runtime/executor/errors.go +++ b/state/runtime/executor/errors.go @@ -454,6 +454,8 @@ func ExecutorErr(errorCode ExecutorError) error { return runtime.ErrExecutorErrorInvalidDataStream case ExecutorError_EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE: return runtime.ErrExecutorErrorInvalidUpdateMerkleTree + case ExecutorError_EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR: + return runtime.ErrExecutorErrorSMMainInvalidTxStatusError } return ErrExecutorUnknown } @@ -694,6 +696,8 @@ func ExecutorErrorCode(err error) ExecutorError { return ExecutorError_EXECUTOR_ERROR_INVALID_DATA_STREAM case runtime.ErrExecutorErrorInvalidUpdateMerkleTree: return ExecutorError_EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE + case runtime.ErrExecutorErrorSMMainInvalidTxStatusError: + return ExecutorError_EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR } return ErrCodeExecutorUnknown diff --git a/state/runtime/executor/executor.pb.go b/state/runtime/executor/executor.pb.go index af7ad962b8..376c3c6252 100644 --- a/state/runtime/executor/executor.pb.go +++ b/state/runtime/executor/executor.pb.go @@ -438,6 +438,8 @@ const ( ExecutorError_EXECUTOR_ERROR_INVALID_DATA_STREAM ExecutorError = 115 // EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE indicates that the provided update merkle tree is invalid, e.g. because the executor is configured not to write to database ExecutorError_EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE ExecutorError = 116 + // EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR indicates that a TX has an invalid status-error combination + ExecutorError_EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR ExecutorError = 117 ) // Enum value maps for ExecutorError. @@ -560,6 +562,7 @@ var ( 114: "EXECUTOR_ERROR_INVALID_CBOR", 115: "EXECUTOR_ERROR_INVALID_DATA_STREAM", 116: "EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE", + 117: "EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR", } ExecutorError_value = map[string]int32{ "EXECUTOR_ERROR_UNSPECIFIED": 0, @@ -679,6 +682,7 @@ var ( "EXECUTOR_ERROR_INVALID_CBOR": 114, "EXECUTOR_ERROR_INVALID_DATA_STREAM": 115, "EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE": 116, + "EXECUTOR_ERROR_SM_MAIN_INVALID_TX_STATUS_ERROR": 117, } ) @@ -4932,7 +4936,7 @@ var file_executor_proto_rawDesc = []byte{ 0x12, 0x36, 0x0a, 0x32, 0x52, 0x4f, 0x4d, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x58, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x4c, 0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x4d, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, - 0x45, 0x53, 0x54, 0x41, 0x4d, 0x50, 0x10, 0x22, 0x2a, 0xb9, 0x2b, 0x0a, 0x0d, 0x45, 0x78, 0x65, + 0x45, 0x53, 0x54, 0x41, 0x4d, 0x50, 0x10, 0x22, 0x2a, 0xed, 0x2b, 0x0a, 0x0d, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1e, 0x0a, 0x1a, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, @@ -5280,29 +5284,32 @@ var file_executor_proto_rawDesc = []byte{ 0x45, 0x41, 0x4d, 0x10, 0x73, 0x12, 0x2d, 0x0a, 0x29, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x52, 0x4b, 0x4c, 0x45, 0x5f, 0x54, 0x52, - 0x45, 0x45, 0x10, 0x74, 0x32, 0x96, 0x02, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, - 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x63, - 0x65, 0x73, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x20, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x65, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x5b, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x56, - 0x32, 0x12, 0x22, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x56, 0x32, 0x1a, 0x23, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, + 0x45, 0x45, 0x10, 0x74, 0x12, 0x32, 0x0a, 0x2e, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x4f, 0x52, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x53, 0x4d, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x58, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x75, 0x32, 0x96, 0x02, 0x0a, 0x0f, 0x45, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x55, 0x0a, 0x0c, + 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x20, 0x2e, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, + 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x56, 0x32, 0x12, 0x22, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x56, 0x32, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x23, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, - 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3e, 0x5a, - 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x78, 0x50, 0x6f, - 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x48, 0x65, 0x72, 0x6d, 0x65, 0x7a, 0x2f, 0x7a, 0x6b, 0x65, 0x76, - 0x6d, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x56, 0x32, 0x1a, 0x23, 0x2e, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x56, 0x32, 0x22, 0x00, + 0x12, 0x4f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x23, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x6f, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x75, 0x73, + 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x30, 0x78, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x48, 0x65, 0x72, 0x6d, 0x65, 0x7a, 0x2f, + 0x7a, 0x6b, 0x65, 0x76, 0x6d, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, + 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/state/runtime/runtime.go b/state/runtime/runtime.go index f1c1bd80f3..2e1b9a744d 100644 --- a/state/runtime/runtime.go +++ b/state/runtime/runtime.go @@ -319,6 +319,8 @@ var ( ErrExecutorErrorInvalidDataStream = errors.New("invalid data stream") // ErrExecutorErrorInvalidUpdateMerkleTree indicates that the input parameter update merkle tree is invalid ErrExecutorErrorInvalidUpdateMerkleTree = errors.New("invalid update merkle tree") + // ErrExecutorErrorSMMainInvalidTxStatusError indicates that the TX has an invalid status-error combination + ErrExecutorErrorSMMainInvalidTxStatusError = errors.New("tx has an invalid status-error combination") // GRPC ERRORS // =========== diff --git a/state/test/forkid_dragonfruit/dragonfruit_test.go b/state/test/forkid_dragonfruit/dragonfruit_test.go index 64adbf042f..a7b1a5de80 100644 --- a/state/test/forkid_dragonfruit/dragonfruit_test.go +++ b/state/test/forkid_dragonfruit/dragonfruit_test.go @@ -1486,6 +1486,7 @@ func TestExecutorRevert(t *testing.T) { }) receipts := []*types.Receipt{receipt, receipt1} + imStateRoots := []common.Hash{common.BytesToHash(processBatchResponse.Responses[0].StateRoot), common.BytesToHash(processBatchResponse.Responses[1].StateRoot)} transactions := []*types.Transaction{signedTx0, signedTx1} @@ -1505,7 +1506,7 @@ func TestExecutorRevert(t *testing.T) { txsL2Hash[i] = common.HexToHash(fmt.Sprintf("0x%d", i)) } - err = testState.AddL2Block(ctx, 0, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx) + err = testState.AddL2Block(ctx, 0, l2Block, receipts, txsL2Hash, storeTxsEGPData, imStateRoots, dbTx) require.NoError(t, err) l2Block, err = testState.GetL2BlockByHash(ctx, l2Block.Hash(), dbTx) require.NoError(t, err) diff --git a/state/test/forkid_independent/independent_test.go b/state/test/forkid_independent/independent_test.go index b24d0e3021..ef919d7ce3 100644 --- a/state/test/forkid_independent/independent_test.go +++ b/state/test/forkid_independent/independent_test.go @@ -643,6 +643,7 @@ func TestAddGetL2Block(t *testing.T) { transactions := []*types.Transaction{tx} receipts := []*types.Receipt{receipt} + imStateRoots := []common.Hash{state.ZeroHash} // Create block to be able to calculate its hash st := trie.NewStackTrie(nil) @@ -659,7 +660,7 @@ func TestAddGetL2Block(t *testing.T) { txsL2Hash[i] = common.HexToHash(fmt.Sprintf("0x%d", i)) } - err = testState.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx) + err = testState.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, imStateRoots, dbTx) require.NoError(t, err) result, err := testState.GetL2BlockByHash(ctx, l2Block.Hash(), dbTx) require.NoError(t, err) diff --git a/state/transaction.go b/state/transaction.go index 3af99b3f64..2847a5e428 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -117,6 +117,8 @@ func (s *State) StoreTransactions(ctx context.Context, batchNumber uint64, proce return ErrBatchAlreadyClosed } + forkID := s.GetForkIDByBatchNumber(batchNumber) + for _, processedBlock := range processedBlocks { processedTxs := processedBlock.TransactionResponses // check existing txs vs parameter txs @@ -167,11 +169,12 @@ func (s *State) StoreTransactions(ctx context.Context, batchNumber uint64, proce header.BlockInfoRoot = processedBlock.BlockInfoRoot transactions := []*types.Transaction{&processedTx.Tx} - receipt := GenerateReceipt(header.Number, processedTx, uint(i)) + receipt := GenerateReceipt(header.Number, processedTx, uint(i), forkID) if !CheckLogOrder(receipt.Logs) { return fmt.Errorf("error: logs received from executor are not in order") } receipts := []*types.Receipt{receipt} + imStateRoots := []common.Hash{processedTx.StateRoot} // Create l2Block to be able to calculate its hash st := trie.NewStackTrie(nil) @@ -187,7 +190,7 @@ func (s *State) StoreTransactions(ctx context.Context, batchNumber uint64, proce txsL2Hash := []common.Hash{processedTx.TxHashL2_V2} // Store L2 block and its transaction - if err := s.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx); err != nil { + if err := s.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, imStateRoots, dbTx); err != nil { return err } } @@ -209,8 +212,11 @@ func (s *State) StoreL2Block(ctx context.Context, batchNumber uint64, l2Block *P return err } + forkID := s.GetForkIDByBatchNumber(batchNumber) + gasLimit := l2Block.GasLimit - if gasLimit > MaxL2BlockGasLimit { + // We check/set the maximum value of gasLimit for batches <= to ETROG fork. For batches >= to ELDERBERRY fork we use always the value returned by the executor + if forkID <= FORKID_ETROG && gasLimit > MaxL2BlockGasLimit { gasLimit = MaxL2BlockGasLimit } @@ -234,6 +240,8 @@ func (s *State) StoreL2Block(ctx context.Context, batchNumber uint64, l2Block *P storeTxsEGPData := make([]StoreTxEGPData, 0, numTxs) receipts := make([]*types.Receipt, 0, numTxs) txsL2Hash := make([]common.Hash, 0, numTxs) + imStateRoots := make([]common.Hash, 0, numTxs) + var receipt *types.Receipt for i, txResponse := range l2Block.TransactionResponses { // if the transaction has an intrinsic invalid tx error it means @@ -256,8 +264,9 @@ func (s *State) StoreL2Block(ctx context.Context, batchNumber uint64, l2Block *P storeTxsEGPData = append(storeTxsEGPData, storeTxEGPData) - receipt := GenerateReceipt(header.Number, txResponse, uint(i)) + receipt = GenerateReceipt(header.Number, txResponse, uint(i), forkID) receipts = append(receipts, receipt) + imStateRoots = append(imStateRoots, txResp.StateRoot) } // Create block to be able to calculate its hash @@ -270,7 +279,7 @@ func (s *State) StoreL2Block(ctx context.Context, batchNumber uint64, l2Block *P } // Store L2 block and its transactions - if err := s.AddL2Block(ctx, batchNumber, block, receipts, txsL2Hash, storeTxsEGPData, dbTx); err != nil { + if err := s.AddL2Block(ctx, batchNumber, block, receipts, txsL2Hash, storeTxsEGPData, imStateRoots, dbTx); err != nil { return err } @@ -642,6 +651,8 @@ func (s *State) StoreTransaction(ctx context.Context, batchNumber uint64, proces return nil, err } + forkID := s.GetForkIDByBatchNumber(batchNumber) + header := NewL2Header(&types.Header{ Number: new(big.Int).SetUint64(lastL2Block.Number().Uint64() + 1), ParentHash: lastL2Block.Hash(), @@ -655,8 +666,9 @@ func (s *State) StoreTransaction(ctx context.Context, batchNumber uint64, proces header.BlockInfoRoot = blockInfoRoot transactions := []*types.Transaction{&processedTx.Tx} - receipt := GenerateReceipt(header.Number, processedTx, 0) + receipt := GenerateReceipt(header.Number, processedTx, 0, forkID) receipts := []*types.Receipt{receipt} + imStateRoots := []common.Hash{processedTx.StateRoot} // Create l2Block to be able to calculate its hash st := trie.NewStackTrie(nil) @@ -669,7 +681,7 @@ func (s *State) StoreTransaction(ctx context.Context, batchNumber uint64, proces txsL2Hash := []common.Hash{processedTx.TxHashL2_V2} // Store L2 block and its transaction - if err := s.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, dbTx); err != nil { + if err := s.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, imStateRoots, dbTx); err != nil { return nil, err } diff --git a/state/types.go b/state/types.go index ea7a0ae289..6b76455a07 100644 --- a/state/types.go +++ b/state/types.go @@ -100,6 +100,8 @@ type ProcessTransactionResponse struct { GasLeft uint64 // GasUsed is the total gas used as result of execution or gas estimation GasUsed uint64 + // CumulativeGasUsed is the accumulated gas used (sum of tx GasUsed and CumulativeGasUsed of the previous tx in the L2 block) + CumulativeGasUsed uint64 // GasRefunded is the total gas refunded as result of execution GasRefunded uint64 // RomError represents any error encountered during the execution