From 32c81ee3d6f09551af839434f61c35cad260e738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20Ram=C3=ADrez?= <58293609+ToniRamirezM@users.noreply.github.com> Date: Wed, 17 May 2023 14:52:48 +0200 Subject: [PATCH] Refactor state errors (#2105) * refactor state errors * refactor state errors * refactor state errors * refactor state errors * refactor state errors * refactor * fix * function rename * fix wg * fix wg * fix --- pool/pool.go | 16 ++-- sequencer/dbmanager.go | 8 +- sequencer/finalizer.go | 61 ++++++++------ sequencer/finalizer_test.go | 2 +- sequencer/interfaces.go | 2 +- sequencer/mock_db_manager.go | 12 +-- state/batch.go | 2 +- state/converters.go | 49 +++++++---- state/pgstatestorage.go | 2 +- state/state_test.go | 156 ----------------------------------- state/transaction.go | 37 --------- state/types.go | 24 +++--- test/Makefile | 66 +++++++-------- 13 files changed, 132 insertions(+), 305 deletions(-) diff --git a/pool/pool.go b/pool/pool.go index cb8aef3a6b..0a3d77e3ed 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -186,16 +186,12 @@ func (p *Pool) PreExecuteTx(ctx context.Context, tx types.Transaction) (preExecu return response, err } - response.usedZkCounters = processBatchResponse.UsedZkCounters - - if !processBatchResponse.RomOOC { - if processBatchResponse.Responses != nil && len(processBatchResponse.Responses) > 0 { - r := processBatchResponse.Responses[0] - response.isOOC = executor.IsROMOutOfGasError(executor.RomErrorCode(r.RomError)) - response.isReverted = errors.Is(r.RomError, runtime.ErrExecutionReverted) - } - } else { - response.isOOG = processBatchResponse.RomOOC + if processBatchResponse.Responses != nil && len(processBatchResponse.Responses) > 0 { + errorToCheck := processBatchResponse.Responses[0].RomError + response.isReverted = errors.Is(errorToCheck, runtime.ErrExecutionReverted) + response.isOOC = executor.IsROMOutOfCountersError(executor.RomErrorCode(errorToCheck)) + response.isOOG = errors.Is(errorToCheck, runtime.ErrOutOfGas) + response.usedZkCounters = processBatchResponse.UsedZkCounters } return response, nil diff --git a/sequencer/dbmanager.go b/sequencer/dbmanager.go index ec04964d04..86c92b3a87 100644 --- a/sequencer/dbmanager.go +++ b/sequencer/dbmanager.go @@ -441,14 +441,14 @@ func (d *dbManager) CloseBatch(ctx context.Context, params ClosingBatchParameter } // ProcessForcedBatch process a forced batch -func (d *dbManager) ProcessForcedBatch(forcedBatchNum uint64, request state.ProcessRequest) (*state.ProcessBatchResponse, error) { +func (d *dbManager) ProcessForcedBatch(ForcedBatchNumber uint64, request state.ProcessRequest) (*state.ProcessBatchResponse, error) { // Open Batch processingCtx := state.ProcessingContext{ BatchNumber: request.BatchNumber, Coinbase: request.Coinbase, Timestamp: request.Timestamp, GlobalExitRoot: request.GlobalExitRoot, - ForcedBatchNum: &forcedBatchNum, + ForcedBatchNum: &ForcedBatchNumber, } dbTx, err := d.state.BeginStateTransaction(d.ctx) if err != nil { @@ -469,7 +469,7 @@ func (d *dbManager) ProcessForcedBatch(forcedBatchNum uint64, request state.Proc } // Fetch Forced Batch - forcedBatch, err := d.state.GetForcedBatch(d.ctx, forcedBatchNum, dbTx) + forcedBatch, err := d.state.GetForcedBatch(d.ctx, ForcedBatchNumber, dbTx) if err != nil { if rollbackErr := dbTx.Rollback(d.ctx); rollbackErr != nil { log.Errorf( @@ -490,7 +490,7 @@ func (d *dbManager) ProcessForcedBatch(forcedBatchNum uint64, request state.Proc // Close Batch txsBytes := uint64(0) for _, resp := range processBatchResponse.Responses { - if !resp.IsProcessed { + if !resp.ChangesStateRoot { continue } txsBytes += resp.Tx.Size() diff --git a/sequencer/finalizer.go b/sequencer/finalizer.go index 77833cb667..0076ab6fd2 100644 --- a/sequencer/finalizer.go +++ b/sequencer/finalizer.go @@ -294,12 +294,14 @@ func (f *finalizer) newWIPBatch(ctx context.Context) (*WipBatch, error) { // Reprocess full batch as sanity check processBatchResponse, err := f.reprocessFullBatch(ctx, f.batch.batchNumber, f.batch.stateRoot) - if err != nil || processBatchResponse.RomOOC { + if err != nil || processBatchResponse.IsRomOOCError || processBatchResponse.ExecutorError != nil { log.Info("halting the finalizer because of a reprocessing error") if err != nil { f.halt(ctx, fmt.Errorf("failed to reprocess batch, err: %v", err)) - } else { + } else if processBatchResponse.IsRomOOCError { f.halt(ctx, fmt.Errorf("out of counters during reprocessFullBath")) + } else { + f.halt(ctx, fmt.Errorf("executor error during reprocessFullBath: %v", processBatchResponse.ExecutorError)) } } @@ -354,14 +356,12 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker) error metrics.ProcessingTime(time.Since(start)) }() - var ger common.Hash if f.batch.isEmpty() { - ger = f.batch.globalExitRoot + f.processRequest.GlobalExitRoot = f.batch.globalExitRoot } else { - ger = state.ZeroHash + f.processRequest.GlobalExitRoot = state.ZeroHash } - f.processRequest.GlobalExitRoot = ger if tx != nil { f.processRequest.Transactions = tx.RawTx } else { @@ -372,37 +372,36 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker) error hash = tx.HashStr } log.Infof("processTransaction: single tx. Batch.BatchNumber: %d, BatchNumber: %d, OldStateRoot: %s, txHash: %s, GER: %s", f.batch.batchNumber, f.processRequest.BatchNumber, f.processRequest.OldStateRoot, hash, f.processRequest.GlobalExitRoot.String()) - result, err := f.executor.ProcessBatch(ctx, f.processRequest, true) + processBatchResponse, err := f.executor.ProcessBatch(ctx, f.processRequest, true) if err != nil { log.Errorf("failed to process transaction: %s", err) return err } oldStateRoot := f.batch.stateRoot - if len(result.Responses) > 0 && tx != nil { - err = f.handleTxProcessResp(ctx, tx, result, oldStateRoot) + if len(processBatchResponse.Responses) > 0 && tx != nil { + err = f.handleProcessTransactionResponse(ctx, tx, processBatchResponse, oldStateRoot) if err != nil { return err } } // Update in-memory batch and processRequest - f.processRequest.OldStateRoot = result.NewStateRoot - f.batch.stateRoot = result.NewStateRoot - f.batch.localExitRoot = result.NewLocalExitRoot - log.Infof("processTransaction: data loaded in memory. batch.batchNumber: %d, batchNumber: %d, result.NewStateRoot: %s, result.NewLocalExitRoot: %s, oldStateRoot: %s", f.batch.batchNumber, f.processRequest.BatchNumber, result.NewStateRoot.String(), result.NewLocalExitRoot.String(), oldStateRoot.String()) + f.processRequest.OldStateRoot = processBatchResponse.NewStateRoot + f.batch.stateRoot = processBatchResponse.NewStateRoot + f.batch.localExitRoot = processBatchResponse.NewLocalExitRoot + log.Infof("processTransaction: data loaded in memory. batch.batchNumber: %d, batchNumber: %d, result.NewStateRoot: %s, result.NewLocalExitRoot: %s, oldStateRoot: %s", f.batch.batchNumber, f.processRequest.BatchNumber, processBatchResponse.NewStateRoot.String(), processBatchResponse.NewLocalExitRoot.String(), oldStateRoot.String()) return nil } -// handleTxProcessResp handles the response of transaction processing. -func (f *finalizer) handleTxProcessResp(ctx context.Context, tx *TxTracker, result *state.ProcessBatchResponse, oldStateRoot common.Hash) error { +// handleProcessTransactionResponse handles the response of transaction processing. +func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *TxTracker, result *state.ProcessBatchResponse, oldStateRoot common.Hash) error { // Handle Transaction Error - errorCode := executor.RomErrorCode(result.Responses[0].RomError) - if result.RomOOC || executor.IsIntrinsicError(errorCode) { + if !state.IsStateRootChanged(errorCode) { // If intrinsic error or OOC error, we skip adding the transaction to the batch - f.handleTransactionError(ctx, result, tx) + f.handleProcessTransactionError(ctx, result, tx) return result.Responses[0].RomError } @@ -473,8 +472,8 @@ func (f *finalizer) updateWorkerAfterTxStored(ctx context.Context, tx *TxTracker metrics.WorkerProcessingTime(time.Since(start)) } -// handleTransactionError handles the error of a transaction -func (f *finalizer) handleTransactionError(ctx context.Context, result *state.ProcessBatchResponse, tx *TxTracker) *sync.WaitGroup { +// handleProcessTransactionError handles the error of a transaction +func (f *finalizer) handleProcessTransactionError(ctx context.Context, result *state.ProcessBatchResponse, tx *TxTracker) *sync.WaitGroup { txResponse := result.Responses[0] errorCode := executor.RomErrorCode(txResponse.RomError) addressInfo := result.ReadWriteAddresses[tx.From] @@ -513,6 +512,7 @@ func (f *finalizer) handleTransactionError(ctx context.Context, result *state.Pr wg.Add(1) txToDelete := txToDelete go func() { + defer wg.Done() err := f.dbManager.UpdateTxStatus(ctx, txToDelete.Hash, pool.TxStatusFailed, false, &failedReason) metrics.TxProcessed(metrics.TxProcessedLabelFailed, 1) if err != nil { @@ -528,6 +528,7 @@ func (f *finalizer) handleTransactionError(ctx context.Context, result *state.Pr wg.Add(1) go func() { + defer wg.Done() // Update the status of the transaction to failed err := f.dbManager.UpdateTxStatus(ctx, tx.Hash, pool.TxStatusFailed, false, &failedReason) if err != nil { @@ -618,11 +619,7 @@ func (f *finalizer) processForcedBatches(ctx context.Context, lastBatchNumberInS defer f.nextForcedBatchesMux.Unlock() f.nextForcedBatchDeadline = 0 - dbTx, err := f.dbManager.BeginStateTransaction(ctx) - if err != nil { - return 0, common.Hash{}, fmt.Errorf("failed to begin state transaction, err: %w", err) - } - lastTrustedForcedBatchNumber, err := f.dbManager.GetLastTrustedForcedBatchNumber(ctx, dbTx) + lastTrustedForcedBatchNumber, err := f.dbManager.GetLastTrustedForcedBatchNumber(ctx, nil) if err != nil { return 0, common.Hash{}, fmt.Errorf("failed to get last trusted forced batch number, err: %w", err) } @@ -669,7 +666,7 @@ func (f *finalizer) processForcedBatch(ctx context.Context, lastBatchNumberInSta f.nextGERMux.Lock() f.lastGERHash = forcedBatch.GlobalExitRoot f.nextGERMux.Unlock() - if len(response.Responses) > 0 && !response.RomOOC { + if len(response.Responses) > 0 && !response.IsRomOOCError { f.handleForcedTxsProcessResp(request, response, stateRoot) } @@ -783,7 +780,7 @@ func (f *finalizer) reprocessFullBatch(ctx context.Context, batchNum uint64, exp return nil, err } - if result.RomOOC { + if result.IsRomOOCError { log.Errorf("failed to process batch %v because OutOfCounters", batch.BatchNumber) payload, err := json.Marshal(processRequest) if err != nil { @@ -886,25 +883,35 @@ func (f *finalizer) isBatchAlmostFull() bool { resources := f.batch.remainingResources zkCounters := resources.ZKCounters result := false + resourceDesc := "" if resources.Bytes <= f.getConstraintThresholdUint64(f.batchConstraints.MaxBatchBytesSize) { + resourceDesc = "MaxBatchBytesSize" result = true } else if zkCounters.UsedSteps <= f.getConstraintThresholdUint32(f.batchConstraints.MaxSteps) { + resourceDesc = "MaxSteps" result = true } else if zkCounters.UsedPoseidonPaddings <= f.getConstraintThresholdUint32(f.batchConstraints.MaxPoseidonPaddings) { + resourceDesc = "MaxPoseidonPaddings" result = true } else if zkCounters.UsedBinaries <= f.getConstraintThresholdUint32(f.batchConstraints.MaxBinaries) { + resourceDesc = "MaxBinaries" result = true } else if zkCounters.UsedKeccakHashes <= f.getConstraintThresholdUint32(f.batchConstraints.MaxKeccakHashes) { + resourceDesc = "MaxKeccakHashes" result = true } else if zkCounters.UsedArithmetics <= f.getConstraintThresholdUint32(f.batchConstraints.MaxArithmetics) { + resourceDesc = "MaxArithmetics" result = true } else if zkCounters.UsedMemAligns <= f.getConstraintThresholdUint32(f.batchConstraints.MaxMemAligns) { + resourceDesc = "MaxMemAligns" result = true } else if zkCounters.CumulativeGasUsed <= f.getConstraintThresholdUint64(f.batchConstraints.MaxCumulativeGasUsed) { + resourceDesc = "MaxCumulativeGasUsed" result = true } if result { + log.Infof("Closing batch: %d, because it reached %s threshold limit", f.batch.batchNumber, resourceDesc) f.batch.closingReason = state.BatchAlmostFullClosingReason } diff --git a/sequencer/finalizer_test.go b/sequencer/finalizer_test.go index 72b60d56c7..8e32e78c67 100644 --- a/sequencer/finalizer_test.go +++ b/sequencer/finalizer_test.go @@ -1123,7 +1123,7 @@ func TestFinalizer_handleTransactionError(t *testing.T) { } // act - wg := f.handleTransactionError(ctx, result, tx) + wg := f.handleProcessTransactionError(ctx, result, tx) if wg != nil { wg.Wait() } diff --git a/sequencer/interfaces.go b/sequencer/interfaces.go index c34ba08870..c8122080a1 100644 --- a/sequencer/interfaces.go +++ b/sequencer/interfaces.go @@ -107,7 +107,7 @@ type dbManagerInterface interface { GetBatchByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.Batch, error) IsBatchClosed(ctx context.Context, batchNum uint64) (bool, error) GetLatestGer(ctx context.Context, maxBlockNumber uint64) (state.GlobalExitRoot, time.Time, error) - ProcessForcedBatch(forcedBatchNum uint64, request state.ProcessRequest) (*state.ProcessBatchResponse, error) + ProcessForcedBatch(ForcedBatchNumber uint64, request state.ProcessRequest) (*state.ProcessBatchResponse, error) GetForcedBatchesSince(ctx context.Context, forcedBatchNumber, maxBlockNumber uint64, dbTx pgx.Tx) ([]*state.ForcedBatch, error) GetLastL2BlockHeader(ctx context.Context, dbTx pgx.Tx) (*types.Header, error) GetLastBlock(ctx context.Context, dbTx pgx.Tx) (*state.Block, error) diff --git a/sequencer/mock_db_manager.go b/sequencer/mock_db_manager.go index 636e131798..7f30bc1a11 100644 --- a/sequencer/mock_db_manager.go +++ b/sequencer/mock_db_manager.go @@ -533,17 +533,17 @@ func (_m *DbManagerMock) OpenBatch(ctx context.Context, processingContext state. return r0 } -// ProcessForcedBatch provides a mock function with given fields: forcedBatchNum, request -func (_m *DbManagerMock) ProcessForcedBatch(forcedBatchNum uint64, request state.ProcessRequest) (*state.ProcessBatchResponse, error) { - ret := _m.Called(forcedBatchNum, request) +// ProcessForcedBatch provides a mock function with given fields: ForcedBatchNumber, request +func (_m *DbManagerMock) ProcessForcedBatch(ForcedBatchNumber uint64, request state.ProcessRequest) (*state.ProcessBatchResponse, error) { + ret := _m.Called(ForcedBatchNumber, request) var r0 *state.ProcessBatchResponse var r1 error if rf, ok := ret.Get(0).(func(uint64, state.ProcessRequest) (*state.ProcessBatchResponse, error)); ok { - return rf(forcedBatchNum, request) + return rf(ForcedBatchNumber, request) } if rf, ok := ret.Get(0).(func(uint64, state.ProcessRequest) *state.ProcessBatchResponse); ok { - r0 = rf(forcedBatchNum, request) + r0 = rf(ForcedBatchNumber, request) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*state.ProcessBatchResponse) @@ -551,7 +551,7 @@ func (_m *DbManagerMock) ProcessForcedBatch(forcedBatchNum uint64, request state } if rf, ok := ret.Get(1).(func(uint64, state.ProcessRequest) error); ok { - r1 = rf(forcedBatchNum, request) + r1 = rf(ForcedBatchNumber, request) } else { r1 = ret.Error(1) } diff --git a/state/batch.go b/state/batch.go index 94dd9e5d35..6f302daa5f 100644 --- a/state/batch.go +++ b/state/batch.go @@ -425,7 +425,7 @@ func (s *State) ProcessAndStoreClosedBatch(ctx context.Context, processingCtx Pr // Filter unprocessed txs and decode txs to store metadata // note that if the batch is not well encoded it will result in an empty batch (with no txs) for i := 0; i < len(processed.Responses); i++ { - if !isProcessed(processed.Responses[i].Error) { + if !IsStateRootChanged(processed.Responses[i].Error) { if executor.IsROMOutOfCountersError(processed.Responses[i].Error) { processed.Responses = []*pb.ProcessTransactionResponse{} break diff --git a/state/converters.go b/state/converters.go index a01611845e..07fa329b8e 100644 --- a/state/converters.go +++ b/state/converters.go @@ -48,27 +48,42 @@ func (s *State) convertToProcessBatchResponse(txs []types.Transaction, response return nil, err } - romOOC := response.Error != executor.EXECUTOR_ERROR_NO_ERROR - if !romOOC && len(response.Responses) > 0 { - // Check out of counters - errorToCheck := response.Responses[len(response.Responses)-1].Error - romOOC = executor.IsROMOutOfCountersError(errorToCheck) + isExecutorLevelError := (response.Error != executor.EXECUTOR_ERROR_NO_ERROR) + isRomLevelError := false + isRomOOCError := false + + if response.Responses != nil { + for _, resp := range response.Responses { + if resp.Error != pb.RomError_ROM_ERROR_NO_ERROR { + isRomLevelError = true + break + } + } + + if len(response.Responses) > 0 { + // Check out of counters + errorToCheck := response.Responses[len(response.Responses)-1].Error + isRomOOCError = executor.IsROMOutOfCountersError(errorToCheck) + } } return &ProcessBatchResponse{ - NewStateRoot: common.BytesToHash(response.NewStateRoot), - NewAccInputHash: common.BytesToHash(response.NewAccInputHash), - NewLocalExitRoot: common.BytesToHash(response.NewLocalExitRoot), - NewBatchNumber: response.NewBatchNum, - UsedZkCounters: convertToCounters(response), - Responses: responses, - ExecutorError: executor.ExecutorErr(response.Error), - RomOOC: romOOC, - ReadWriteAddresses: readWriteAddresses, + NewStateRoot: common.BytesToHash(response.NewStateRoot), + NewAccInputHash: common.BytesToHash(response.NewAccInputHash), + NewLocalExitRoot: common.BytesToHash(response.NewLocalExitRoot), + NewBatchNumber: response.NewBatchNum, + UsedZkCounters: convertToCounters(response), + Responses: responses, + ExecutorError: executor.ExecutorErr(response.Error), + IsExecutorLevelError: isExecutorLevelError, + IsRomLevelError: isRomLevelError, + IsRomOOCError: isRomOOCError, + ReadWriteAddresses: readWriteAddresses, }, nil } -func isProcessed(err pb.RomError) bool { +// IsStateRootChanged returns true if the transaction changes the state root +func IsStateRootChanged(err pb.RomError) bool { return !executor.IsIntrinsicError(err) && !executor.IsROMOutOfCountersError(err) } @@ -125,7 +140,7 @@ func (s *State) convertToProcessTransactionResponse(txs []types.Transaction, res result.CreateAddress = common.HexToAddress(response.CreateAddress) result.StateRoot = common.BytesToHash(response.StateRoot) result.Logs = convertToLog(response.Logs) - result.IsProcessed = isProcessed(response.Error) + result.ChangesStateRoot = IsStateRootChanged(response.Error) result.ExecutionTrace = *trace result.CallTrace = convertToExecutorTrace(response.CallTrace) result.Tx = txs[i] @@ -158,7 +173,7 @@ func (s *State) convertToProcessTransactionResponse(txs []types.Transaction, res log.Debugf("ProcessTransactionResponse[GasUsed]: %v", result.GasUsed) log.Debugf("ProcessTransactionResponse[GasLeft]: %v", result.GasLeft) log.Debugf("ProcessTransactionResponse[GasRefunded]: %v", result.GasRefunded) - log.Debugf("ProcessTransactionResponse[IsProcessed]: %v", result.IsProcessed) + log.Debugf("ProcessTransactionResponse[ChangesStateRoot]: %v", result.ChangesStateRoot) } return results, nil diff --git a/state/pgstatestorage.go b/state/pgstatestorage.go index 9435d1a428..9389df410a 100644 --- a/state/pgstatestorage.go +++ b/state/pgstatestorage.go @@ -334,7 +334,7 @@ func (p *PostgresStorage) GetForcedBatch(ctx context.Context, forcedBatchNumber // GetForcedBatchesSince gets L1 forced batches since forcedBatchNumber func (p *PostgresStorage) GetForcedBatchesSince(ctx context.Context, forcedBatchNumber, maxBlockNumber uint64, dbTx pgx.Tx) ([]*ForcedBatch, error) { - const getForcedBatchesSQL = "SELECT forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, block_num FROM state.forced_batch WHERE forced_batch_num > $1 AND block_num <= $2" + const getForcedBatchesSQL = "SELECT forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase, block_num FROM state.forced_batch WHERE forced_batch_num > $1 AND block_num <= $2 ORDER BY forced_batch_num ASC" q := p.getExecQuerier(dbTx) rows, err := q.Query(ctx, getForcedBatchesSQL, forcedBatchNumber, maxBlockNumber) if errors.Is(err, pgx.ErrNoRows) { diff --git a/state/state_test.go b/state/state_test.go index 6144a1631c..a31c0fee30 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -650,162 +650,6 @@ func TestGetTxsHashesByBatchNumber(t *testing.T) { require.NoError(t, dbTx.Commit(ctx)) } -func TestDetermineProcessedTransactions(t *testing.T) { - tcs := []struct { - description string - input []*state.ProcessTransactionResponse - expectedProcessedOutput []*state.ProcessTransactionResponse - expectedUnprocessedOutput map[string]*state.ProcessTransactionResponse - }{ - { - description: "empty input returns empty", - input: []*state.ProcessTransactionResponse{}, - expectedProcessedOutput: []*state.ProcessTransactionResponse{}, - expectedUnprocessedOutput: map[string]*state.ProcessTransactionResponse{}, - }, - { - description: "single processed transaction returns itself", - input: []*state.ProcessTransactionResponse{ - {IsProcessed: true}, - }, - expectedProcessedOutput: []*state.ProcessTransactionResponse{ - {IsProcessed: true}, - }, - expectedUnprocessedOutput: map[string]*state.ProcessTransactionResponse{}, - }, - { - description: "single unprocessed transaction returns empty", - input: []*state.ProcessTransactionResponse{ - { - TxHash: common.HexToHash("a"), - IsProcessed: false, - }, - }, - expectedProcessedOutput: []*state.ProcessTransactionResponse{}, - expectedUnprocessedOutput: map[string]*state.ProcessTransactionResponse{ - "0x000000000000000000000000000000000000000000000000000000000000000a": { - TxHash: common.HexToHash("a"), - IsProcessed: false, - }, - }, - }, - { - description: "multiple processed transactions", - input: []*state.ProcessTransactionResponse{ - { - TxHash: common.HexToHash("a"), - IsProcessed: true, - }, - { - TxHash: common.HexToHash("b"), - IsProcessed: true, - }, - { - TxHash: common.HexToHash("c"), - IsProcessed: true, - }, - }, - expectedProcessedOutput: []*state.ProcessTransactionResponse{ - { - TxHash: common.HexToHash("a"), - IsProcessed: true, - }, - { - TxHash: common.HexToHash("b"), - IsProcessed: true, - }, - { - TxHash: common.HexToHash("c"), - IsProcessed: true, - }, - }, - expectedUnprocessedOutput: map[string]*state.ProcessTransactionResponse{}, - }, - { - description: "multiple unprocessed transactions", - input: []*state.ProcessTransactionResponse{ - { - TxHash: common.HexToHash("a"), - IsProcessed: false, - }, - { - TxHash: common.HexToHash("b"), - IsProcessed: false, - }, - { - TxHash: common.HexToHash("c"), - IsProcessed: false, - }, - }, - expectedProcessedOutput: []*state.ProcessTransactionResponse{}, - expectedUnprocessedOutput: map[string]*state.ProcessTransactionResponse{ - "0x000000000000000000000000000000000000000000000000000000000000000a": { - TxHash: common.HexToHash("a"), - IsProcessed: false, - }, - "0x000000000000000000000000000000000000000000000000000000000000000b": { - TxHash: common.HexToHash("b"), - IsProcessed: false, - }, - "0x000000000000000000000000000000000000000000000000000000000000000c": { - TxHash: common.HexToHash("c"), - IsProcessed: false, - }, - }, - }, - { - description: "mixed processed and unprocessed transactions", - input: []*state.ProcessTransactionResponse{ - { - TxHash: common.HexToHash("a"), - IsProcessed: true, - }, - { - TxHash: common.HexToHash("b"), - IsProcessed: false, - }, - { - TxHash: common.HexToHash("c"), - IsProcessed: true, - }, - { - TxHash: common.HexToHash("d"), - IsProcessed: false, - }, - }, - expectedProcessedOutput: []*state.ProcessTransactionResponse{ - { - TxHash: common.HexToHash("a"), - IsProcessed: true, - }, - { - TxHash: common.HexToHash("c"), - IsProcessed: true, - }, - }, - expectedUnprocessedOutput: map[string]*state.ProcessTransactionResponse{ - "0x000000000000000000000000000000000000000000000000000000000000000b": { - TxHash: common.HexToHash("b"), - IsProcessed: false, - }, - "0x000000000000000000000000000000000000000000000000000000000000000d": { - TxHash: common.HexToHash("d"), - IsProcessed: false, - }, - }, - }, - } - - for _, tc := range tcs { - tc := tc - t.Run(tc.description, func(t *testing.T) { - actualProcessedTx, _, actualUnprocessedTxs, _ := state.DetermineProcessedTransactions(tc.input) - require.Equal(t, tc.expectedProcessedOutput, actualProcessedTx) - require.Equal(t, tc.expectedUnprocessedOutput, actualUnprocessedTxs) - }) - } -} - func TestGenesis(t *testing.T) { block := state.Block{ BlockNumber: 1, diff --git a/state/transaction.go b/state/transaction.go index 56f1c067e6..65fbde338e 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -738,49 +738,12 @@ func (s *State) isContractCreation(tx *types.Transaction) bool { return tx.To() == nil && len(tx.Data()) > 0 } -// DetermineProcessedTransactions splits the given tx process responses -// returning a slice with only processed and a map unprocessed txs -// respectively. -func DetermineProcessedTransactions(responses []*ProcessTransactionResponse) ( - []*ProcessTransactionResponse, []string, map[string]*ProcessTransactionResponse, []string) { - processedTxResponses := []*ProcessTransactionResponse{} - processedTxsHashes := []string{} - unprocessedTxResponses := map[string]*ProcessTransactionResponse{} - unprocessedTxsHashes := []string{} - for _, response := range responses { - if response.IsProcessed { - processedTxResponses = append(processedTxResponses, response) - processedTxsHashes = append(processedTxsHashes, response.TxHash.String()) - } else { - log.Infof("Tx %s has not been processed", response.TxHash) - unprocessedTxResponses[response.TxHash.String()] = response - unprocessedTxsHashes = append(unprocessedTxsHashes, response.TxHash.String()) - } - } - return processedTxResponses, processedTxsHashes, unprocessedTxResponses, unprocessedTxsHashes -} - // StoreTransaction is used by the sequencer to add process a transaction func (s *State) StoreTransaction(ctx context.Context, batchNumber uint64, processedTx *ProcessTransactionResponse, coinbase common.Address, timestamp uint64, dbTx pgx.Tx) error { if dbTx == nil { return ErrDBTxNil } - // Check if last batch is closed. Note that it's assumed that only the latest batch can be open - /* - isBatchClosed, err := s.PostgresStorage.IsBatchClosed(ctx, batchNumber, dbTx) - if err != nil { - return err - } - if isBatchClosed { - return ErrBatchAlreadyClosed - } - - processingContext, err := s.GetProcessingContext(ctx, batchNumber, dbTx) - if err != nil { - return err - } - */ // if the transaction has an intrinsic invalid tx error it means // the transaction has not changed the state, so we don't store it if executor.IsIntrinsicError(executor.RomErrorCode(processedTx.RomError)) { diff --git a/state/types.go b/state/types.go index eccf1ed0bf..72e8c4c14e 100644 --- a/state/types.go +++ b/state/types.go @@ -27,15 +27,17 @@ type ProcessRequest struct { // ProcessBatchResponse represents the response of a batch process. type ProcessBatchResponse struct { - NewStateRoot common.Hash - NewAccInputHash common.Hash - NewLocalExitRoot common.Hash - NewBatchNumber uint64 - UsedZkCounters ZKCounters - Responses []*ProcessTransactionResponse - ExecutorError error - RomOOC bool - ReadWriteAddresses map[common.Address]*InfoReadWrite + NewStateRoot common.Hash + NewAccInputHash common.Hash + NewLocalExitRoot common.Hash + NewBatchNumber uint64 + UsedZkCounters ZKCounters + Responses []*ProcessTransactionResponse + ExecutorError error + IsRomLevelError bool + IsExecutorLevelError bool + IsRomOOCError bool + ReadWriteAddresses map[common.Address]*InfoReadWrite } // ProcessTransactionResponse represents the response of a tx process. @@ -61,8 +63,8 @@ type ProcessTransactionResponse struct { StateRoot common.Hash // Logs emitted by LOG opcode Logs []*types.Log - // IsProcessed indicates if this tx didn't fit into the batch - IsProcessed bool + // ChangesStateRoot indicates if this tx affects the state + ChangesStateRoot bool // Tx is the whole transaction object Tx types.Transaction // ExecutionTrace contains the traces produced in the execution diff --git a/test/Makefile b/test/Makefile index d0641ba09f..eb23d6a773 100644 --- a/test/Makefile +++ b/test/Makefile @@ -474,41 +474,41 @@ install-mockery: ## Installs mockery with the correct version to generate the mo .PHONY: generate-mocks generate-mocks: ## Generates mocks for the tests, using mockery tool - mockery --name=storageInterface --dir=../jsonrpc --output=../jsonrpc --outpkg=jsonrpc --inpackage --structname=storageMock --filename=mock_storage.go - mockery --name=PoolInterface --dir=../jsonrpc/types --output=../jsonrpc/mocks --outpkg=mocks --structname=PoolMock --filename=mock_pool.go - mockery --name=StateInterface --dir=../jsonrpc/types --output=../jsonrpc/mocks --outpkg=mocks --structname=StateMock --filename=mock_state.go - mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../jsonrpc/mocks --outpkg=mocks --structname=DBTxMock --filename=mock_dbtx.go - - mockery --name=workerInterface --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=WorkerMock --filename=mock_worker.go - mockery --name=stateInterface --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=StateMock --filename=mock_state.go - mockery --name=txPool --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=PoolMock --filename=mock_pool.go - mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../sequencer --outpkg=sequencer --structname=DbTxMock --filename=mock_dbtx.go - mockery --name=dbManagerInterface --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=DbManagerMock --filename=mock_db_manager.go - mockery --name=etherman --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=EthermanMock --filename=mock_etherman.go - - mockery --name=ethermanInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=ethermanMock --filename=mock_etherman.go - mockery --name=stateInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=stateMock --filename=mock_state.go - mockery --name=ethTxManager --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=ethTxManagerMock --filename=mock_ethtxmanager.go - mockery --name=poolInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=poolMock --filename=mock_pool.go - mockery --name=zkEVMClientInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=zkEVMClientMock --filename=mock_zkevmclient.go - mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../synchronizer --outpkg=synchronizer --structname=dbTxMock --filename=mock_dbtx.go - - mockery --name=GasPricer --srcpkg=github.com/ethereum/go-ethereum --output=../etherman --outpkg=etherman --structname=etherscanMock --filename=mock_etherscan.go - mockery --name=GasPricer --srcpkg=github.com/ethereum/go-ethereum --output=../etherman --outpkg=etherman --structname=ethGasStationMock --filename=mock_ethgasstation.go - - mockery --name=ethermanInterface --dir=../ethtxmanager --output=../ethtxmanager --outpkg=ethtxmanager --structname=ethermanMock --filename=mock_etherman_test.go - mockery --name=stateInterface --dir=../ethtxmanager --output=../ethtxmanager --outpkg=ethtxmanager --structname=stateMock --filename=mock_state_test.go - - mockery --name=pool --dir=../gasprice --output=../gasprice --outpkg=gasprice --structname=poolMock --filename=mock_pool.go - mockery --name=ethermanInterface --dir=../gasprice --output=../gasprice --outpkg=gasprice --structname=ethermanMock --filename=mock_etherman.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=storageInterface --dir=../jsonrpc --output=../jsonrpc --outpkg=jsonrpc --inpackage --structname=storageMock --filename=mock_storage.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=PoolInterface --dir=../jsonrpc/types --output=../jsonrpc/mocks --outpkg=mocks --structname=PoolMock --filename=mock_pool.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=StateInterface --dir=../jsonrpc/types --output=../jsonrpc/mocks --outpkg=mocks --structname=StateMock --filename=mock_state.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../jsonrpc/mocks --outpkg=mocks --structname=DBTxMock --filename=mock_dbtx.go + + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=workerInterface --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=WorkerMock --filename=mock_worker.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=stateInterface --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=StateMock --filename=mock_state.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=txPool --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=PoolMock --filename=mock_pool.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../sequencer --outpkg=sequencer --structname=DbTxMock --filename=mock_dbtx.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=dbManagerInterface --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=DbManagerMock --filename=mock_db_manager.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=etherman --dir=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=EthermanMock --filename=mock_etherman.go + + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ethermanInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=ethermanMock --filename=mock_etherman.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=stateInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=stateMock --filename=mock_state.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ethTxManager --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=ethTxManagerMock --filename=mock_ethtxmanager.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=poolInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=poolMock --filename=mock_pool.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=zkEVMClientInterface --dir=../synchronizer --output=../synchronizer --outpkg=synchronizer --structname=zkEVMClientMock --filename=mock_zkevmclient.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../synchronizer --outpkg=synchronizer --structname=dbTxMock --filename=mock_dbtx.go + + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=GasPricer --srcpkg=github.com/ethereum/go-ethereum --output=../etherman --outpkg=etherman --structname=etherscanMock --filename=mock_etherscan.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=GasPricer --srcpkg=github.com/ethereum/go-ethereum --output=../etherman --outpkg=etherman --structname=ethGasStationMock --filename=mock_ethgasstation.go + + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ethermanInterface --dir=../ethtxmanager --output=../ethtxmanager --outpkg=ethtxmanager --structname=ethermanMock --filename=mock_etherman_test.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=stateInterface --dir=../ethtxmanager --output=../ethtxmanager --outpkg=ethtxmanager --structname=stateMock --filename=mock_state_test.go + + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=pool --dir=../gasprice --output=../gasprice --outpkg=gasprice --structname=poolMock --filename=mock_pool.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ethermanInterface --dir=../gasprice --output=../gasprice --outpkg=gasprice --structname=ethermanMock --filename=mock_etherman.go ## mocks for the aggregator tests - mockery --name=stateInterface --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=StateMock --filename=mock_state.go - mockery --name=proverInterface --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=ProverMock --filename=mock_prover.go - mockery --name=etherman --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=Etherman --filename=mock_etherman.go - mockery --name=ethTxManager --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=EthTxManager --filename=mock_ethtxmanager.go - mockery --name=aggregatorTxProfitabilityChecker --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=ProfitabilityCheckerMock --filename=mock_profitabilitychecker.go - mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../aggregator/mocks --outpkg=mocks --structname=DbTxMock --filename=mock_dbtx.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=stateInterface --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=StateMock --filename=mock_state.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=proverInterface --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=ProverMock --filename=mock_prover.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=etherman --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=Etherman --filename=mock_etherman.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ethTxManager --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=EthTxManager --filename=mock_ethtxmanager.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=aggregatorTxProfitabilityChecker --dir=../aggregator --output=../aggregator/mocks --outpkg=mocks --structname=ProfitabilityCheckerMock --filename=mock_profitabilitychecker.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../aggregator/mocks --outpkg=mocks --structname=DbTxMock --filename=mock_dbtx.go .PHONY: run-benchmarks run-benchmarks: run-db ## Runs benchmars