Skip to content

Commit

Permalink
check unsupported precompiles (#3264)
Browse files Browse the repository at this point in the history
* check unsupported precompiles

* downgrade prover

* restore solc version

* update SC

* new errors

* fix as workaround to close batch on tx oog (#3271)

Co-authored-by: agnusmor <[email protected]>

* handle executor close batch

* added sanity check closing an empty batch

* change log

---------

Co-authored-by: agnusmor <[email protected]>
  • Loading branch information
ToniRamirezM and agnusmor authored Feb 14, 2024
1 parent 2f1ecc4 commit 0171536
Show file tree
Hide file tree
Showing 14 changed files with 353 additions and 46 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ services:
zkevm-prover:
container_name: zkevm-prover
restart: unless-stopped
image: hermeznetwork/zkevm-prover:v4.0.4
image: hermeznetwork/zkevm-prover:v4.0.10
depends_on:
zkevm-state-db:
condition: service_healthy
Expand Down
3 changes: 3 additions & 0 deletions event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ const (
EventID_SynchronizerHalt EventID = "SYNCHRONIZER HALT"
// EventID_SequenceSenderHalt is triggered when the SequenceSender halts
EventID_SequenceSenderHalt EventID = "SEQUENCESENDER HALT"
// EventID_UnsupportedPrecompile is triggered when the executor returns an unsupported precompile error
EventID_UnsupportedPrecompile EventID = "UNSUPPORTED PRECOMPILE"

// EventID_NodeOOC is triggered when an OOC at node level is detected
EventID_NodeOOC EventID = "NODE OOC"
// Source_Node is the source of the event
Expand Down
14 changes: 14 additions & 0 deletions proto/src/proto/executor/v1/executor.proto
Original file line number Diff line number Diff line change
Expand Up @@ -854,4 +854,18 @@ enum ExecutorError {
EXECUTOR_ERROR_INVALID_L1_INFO_TREE_INDEX = 111;
// EXECUTOR_ERROR_INVALID_L1_INFO_TREE_SMT_PROOF_VALUE indicates that the ROM asked for an L1InfoTree SMT proof that was not present in the input
EXECUTOR_ERROR_INVALID_L1_INFO_TREE_SMT_PROOF_VALUE = 112;
// EXECUTOR_ERROR_INVALID_WITNESS indicates that the provided witness data is invalid
EXECUTOR_ERROR_INVALID_WITNESS = 113;
// EXECUTOR_ERROR_INVALID_CBOR indicates that the provided CBOR data is invalid
EXECUTOR_ERROR_INVALID_CBOR = 114;
// EXECUTOR_ERROR_INVALID_DATA_STREAM indicates that the provided data stream data is invalid
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_UNSUPPORTED_PRECOMPILED indicates that an unsupported precompiled has been used
EXECUTOR_ERROR_UNSUPPORTED_PRECOMPILED = 117;
// EXECUTOR_ERROR_OOG_2 indicates that an out of gas has occurred
EXECUTOR_ERROR_OOG_2 = 118;
// EXECUTOR_ERROR_CLOSE_BATCH indicates that batch must be closed
EXECUTOR_ERROR_CLOSE_BATCH = 119;
}
5 changes: 5 additions & 0 deletions sequencer/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,11 @@ func (f *finalizer) openNewWIPBatch(ctx context.Context, batchNumber uint64, sta

// closeWIPBatch closes the current batch in the state
func (f *finalizer) closeWIPBatch(ctx context.Context) error {
// Sanity check: batch must not be empty (should have L2 blocks)
if f.wipBatch.isEmpty() {
f.Halt(ctx, fmt.Errorf("closing WIP batch %d without L2 blocks and should have at least 1", f.wipBatch.batchNumber), false)
}

usedResources := getUsedBatchResources(f.batchConstraints, f.wipBatch.imRemainingResources)
receipt := state.ProcessingReceipt{
BatchNumber: f.wipBatch.batchNumber,
Expand Down
70 changes: 52 additions & 18 deletions sequencer/finalizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sequencer

import (
"context"
"encoding/json"
"errors"
"fmt"
"math/big"
Expand Down Expand Up @@ -283,14 +284,16 @@ func (f *finalizer) finalizeBatches(ctx context.Context) {
continue
}

closeWIPBatch := false
metrics.WorkerProcessingTime(time.Since(start))
if tx != nil {
showNotFoundTxLog = true

firstTxProcess := true

for {
_, err := f.processTransaction(ctx, tx, firstTxProcess)
var err error
_, closeWIPBatch, err = f.processTransaction(ctx, tx, firstTxProcess)
if err != nil {
if err == ErrEffectiveGasPriceReprocess {
firstTxProcess = false
Expand Down Expand Up @@ -325,7 +328,11 @@ func (f *finalizer) finalizeBatches(ctx context.Context) {
}

// Check if we must finalize the batch due to a closing reason (resources exhausted, max txs, timestamp resolution, forced batches deadline)
if finalize, closeReason := f.checkIfFinalizeBatch(); finalize {
finalize, closeReason := f.checkIfFinalizeBatch()
if closeWIPBatch || finalize {
if closeWIPBatch {
closeReason = "Executor close batch"
}
f.finalizeWIPBatch(ctx, closeReason)
}

Expand All @@ -337,7 +344,7 @@ func (f *finalizer) finalizeBatches(ctx context.Context) {
}

// processTransaction processes a single transaction.
func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, firstTxProcess bool) (errWg *sync.WaitGroup, err error) {
func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, firstTxProcess bool) (errWg *sync.WaitGroup, closeWIPBatch bool, err error) {
start := time.Now()
defer func() {
metrics.ProcessingTime(time.Since(start))
Expand Down Expand Up @@ -380,7 +387,7 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first
egp, err := f.effectiveGasPrice.CalculateEffectiveGasPrice(tx.RawTx, txGasPrice, tx.BatchResources.ZKCounters.GasUsed, tx.L1GasPrice, txL2GasPrice)
if err != nil {
if f.effectiveGasPrice.IsEnabled() {
return nil, err
return nil, false, err
} else {
log.Warnf("effectiveGasPrice is disabled, but failed to calculate effectiveGasPrice for tx %s, error: %v", tx.HashStr, err)
tx.EGPLog.Error = fmt.Sprintf("CalculateEffectiveGasPrice#1: %s", err)
Expand Down Expand Up @@ -408,7 +415,7 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first
egpPercentage, err := f.effectiveGasPrice.CalculateEffectiveGasPricePercentage(txGasPrice, tx.EffectiveGasPrice)
if err != nil {
if f.effectiveGasPrice.IsEnabled() {
return nil, err
return nil, false, err
} else {
log.Warnf("effectiveGasPrice is disabled, but failed to to calculate efftive gas price percentage (#1), error: %v", err)
tx.EGPLog.Error = fmt.Sprintf("%s; CalculateEffectiveGasPricePercentage#1: %s", tx.EGPLog.Error, err)
Expand All @@ -428,7 +435,7 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first

effectivePercentageAsDecodedHex, err := hex.DecodeHex(fmt.Sprintf("%x", tx.EGPPercentage))
if err != nil {
return nil, err
return nil, false, err
}

batchRequest.Transactions = append(batchRequest.Transactions, effectivePercentageAsDecodedHex...)
Expand All @@ -437,12 +444,34 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first

if err != nil && (errors.Is(err, runtime.ErrExecutorDBError) || errors.Is(err, runtime.ErrInvalidTxChangeL2BlockMinTimestamp)) {
log.Errorf("failed to process tx %s, error: %v", tx.HashStr, err)
return nil, err
return nil, false, err
} else if err == nil && !batchResponse.IsRomLevelError && len(batchResponse.BlockResponses) == 0 {
err = fmt.Errorf("executor returned no errors and no responses for tx %s", tx.HashStr)
f.Halt(ctx, err, false)
} else if err != nil {
log.Errorf("error received from executor, error: %v", err)

if errors.Is(err, runtime.ErrExecutorErrorUnsupportedPrecompile) {
payload, err := json.Marshal(batchRequest)
if err != nil {
log.Errorf("error marshaling payload, error: %v", err)
} else {
event := &event.Event{
ReceivedAt: time.Now(),
Source: event.Source_Node,
Component: event.Component_Sequencer,
Level: event.Level_Warning,
EventID: event.EventID_UnsupportedPrecompile,
Description: string(payload),
Json: batchRequest,
}
err = f.eventLog.LogEvent(ctx, event)
if err != nil {
log.Errorf("error storing payload, error: %v", err)
}
}
}

// Delete tx from the worker
f.workerIntf.DeleteTx(tx.Hash, tx.From)

Expand All @@ -454,14 +483,15 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first
} else {
metrics.TxProcessed(metrics.TxProcessedLabelInvalid, 1)
}
return nil, err
return nil, false, err
}

closeBatch := false
oldStateRoot := f.wipBatch.imStateRoot
if len(batchResponse.BlockResponses) > 0 {
errWg, err = f.handleProcessTransactionResponse(ctx, tx, batchResponse, oldStateRoot)
errWg, closeBatch, err = f.handleProcessTransactionResponse(ctx, tx, batchResponse, oldStateRoot)
if err != nil {
return errWg, err
return errWg, false, err
}
}

Expand All @@ -471,17 +501,17 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first
log.Infof("processed tx %s, batchNumber: %d, l2Block: [%d], newStateRoot: %s, oldStateRoot: %s, used counters: %s",
tx.HashStr, batchRequest.BatchNumber, f.wipL2Block.trackingNum, batchResponse.NewStateRoot.String(), batchRequest.OldStateRoot.String(), f.logZKCounters(batchResponse.UsedZkCounters))

return nil, nil
return nil, closeBatch, nil
}

// handleProcessTransactionResponse handles the response of transaction processing.
func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *TxTracker, result *state.ProcessBatchResponse, oldStateRoot common.Hash) (errWg *sync.WaitGroup, err error) {
func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *TxTracker, result *state.ProcessBatchResponse, oldStateRoot common.Hash) (errWg *sync.WaitGroup, closeWIPBatch bool, err error) {
// Handle Transaction Error
errorCode := executor.RomErrorCode(result.BlockResponses[0].TransactionResponses[0].RomError)
if !state.IsStateRootChanged(errorCode) {
// If intrinsic error or OOC error, we skip adding the transaction to the batch
errWg = f.handleProcessTransactionError(ctx, result, tx)
return errWg, result.BlockResponses[0].TransactionResponses[0].RomError
return errWg, false, result.BlockResponses[0].TransactionResponses[0].RomError
}

egpEnabled := f.effectiveGasPrice.IsEnabled()
Expand All @@ -496,7 +526,7 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx
if err != nil {
if egpEnabled {
log.Errorf("failed to calculate effective gas price with new gasUsed for tx %s, error: %v", tx.HashStr, err.Error())
return nil, err
return nil, false, err
} else {
log.Warnf("effectiveGasPrice is disabled, but failed to calculate effective gas price with new gasUsed for tx %s, error: %v", tx.HashStr, err.Error())
tx.EGPLog.Error = fmt.Sprintf("%s; CalculateEffectiveGasPrice#2: %s", tx.EGPLog.Error, err)
Expand All @@ -521,7 +551,7 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx
}

if errCompare != nil && egpEnabled {
return nil, errCompare
return nil, false, errCompare
}
}
}
Expand Down Expand Up @@ -557,12 +587,12 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx
log.Errorf("failed to update status to invalid in the pool for tx %s, error: %v", tx.Hash.String(), err)
}

return nil, ErrBatchResourceUnderFlow
return nil, false, ErrBatchResourceUnderFlow
} else {
start := time.Now()
f.workerIntf.UpdateTxZKCounters(result.BlockResponses[0].TransactionResponses[0].TxHash, tx.From, result.UsedZkCounters)
metrics.WorkerProcessingTime(time.Since(start))
return nil, ErrBatchResourceUnderFlow
return nil, false, ErrBatchResourceUnderFlow
}
}

Expand All @@ -583,7 +613,11 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx

f.updateWorkerAfterSuccessfulProcessing(ctx, tx.Hash, tx.From, false, result)

return nil, nil
if result.CloseBatch_V2 {
return nil, true, nil
}

return nil, false, nil
}

// compareTxEffectiveGasPrice compares newEffectiveGasPrice with tx.EffectiveGasPrice.
Expand Down
3 changes: 2 additions & 1 deletion state/convertersV2.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (s *State) convertToProcessBatchResponseV2(batchResponse *executor.ProcessB
FlushID: batchResponse.FlushId,
StoredFlushID: batchResponse.StoredFlushId,
ProverID: batchResponse.ProverId,
IsExecutorLevelError: (batchResponse.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR),
IsExecutorLevelError: (batchResponse.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR && batchResponse.Error != executor.ExecutorError_EXECUTOR_ERROR_CLOSE_BATCH),
IsRomLevelError: isRomLevelError,
IsRomOOCError: isRomOOCError,
GasUsed_V2: batchResponse.GasUsed,
Expand All @@ -65,6 +65,7 @@ func (s *State) convertToProcessBatchResponseV2(batchResponse *executor.ProcessB
ForkID: batchResponse.ForkId,
InvalidBatch_V2: batchResponse.InvalidBatch != 0,
RomError_V2: executor.RomErr(batchResponse.ErrorRom),
CloseBatch_V2: batchResponse.Error == executor.ExecutorError_EXECUTOR_ERROR_CLOSE_BATCH,
}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion state/pgstatestorage/datastream.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (p *PostgresStorage) GetDSGenesisBlock(ctx context.Context, dbTx pgx.Tx) (*

// GetDSL2Blocks returns the L2 blocks
func (p *PostgresStorage) GetDSL2Blocks(ctx context.Context, firstBatchNumber, lastBatchNumber uint64, dbTx pgx.Tx) ([]*state.DSL2Block, error) {
const l2BlockSQL = `SELECT l2b.batch_num, l2b.block_num, l2b.received_at, b.global_exit_root, l2b.header->>'globalExitRoot' AS block_global_exit_root, l2b.header->>'miner' AS coinbase, f.fork_id, l2b.block_hash, l2b.state_root
const l2BlockSQL = `SELECT l2b.batch_num, l2b.block_num, l2b.received_at, b.global_exit_root, COALESCE(l2b.header->>'globalExitRoot', '') AS block_global_exit_root, l2b.header->>'miner' AS coinbase, f.fork_id, l2b.block_hash, l2b.state_root
FROM state.l2block l2b, state.batch b, state.fork_id f
WHERE l2b.batch_num BETWEEN $1 AND $2 AND l2b.batch_num = b.batch_num AND l2b.batch_num between f.from_batch_num AND f.to_batch_num
ORDER BY l2b.block_num ASC`
Expand Down
28 changes: 28 additions & 0 deletions state/runtime/executor/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,20 @@ func ExecutorErr(errorCode ExecutorError) error {
return runtime.ErrExecutorErrorInvalidL1InfoTreeIndex
case ExecutorError_EXECUTOR_ERROR_INVALID_L1_INFO_TREE_SMT_PROOF_VALUE:
return runtime.ErrExecutorErrorInvalidL1InfoTreeSmtProofValue
case ExecutorError_EXECUTOR_ERROR_INVALID_WITNESS:
return runtime.ErrExecutorErrorInvalidWitness
case ExecutorError_EXECUTOR_ERROR_INVALID_CBOR:
return runtime.ErrExecutorErrorInvalidCBOR
case ExecutorError_EXECUTOR_ERROR_INVALID_DATA_STREAM:
return runtime.ErrExecutorErrorInvalidDataStream
case ExecutorError_EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE:
return runtime.ErrExecutorErrorInvalidUpdateMerkleTree
case ExecutorError_EXECUTOR_ERROR_UNSUPPORTED_PRECOMPILED:
return runtime.ErrExecutorErrorUnsupportedPrecompile
case ExecutorError_EXECUTOR_ERROR_OOG_2:
return runtime.ErrExecutorErrorOOG2
case ExecutorError_EXECUTOR_ERROR_CLOSE_BATCH:
return runtime.ErrExecutorErrorCloseBatch
}
return ErrExecutorUnknown
}
Expand Down Expand Up @@ -678,6 +692,20 @@ func ExecutorErrorCode(err error) ExecutorError {
return ExecutorError_EXECUTOR_ERROR_INVALID_L1_INFO_TREE_INDEX
case runtime.ErrExecutorErrorInvalidL1InfoTreeSmtProofValue:
return ExecutorError_EXECUTOR_ERROR_INVALID_L1_INFO_TREE_SMT_PROOF_VALUE
case runtime.ErrExecutorErrorInvalidWitness:
return ExecutorError_EXECUTOR_ERROR_INVALID_WITNESS
case runtime.ErrExecutorErrorInvalidCBOR:
return ExecutorError_EXECUTOR_ERROR_INVALID_CBOR
case runtime.ErrExecutorErrorInvalidDataStream:
return ExecutorError_EXECUTOR_ERROR_INVALID_DATA_STREAM
case runtime.ErrExecutorErrorInvalidUpdateMerkleTree:
return ExecutorError_EXECUTOR_ERROR_INVALID_UPDATE_MERKLE_TREE
case runtime.ErrExecutorErrorUnsupportedPrecompile:
return ExecutorError_EXECUTOR_ERROR_UNSUPPORTED_PRECOMPILED
case runtime.ErrExecutorErrorOOG2:
return ExecutorError_EXECUTOR_ERROR_OOG_2
case runtime.ErrExecutorErrorCloseBatch:
return ExecutorError_EXECUTOR_ERROR_CLOSE_BATCH
}

return ErrCodeExecutorUnknown
Expand Down
Loading

0 comments on commit 0171536

Please sign in to comment.