diff --git a/config/config_test.go b/config/config_test.go index f2e01575b8..cf918c4afe 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -60,6 +60,11 @@ func Test_Defaults(t *testing.T) { path: "Synchronizer.L2Synchronization.ReprocessFullBatchOnClose", expectedValue: false, }, + { + path: "Synchronizer.L2Synchronization.CheckLastL2BlockHashOnCloseBatch", + expectedValue: true, + }, + { path: "Sequencer.DeletePoolTxsL1BlockConfirmations", expectedValue: uint64(100), diff --git a/config/default.go b/config/default.go index b28076b251..c8db9dbc2d 100644 --- a/config/default.go +++ b/config/default.go @@ -119,6 +119,7 @@ L1SynchronizationMode = "sequential" [Synchronizer.L2Synchronization] AcceptEmptyClosedBatches = false ReprocessFullBatchOnClose = false + CheckLastL2BlockHashOnCloseBatch = true [Sequencer] DeletePoolTxsL1BlockConfirmations = 100 diff --git a/docs/config-file/node-config-doc.html b/docs/config-file/node-config-doc.html index d76299260d..6b95d5c91b 100644 --- a/docs/config-file/node-config-doc.html +++ b/docs/config-file/node-config-doc.html @@ -28,7 +28,7 @@
"300ms"
RollupInfoRetriesSpacing is the minimum time between retries to request rollup info (it will sleep for fulfill this time) to avoid spamming L1
"1m"
"300ms"
-
FallbackToSequentialModeOnSynchronized if true switch to sequential mode if the system is synchronized
AcceptEmptyClosedBatches is a flag to enable or disable the acceptance of empty batches.
if true, the synchronizer will accept empty batches and process them.
ReprocessFullBatchOnClose if is true when a batch is closed is force to reprocess again
DeletePoolTxsL1BlockConfirmations is blocks amount after which txs will be deleted from the pool
DeletePoolTxsCheckInterval is frequency with which txs will be checked for deleting
"1m"
+
FallbackToSequentialModeOnSynchronized if true switch to sequential mode if the system is synchronized
AcceptEmptyClosedBatches is a flag to enable or disable the acceptance of empty batches.
if true, the synchronizer will accept empty batches and process them.
ReprocessFullBatchOnClose if is true when a batch is closed is force to reprocess again
DeletePoolTxsL1BlockConfirmations is blocks amount after which txs will be deleted from the pool
DeletePoolTxsCheckInterval is frequency with which txs will be checked for deleting
"1m"
"300ms"
TxLifetimeCheckInterval is the time the sequencer waits to check txs lifetime
"1m"
"300ms"
diff --git a/docs/config-file/node-config-doc.md b/docs/config-file/node-config-doc.md
index 5ca12d7e8b..0d70da8e62 100644
--- a/docs/config-file/node-config-doc.md
+++ b/docs/config-file/node-config-doc.md
@@ -1683,10 +1683,11 @@ FallbackToSequentialModeOnSynchronized=false
**Type:** : `object`
**Description:** L2Synchronization Configuration for L2 synchronization
-| Property | Pattern | Type | Deprecated | Definition | Title/Description |
-| ----------------------------------------------------------------------------------------- | ------- | ------- | ---------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| - [AcceptEmptyClosedBatches](#Synchronizer_L2Synchronization_AcceptEmptyClosedBatches ) | No | boolean | No | - | AcceptEmptyClosedBatches is a flag to enable or disable the acceptance of empty batches.
if true, the synchronizer will accept empty batches and process them. |
-| - [ReprocessFullBatchOnClose](#Synchronizer_L2Synchronization_ReprocessFullBatchOnClose ) | No | boolean | No | - | ReprocessFullBatchOnClose if is true when a batch is closed is force to reprocess again |
+| Property | Pattern | Type | Deprecated | Definition | Title/Description |
+| ------------------------------------------------------------------------------------------------------- | ------- | ------- | ---------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| - [AcceptEmptyClosedBatches](#Synchronizer_L2Synchronization_AcceptEmptyClosedBatches ) | No | boolean | No | - | AcceptEmptyClosedBatches is a flag to enable or disable the acceptance of empty batches.
if true, the synchronizer will accept empty batches and process them. |
+| - [ReprocessFullBatchOnClose](#Synchronizer_L2Synchronization_ReprocessFullBatchOnClose ) | No | boolean | No | - | ReprocessFullBatchOnClose if is true when a batch is closed is force to reprocess again |
+| - [CheckLastL2BlockHashOnCloseBatch](#Synchronizer_L2Synchronization_CheckLastL2BlockHashOnCloseBatch ) | No | boolean | No | - | CheckLastL2BlockHashOnCloseBatch if is true when a batch is closed is force to check the last L2Block hash |
#### 9.6.1. `Synchronizer.L2Synchronization.AcceptEmptyClosedBatches`
@@ -1717,6 +1718,20 @@ AcceptEmptyClosedBatches=false
ReprocessFullBatchOnClose=false
```
+#### 9.6.3. `Synchronizer.L2Synchronization.CheckLastL2BlockHashOnCloseBatch`
+
+**Type:** : `boolean`
+
+**Default:** `true`
+
+**Description:** CheckLastL2BlockHashOnCloseBatch if is true when a batch is closed is force to check the last L2Block hash
+
+**Example setting the default value** (true):
+```
+[Synchronizer.L2Synchronization]
+CheckLastL2BlockHashOnCloseBatch=true
+```
+
## 10. `[Sequencer]`
**Type:** : `object`
diff --git a/docs/config-file/node-config-schema.json b/docs/config-file/node-config-schema.json
index 3d8842e926..867558ea25 100644
--- a/docs/config-file/node-config-schema.json
+++ b/docs/config-file/node-config-schema.json
@@ -635,7 +635,7 @@
"ReprocessFullBatchOnClose": {
"type": "boolean",
"description": "ReprocessFullBatchOnClose if is true when a batch is closed is force to reprocess again",
- "default": false
+ "default": true
}
},
"additionalProperties": false,
diff --git a/synchronizer/l2_sync/config.go b/synchronizer/l2_sync/config.go
index 7166765b88..7781c7bd6c 100644
--- a/synchronizer/l2_sync/config.go
+++ b/synchronizer/l2_sync/config.go
@@ -8,4 +8,7 @@ type Config struct {
// ReprocessFullBatchOnClose if is true when a batch is closed is force to reprocess again
ReprocessFullBatchOnClose bool `mapstructure:"ReprocessFullBatchOnClose"`
+
+ // CheckLastL2BlockHashOnCloseBatch if is true when a batch is closed is force to check the last L2Block hash
+ CheckLastL2BlockHashOnCloseBatch bool `mapstructure:"CheckLastL2BlockHashOnCloseBatch"`
}
diff --git a/synchronizer/l2_sync/l2_shared/post_closed_batch_check_l2block.go b/synchronizer/l2_sync/l2_shared/post_closed_batch_check_l2block.go
new file mode 100644
index 0000000000..e42842aa8a
--- /dev/null
+++ b/synchronizer/l2_sync/l2_shared/post_closed_batch_check_l2block.go
@@ -0,0 +1,63 @@
+package l2_shared
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ "github.com/0xPolygonHermez/zkevm-node/log"
+ "github.com/0xPolygonHermez/zkevm-node/state"
+ "github.com/jackc/pgx/v4"
+)
+
+// Implements PostClosedBatchChecker
+
+type statePostClosedBatchCheckL2Block interface {
+ GetLastL2BlockByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.L2Block, error)
+}
+
+// PostClosedBatchCheckL2Block is a struct that implements the PostClosedBatchChecker interface and check the las L2Block hash on close batch
+type PostClosedBatchCheckL2Block struct {
+ state statePostClosedBatchCheckL2Block
+}
+
+// NewPostClosedBatchCheckL2Block creates a new PostClosedBatchCheckL2Block
+func NewPostClosedBatchCheckL2Block(state statePostClosedBatchCheckL2Block) *PostClosedBatchCheckL2Block {
+ return &PostClosedBatchCheckL2Block{
+ state: state,
+ }
+}
+
+// CheckPostClosedBatch checks the last L2Block hash on close batch
+func (p *PostClosedBatchCheckL2Block) CheckPostClosedBatch(ctx context.Context, processData ProcessData, dbTx pgx.Tx) error {
+ if processData.TrustedBatch == nil {
+ log.Warnf("%s trusted batch is nil", processData.DebugPrefix)
+ return nil
+ }
+ if len(processData.TrustedBatch.Blocks) == 0 {
+ log.Infof("%s trusted batch have no Blocks, so nothing to check", processData.DebugPrefix)
+ return nil
+ }
+
+ // Get last L2Block from the database
+ statelastL2Block, err := p.state.GetLastL2BlockByBatchNumber(ctx, processData.BatchNumber, dbTx)
+ if err != nil {
+ return err
+ }
+ if statelastL2Block == nil {
+ return fmt.Errorf("last L2Block in the database is nil")
+ }
+ trustedLastL2Block := processData.TrustedBatch.Blocks[len(processData.TrustedBatch.Blocks)-1].Block
+ log.Info(trustedLastL2Block)
+ if statelastL2Block.Number().Cmp(big.NewInt(int64(trustedLastL2Block.Number))) != 0 {
+ return fmt.Errorf("last L2Block in the database %s and the trusted batch %d are different", statelastL2Block.Number().String(), trustedLastL2Block.Number)
+ }
+
+ if statelastL2Block.Hash() != *trustedLastL2Block.Hash {
+ return fmt.Errorf("last L2Block %s in the database %s and the trusted batch %s are different", statelastL2Block.Number().String(), statelastL2Block.Hash().String(), trustedLastL2Block.Hash.String())
+ }
+ log.Infof("%s last L2Block in the database %s and the trusted batch %s are the same", processData.DebugPrefix, statelastL2Block.Number().String(), trustedLastL2Block.Number)
+ // Compare the two blocks
+
+ return nil
+}
diff --git a/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go b/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go
index 94535ebe4e..db4ddd15e0 100644
--- a/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go
+++ b/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go
@@ -132,16 +132,22 @@ type L1SyncGlobalExitRootChecker interface {
CheckL1SyncGlobalExitRootEnoughToProcessBatch(ctx context.Context, batchNumber uint64, globalExitRoot common.Hash, dbTx pgx.Tx) error
}
+// PostClosedBatchChecker is the interface to implement a checker post closed batch
+type PostClosedBatchChecker interface {
+ CheckPostClosedBatch(ctx context.Context, processData ProcessData, dbTx pgx.Tx) error
+}
+
// ProcessorTrustedBatchSync is a template to sync trusted state. It classify what kind of update is needed and call to SyncTrustedStateBatchExecutorSteps
//
// that is the one that execute the sync process
//
// the real implementation of the steps is in the SyncTrustedStateBatchExecutorSteps interface that known how to process a batch
type ProcessorTrustedBatchSync struct {
- Steps SyncTrustedBatchExecutor
- timeProvider syncCommon.TimeProvider
- l1SyncChecker L1SyncGlobalExitRootChecker
- Cfg l2_sync.Config
+ Steps SyncTrustedBatchExecutor
+ timeProvider syncCommon.TimeProvider
+ l1SyncChecker L1SyncGlobalExitRootChecker
+ postClosedCheckers []PostClosedBatchChecker
+ Cfg l2_sync.Config
}
// NewProcessorTrustedBatchSync creates a new SyncTrustedStateBatchExecutorTemplate
@@ -155,6 +161,14 @@ func NewProcessorTrustedBatchSync(steps SyncTrustedBatchExecutor,
}
}
+// AddPostChecker add a post closed batch checker
+func (s *ProcessorTrustedBatchSync) AddPostChecker(checker PostClosedBatchChecker) {
+ if s.postClosedCheckers == nil {
+ s.postClosedCheckers = make([]PostClosedBatchChecker, 0)
+ }
+ s.postClosedCheckers = append(s.postClosedCheckers, checker)
+}
+
// ProcessTrustedBatch processes a trusted batch and return the new state
func (s *ProcessorTrustedBatchSync) ProcessTrustedBatch(ctx context.Context, trustedBatch *types.Batch, status TrustedState, dbTx pgx.Tx, debugPrefix string) (*TrustedState, error) {
log.Debugf("%s Processing trusted batch: %v", debugPrefix, trustedBatch.Number)
@@ -241,6 +255,15 @@ func (s *ProcessorTrustedBatchSync) ExecuteProcessBatch(ctx context.Context, pro
log.Error("%s error verifying batch result! Error: ", processMode.DebugPrefix, err)
return nil, err
}
+ if s.postClosedCheckers != nil && len(s.postClosedCheckers) > 0 {
+ for _, checker := range s.postClosedCheckers {
+ err := checker.CheckPostClosedBatch(ctx, *processMode, dbTx)
+ if err != nil {
+ log.Errorf("%s error checking post closed batch. Error: ", processMode.DebugPrefix, err)
+ return nil, err
+ }
+ }
+ }
}
return processBatchResp, err
}
diff --git a/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync.go b/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync.go
index 377825bf56..bb1a0798fa 100644
--- a/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync.go
+++ b/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync.go
@@ -11,16 +11,11 @@ import (
"github.com/0xPolygonHermez/zkevm-node/state"
syncCommon "github.com/0xPolygonHermez/zkevm-node/synchronizer/common"
"github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces"
- "github.com/0xPolygonHermez/zkevm-node/synchronizer/l2_sync"
"github.com/0xPolygonHermez/zkevm-node/synchronizer/l2_sync/l2_shared"
"github.com/ethereum/go-ethereum/common"
"github.com/jackc/pgx/v4"
)
-const (
- timeOfLiveBatchOnCache = 5 * time.Minute
-)
-
var (
// ErrNotImplemented is returned when a method is not implemented
ErrNotImplemented = errors.New("not implemented")
@@ -54,19 +49,13 @@ type SyncTrustedBatchExecutorForEtrog struct {
sync syncinterfaces.SynchronizerFlushIDManager
}
-// NewSyncTrustedBatchExecutorForEtrog creates a new prcessor for sync with L2 batches
-func NewSyncTrustedBatchExecutorForEtrog(zkEVMClient syncinterfaces.ZKEVMClientTrustedBatchesGetter,
- state l2_shared.StateInterface, stateBatchExecutor StateInterface,
- sync syncinterfaces.SynchronizerFlushIDManager, timeProvider syncCommon.TimeProvider, l1SyncChecker l2_shared.L1SyncGlobalExitRootChecker,
- cfg l2_sync.Config) *l2_shared.TrustedBatchesRetrieve {
- executorSteps := &SyncTrustedBatchExecutorForEtrog{
+// NewSyncTrustedBatchExecutorForEtrog creates a new SyncTrustedBatchExecutorForEtrog
+func NewSyncTrustedBatchExecutorForEtrog(stateBatchExecutor StateInterface,
+ sync syncinterfaces.SynchronizerFlushIDManager) *SyncTrustedBatchExecutorForEtrog {
+ return &SyncTrustedBatchExecutorForEtrog{
state: stateBatchExecutor,
sync: sync,
}
-
- executor := l2_shared.NewProcessorTrustedBatchSync(executorSteps, timeProvider, l1SyncChecker, cfg)
- a := l2_shared.NewTrustedBatchesRetrieve(executor, zkEVMClient, state, sync, *l2_shared.NewTrustedStateManager(timeProvider, timeOfLiveBatchOnCache))
- return a
}
// NothingProcess process a batch that is already on database and no new L2batchData, so it is not going to be processed again.
diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go
index 591b2f4357..8029ec36a1 100644
--- a/synchronizer/synchronizer.go
+++ b/synchronizer/synchronizer.go
@@ -29,8 +29,9 @@ const (
// ParallelMode is the value for L1SynchronizationMode to run in parallel mode
ParallelMode = "parallel"
// SequentialMode is the value for L1SynchronizationMode to run in sequential mode
- SequentialMode = "sequential"
- maxBatchNumber = ^uint64(0)
+ SequentialMode = "sequential"
+ maxBatchNumber = ^uint64(0)
+ timeOfLiveBatchOnCache = 5 * time.Minute
)
// Synchronizer connects L1 and L2
@@ -113,10 +114,17 @@ func NewSynchronizer(
if !isTrustedSequencer {
log.Info("Permissionless: creating and Initializing L2 synchronization components")
L1SyncChecker := l2_sync_etrog.NewCheckSyncStatusToProcessBatch(res.zkEVMClient, res.state)
+ sync := &res
+ //syncTrustedStateEtrog := l2_sync_etrog.NewSyncTrustedBatchExecutorForEtrog(res.zkEVMClient, res.state, res.state, res,
+ // syncCommon.DefaultTimeProvider{}, L1SyncChecker, cfg.L2Synchronization)
+ executorSteps := l2_sync_etrog.NewSyncTrustedBatchExecutorForEtrog(res.state, *sync)
+ executor := l2_shared.NewProcessorTrustedBatchSync(executorSteps, syncCommon.DefaultTimeProvider{}, L1SyncChecker, cfg.L2Synchronization)
+ if cfg.L2Synchronization.CheckLastL2BlockHashOnCloseBatch {
+ log.Infof("Adding check of L2Block hash on close batch when sync from trusted node")
+ executor.AddPostChecker(l2_shared.NewPostClosedBatchCheckL2Block(res.state))
+ }
- syncTrustedStateEtrog := l2_sync_etrog.NewSyncTrustedBatchExecutorForEtrog(res.zkEVMClient, res.state, res.state, res,
- syncCommon.DefaultTimeProvider{}, L1SyncChecker, cfg.L2Synchronization)
-
+ syncTrustedStateEtrog := l2_shared.NewTrustedBatchesRetrieve(executor, zkEVMClient, res.state, *sync, *l2_shared.NewTrustedStateManager(syncCommon.DefaultTimeProvider{}, timeOfLiveBatchOnCache))
res.syncTrustedStateExecutor = l2_shared.NewSyncTrustedStateExecutorSelector(map[uint64]syncinterfaces.SyncTrustedStateExecutor{
uint64(state.FORKID_ETROG): syncTrustedStateEtrog,
uint64(state.FORKID_ELDERBERRY): syncTrustedStateEtrog,