From 1f1550814b356034cd9b1a926126762966dc0e94 Mon Sep 17 00:00:00 2001 From: agnusmor <100322135+agnusmor@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:58:02 +0200 Subject: [PATCH 01/23] check GER and index of synced L1InfoRoot matches with sc values (#3551) --- etherman/etherman.go | 11 +++ sequencer/finalizer.go | 120 ++++++++++++++++++++++------- sequencer/interfaces.go | 7 +- sequencer/mock_etherman.go | 73 +++++++++++++++++- sequencer/sequencer.go | 4 +- state/pgstatestorage/l1infotree.go | 2 +- 6 files changed, 183 insertions(+), 34 deletions(-) diff --git a/etherman/etherman.go b/etherman/etherman.go index c7e4ec77b0..060782dd07 100644 --- a/etherman/etherman.go +++ b/etherman/etherman.go @@ -1817,6 +1817,17 @@ func (etherMan *Client) EstimateGas(ctx context.Context, from common.Address, to }) } +// DepositCount returns deposits count +func (etherman *Client) DepositCount(ctx context.Context, blockNumber *uint64) (*big.Int, error) { + var opts *bind.CallOpts + if blockNumber != nil { + opts = new(bind.CallOpts) + opts.BlockNumber = new(big.Int).SetUint64(*blockNumber) + } + + return etherman.GlobalExitRootManager.DepositCount(opts) +} + // CheckTxWasMined check if a tx was already mined func (etherMan *Client) CheckTxWasMined(ctx context.Context, txHash common.Hash) (bool, *types.Receipt, error) { receipt, err := etherMan.EthClient.TransactionReceipt(ctx, txHash) diff --git a/sequencer/finalizer.go b/sequencer/finalizer.go index 7a77f330e1..305b809240 100644 --- a/sequencer/finalizer.go +++ b/sequencer/finalizer.go @@ -10,6 +10,7 @@ import ( "time" "github.com/0xPolygonHermez/zkevm-data-streamer/datastreamer" + ethermanTypes "github.com/0xPolygonHermez/zkevm-node/etherman" "github.com/0xPolygonHermez/zkevm-node/event" "github.com/0xPolygonHermez/zkevm-node/hex" "github.com/0xPolygonHermez/zkevm-node/log" @@ -38,7 +39,7 @@ type finalizer struct { workerIntf workerInterface poolIntf txPool stateIntf stateInterface - etherman etherman + etherman ethermanInterface wipBatch *Batch wipL2Block *L2Block batchConstraints state.BatchConstraintsCfg @@ -87,7 +88,7 @@ func newFinalizer( workerIntf workerInterface, poolIntf txPool, stateIntf stateInterface, - etherman etherman, + etherman ethermanInterface, sequencerAddr common.Address, isSynced func(ctx context.Context) bool, batchConstraints state.BatchConstraintsCfg, @@ -220,18 +221,95 @@ func (f *finalizer) updateFlushIDs(newPendingFlushID, newStoredFlushID uint64) { f.storedFlushIDCond.L.Unlock() } -func (f *finalizer) checkL1InfoTreeUpdate(ctx context.Context) { - firstL1InfoRootUpdate := true - skipFirstSleep := true +func (f *finalizer) checkValidL1InfoRoot(ctx context.Context, l1InfoRoot state.L1InfoTreeExitRootStorageEntry) (bool, error) { + // Check L1 block hash matches + l1BlockState, err := f.stateIntf.GetBlockByNumber(ctx, l1InfoRoot.BlockNumber, nil) + if err != nil { + return false, fmt.Errorf("error getting L1 block %d from the state, error: %v", l1InfoRoot.BlockNumber, err) + } + + l1BlockEth, err := f.etherman.HeaderByNumber(ctx, new(big.Int).SetUint64(l1InfoRoot.BlockNumber)) + if err != nil { + return false, fmt.Errorf("error getting L1 block %d from ethereum, error: %v", l1InfoRoot.BlockNumber, err) + } + + if l1BlockState.BlockHash != l1BlockEth.Hash() { + warnmsg := fmt.Sprintf("invalid l1InfoRoot %s, index: %d, GER: %s, l1Block: %d. L1 block hash %s doesn't match block hash on ethereum %s (L1 reorg?)", + l1InfoRoot.L1InfoTreeRoot, l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.GlobalExitRoot.GlobalExitRoot, l1InfoRoot.BlockNumber, l1BlockState.BlockHash, l1BlockEth.Hash()) + log.Warnf(warnmsg) + f.LogEvent(ctx, event.Level_Critical, event.EventID_InvalidInfoRoot, warnmsg, nil) + + return false, nil + } + + // Check l1InfoRootIndex and GER matches. We retrieve the info of the last l1InfoTree event in the block, since in the case we have several l1InfoTree events + // in the same block, the function checkL1InfoTreeUpdate retrieves only the last one and skips the others + log.Debugf("getting l1InfoRoot events for L1 block %d, hash: %s", l1InfoRoot.BlockNumber, l1BlockState.BlockHash) + blocks, eventsOrder, err := f.etherman.GetRollupInfoByBlockRange(ctx, l1InfoRoot.BlockNumber, &l1InfoRoot.BlockNumber) + if err != nil { + return false, err + } + + //Get L1InfoTree events of the L1 block where the l1InforRoot we need to check was synced + lastGER := state.ZeroHash + for _, block := range blocks { + blockEventsOrder := eventsOrder[block.BlockHash] + for _, order := range blockEventsOrder { + if order.Name == ethermanTypes.L1InfoTreeOrder { + lastGER = block.L1InfoTree[order.Pos].GlobalExitRoot + log.Debugf("l1InfoTree event, pos: %d, GER: %s", order.Pos, lastGER) + } + } + } - if f.cfg.L1InfoTreeCheckInterval.Duration.Seconds() == 999999 { //nolint:gomnd + // Get the deposit count in the moment when the L1InfoRoot was synced + depositCount, err := f.etherman.DepositCount(ctx, &l1InfoRoot.BlockNumber) + if err != nil { + return false, err + } + // l1InfoTree index starts at 0, therefore we need to subtract 1 to the depositCount to get the last index at that moment + index := uint32(depositCount.Uint64()) + if index > 0 { // we check this as protection, but depositCount should be greater that 0 in this context + index-- + } else { + warnmsg := fmt.Sprintf("invalid l1InfoRoot %s, index: %d, GER: %s, blockNum: %d. DepositCount value returned by the smartcontrat is 0 and that isn't possible in this context", + l1InfoRoot.L1InfoTreeRoot, l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.GlobalExitRoot.GlobalExitRoot, l1InfoRoot.BlockNumber) + log.Warn(warnmsg) + f.LogEvent(ctx, event.Level_Critical, event.EventID_InvalidInfoRoot, warnmsg, nil) + + return false, nil + } + + log.Debugf("checking valid l1InfoRoot, index: %d, GER: %s, l1Block: %d, scIndex: %d, scGER: %s", + l1InfoRoot.BlockNumber, l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.GlobalExitRoot.GlobalExitRoot, index, lastGER) + + if (l1InfoRoot.GlobalExitRoot.GlobalExitRoot != lastGER) || (l1InfoRoot.L1InfoTreeIndex != index) { + warnmsg := fmt.Sprintf("invalid l1InfoRoot %s, index: %d, GER: %s, blockNum: %d. It doesn't match with smartcontract l1InfoRoot, index: %d, GER: %s", + l1InfoRoot.L1InfoTreeRoot, l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.GlobalExitRoot.GlobalExitRoot, l1InfoRoot.BlockNumber, index, lastGER) + log.Warn(warnmsg) + f.LogEvent(ctx, event.Level_Critical, event.EventID_InvalidInfoRoot, warnmsg, nil) + + return false, nil + } + + return true, nil +} + +func (f *finalizer) checkL1InfoTreeUpdate(ctx context.Context) { + broadcastL1InfoTreeValid := func() { if !f.lastL1InfoTreeValid { f.lastL1InfoTreeCond.L.Lock() f.lastL1InfoTreeValid = true f.lastL1InfoTreeCond.Broadcast() f.lastL1InfoTreeCond.L.Unlock() } + } + + firstL1InfoRootUpdate := true + skipFirstSleep := true + if f.cfg.L1InfoTreeCheckInterval.Duration.Seconds() == 0 { //nolint:gomnd + broadcastL1InfoTreeValid() return } @@ -255,7 +333,7 @@ func (f *finalizer) checkL1InfoTreeUpdate(ctx context.Context) { l1InfoRoot, err := f.stateIntf.GetLatestL1InfoRoot(ctx, maxBlockNumber) if err != nil { - log.Errorf("error checking latest L1InfoRoot, error: %v", err) + log.Errorf("error getting latest l1InfoRoot, error: %v", err) continue } @@ -265,27 +343,18 @@ func (f *finalizer) checkL1InfoTreeUpdate(ctx context.Context) { } if firstL1InfoRootUpdate || l1InfoRoot.L1InfoTreeIndex > f.lastL1InfoTree.L1InfoTreeIndex { - log.Infof("received new L1InfoRoot, l1InfoTreeIndex: %d, l1InfoTreeRoot: %s, l1Block: %d", - l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.L1InfoTreeRoot, l1InfoRoot.BlockNumber) + log.Infof("received new l1InfoRoot %s, index: %d, l1Block: %d", l1InfoRoot.L1InfoTreeRoot, l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.BlockNumber) - // Sanity check l1BlockState (l1InfoRoot.BlockNumber) blockhash matches blockhash on ethereum. We skip it if l1InfoRoot.BlockNumber == 0 (empty tree) + // Check if new l1InfoRoot is valid. We skip it if l1InfoRoot.BlockNumber == 0 (empty tree) if l1InfoRoot.BlockNumber > 0 { - l1BlockState, err := f.stateIntf.GetBlockByNumber(ctx, l1InfoRoot.BlockNumber, nil) + valid, err := f.checkValidL1InfoRoot(ctx, l1InfoRoot) if err != nil { - log.Errorf("error getting L1 block %d from the state, error: %v", l1InfoRoot.BlockNumber, err) + log.Errorf("error validating new l1InfoRoot, index: %d, error: %v", l1InfoRoot.L1InfoTreeIndex, err) continue } - l1BlockEth, err := f.etherman.HeaderByNumber(ctx, new(big.Int).SetUint64(l1InfoRoot.BlockNumber)) - if err != nil { - log.Errorf("error getting L1 block %d from ethereum, error: %v", l1InfoRoot.BlockNumber, err) - continue - } - if l1BlockState.BlockHash != l1BlockEth.Hash() { - warnmsg := fmt.Sprintf("invalid l1InfoTreeIndex %d, L1 block %d blockhash %s doesn't match blockhash on ethereum %s (L1 reorg?). Stopping syncing l1IntroTreeIndex", - l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.BlockNumber, l1BlockState.BlockHash, l1BlockEth.Hash()) - log.Warn(warnmsg) - f.LogEvent(ctx, event.Level_Critical, event.EventID_InvalidInfoRoot, warnmsg, nil) + if !valid { + log.Warnf("invalid l1InfoRoot %s, index: %d, l1Block: %d. Stopping syncing l1InfoTreeIndex", l1InfoRoot.L1InfoTreeRoot, l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.BlockNumber) return } } @@ -296,12 +365,7 @@ func (f *finalizer) checkL1InfoTreeUpdate(ctx context.Context) { f.lastL1InfoTree = l1InfoRoot f.lastL1InfoTreeMux.Unlock() - if !f.lastL1InfoTreeValid { - f.lastL1InfoTreeCond.L.Lock() - f.lastL1InfoTreeValid = true - f.lastL1InfoTreeCond.Broadcast() - f.lastL1InfoTreeCond.L.Unlock() - } + broadcastL1InfoTreeValid() } } } diff --git a/sequencer/interfaces.go b/sequencer/interfaces.go index afe49bceb9..10c58980ac 100644 --- a/sequencer/interfaces.go +++ b/sequencer/interfaces.go @@ -5,6 +5,7 @@ import ( "math/big" "time" + ethermanTypes "github.com/0xPolygonHermez/zkevm-node/etherman" "github.com/0xPolygonHermez/zkevm-node/pool" "github.com/0xPolygonHermez/zkevm-node/state" "github.com/ethereum/go-ethereum/common" @@ -30,12 +31,14 @@ type txPool interface { GetEarliestProcessedTx(ctx context.Context) (common.Hash, error) } -// etherman contains the methods required to interact with ethereum. -type etherman interface { +// ethermanInterface contains the methods required to interact with ethereum. +type ethermanInterface interface { TrustedSequencer() (common.Address, error) GetLatestBatchNumber() (uint64, error) GetLatestBlockNumber(ctx context.Context) (uint64, error) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) + GetRollupInfoByBlockRange(ctx context.Context, fromBlock uint64, toBlock *uint64) ([]ethermanTypes.Block, map[common.Hash][]ethermanTypes.Order, error) + DepositCount(ctx context.Context, blockNumber *uint64) (*big.Int, error) } // stateInterface gathers the methods required to interact with the state. diff --git a/sequencer/mock_etherman.go b/sequencer/mock_etherman.go index 3169ca6f3f..f51eb11d09 100644 --- a/sequencer/mock_etherman.go +++ b/sequencer/mock_etherman.go @@ -8,16 +8,48 @@ import ( common "github.com/ethereum/go-ethereum/common" + etherman "github.com/0xPolygonHermez/zkevm-node/etherman" + mock "github.com/stretchr/testify/mock" types "github.com/ethereum/go-ethereum/core/types" ) -// EthermanMock is an autogenerated mock type for the etherman type +// EthermanMock is an autogenerated mock type for the ethermanInterface type type EthermanMock struct { mock.Mock } +// DepositCount provides a mock function with given fields: ctx, blockNumber +func (_m *EthermanMock) DepositCount(ctx context.Context, blockNumber *uint64) (*big.Int, error) { + ret := _m.Called(ctx, blockNumber) + + if len(ret) == 0 { + panic("no return value specified for DepositCount") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *uint64) (*big.Int, error)); ok { + return rf(ctx, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, *uint64) *big.Int); ok { + r0 = rf(ctx, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *uint64) error); ok { + r1 = rf(ctx, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetLatestBatchNumber provides a mock function with given fields: func (_m *EthermanMock) GetLatestBatchNumber() (uint64, error) { ret := _m.Called() @@ -74,6 +106,45 @@ func (_m *EthermanMock) GetLatestBlockNumber(ctx context.Context) (uint64, error return r0, r1 } +// GetRollupInfoByBlockRange provides a mock function with given fields: ctx, fromBlock, toBlock +func (_m *EthermanMock) GetRollupInfoByBlockRange(ctx context.Context, fromBlock uint64, toBlock *uint64) ([]etherman.Block, map[common.Hash][]etherman.Order, error) { + ret := _m.Called(ctx, fromBlock, toBlock) + + if len(ret) == 0 { + panic("no return value specified for GetRollupInfoByBlockRange") + } + + var r0 []etherman.Block + var r1 map[common.Hash][]etherman.Order + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, *uint64) ([]etherman.Block, map[common.Hash][]etherman.Order, error)); ok { + return rf(ctx, fromBlock, toBlock) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, *uint64) []etherman.Block); ok { + r0 = rf(ctx, fromBlock, toBlock) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]etherman.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, *uint64) map[common.Hash][]etherman.Order); ok { + r1 = rf(ctx, fromBlock, toBlock) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(map[common.Hash][]etherman.Order) + } + } + + if rf, ok := ret.Get(2).(func(context.Context, uint64, *uint64) error); ok { + r2 = rf(ctx, fromBlock, toBlock) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // HeaderByNumber provides a mock function with given fields: ctx, number func (_m *EthermanMock) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { ret := _m.Called(ctx, number) diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go index e98c367fc1..64b5711fae 100644 --- a/sequencer/sequencer.go +++ b/sequencer/sequencer.go @@ -27,7 +27,7 @@ type Sequencer struct { pool txPool stateIntf stateInterface eventLog *event.EventLog - etherman etherman + etherman ethermanInterface worker *Worker finalizer *finalizer @@ -42,7 +42,7 @@ type Sequencer struct { } // New init sequencer -func New(cfg Config, batchCfg state.BatchConfig, poolCfg pool.Config, txPool txPool, stateIntf stateInterface, etherman etherman, eventLog *event.EventLog) (*Sequencer, error) { +func New(cfg Config, batchCfg state.BatchConfig, poolCfg pool.Config, txPool txPool, stateIntf stateInterface, etherman ethermanInterface, eventLog *event.EventLog) (*Sequencer, error) { addr, err := etherman.TrustedSequencer() if err != nil { return nil, fmt.Errorf("failed to get trusted sequencer address, error: %v", err) diff --git a/state/pgstatestorage/l1infotree.go b/state/pgstatestorage/l1infotree.go index ed3fe2dd38..83c869cf5a 100644 --- a/state/pgstatestorage/l1infotree.go +++ b/state/pgstatestorage/l1infotree.go @@ -53,7 +53,7 @@ func (p *PostgresStorage) GetLatestL1InfoRoot(ctx context.Context, maxBlockNumbe const getL1InfoRootSQL = `SELECT block_num, timestamp, mainnet_exit_root, rollup_exit_root, global_exit_root, prev_block_hash, l1_info_root, l1_info_tree_index FROM state.exit_root WHERE l1_info_tree_index IS NOT NULL AND block_num <= $1 - ORDER BY l1_info_tree_index DESC` + ORDER BY l1_info_tree_index DESC LIMIT 1` entry := state.L1InfoTreeExitRootStorageEntry{} From 0476a8b4f7dfec9d6316c62ae88ee59cc4076620 Mon Sep 17 00:00:00 2001 From: Thiago Coimbra Lemos Date: Fri, 12 Apr 2024 12:27:22 -0300 Subject: [PATCH 02/23] apply txIndex fix to StoreTransactions; add migration to fix wrong txIndexes (#3556) --- db/migrations/state/0019.sql | 25 ++++++ db/migrations/state/0019_test.go | 145 +++++++++++++++++++++++++++++++ state/transaction.go | 5 +- 3 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 db/migrations/state/0019.sql create mode 100644 db/migrations/state/0019_test.go diff --git a/db/migrations/state/0019.sql b/db/migrations/state/0019.sql new file mode 100644 index 0000000000..bd982feab1 --- /dev/null +++ b/db/migrations/state/0019.sql @@ -0,0 +1,25 @@ +-- +migrate Up + +-- the update below fix the wrong receipt TX indexes +WITH map_fix_tx_index AS ( + SELECT t.l2_block_num AS block_num + , t.hash AS tx_hash + , r.tx_index AS current_index + , (ROW_NUMBER() OVER (PARTITION BY t.l2_block_num ORDER BY r.tx_index))-1 AS correct_index + FROM state.receipt r + INNER JOIN state."transaction" t + ON t.hash = r.tx_hash +) +UPDATE state.receipt AS r + SET tx_index = m.correct_index + FROM map_fix_tx_index m + WHERE m.block_num = r.block_num + AND m.tx_hash = r.tx_hash + AND m.current_index = r.tx_index + AND m.current_index != m.correct_index; + + +-- +migrate Down + +-- no action is needed, the data fixed by the +-- migrate up must remain fixed \ No newline at end of file diff --git a/db/migrations/state/0019_test.go b/db/migrations/state/0019_test.go new file mode 100644 index 0000000000..7205998d60 --- /dev/null +++ b/db/migrations/state/0019_test.go @@ -0,0 +1,145 @@ +package migrations_test + +import ( + "database/sql" + "testing" + + "github.com/0xPolygonHermez/zkevm-node/hex" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +type migrationTest0019TestCase struct { + Name string + Block migrationTest0019TestCaseBlock +} + +type migrationTest0019TestCaseBlock struct { + Transactions []migrationTest0019TestCaseTransaction +} + +type migrationTest0019TestCaseTransaction struct { + CurrentIndex uint +} + +type migrationTest0019 struct { + TestCases []migrationTest0019TestCase +} + +func (m migrationTest0019) InsertData(db *sql.DB) error { + const addBlock0 = "INSERT INTO state.block (block_num, received_at, block_hash) VALUES (0, now(), '0x0')" + if _, err := db.Exec(addBlock0); err != nil { + return err + } + + const addBatch0 = ` + INSERT INTO state.batch (batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, wip) + VALUES (0,'0x0000', '0x0000', '0x0000', '0x0000', now(), '0x0000', null, null, true)` + if _, err := db.Exec(addBatch0); err != nil { + return err + } + + const addL2Block = "INSERT INTO state.l2block (block_num, block_hash, header, uncles, parent_hash, state_root, received_at, batch_num, created_at) VALUES ($1, $2, '{}', '{}', '0x0', '0x0', now(), 0, now())" + const addTransaction = "INSERT INTO state.transaction (hash, encoded, decoded, l2_block_num, effective_percentage, l2_hash) VALUES ($1, 'ABCDEF', '{}', $2, 255, $1)" + const addReceipt = "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, 1, null, 1, 1234, 1234, 1, $2, $3, '')" + + txUnique := 0 + for tci, testCase := range m.TestCases { + blockNum := uint64(tci + 1) + blockHash := common.HexToHash(hex.EncodeUint64(blockNum)).String() + if _, err := db.Exec(addL2Block, blockNum, blockHash); err != nil { + return err + } + for _, tx := range testCase.Block.Transactions { + txUnique++ + txHash := common.HexToHash(hex.EncodeUint64(uint64(txUnique))).String() + if _, err := db.Exec(addTransaction, txHash, blockNum); err != nil { + return err + } + if _, err := db.Exec(addReceipt, txHash, blockNum, tx.CurrentIndex); err != nil { + return err + } + } + } + + return nil +} + +func (m migrationTest0019) RunAssertsAfterMigrationUp(t *testing.T, db *sql.DB) { + const getReceiptsByBlock = "SELECT r.tx_index FROM state.receipt r WHERE r.block_num = $1 ORDER BY r.tx_index" + + for tci := range m.TestCases { + blockNum := uint64(tci + 1) + + rows, err := db.Query(getReceiptsByBlock, blockNum) + require.NoError(t, err) + + var expectedIndex = uint(0) + var txIndex uint + for rows.Next() { + err := rows.Scan(&txIndex) + require.NoError(t, err) + require.Equal(t, expectedIndex, txIndex) + expectedIndex++ + } + } +} + +func (m migrationTest0019) RunAssertsAfterMigrationDown(t *testing.T, db *sql.DB) { + m.RunAssertsAfterMigrationUp(t, db) +} + +func TestMigration0019(t *testing.T) { + runMigrationTest(t, 19, migrationTest0019{ + TestCases: []migrationTest0019TestCase{ + { + Name: "single tx with correct index", + Block: migrationTest0019TestCaseBlock{ + Transactions: []migrationTest0019TestCaseTransaction{ + {CurrentIndex: 0}, + }, + }, + }, + { + Name: "multiple txs indexes are correct", + Block: migrationTest0019TestCaseBlock{ + Transactions: []migrationTest0019TestCaseTransaction{ + {CurrentIndex: 0}, + {CurrentIndex: 1}, + {CurrentIndex: 2}, + }, + }, + }, + { + Name: "single tx with wrong tx index", + Block: migrationTest0019TestCaseBlock{ + Transactions: []migrationTest0019TestCaseTransaction{ + {CurrentIndex: 3}, + }, + }, + }, + { + Name: "multiple txs missing 0 index", + Block: migrationTest0019TestCaseBlock{ + Transactions: []migrationTest0019TestCaseTransaction{ + {CurrentIndex: 1}, + {CurrentIndex: 2}, + {CurrentIndex: 3}, + {CurrentIndex: 4}, + }, + }, + }, + { + Name: "multiple has index 0 but also txs index gap", + Block: migrationTest0019TestCaseBlock{ + Transactions: []migrationTest0019TestCaseTransaction{ + {CurrentIndex: 0}, + {CurrentIndex: 2}, + {CurrentIndex: 4}, + {CurrentIndex: 6}, + }, + }, + }, + }, + }) +} diff --git a/state/transaction.go b/state/transaction.go index 355fdad9ad..56e64b83e1 100644 --- a/state/transaction.go +++ b/state/transaction.go @@ -141,7 +141,7 @@ func (s *State) StoreTransactions(ctx context.Context, batchNumber uint64, proce } // firstTxToInsert := len(existingTxs) - + txIndex := 0 for i := 0; i < len(processedTxs); i++ { processedTx := processedTxs[i] // if the transaction has an intrinsic invalid tx error it means @@ -169,7 +169,7 @@ 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), forkID) + receipt := GenerateReceipt(header.Number, processedTx, uint(txIndex), forkID) if !CheckLogOrder(receipt.Logs) { return fmt.Errorf("error: logs received from executor are not in order") } @@ -193,6 +193,7 @@ func (s *State) StoreTransactions(ctx context.Context, batchNumber uint64, proce if err := s.AddL2Block(ctx, batchNumber, l2Block, receipts, txsL2Hash, storeTxsEGPData, imStateRoots, dbTx); err != nil { return err } + txIndex++ } } return nil From 32a775053a4881bdeef96e51a0852bd1da2c497c Mon Sep 17 00:00:00 2001 From: Alonso Rodriguez Date: Mon, 15 Apr 2024 12:31:41 +0200 Subject: [PATCH 03/23] Feature/#3549 reorgs improvement (#3553) * New reorg function * mocks * linter * Synchronizer tests * new elderberry smc docker image * new image * logs * fix json rpc * fix * Test sync from empty block * Regular reorg case tested * linter * remove empty block + fix LatestSyncedBlockEmpty * Improve check reorgs when no block is received during the call * fix RPC error code for eth_estimateGas and eth_call for reverted tx and no return value; fix e2e test; * fix test * Extra unit test * fix reorg until genesis * disable parallel synchronization --------- Co-authored-by: tclemos --- .../local/local.genesis.config.json | 32 +- docs/running_local.md | 2 +- etherman/etherman.go | 4 +- jsonrpc/endpoints_eth.go | 8 +- jsonrpc/endpoints_eth_test.go | 2 +- .../common/syncinterfaces/etherman.go | 1 + .../mocks/etherman_full_interface.go | 56 + ...ent_ethereum_compatible_l2_block_getter.go | 98 ++ synchronizer/synchronizer.go | 174 ++- synchronizer/synchronizer_test.go | 1165 ++++++++++++++++- test/config/test.genesis.config.json | 184 +-- test/docker-compose.yml | 2 +- test/e2e/jsonrpc2_test.go | 117 +- 13 files changed, 1592 insertions(+), 253 deletions(-) create mode 100644 synchronizer/common/syncinterfaces/mocks/zkevm_client_ethereum_compatible_l2_block_getter.go diff --git a/config/environments/local/local.genesis.config.json b/config/environments/local/local.genesis.config.json index 042bd754a9..3c2db9d886 100644 --- a/config/environments/local/local.genesis.config.json +++ b/config/environments/local/local.genesis.config.json @@ -6,15 +6,15 @@ "polTokenAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3", "polygonZkEVMGlobalExitRootAddress": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" }, - "genesisBlockNumber": 138, - "root": "0xa64456534f3bbe93f991c0139342a0ef52df95c6999eaa5ec8a69741da407f9a", + "genesisBlockNumber": 136, + "root": "0x489e44072604e671274ea693d5309e797fb37a3e0d91e5b0f04639c251c05332", "genesis": [ { "contractName": "PolygonZkEVMDeployer", "balance": "0", "nonce": "4", - "address": "0x51dbd54FCCb6b3A07738fd3E156D588e71f79973", - "bytecode": "0x6080604052600436106100705760003560e01c8063715018a61161004e578063715018a6146100e65780638da5cb5b146100fb578063e11ae6cb14610126578063f2fde38b1461013957600080fd5b80632b79805a146100755780634a94d4871461008a5780636d07dbf81461009d575b600080fd5b610088610083366004610927565b610159565b005b6100886100983660046109c7565b6101cb565b3480156100a957600080fd5b506100bd6100b8366004610a1e565b61020d565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b50610088610220565b34801561010757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100bd565b610088610134366004610a40565b610234565b34801561014557600080fd5b50610088610154366004610a90565b61029b565b610161610357565b600061016e8585856103d8565b905061017a8183610537565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a15050505050565b6101d3610357565b6101de83838361057b565b506040517f25adb19089b6a549831a273acdf7908cff8b7ee5f551f8d1d37996cf01c5df5b90600090a1505050565b600061021983836105a9565b9392505050565b610228610357565b61023260006105b6565b565b61023c610357565b60006102498484846103d8565b60405173ffffffffffffffffffffffffffffffffffffffff821681529091507fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a150505050565b6102a3610357565b73ffffffffffffffffffffffffffffffffffffffff811661034b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610354816105b6565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610232576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610342565b600083471015610444576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610342565b81516000036104af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610342565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610342565b6060610219838360006040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c6564000081525061062b565b60606105a1848484604051806060016040528060298152602001610b3d6029913961062b565b949350505050565b6000610219838330610744565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060824710156106bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610342565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516106e69190610acf565b60006040518083038185875af1925050503d8060008114610723576040519150601f19603f3d011682016040523d82523d6000602084013e610728565b606091505b50915091506107398783838761076e565b979650505050505050565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b606083156108045782516000036107fd5773ffffffffffffffffffffffffffffffffffffffff85163b6107fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610342565b50816105a1565b6105a183838151156108195781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103429190610aeb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261088d57600080fd5b813567ffffffffffffffff808211156108a8576108a861084d565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156108ee576108ee61084d565b8160405283815286602085880101111561090757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806080858703121561093d57600080fd5b8435935060208501359250604085013567ffffffffffffffff8082111561096357600080fd5b61096f8883890161087c565b9350606087013591508082111561098557600080fd5b506109928782880161087c565b91505092959194509250565b803573ffffffffffffffffffffffffffffffffffffffff811681146109c257600080fd5b919050565b6000806000606084860312156109dc57600080fd5b6109e58461099e565b9250602084013567ffffffffffffffff811115610a0157600080fd5b610a0d8682870161087c565b925050604084013590509250925092565b60008060408385031215610a3157600080fd5b50508035926020909101359150565b600080600060608486031215610a5557600080fd5b8335925060208401359150604084013567ffffffffffffffff811115610a7a57600080fd5b610a868682870161087c565b9150509250925092565b600060208284031215610aa257600080fd5b6102198261099e565b60005b83811015610ac6578181015183820152602001610aae565b50506000910152565b60008251610ae1818460208701610aab565b9190910192915050565b6020815260008251806020840152610b0a816040850160208701610aab565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220964619cee0e0baf94c6f8763f013be157da5d54c89e5cff4a8caf4266e13f13a64736f6c63430008140033", + "address": "0xFbD07134824dDEa24E4ae414c18ecbFa98169A24", + "bytecode": "0x60806040526004361061006e575f3560e01c8063715018a61161004c578063715018a6146100e25780638da5cb5b146100f6578063e11ae6cb1461011f578063f2fde38b14610132575f80fd5b80632b79805a146100725780634a94d487146100875780636d07dbf81461009a575b5f80fd5b610085610080366004610908565b610151565b005b6100856100953660046109a2565b6101c2565b3480156100a5575f80fd5b506100b96100b43660046109f5565b610203565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ed575f80fd5b50610085610215565b348015610101575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166100b9565b61008561012d366004610a15565b610228565b34801561013d575f80fd5b5061008561014c366004610a61565b61028e565b61015961034a565b5f6101658585856103ca565b90506101718183610527565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a15050505050565b6101ca61034a565b6101d583838361056a565b506040517f25adb19089b6a549831a273acdf7908cff8b7ee5f551f8d1d37996cf01c5df5b905f90a1505050565b5f61020e8383610598565b9392505050565b61021d61034a565b6102265f6105a4565b565b61023061034a565b5f61023c8484846103ca565b60405173ffffffffffffffffffffffffffffffffffffffff821681529091507fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a150505050565b61029661034a565b73ffffffffffffffffffffffffffffffffffffffff811661033e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610347816105a4565b50565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610226576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610335565b5f83471015610435576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610335565b81515f0361049f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610335565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff811661020e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610335565b606061020e83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250610618565b6060610590848484604051806060016040528060298152602001610b0860299139610618565b949350505050565b5f61020e83833061072d565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060824710156106aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610335565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516106d29190610a9c565b5f6040518083038185875af1925050503d805f811461070c576040519150601f19603f3d011682016040523d82523d5f602084013e610711565b606091505b509150915061072287838387610756565b979650505050505050565b5f604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b606083156107eb5782515f036107e45773ffffffffffffffffffffffffffffffffffffffff85163b6107e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610335565b5081610590565b61059083838151156108005781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103359190610ab7565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112610870575f80fd5b813567ffffffffffffffff8082111561088b5761088b610834565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156108d1576108d1610834565b816040528381528660208588010111156108e9575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f805f806080858703121561091b575f80fd5b8435935060208501359250604085013567ffffffffffffffff80821115610940575f80fd5b61094c88838901610861565b93506060870135915080821115610961575f80fd5b5061096e87828801610861565b91505092959194509250565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099d575f80fd5b919050565b5f805f606084860312156109b4575f80fd5b6109bd8461097a565b9250602084013567ffffffffffffffff8111156109d8575f80fd5b6109e486828701610861565b925050604084013590509250925092565b5f8060408385031215610a06575f80fd5b50508035926020909101359150565b5f805f60608486031215610a27575f80fd5b8335925060208401359150604084013567ffffffffffffffff811115610a4b575f80fd5b610a5786828701610861565b9150509250925092565b5f60208284031215610a71575f80fd5b61020e8261097a565b5f5b83811015610a94578181015183820152602001610a7c565b50505f910152565b5f8251610aad818460208701610a7a565b9190910192915050565b602081525f8251806020840152610ad5816040850160208701610a7a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220330b94dc698c4d290bf55c23f13b473cde6a6bae0030cb902de18af54e35839f64736f6c63430008140033", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266" } @@ -23,8 +23,8 @@ "contractName": "ProxyAdmin", "balance": "0", "nonce": "1", - "address": "0xe34Fe58DDa5b8c6D547E4857E987633aa86a5e90", - "bytecode": "0x60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461012b57806399a88ec41461013e578063f2fde38b1461015e578063f3b7dead1461017e57600080fd5b8063204e1c7a14610080578063715018a6146100c95780637eff275e146100e05780638da5cb5b14610100575b600080fd5b34801561008c57600080fd5b506100a061009b366004610608565b61019e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d557600080fd5b506100de610255565b005b3480156100ec57600080fd5b506100de6100fb36600461062c565b610269565b34801561010c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100a0565b6100de610139366004610694565b6102f7565b34801561014a57600080fd5b506100de61015936600461062c565b61038c565b34801561016a57600080fd5b506100de610179366004610608565b6103e8565b34801561018a57600080fd5b506100a0610199366004610608565b6104a4565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b600060405180830381855afa9150503d8060008114610225576040519150601f19603f3d011682016040523d82523d6000602084013e61022a565b606091505b50915091508161023957600080fd5b8080602001905181019061024d9190610788565b949350505050565b61025d6104f0565b6102676000610571565b565b6102716104f0565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b600060405180830381600087803b1580156102db57600080fd5b505af11580156102ef573d6000803e3d6000fd5b505050505050565b6102ff6104f0565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef28690349061035590869086906004016107a5565b6000604051808303818588803b15801561036e57600080fd5b505af1158015610382573d6000803e3d6000fd5b5050505050505050565b6103946104f0565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102c1565b6103f06104f0565b73ffffffffffffffffffffffffffffffffffffffff8116610498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6104a181610571565b50565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b60005473ffffffffffffffffffffffffffffffffffffffff163314610267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161048f565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff811681146104a157600080fd5b60006020828403121561061a57600080fd5b8135610625816105e6565b9392505050565b6000806040838503121561063f57600080fd5b823561064a816105e6565b9150602083013561065a816105e6565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156106a957600080fd5b83356106b4816105e6565b925060208401356106c4816105e6565b9150604084013567ffffffffffffffff808211156106e157600080fd5b818601915086601f8301126106f557600080fd5b81358181111561070757610707610665565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561074d5761074d610665565b8160405282815289602084870101111561076657600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561079a57600080fd5b8151610625816105e6565b73ffffffffffffffffffffffffffffffffffffffff8316815260006020604081840152835180604085015260005b818110156107ef578581018301518582016060015282016107d3565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050939250505056fea2646970667358221220c9867ffac53151bdb1305d8f5e3e883cd83e5270c7ec09cdc24e837b2e65239064736f6c63430008140033", + "address": "0xfADB60b5059e31614e02083fF6C021a24C31c891", + "bytecode": "0x608060405260043610610079575f3560e01c80639623609d1161004c5780639623609d1461012357806399a88ec414610136578063f2fde38b14610155578063f3b7dead14610174575f80fd5b8063204e1c7a1461007d578063715018a6146100c55780637eff275e146100db5780638da5cb5b146100fa575b5f80fd5b348015610088575f80fd5b5061009c6100973660046105e8565b610193565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d0575f80fd5b506100d9610244565b005b3480156100e6575f80fd5b506100d96100f536600461060a565b610257565b348015610105575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff1661009c565b6100d961013136600461066e565b6102e0565b348015610141575f80fd5b506100d961015036600461060a565b610371565b348015610160575f80fd5b506100d961016f3660046105e8565b6103cd565b34801561017f575f80fd5b5061009c61018e3660046105e8565b610489565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b5f60405180830381855afa9150503d805f8114610215576040519150601f19603f3d011682016040523d82523d5f602084013e61021a565b606091505b509150915081610228575f80fd5b8080602001905181019061023c919061075b565b949350505050565b61024c6104d3565b6102555f610553565b565b61025f6104d3565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b5f604051808303815f87803b1580156102c6575f80fd5b505af11580156102d8573d5f803e3d5ffd5b505050505050565b6102e86104d3565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef28690349061033e9086908690600401610776565b5f604051808303818588803b158015610355575f80fd5b505af1158015610367573d5f803e3d5ffd5b5050505050505050565b6103796104d3565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102af565b6103d56104d3565b73ffffffffffffffffffffffffffffffffffffffff811661047d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61048681610553565b50565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610255576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610474565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81168114610486575f80fd5b5f602082840312156105f8575f80fd5b8135610603816105c7565b9392505050565b5f806040838503121561061b575f80fd5b8235610626816105c7565b91506020830135610636816105c7565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f805f60608486031215610680575f80fd5b833561068b816105c7565b9250602084013561069b816105c7565b9150604084013567ffffffffffffffff808211156106b7575f80fd5b818601915086601f8301126106ca575f80fd5b8135818111156106dc576106dc610641565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561072257610722610641565b8160405282815289602084870101111561073a575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f6020828403121561076b575f80fd5b8151610603816105c7565b73ffffffffffffffffffffffffffffffffffffffff831681525f602060408184015283518060408501525f5b818110156107be578581018301518582016060015282016107a2565b505f6060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050939250505056fea26469706673582212203083a4ccc2e42eed60bd19037f2efa77ed086dc7a5403f75bebb995dcba2221c64736f6c63430008140033", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f" } @@ -33,18 +33,18 @@ "contractName": "PolygonZkEVMBridge implementation", "balance": "0", "nonce": "1", - "address": "0x12864938EADb26501034339667CabFB3d7045CD2", - "bytecode": "0x608060405260043610620001ff5760003560e01c806383f244031162000117578063ccaa2d1111620000a1578063ee25560b116200006c578063ee25560b1462000639578063f5efcd79146200066a578063f811bff7146200068f578063fb57083414620006b457600080fd5b8063ccaa2d1114620005ba578063cd58657914620005df578063d02103ca14620005f6578063dbc16976146200062157600080fd5b8063bab161bf11620000e2578063bab161bf1462000526578063be5831c7146200054a578063c00f14ab1462000570578063cc461632146200059557600080fd5b806383f2440314620004955780638ed7e3f214620004ba578063aaa13cc214620004dc578063b8b284d0146200050157600080fd5b80633c351e1011620001995780635ca1e16511620001645780635ca1e16514620004065780637843298b146200041e57806379e2cf97146200044357806381b1c174146200045b57600080fd5b80633c351e1014620003615780633cbc795b14620003835780633e19704314620003bf5780634b2f336d14620003e457600080fd5b8063240ff37811620001da578063240ff378146200028d57806327aef4e814620002a45780632dfdf0b514620002cb578063318aee3d14620002f257600080fd5b806315064c9614620002045780632072f6c5146200023557806322e95f2c146200024f575b600080fd5b3480156200021157600080fd5b50606854620002209060ff1681565b60405190151581526020015b60405180910390f35b3480156200024257600080fd5b506200024d620006d9565b005b3480156200025c57600080fd5b50620002746200026e366004620031fd565b62000711565b6040516001600160a01b0390911681526020016200022c565b6200024d6200029e36600462003294565b6200077c565b348015620002b157600080fd5b50620002bc6200080a565b6040516200022c91906200336c565b348015620002d857600080fd5b50620002e360535481565b6040519081526020016200022c565b348015620002ff57600080fd5b506200033c6200031136600462003388565b606b6020526000908152604090205463ffffffff81169064010000000090046001600160a01b031682565b6040805163ffffffff90931683526001600160a01b039091166020830152016200022c565b3480156200036e57600080fd5b50606d5462000274906001600160a01b031681565b3480156200039057600080fd5b50606d54620003a990600160a01b900463ffffffff1681565b60405163ffffffff90911681526020016200022c565b348015620003cc57600080fd5b50620002e3620003de366004620033b8565b620008a0565b348015620003f157600080fd5b50606f5462000274906001600160a01b031681565b3480156200041357600080fd5b50620002e36200094a565b3480156200042b57600080fd5b50620002746200043d36600462003442565b62000a30565b3480156200045057600080fd5b506200024d62000a61565b3480156200046857600080fd5b50620002746200047a36600462003492565b606a602052600090815260409020546001600160a01b031681565b348015620004a257600080fd5b50620002e3620004b4366004620034bf565b62000a85565b348015620004c757600080fd5b50606c5462000274906001600160a01b031681565b348015620004e957600080fd5b5062000274620004fb366004620035de565b62000b69565b3480156200050e57600080fd5b506200024d6200052036600462003687565b62000cb7565b3480156200053357600080fd5b50606854620003a990610100900463ffffffff1681565b3480156200055757600080fd5b50606854620003a990600160c81b900463ffffffff1681565b3480156200057d57600080fd5b50620002bc6200058f36600462003388565b62000d9d565b348015620005a257600080fd5b5062000220620005b436600462003714565b62000dea565b348015620005c757600080fd5b506200024d620005d93660046200374c565b62000e7b565b6200024d620005f036600462003848565b6200140e565b3480156200060357600080fd5b5060685462000274906501000000000090046001600160a01b031681565b3480156200062e57600080fd5b506200024d620018c2565b3480156200064657600080fd5b50620002e36200065836600462003492565b60696020526000908152604090205481565b3480156200067757600080fd5b506200024d620006893660046200374c565b620018f8565b3480156200069c57600080fd5b506200024d620006ae366004620038ea565b62001be2565b348015620006c157600080fd5b5062000220620006d3366004620039a2565b62001f1b565b606c546001600160a01b031633146200070557604051631736745960e31b815260040160405180910390fd5b6200070f62001f35565b565b6040805160e084901b6001600160e01b031916602080830191909152606084901b6bffffffffffffffffffffffff1916602483015282516018818403018152603890920183528151918101919091206000908152606a90915220546001600160a01b03165b92915050565b60685460ff1615620007a157604051630bc011ff60e21b815260040160405180910390fd5b3415801590620007bb5750606f546001600160a01b031615155b15620007f3576040517f6f625c4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6200080385853486868662001f92565b5050505050565b606e80546200081990620039ef565b80601f01602080910402602001604051908101604052809291908181526020018280546200084790620039ef565b8015620008985780601f106200086c5761010080835404028352916020019162000898565b820191906000526020600020905b8154815290600101906020018083116200087a57829003601f168201915b505050505081565b6040517fff0000000000000000000000000000000000000000000000000000000000000060f889901b1660208201526001600160e01b031960e088811b821660218401526bffffffffffffffffffffffff19606089811b821660258601529188901b909216603984015285901b16603d8201526051810183905260718101829052600090609101604051602081830303815290604052805190602001209050979650505050505050565b605354600090819081805b602081101562000a27578083901c600116600103620009b8576033816020811062000984576200098462003a2b565b01546040805160208101929092528101859052606001604051602081830303815290604052805190602001209350620009e5565b60408051602081018690529081018390526060016040516020818303038152906040528051906020012093505b6040805160208101849052908101839052606001604051602081830303815290604052805190602001209150808062000a1e9062003a57565b91505062000955565b50919392505050565b600062000a59848462000a438562002066565b62000a4e866200215c565b620004fb8762002247565b949350505050565b605354606854600160c81b900463ffffffff1610156200070f576200070f62002321565b600083815b602081101562000b6057600163ffffffff8516821c8116900362000afc5784816020811062000abd5762000abd62003a2b565b60200201358260405160200162000ade929190918252602082015260400190565b60405160208183030381529060405280519060200120915062000b4b565b8185826020811062000b125762000b1262003a2b565b602002013560405160200162000b32929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b8062000b578162003a57565b91505062000a8a565b50949350505050565b6040516001600160e01b031960e087901b1660208201526bffffffffffffffffffffffff19606086901b1660248201526000908190603801604051602081830303815290604052805190602001209050600060ff60f81b30836040518060200162000bd490620031c1565b601f1982820381018352601f90910116604081905262000bfd908b908b908b9060200162003a73565b60408051601f198184030181529082905262000c1d929160200162003ab0565b6040516020818303038152906040528051906020012060405160200162000c9394939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051808303601f19018152919052805160209091012098975050505050505050565b60685460ff161562000cdc57604051630bc011ff60e21b815260040160405180910390fd5b606f546001600160a01b031662000d1f576040517fdde3cda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f54604051632770a7eb60e21b8152336004820152602481018690526001600160a01b0390911690639dc29fac90604401600060405180830381600087803b15801562000d6c57600080fd5b505af115801562000d81573d6000803e3d6000fd5b5050505062000d9586868686868662001f92565b505050505050565b606062000daa8262002066565b62000db5836200215c565b62000dc08462002247565b60405160200162000dd49392919062003a73565b6040516020818303038152906040529050919050565b6068546000908190610100900463ffffffff1615801562000e11575063ffffffff83166001145b1562000e25575063ffffffff831662000e51565b62000e3c64010000000063ffffffff851662003ae3565b62000e4e9063ffffffff861662003afd565b90505b600881901c600090815260696020526040902054600160ff9092169190911b908116149392505050565b60685460ff161562000ea057604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff868116610100909204161462000ed1576040516302caf51760e11b815260040160405180910390fd5b62000f0b8c8c8c8c8c62000f0560008e8e8e8e8e8e8e60405162000ef792919062003b13565b6040518091039020620008a0565b620023d9565b6001600160a01b0386166200106a57606f546001600160a01b031662000ffc5760006001600160a01b03851684825b6040519080825280601f01601f19166020018201604052801562000f65576020820181803683370190505b5060405162000f75919062003b23565b60006040518083038185875af1925050503d806000811462000fb4576040519150601f19603f3d011682016040523d82523d6000602084013e62000fb9565b606091505b505090508062000ff5576040517f6747a28800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50620013a4565b606f546040516340c10f1960e01b81526001600160a01b03868116600483015260248201869052909116906340c10f1990604401600060405180830381600087803b1580156200104b57600080fd5b505af115801562001060573d6000803e3d6000fd5b50505050620013a4565b606d546001600160a01b038781169116148015620010995750606d5463ffffffff888116600160a01b90920416145b15620010b35760006001600160a01b038516848262000f3a565b60685463ffffffff610100909104811690881603620010e857620010e26001600160a01b038716858562002583565b620013a4565b6040516001600160e01b031960e089901b1660208201526bffffffffffffffffffffffff19606088901b16602482015260009060380160408051601f1981840301815291815281516020928301206000818152606a9093529120549091506001600160a01b0316806200133c5760008080620011678688018862003b41565b9250925092506000858484846040516200118190620031c1565b6200118f9392919062003a73565b8190604051809103906000f5905080158015620011b0573d6000803e3d6000fd5b506040516340c10f1960e01b81526001600160a01b038c81166004830152602482018c9052919250908216906340c10f1990604401600060405180830381600087803b1580156200120057600080fd5b505af115801562001215573d6000803e3d6000fd5b5050505080606a600088815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060405180604001604052808e63ffffffff1681526020018d6001600160a01b0316815250606b6000836001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f490e59a1701b938786ac72570a1efeac994a3dbe96e2e883e19e902ace6e6a398d8d838b8b6040516200132a95949392919062003be0565b60405180910390a150505050620013a1565b6040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b1580156200138757600080fd5b505af11580156200139c573d6000803e3d6000fd5b505050505b50505b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b60685460ff16156200143357604051630bc011ff60e21b815260040160405180910390fd5b6200143d62002606565b60685463ffffffff6101009091048116908816036200146f576040516302caf51760e11b815260040160405180910390fd5b6000806060876001600160a01b0388166200157957883414620014be576040517fb89240f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606d54606e80546001600160a01b0383169650600160a01b90920463ffffffff16945090620014ed90620039ef565b80601f01602080910402602001604051908101604052809291908181526020018280546200151b90620039ef565b80156200156c5780601f1062001540576101008083540402835291602001916200156c565b820191906000526020600020905b8154815290600101906020018083116200154e57829003601f168201915b505050505091506200182d565b3415620015b2576040517f798ee6f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546001600160a01b03908116908916036200163157604051632770a7eb60e21b8152336004820152602481018a90526001600160a01b03891690639dc29fac90604401600060405180830381600087803b1580156200161257600080fd5b505af115801562001627573d6000803e3d6000fd5b505050506200182d565b6001600160a01b038089166000908152606b602090815260409182902082518084019093525463ffffffff8116835264010000000090049092169181018290529015620016ee57604051632770a7eb60e21b8152336004820152602481018b90526001600160a01b038a1690639dc29fac90604401600060405180830381600087803b158015620016c157600080fd5b505af1158015620016d6573d6000803e3d6000fd5b5050505080602001519450806000015193506200181e565b8515620017035762001703898b898962002661565b6040516370a0823160e01b81523060048201526000906001600160a01b038b16906370a0823190602401602060405180830381865afa1580156200174b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001771919062003c1b565b90506200178a6001600160a01b038b1633308e62002a27565b6040516370a0823160e01b81523060048201526000906001600160a01b038c16906370a0823190602401602060405180830381865afa158015620017d2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620017f8919062003c1b565b905062001806828262003c35565b6068548c9850610100900463ffffffff169650935050505b620018298962000d9d565b9250505b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b600084868e8e86886053546040516200186f98979695949392919062003c4b565b60405180910390a16200189a62001894600085878f8f878980519060200120620008a0565b62002a7a565b8615620018ab57620018ab62002321565b50505050620018b960018055565b50505050505050565b606c546001600160a01b03163314620018ee57604051631736745960e31b815260040160405180910390fd5b6200070f62002b92565b60685460ff16156200191d57604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff86811661010090920416146200194e576040516302caf51760e11b815260040160405180910390fd5b620019748c8c8c8c8c62000f0560018e8e8e8e8e8e8e60405162000ef792919062003b13565b606f546000906001600160a01b031662001a3357846001600160a01b031684888a8686604051602401620019ac949392919062003cb7565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b17905251620019e3919062003b23565b60006040518083038185875af1925050503d806000811462001a22576040519150601f19603f3d011682016040523d82523d6000602084013e62001a27565b606091505b50508091505062001b3f565b606f546040516340c10f1960e01b81526001600160a01b03878116600483015260248201879052909116906340c10f1990604401600060405180830381600087803b15801562001a8257600080fd5b505af115801562001a97573d6000803e3d6000fd5b50505050846001600160a01b03168789858560405160240162001abe949392919062003cb7565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525162001af5919062003b23565b6000604051808303816000865af19150503d806000811462001b34576040519150601f19603f3d011682016040523d82523d6000602084013e62001b39565b606091505b50909150505b8062001b77576040517f37e391c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518c815263ffffffff8a1660208201526001600160a01b0389811682840152871660608201526080810186905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a150505050505050505050505050565b600054610100900460ff161580801562001c035750600054600160ff909116105b8062001c1f5750303b15801562001c1f575060005460ff166001145b62001c975760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b6000805460ff19166001179055801562001cbb576000805461ff0019166101001790555b606880547fffffffffffffff000000000000000000000000000000000000000000000000ff1661010063ffffffff8a16027fffffffffffffff0000000000000000000000000000000000000000ffffffffff1617650100000000006001600160a01b038781169190910291909117909155606c805473ffffffffffffffffffffffffffffffffffffffff1916858316179055861662001d995763ffffffff85161562001d93576040517f1a874c1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62001ec2565b606d805463ffffffff8716600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009091166001600160a01b03891617179055606e62001dea838262003d3c565b506000801b601260405162001dff90620031c1565b6060808252600d908201527f5772617070656420457468657200000000000000000000000000000000000000608082015260a0602082018190526004908201527f574554480000000000000000000000000000000000000000000000000000000060c082015260ff909116604082015260e0018190604051809103906000f590508015801562001e93573d6000803e3d6000fd5b50606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555b62001ecc62002c04565b8015620018b9576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b60008162001f2b86868662000a85565b1495945050505050565b60685460ff161562001f5a57604051630bc011ff60e21b815260040160405180910390fd5b6068805460ff191660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a549790600090a1565b60685463ffffffff61010090910481169087160362001fc4576040516302caf51760e11b815260040160405180910390fd5b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b6001606860019054906101000a900463ffffffff163389898988886053546040516200201a9998979695949392919062003e09565b60405180910390a162002055620018946001606860019054906101000a900463ffffffff16338a8a8a898960405162000ef792919062003b13565b821562000d955762000d9562002321565b60408051600481526024810182526020810180516001600160e01b03167f06fdde0300000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b03861691620020c8919062003b23565b600060405180830381855afa9150503d806000811462002105576040519150601f19603f3d011682016040523d82523d6000602084013e6200210a565b606091505b50915091508162002151576040518060400160405280600781526020017f4e4f5f4e414d450000000000000000000000000000000000000000000000000081525062000a59565b62000a598162002c7b565b60408051600481526024810182526020810180516001600160e01b03167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b03861691620021be919062003b23565b600060405180830381855afa9150503d8060008114620021fb576040519150601f19603f3d011682016040523d82523d6000602084013e62002200565b606091505b50915091508162002151576040518060400160405280600981526020017f4e4f5f53594d424f4c000000000000000000000000000000000000000000000081525062000a59565b60408051600481526024810182526020810180516001600160e01b03167f313ce567000000000000000000000000000000000000000000000000000000001790529051600091829182916001600160a01b03861691620022a8919062003b23565b600060405180830381855afa9150503d8060008114620022e5576040519150601f19603f3d011682016040523d82523d6000602084013e620022ea565b606091505b5091509150818015620022fe575080516020145b6200230b57601262000a59565b8080602001905181019062000a59919062003e77565b6053546068805463ffffffff909216600160c81b027fffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117908190556001600160a01b0365010000000000909104166333d6247d620023846200094a565b6040518263ffffffff1660e01b8152600401620023a391815260200190565b600060405180830381600087803b158015620023be57600080fd5b505af1158015620023d3573d6000803e3d6000fd5b50505050565b606854604080516020808201879052818301869052825180830384018152606083019384905280519101207f257b36320000000000000000000000000000000000000000000000000000000090925260648101919091526000916501000000000090046001600160a01b03169063257b3632906084016020604051808303816000875af11580156200246f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002495919062003c1b565b905080600003620024d1576040517e2f6fad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080680100000000000000008716156200251b57869150620024f7848a848962001f1b565b62002515576040516338105f3b60e21b815260040160405180910390fd5b6200256c565b602087901c6200252d81600162003e97565b91508792506200254c62002543868c8662000a85565b8a838962001f1b565b6200256a576040516338105f3b60e21b815260040160405180910390fd5b505b62002578828262002e6b565b505050505050505050565b6040516001600160a01b038316602482015260448101829052620026019084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915262002f35565b505050565b6002600154036200265a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162001c8e565b6002600155565b600062002672600482848662003ebe565b6200267d9162003eea565b90507f2afa5331000000000000000000000000000000000000000000000000000000006001600160e01b031982160162002869576000808080808080620026c8896004818d62003ebe565b810190620026d7919062003f1b565b9650965096509650965096509650336001600160a01b0316876001600160a01b031614620027185760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b0386163014620027425760405163750643af60e01b815260040160405180910390fd5b8a85146200277c576040517f03fffc4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b0389811660248301528881166044830152606482018890526084820187905260ff861660a483015260c4820185905260e48083018590528351808403909101815261010490920183526020820180516001600160e01b03167fd505accf000000000000000000000000000000000000000000000000000000001790529151918e169162002815919062003b23565b6000604051808303816000865af19150503d806000811462002854576040519150601f19603f3d011682016040523d82523d6000602084013e62002859565b606091505b5050505050505050505062000803565b6001600160e01b031981166323f2ebc360e21b14620028b4576040517fe282c0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808080620028cc8a6004818e62003ebe565b810190620028db919062003f76565b97509750975097509750975097509750336001600160a01b0316886001600160a01b0316146200291e5760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b0387163014620029485760405163750643af60e01b815260040160405180910390fd5b604080516001600160a01b038a811660248301528981166044830152606482018990526084820188905286151560a483015260ff861660c483015260e482018590526101048083018590528351808403909101815261012490920183526020820180516001600160e01b03166323f2ebc360e21b1790529151918f1691620029d1919062003b23565b6000604051808303816000865af19150503d806000811462002a10576040519150601f19603f3d011682016040523d82523d6000602084013e62002a15565b606091505b50505050505050505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052620023d39085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401620025c9565b80600162002a8b60206002620040ff565b62002a97919062003c35565b6053541062002ad2576040517fef5ccf6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060536000815462002ae59062003a57565b9182905550905060005b602081101562002b81578082901c60011660010362002b2757826033826020811062002b1f5762002b1f62003a2b565b015550505050565b6033816020811062002b3d5762002b3d62003a2b565b01546040805160208101929092528101849052606001604051602081830303815290604052805190602001209250808062002b789062003a57565b91505062002aef565b50620026016200410d565b60018055565b60685460ff1662002bcf576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6068805460ff191690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b390600090a1565b600054610100900460ff1662002c715760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840162001c8e565b6200070f62003021565b6060604082511062002c9d578180602001905181019062000776919062004123565b815160200362002e2d5760005b60208110801562002cf5575082818151811062002ccb5762002ccb62003a2b565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b1562002d10578062002d078162003a57565b91505062002caa565b8060000362002d5457505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b60008167ffffffffffffffff81111562002d725762002d7262003503565b6040519080825280601f01601f19166020018201604052801562002d9d576020820181803683370190505b50905060005b8281101562002e255784818151811062002dc15762002dc162003a2b565b602001015160f81c60f81b82828151811062002de15762002de162003a2b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002e1c8162003a57565b91505062002da3565b509392505050565b505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b919050565b606854600090610100900463ffffffff1615801562002e90575063ffffffff82166001145b1562002ea4575063ffffffff821662002ed0565b62002ebb64010000000063ffffffff841662003ae3565b62002ecd9063ffffffff851662003afd565b90505b600881901c60008181526069602052604081208054600160ff861690811b91821892839055929091908183169003620018b9576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600062002f8c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200308e9092919063ffffffff16565b80519091501562002601578080602001905181019062002fad9190620041a3565b620026015760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840162001c8e565b600054610100900460ff1662002b8c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840162001c8e565b606062000a59848460008585600080866001600160a01b03168587604051620030b8919062003b23565b60006040518083038185875af1925050503d8060008114620030f7576040519150601f19603f3d011682016040523d82523d6000602084013e620030fc565b606091505b50915091506200310f878383876200311a565b979650505050505050565b606083156200318e57825160000362003186576001600160a01b0385163b620031865760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162001c8e565b508162000a59565b62000a598383815115620031a55781518083602001fd5b8060405162461bcd60e51b815260040162001c8e91906200336c565b6117a780620041c483390190565b803563ffffffff8116811462002e6657600080fd5b6001600160a01b0381168114620031fa57600080fd5b50565b600080604083850312156200321157600080fd5b6200321c83620031cf565b915060208301356200322e81620031e4565b809150509250929050565b8015158114620031fa57600080fd5b60008083601f8401126200325b57600080fd5b50813567ffffffffffffffff8111156200327457600080fd5b6020830191508360208285010111156200328d57600080fd5b9250929050565b600080600080600060808688031215620032ad57600080fd5b620032b886620031cf565b94506020860135620032ca81620031e4565b93506040860135620032dc8162003239565b9250606086013567ffffffffffffffff811115620032f957600080fd5b620033078882890162003248565b969995985093965092949392505050565b60005b83811015620033355781810151838201526020016200331b565b50506000910152565b600081518084526200335881602086016020860162003318565b601f01601f19169290920160200192915050565b6020815260006200338160208301846200333e565b9392505050565b6000602082840312156200339b57600080fd5b81356200338181620031e4565b60ff81168114620031fa57600080fd5b600080600080600080600060e0888a031215620033d457600080fd5b8735620033e181620033a8565b9650620033f160208901620031cf565b955060408801356200340381620031e4565b94506200341360608901620031cf565b935060808801356200342581620031e4565b9699959850939692959460a0840135945060c09093013592915050565b6000806000606084860312156200345857600080fd5b6200346384620031cf565b925060208401356200347581620031e4565b915060408401356200348781620031e4565b809150509250925092565b600060208284031215620034a557600080fd5b5035919050565b8061040081018310156200077657600080fd5b60008060006104408486031215620034d657600080fd5b83359250620034e98560208601620034ac565b9150620034fa6104208501620031cf565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171562003545576200354562003503565b604052919050565b600067ffffffffffffffff8211156200356a576200356a62003503565b50601f01601f191660200190565b60006200358f62003589846200354d565b62003519565b9050828152838383011115620035a457600080fd5b828260208301376000602084830101529392505050565b600082601f830112620035cd57600080fd5b620033818383356020850162003578565b600080600080600060a08688031215620035f757600080fd5b6200360286620031cf565b945060208601356200361481620031e4565b9350604086013567ffffffffffffffff808211156200363257600080fd5b6200364089838a01620035bb565b945060608801359150808211156200365757600080fd5b506200366688828901620035bb565b92505060808601356200367981620033a8565b809150509295509295909350565b60008060008060008060a08789031215620036a157600080fd5b620036ac87620031cf565b95506020870135620036be81620031e4565b9450604087013593506060870135620036d78162003239565b9250608087013567ffffffffffffffff811115620036f457600080fd5b6200370289828a0162003248565b979a9699509497509295939492505050565b600080604083850312156200372857600080fd5b6200373383620031cf565b91506200374360208401620031cf565b90509250929050565b6000806000806000806000806000806000806109208d8f0312156200377057600080fd5b6200377c8e8e620034ac565b9b506200378e8e6104008f01620034ac565b9a506108008d013599506108208d013598506108408d01359750620037b76108608e01620031cf565b9650620037c96108808e0135620031e4565b6108808d01359550620037e06108a08e01620031cf565b9450620037f26108c08e0135620031e4565b6108c08d013593506108e08d0135925067ffffffffffffffff6109008e013511156200381d57600080fd5b620038308e6109008f01358f0162003248565b81935080925050509295989b509295989b509295989b565b600080600080600080600060c0888a0312156200386457600080fd5b6200386f88620031cf565b965060208801356200388181620031e4565b95506040880135945060608801356200389a81620031e4565b93506080880135620038ac8162003239565b925060a088013567ffffffffffffffff811115620038c957600080fd5b620038d78a828b0162003248565b989b979a50959850939692959293505050565b60008060008060008060c087890312156200390457600080fd5b6200390f87620031cf565b955060208701356200392181620031e4565b94506200393160408801620031cf565b935060608701356200394381620031e4565b925060808701356200395581620031e4565b915060a087013567ffffffffffffffff8111156200397257600080fd5b8701601f810189136200398457600080fd5b620039958982356020840162003578565b9150509295509295509295565b6000806000806104608587031215620039ba57600080fd5b84359350620039cd8660208701620034ac565b9250620039de6104208601620031cf565b939692955092936104400135925050565b600181811c9082168062003a0457607f821691505b60208210810362003a2557634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820162003a6c5762003a6c62003a41565b5060010190565b60608152600062003a8860608301866200333e565b828103602084015262003a9c81866200333e565b91505060ff83166040830152949350505050565b6000835162003ac481846020880162003318565b83519083019062003ada81836020880162003318565b01949350505050565b808202811582820484141762000776576200077662003a41565b8082018082111562000776576200077662003a41565b8183823760009101908152919050565b6000825162003b3781846020870162003318565b9190910192915050565b60008060006060848603121562003b5757600080fd5b833567ffffffffffffffff8082111562003b7057600080fd5b62003b7e87838801620035bb565b9450602086013591508082111562003b9557600080fd5b5062003ba486828701620035bb565b92505060408401356200348781620033a8565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b63ffffffff8616815260006001600160a01b038087166020840152808616604084015250608060608301526200310f60808301848662003bb7565b60006020828403121562003c2e57600080fd5b5051919050565b8181038181111562000776576200077662003a41565b600061010060ff8b16835263ffffffff808b1660208501526001600160a01b03808b166040860152818a1660608601528089166080860152508660a08501528160c085015262003c9e828501876200333e565b925080851660e085015250509998505050505050505050565b6001600160a01b038516815263ffffffff8416602082015260606040820152600062003ce860608301848662003bb7565b9695505050505050565b601f8211156200260157600081815260208120601f850160051c8101602086101562003d1b5750805b601f850160051c820191505b8181101562000d955782815560010162003d27565b815167ffffffffffffffff81111562003d595762003d5962003503565b62003d718162003d6a8454620039ef565b8462003cf2565b602080601f83116001811462003da9576000841562003d905750858301515b600019600386901b1c1916600185901b17855562000d95565b600085815260208120601f198616915b8281101562003dda5788860151825594840194600190910190840162003db9565b508582101562003df95787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600061010060ff8c16835263ffffffff808c1660208501526001600160a01b03808c166040860152818b166060860152808a166080860152508760a08501528160c085015262003e5d828501878962003bb7565b925080851660e085015250509a9950505050505050505050565b60006020828403121562003e8a57600080fd5b81516200338181620033a8565b63ffffffff81811683821601908082111562003eb75762003eb762003a41565b5092915050565b6000808585111562003ecf57600080fd5b8386111562003edd57600080fd5b5050820193919092039150565b6001600160e01b0319813581811691600485101562003f135780818660040360031b1b83161692505b505092915050565b600080600080600080600060e0888a03121562003f3757600080fd5b873562003f4481620031e4565b9650602088013562003f5681620031e4565b9550604088013594506060880135935060808801356200342581620033a8565b600080600080600080600080610100898b03121562003f9457600080fd5b883562003fa181620031e4565b9750602089013562003fb381620031e4565b96506040890135955060608901359450608089013562003fd38162003239565b935060a089013562003fe581620033a8565b979a969950949793969295929450505060c08201359160e0013590565b600181815b808511156200404357816000190482111562004027576200402762003a41565b808516156200403557918102915b93841c939080029062004007565b509250929050565b6000826200405c5750600162000776565b816200406b5750600062000776565b81600181146200408457600281146200408f57620040af565b600191505062000776565b60ff841115620040a357620040a362003a41565b50506001821b62000776565b5060208310610133831016604e8410600b8410161715620040d4575081810a62000776565b620040e0838362004002565b8060001904821115620040f757620040f762003a41565b029392505050565b60006200338183836200404b565b634e487b7160e01b600052600160045260246000fd5b6000602082840312156200413657600080fd5b815167ffffffffffffffff8111156200414e57600080fd5b8201601f810184136200416057600080fd5b80516200417162003589826200354d565b8181528560208385010111156200418757600080fd5b6200419a82602083016020860162003318565b95945050505050565b600060208284031215620041b657600080fd5b815162003381816200323956fe6101006040523480156200001257600080fd5b50604051620017a7380380620017a783398101604081905262000035916200028d565b82826003620000458382620003a1565b506004620000548282620003a1565b50503360c0525060ff811660e052466080819052620000739062000080565b60a052506200046d915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620000ad6200012e565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6060600380546200013f9062000312565b80601f01602080910402602001604051908101604052809291908181526020018280546200016d9062000312565b8015620001be5780601f106200019257610100808354040283529160200191620001be565b820191906000526020600020905b815481529060010190602001808311620001a057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f057600080fd5b81516001600160401b03808211156200020d576200020d620001c8565b604051601f8301601f19908116603f01168101908282118183101715620002385762000238620001c8565b816040528381526020925086838588010111156200025557600080fd5b600091505b838210156200027957858201830151818301840152908201906200025a565b600093810190920192909252949350505050565b600080600060608486031215620002a357600080fd5b83516001600160401b0380821115620002bb57600080fd5b620002c987838801620001de565b94506020860151915080821115620002e057600080fd5b50620002ef86828701620001de565b925050604084015160ff811681146200030757600080fd5b809150509250925092565b600181811c908216806200032757607f821691505b6020821081036200034857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039c57600081815260208120601f850160051c81016020861015620003775750805b601f850160051c820191505b81811015620003985782815560010162000383565b5050505b505050565b81516001600160401b03811115620003bd57620003bd620001c8565b620003d581620003ce845462000312565b846200034e565b602080601f8311600181146200040d5760008415620003f45750858301515b600019600386901b1c1916600185901b17855562000398565b600085815260208120601f198616915b828110156200043e578886015182559484019460019091019084016200041d565b50858210156200045d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516112eb620004bc60003960006102370152600081816102fa015281816105630152610623015260006104f701526000818161035f01526104c101526112eb6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806370a08231116100d8578063a457c2d71161008c578063d505accf11610066578063d505accf14610381578063dd62ed3e14610394578063ffa1ad74146103cd57600080fd5b8063a457c2d714610334578063a9059cbb14610347578063cd0d00961461035a57600080fd5b806395d89b41116100bd57806395d89b41146102da5780639dc29fac146102e2578063a3c573eb146102f557600080fd5b806370a08231146102915780637ecebe00146102ba57600080fd5b806330adf81f1161012f5780633644e515116101145780633644e51514610261578063395093511461026957806340c10f191461027c57600080fd5b806330adf81f14610209578063313ce5671461023057600080fd5b806318160ddd1161016057806318160ddd146101bd57806320606b70146101cf57806323b872dd146101f657600080fd5b806306fdde031461017c578063095ea7b31461019a575b600080fd5b6101846103ed565b60405161019191906110a1565b60405180910390f35b6101ad6101a836600461110b565b61047f565b6040519015158152602001610191565b6002545b604051908152602001610191565b6101c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6101ad610204366004611135565b610499565b6101c17f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610191565b6101c16104bd565b6101ad61027736600461110b565b610519565b61028f61028a36600461110b565b610558565b005b6101c161029f366004611171565b6001600160a01b031660009081526020819052604090205490565b6101c16102c8366004611171565b60056020526000908152604090205481565b610184610609565b61028f6102f036600461110b565b610618565b61031c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610191565b6101ad61034236600461110b565b6106c0565b6101ad61035536600461110b565b61076a565b6101c17f000000000000000000000000000000000000000000000000000000000000000081565b61028f61038f366004611193565b610778565b6101c16103a2366004611206565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610184604051806040016040528060018152602001603160f81b81525081565b6060600380546103fc90611239565b80601f016020809104026020016040519081016040528092919081815260200182805461042890611239565b80156104755780601f1061044a57610100808354040283529160200191610475565b820191906000526020600020905b81548152906001019060200180831161045857829003601f168201915b5050505050905090565b60003361048d8185856109fd565b60019150505b92915050565b6000336104a7858285610b56565b6104b2858585610be8565b506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104f4576104ef46610dd5565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919061048d9082908690610553908790611289565b6109fd565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105fb5760405162461bcd60e51b815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084015b60405180910390fd5b6106058282610e81565b5050565b6060600480546103fc90611239565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106b65760405162461bcd60e51b815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084016105f2565b6106058282610f40565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091908381101561075d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084016105f2565b6104b282868684036109fd565b60003361048d818585610be8565b834211156107ed5760405162461bcd60e51b8152602060048201526024808201527f546f6b656e577261707065643a3a7065726d69743a204578706972656420706560448201527f726d69740000000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b038716600090815260056020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a91908661083a8361129c565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060006108986104bd565b6040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810183905260620160408051601f198184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa15801561093e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906109745750896001600160a01b0316816001600160a01b0316145b6109e65760405162461bcd60e51b815260206004820152602760248201527f546f6b656e577261707065643a3a7065726d69743a20496e76616c696420736960448201527f676e61747572650000000000000000000000000000000000000000000000000060648201526084016105f2565b6109f18a8a8a6109fd565b50505050505050505050565b6001600160a01b038316610a785760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b038216610af45760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610be25781811015610bd55760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016105f2565b610be284848484036109fd565b50505050565b6001600160a01b038316610c645760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b038216610ce05760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b03831660009081526020819052604090205481811015610d6f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610be2565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610e006103ed565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6001600160a01b038216610ed75760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016105f2565b8060026000828254610ee99190611289565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610fbc5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b0382166000908152602081905260409020548181101561104b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016105f2565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610b49565b600060208083528351808285015260005b818110156110ce578581018301518582016040015282016110b2565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461110657600080fd5b919050565b6000806040838503121561111e57600080fd5b611127836110ef565b946020939093013593505050565b60008060006060848603121561114a57600080fd5b611153846110ef565b9250611161602085016110ef565b9150604084013590509250925092565b60006020828403121561118357600080fd5b61118c826110ef565b9392505050565b600080600080600080600060e0888a0312156111ae57600080fd5b6111b7886110ef565b96506111c5602089016110ef565b95506040880135945060608801359350608088013560ff811681146111e957600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561121957600080fd5b611222836110ef565b9150611230602084016110ef565b90509250929050565b600181811c9082168061124d57607f821691505b60208210810361126d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561049357610493611273565b6000600182016112ae576112ae611273565b506001019056fea2646970667358221220aee05225eb578ca4601af39623d6cec4d7df11fc43f9c71ce59466ac2db4e37864736f6c63430008140033a26469706673582212202371b7d4c0384f70a2b904847ca70da52a1432c9a54bc07a292aeb4703fc816864736f6c63430008140033" + "address": "0x608484d3e94Fc775E3dCb06B0B48486c60A315e6", + "bytecode": "0x6080604052600436106101db575f3560e01c806383f24403116100fd578063ccaa2d1111610092578063ee25560b11610062578063ee25560b146105a9578063f5efcd79146105d4578063f811bff7146105f3578063fb57083414610612575f80fd5b8063ccaa2d111461053b578063cd5865791461055a578063d02103ca1461056d578063dbc1697614610595575f80fd5b8063bab161bf116100cd578063bab161bf146104b9578063be5831c7146104da578063c00f14ab146104fd578063cc4616321461051c575f80fd5b806383f244031461043d5780638ed7e3f21461045c578063aaa13cc21461047b578063b8b284d01461049a575f80fd5b80633cbc795b116101735780637843298b116101435780637843298b146103c257806379e2cf97146103e157806381b1c174146103f557806383c43a5514610429575f80fd5b80633cbc795b146103385780633e197043146103705780634b2f336d1461038f5780635ca1e165146103ae575f80fd5b806327aef4e8116101ae57806327aef4e81461026d5780632dfdf0b51461028e578063318aee3d146102b15780633c351e1014610319575f80fd5b806315064c96146101df5780632072f6c51461020d57806322e95f2c14610223578063240ff3781461025a575b5f80fd5b3480156101ea575f80fd5b506068546101f89060ff1681565b60405190151581526020015b60405180910390f35b348015610218575f80fd5b50610221610631565b005b34801561022e575f80fd5b5061024261023d366004612fb9565b610666565b6040516001600160a01b039091168152602001610204565b610221610268366004613040565b6106d0565b348015610278575f80fd5b50610281610759565b6040516102049190613102565b348015610299575f80fd5b506102a360535481565b604051908152602001610204565b3480156102bc575f80fd5b506102f56102cb36600461311b565b606b6020525f908152604090205463ffffffff81169064010000000090046001600160a01b031682565b6040805163ffffffff90931683526001600160a01b03909116602083015201610204565b348015610324575f80fd5b50606d54610242906001600160a01b031681565b348015610343575f80fd5b50606d5461035b90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610204565b34801561037b575f80fd5b506102a361038a366004613144565b6107e5565b34801561039a575f80fd5b50606f54610242906001600160a01b031681565b3480156103b9575f80fd5b506102a361088e565b3480156103cd575f80fd5b506102426103dc3660046131be565b61096a565b3480156103ec575f80fd5b50610221610993565b348015610400575f80fd5b5061024261040f366004613204565b606a6020525f90815260409020546001600160a01b031681565b348015610434575f80fd5b506102816109b4565b348015610448575f80fd5b506102a361045736600461322c565b6109d3565b348015610467575f80fd5b50606c54610242906001600160a01b031681565b348015610486575f80fd5b5061024261049536600461332d565b610aa8565b3480156104a5575f80fd5b506102216104b43660046133c3565b610be7565b3480156104c4575f80fd5b5060685461035b90610100900463ffffffff1681565b3480156104e5575f80fd5b5060685461035b90600160c81b900463ffffffff1681565b348015610508575f80fd5b5061028161051736600461311b565b610cc2565b348015610527575f80fd5b506101f8610536366004613441565b610d07565b348015610546575f80fd5b50610221610555366004613472565b610d8f565b610221610568366004613556565b6112c0565b348015610578575f80fd5b50606854610242906501000000000090046001600160a01b031681565b3480156105a0575f80fd5b5061022161172c565b3480156105b4575f80fd5b506102a36105c3366004613204565b60696020525f908152604090205481565b3480156105df575f80fd5b506102216105ee366004613472565b61175f565b3480156105fe575f80fd5b5061022161060d3660046135e6565b611a25565b34801561061d575f80fd5b506101f861062c366004613689565b611d40565b606c546001600160a01b0316331461065c57604051631736745960e31b815260040160405180910390fd5b610664611d57565b565b6040805160e084901b6001600160e01b031916602080830191909152606084901b6bffffffffffffffffffffffff1916602483015282516018818403018152603890920183528151918101919091205f908152606a90915220546001600160a01b03165b92915050565b60685460ff16156106f457604051630bc011ff60e21b815260040160405180910390fd5b341580159061070d5750606f546001600160a01b031615155b15610744576040517f6f625c4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610752858534868686611db2565b5050505050565b606e8054610766906136ce565b80601f0160208091040260200160405190810160405280929190818152602001828054610792906136ce565b80156107dd5780601f106107b4576101008083540402835291602001916107dd565b820191905f5260205f20905b8154815290600101906020018083116107c057829003601f168201915b505050505081565b6040517fff0000000000000000000000000000000000000000000000000000000000000060f889901b1660208201526001600160e01b031960e088811b821660218401526bffffffffffffffffffffffff19606089811b821660258601529188901b909216603984015285901b16603d82015260518101839052607181018290525f90609101604051602081830303815290604052805190602001209050979650505050505050565b6053545f90819081805b6020811015610961578083901c6001166001036108f557603381602081106108c2576108c2613706565b01546040805160208101929092528101859052606001604051602081830303815290604052805190602001209350610922565b60408051602081018690529081018390526060016040516020818303038152906040528051906020012093505b604080516020810184905290810183905260600160405160208183030381529060405280519060200120915080806109599061372e565b915050610898565b50919392505050565b5f61098b848461097985611e7c565b61098286611f66565b61049587612047565b949350505050565b605354606854600160c81b900463ffffffff16101561066457610664612114565b60405180611ba00160405280611b668152602001613d80611b66913981565b5f83815b6020811015610a9f57600163ffffffff8516821c81169003610a4257848160208110610a0557610a05613706565b602002013582604051602001610a25929190918252602082015260400190565b604051602081830303815290604052805190602001209150610a8d565b81858260208110610a5557610a55613706565b6020020135604051602001610a74929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b80610a978161372e565b9150506109d7565b50949350505050565b6040516001600160e01b031960e087901b1660208201526bffffffffffffffffffffffff19606086901b1660248201525f9081906038016040516020818303038152906040528051906020012090505f60ff60f81b308360405180611ba00160405280611b668152602001613d80611b669139898989604051602001610b3093929190613746565b60408051601f1981840301815290829052610b4e929160200161377e565b60405160208183030381529060405280519060200120604051602001610bc394939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051808303601f19018152919052805160209091012098975050505050505050565b60685460ff1615610c0b57604051630bc011ff60e21b815260040160405180910390fd5b606f546001600160a01b0316610c4d576040517fdde3cda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f54604051632770a7eb60e21b8152336004820152602481018690526001600160a01b0390911690639dc29fac906044015f604051808303815f87803b158015610c96575f80fd5b505af1158015610ca8573d5f803e3d5ffd5b50505050610cba868686868686611db2565b505050505050565b6060610ccd82611e7c565b610cd683611f66565b610cdf84612047565b604051602001610cf193929190613746565b6040516020818303038152906040529050919050565b6068545f908190610100900463ffffffff16158015610d2c575063ffffffff83166001145b15610d3e575063ffffffff8316610d66565b610d5364010000000063ffffffff85166137ac565b610d639063ffffffff86166137c3565b90505b600881901c5f90815260696020526040902054600160ff9092169190911b908116149392505050565b60685460ff1615610db357604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff8681166101009092041614610de3576040516302caf51760e11b815260040160405180910390fd5b610e168c8c8c8c8c610e115f8e8e8e8e8e8e8e604051610e049291906137d6565b60405180910390206107e5565b6121c2565b6001600160a01b038616610f6057606f546001600160a01b0316610efa575f6001600160a01b03851684825b6040519080825280601f01601f191660200182016040528015610e6c576020820181803683370190505b50604051610e7a91906137e5565b5f6040518083038185875af1925050503d805f8114610eb4576040519150601f19603f3d011682016040523d82523d5f602084013e610eb9565b606091505b5050905080610ef4576040517f6747a28800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611256565b606f546040516340c10f1960e01b81526001600160a01b03868116600483015260248201869052909116906340c10f19906044015f604051808303815f87803b158015610f45575f80fd5b505af1158015610f57573d5f803e3d5ffd5b50505050611256565b606d546001600160a01b038781169116148015610f8e5750606d5463ffffffff888116600160a01b90920416145b15610fa5575f6001600160a01b0385168482610e42565b60685463ffffffff610100909104811690881603610fd657610fd16001600160a01b0387168585612354565b611256565b6040516001600160e01b031960e089901b1660208201526bffffffffffffffffffffffff19606088901b1660248201525f9060380160408051601f1981840301815291815281516020928301205f818152606a9093529120549091506001600160a01b0316806111f5575f6110808386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506123d592505050565b6040516340c10f1960e01b81526001600160a01b03898116600483015260248201899052919250908216906340c10f19906044015f604051808303815f87803b1580156110cb575f80fd5b505af11580156110dd573d5f803e3d5ffd5b5050505080606a5f8581526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060405180604001604052808b63ffffffff1681526020018a6001600160a01b0316815250606b5f836001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548163ffffffff021916908363ffffffff1602179055506020820151815f0160046101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f490e59a1701b938786ac72570a1efeac994a3dbe96e2e883e19e902ace6e6a398a8a8388886040516111e7959493929190613828565b60405180910390a150611253565b6040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f19906044015f604051808303815f87803b15801561123c575f80fd5b505af115801561124e573d5f803e3d5ffd5b505050505b50505b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b60685460ff16156112e457604051630bc011ff60e21b815260040160405180910390fd5b6112ec612468565b60685463ffffffff61010090910481169088160361131d576040516302caf51760e11b815260040160405180910390fd5b5f806060876001600160a01b03881661141957883414611369576040517fb89240f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606d54606e80546001600160a01b0383169650600160a01b90920463ffffffff16945090611396906136ce565b80601f01602080910402602001604051908101604052809291908181526020018280546113c2906136ce565b801561140d5780601f106113e45761010080835404028352916020019161140d565b820191905f5260205f20905b8154815290600101906020018083116113f057829003601f168201915b505050505091506116a3565b3415611451576040517f798ee6f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546001600160a01b03908116908916036114c757604051632770a7eb60e21b8152336004820152602481018a90526001600160a01b03891690639dc29fac906044015f604051808303815f87803b1580156114ac575f80fd5b505af11580156114be573d5f803e3d5ffd5b505050506116a3565b6001600160a01b038089165f908152606b602090815260409182902082518084019093525463ffffffff811683526401000000009004909216918101829052901561157957604051632770a7eb60e21b8152336004820152602481018b90526001600160a01b038a1690639dc29fac906044015f604051808303815f87803b158015611551575f80fd5b505af1158015611563573d5f803e3d5ffd5b5050505080602001519450805f01519350611696565b851561158b5761158b898b89896124c1565b6040516370a0823160e01b81523060048201525f906001600160a01b038b16906370a0823190602401602060405180830381865afa1580156115cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f39190613860565b905061160a6001600160a01b038b1633308e612860565b6040516370a0823160e01b81523060048201525f906001600160a01b038c16906370a0823190602401602060405180830381865afa15801561164e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116729190613860565b905061167e8282613877565b6068548c9850610100900463ffffffff169650935050505b61169f89610cc2565b9250505b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b5f84868e8e86886053546040516116e298979695949392919061388a565b60405180910390a16117086117035f85878f8f8789805190602001206107e5565b6128b1565b861561171657611716612114565b5050505061172360018055565b50505050505050565b606c546001600160a01b0316331461175757604051631736745960e31b815260040160405180910390fd5b6106646129b2565b60685460ff161561178357604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff86811661010090920416146117b3576040516302caf51760e11b815260040160405180910390fd5b6117d58c8c8c8c8c610e1160018e8e8e8e8e8e8e604051610e049291906137d6565b606f545f906001600160a01b031661188857846001600160a01b031684888a868660405160240161180994939291906138f3565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161183e91906137e5565b5f6040518083038185875af1925050503d805f8114611878576040519150601f19603f3d011682016040523d82523d5f602084013e61187d565b606091505b505080915050611983565b606f546040516340c10f1960e01b81526001600160a01b03878116600483015260248201879052909116906340c10f19906044015f604051808303815f87803b1580156118d3575f80fd5b505af11580156118e5573d5f803e3d5ffd5b50505050846001600160a01b03168789858560405160240161190a94939291906138f3565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161193f91906137e5565b5f604051808303815f865af19150503d805f8114611978576040519150601f19603f3d011682016040523d82523d5f602084013e61197d565b606091505b50909150505b806119ba576040517f37e391c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518c815263ffffffff8a1660208201526001600160a01b0389811682840152871660608201526080810186905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a150505050505050505050505050565b5f54610100900460ff1615808015611a4357505f54600160ff909116105b80611a5c5750303b158015611a5c57505f5460ff166001145b611ad35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f805460ff191660011790558015611af4575f805461ff0019166101001790555b606880547fffffffffffffff000000000000000000000000000000000000000000000000ff1661010063ffffffff8a16027fffffffffffffff0000000000000000000000000000000000000000ffffffffff1617650100000000006001600160a01b038781169190910291909117909155606c805473ffffffffffffffffffffffffffffffffffffffff19168583161790558616611bcf5763ffffffff851615611bca576040517f1a874c1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ceb565b606d805463ffffffff8716600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009091166001600160a01b03891617179055606e611c1e8382613970565b50611cbd5f801b6012604051602001611ca991906060808252600d908201527f5772617070656420457468657200000000000000000000000000000000000000608082015260a0602082018190526004908201527f574554480000000000000000000000000000000000000000000000000000000060c082015260ff91909116604082015260e00190565b6040516020818303038152906040526123d5565b606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555b611cf3612a22565b8015611723575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b5f81611d4d8686866109d3565b1495945050505050565b60685460ff1615611d7b57604051630bc011ff60e21b815260040160405180910390fd5b6068805460ff191660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a5497905f90a1565b60685463ffffffff610100909104811690871603611de3576040516302caf51760e11b815260040160405180910390fd5b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b6001606860019054906101000a900463ffffffff16338989898888605354604051611e3799989796959493929190613a2c565b60405180910390a1611e6e6117036001606860019054906101000a900463ffffffff16338a8a8a8989604051610e049291906137d6565b8215610cba57610cba612114565b60408051600481526024810182526020810180516001600160e01b03167f06fdde030000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611edb91906137e5565b5f60405180830381855afa9150503d805f8114611f13576040519150601f19603f3d011682016040523d82523d5f602084013e611f18565b606091505b509150915081611f5d576040518060400160405280600781526020017f4e4f5f4e414d450000000000000000000000000000000000000000000000000081525061098b565b61098b81612a94565b60408051600481526024810182526020810180516001600160e01b03167f95d89b410000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611fc591906137e5565b5f60405180830381855afa9150503d805f8114611ffd576040519150601f19603f3d011682016040523d82523d5f602084013e612002565b606091505b509150915081611f5d576040518060400160405280600981526020017f4e4f5f53594d424f4c000000000000000000000000000000000000000000000081525061098b565b60408051600481526024810182526020810180516001600160e01b03167f313ce5670000000000000000000000000000000000000000000000000000000017905290515f91829182916001600160a01b038616916120a591906137e5565b5f60405180830381855afa9150503d805f81146120dd576040519150601f19603f3d011682016040523d82523d5f602084013e6120e2565b606091505b50915091508180156120f5575080516020145b61210057601261098b565b8080602001905181019061098b9190613a97565b6053546068805463ffffffff909216600160c81b027fffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117908190556001600160a01b0365010000000000909104166333d6247d61217561088e565b6040518263ffffffff1660e01b815260040161219391815260200190565b5f604051808303815f87803b1580156121aa575f80fd5b505af11580156121bc573d5f803e3d5ffd5b50505050565b606854604080516020808201879052818301869052825180830384018152606083019384905280519101207f257b36320000000000000000000000000000000000000000000000000000000090925260648101919091525f916501000000000090046001600160a01b03169063257b3632906084016020604051808303815f875af1158015612253573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122779190613860565b9050805f036122b1576040517e2f6fad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80680100000000000000008716156122f5578691506122d3848a8489611d40565b6122f0576040516338105f3b60e21b815260040160405180910390fd5b61233f565b602087901c612305816001613ab2565b9150879250612320612318868c866109d3565b8a8389611d40565b61233d576040516338105f3b60e21b815260040160405180910390fd5b505b6123498282612c64565b505050505050505050565b6040516001600160a01b0383166024820152604481018290526123d09084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612d24565b505050565b5f8060405180611ba00160405280611b668152602001613d80611b6691398360405160200161240592919061377e565b6040516020818303038152906040529050838151602083015ff591506001600160a01b038216612461576040517fbefb092000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092915050565b6002600154036124ba5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611aca565b6002600155565b5f6124cf6004828486613acf565b6124d891613af6565b90507f2afa5331000000000000000000000000000000000000000000000000000000006001600160e01b03198216016126b2575f80808080808061251f896004818d613acf565b81019061252c9190613b26565b9650965096509650965096509650336001600160a01b0316876001600160a01b03161461256c5760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03861630146125955760405163750643af60e01b815260040160405180910390fd5b8a85146125ce576040517f03fffc4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b0389811660248301528881166044830152606482018890526084820187905260ff861660a483015260c4820185905260e48083018590528351808403909101815261010490920183526020820180516001600160e01b03167fd505accf000000000000000000000000000000000000000000000000000000001790529151918e169161266591906137e5565b5f604051808303815f865af19150503d805f811461269e576040519150601f19603f3d011682016040523d82523d5f602084013e6126a3565b606091505b50505050505050505050610752565b6001600160e01b031981166323f2ebc360e21b146126fc576040517fe282c0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f808080808080806127118a6004818e613acf565b81019061271e9190613b75565b97509750975097509750975097509750336001600160a01b0316886001600160a01b0316146127605760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03871630146127895760405163750643af60e01b815260040160405180910390fd5b604080516001600160a01b038a811660248301528981166044830152606482018990526084820188905286151560a483015260ff861660c483015260e482018590526101048083018590528351808403909101815261012490920183526020820180516001600160e01b03166323f2ebc360e21b1790529151918f169161281091906137e5565b5f604051808303815f865af19150503d805f8114612849576040519150601f19603f3d011682016040523d82523d5f602084013e61284e565b606091505b50505050505050505050505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526121bc9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612399565b8060016128c060206002613cd3565b6128ca9190613877565b60535410612904576040517fef5ccf6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60535f81546129139061372e565b918290555090505f5b60208110156129a3578082901c60011660010361294f57826033826020811061294757612947613706565b015550505050565b6033816020811061296257612962613706565b01546040805160208101929092528101849052606001604051602081830303815290604052805190602001209250808061299b9061372e565b91505061291c565b506123d0613cde565b60018055565b60685460ff166129ee576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6068805460ff191690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b3905f90a1565b5f54610100900460ff16612a8c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611aca565b610664612e08565b60606040825110612ab357818060200190518101906106ca9190613cf2565b8151602003612c26575f5b602081108015612b055750828181518110612adb57612adb613706565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612b1c5780612b148161372e565b915050612abe565b805f03612b5e57505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b5f8167ffffffffffffffff811115612b7857612b78613268565b6040519080825280601f01601f191660200182016040528015612ba2576020820181803683370190505b5090505f5b82811015612c1e57848181518110612bc157612bc1613706565b602001015160f81c60f81b828281518110612bde57612bde613706565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535080612c168161372e565b915050612ba7565b509392505050565b505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b919050565b6068545f90610100900463ffffffff16158015612c87575063ffffffff82166001145b15612c99575063ffffffff8216612cc1565b612cae64010000000063ffffffff84166137ac565b612cbe9063ffffffff85166137c3565b90505b600881901c5f8181526069602052604081208054600160ff861690811b91821892839055929091908183169003611723576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612d78826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e729092919063ffffffff16565b8051909150156123d05780806020019051810190612d969190613d64565b6123d05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611aca565b5f54610100900460ff166129ac5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611aca565b606061098b84845f85855f80866001600160a01b03168587604051612e9791906137e5565b5f6040518083038185875af1925050503d805f8114612ed1576040519150601f19603f3d011682016040523d82523d5f602084013e612ed6565b606091505b5091509150612ee787838387612ef2565b979650505050505050565b60608315612f605782515f03612f59576001600160a01b0385163b612f595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611aca565b508161098b565b61098b8383815115612f755781518083602001fd5b8060405162461bcd60e51b8152600401611aca9190613102565b803563ffffffff81168114612c5f575f80fd5b6001600160a01b0381168114612fb6575f80fd5b50565b5f8060408385031215612fca575f80fd5b612fd383612f8f565b91506020830135612fe381612fa2565b809150509250929050565b8015158114612fb6575f80fd5b5f8083601f84011261300b575f80fd5b50813567ffffffffffffffff811115613022575f80fd5b602083019150836020828501011115613039575f80fd5b9250929050565b5f805f805f60808688031215613054575f80fd5b61305d86612f8f565b9450602086013561306d81612fa2565b9350604086013561307d81612fee565b9250606086013567ffffffffffffffff811115613098575f80fd5b6130a488828901612ffb565b969995985093965092949392505050565b5f5b838110156130cf5781810151838201526020016130b7565b50505f910152565b5f81518084526130ee8160208601602086016130b5565b601f01601f19169290920160200192915050565b602081525f61311460208301846130d7565b9392505050565b5f6020828403121561312b575f80fd5b813561311481612fa2565b60ff81168114612fb6575f80fd5b5f805f805f805f60e0888a03121561315a575f80fd5b873561316581613136565b965061317360208901612f8f565b9550604088013561318381612fa2565b945061319160608901612f8f565b935060808801356131a181612fa2565b9699959850939692959460a0840135945060c09093013592915050565b5f805f606084860312156131d0575f80fd5b6131d984612f8f565b925060208401356131e981612fa2565b915060408401356131f981612fa2565b809150509250925092565b5f60208284031215613214575f80fd5b5035919050565b8061040081018310156106ca575f80fd5b5f805f610440848603121561323f575f80fd5b83359250613250856020860161321b565b915061325f6104208501612f8f565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156132a5576132a5613268565b604052919050565b5f67ffffffffffffffff8211156132c6576132c6613268565b50601f01601f191660200190565b5f6132e66132e1846132ad565b61327c565b90508281528383830111156132f9575f80fd5b828260208301375f602084830101529392505050565b5f82601f83011261331e575f80fd5b613114838335602085016132d4565b5f805f805f60a08688031215613341575f80fd5b61334a86612f8f565b9450602086013561335a81612fa2565b9350604086013567ffffffffffffffff80821115613376575f80fd5b61338289838a0161330f565b94506060880135915080821115613397575f80fd5b506133a48882890161330f565b92505060808601356133b581613136565b809150509295509295909350565b5f805f805f8060a087890312156133d8575f80fd5b6133e187612f8f565b955060208701356133f181612fa2565b945060408701359350606087013561340881612fee565b9250608087013567ffffffffffffffff811115613423575f80fd5b61342f89828a01612ffb565b979a9699509497509295939492505050565b5f8060408385031215613452575f80fd5b61345b83612f8f565b915061346960208401612f8f565b90509250929050565b5f805f805f805f805f805f806109208d8f03121561348e575f80fd5b6134988e8e61321b565b9b506134a88e6104008f0161321b565b9a506108008d013599506108208d013598506108408d013597506134cf6108608e01612f8f565b96506134df6108808e0135612fa2565b6108808d013595506134f46108a08e01612f8f565b94506135046108c08e0135612fa2565b6108c08d013593506108e08d0135925067ffffffffffffffff6109008e0135111561352d575f80fd5b61353e8e6109008f01358f01612ffb565b81935080925050509295989b509295989b509295989b565b5f805f805f805f60c0888a03121561356c575f80fd5b61357588612f8f565b9650602088013561358581612fa2565b955060408801359450606088013561359c81612fa2565b935060808801356135ac81612fee565b925060a088013567ffffffffffffffff8111156135c7575f80fd5b6135d38a828b01612ffb565b989b979a50959850939692959293505050565b5f805f805f8060c087890312156135fb575f80fd5b61360487612f8f565b9550602087013561361481612fa2565b945061362260408801612f8f565b9350606087013561363281612fa2565b9250608087013561364281612fa2565b915060a087013567ffffffffffffffff81111561365d575f80fd5b8701601f8101891361366d575f80fd5b61367c898235602084016132d4565b9150509295509295509295565b5f805f80610460858703121561369d575f80fd5b843593506136ae866020870161321b565b92506136bd6104208601612f8f565b939692955092936104400135925050565b600181811c908216806136e257607f821691505b60208210810361370057634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161373f5761373f61371a565b5060010190565b606081525f61375860608301866130d7565b828103602084015261376a81866130d7565b91505060ff83166040830152949350505050565b5f835161378f8184602088016130b5565b8351908301906137a38183602088016130b5565b01949350505050565b80820281158282048414176106ca576106ca61371a565b808201808211156106ca576106ca61371a565b818382375f9101908152919050565b5f82516137f68184602087016130b5565b9190910192915050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b63ffffffff861681525f6001600160a01b03808716602084015280861660408401525060806060830152612ee7608083018486613800565b5f60208284031215613870575f80fd5b5051919050565b818103818111156106ca576106ca61371a565b5f61010060ff8b16835263ffffffff808b1660208501526001600160a01b03808b166040860152818a1660608601528089166080860152508660a08501528160c08501526138da828501876130d7565b925080851660e085015250509998505050505050505050565b6001600160a01b038516815263ffffffff84166020820152606060408201525f613921606083018486613800565b9695505050505050565b601f8211156123d0575f81815260208120601f850160051c810160208610156139515750805b601f850160051c820191505b81811015610cba5782815560010161395d565b815167ffffffffffffffff81111561398a5761398a613268565b61399e8161399884546136ce565b8461392b565b602080601f8311600181146139d1575f84156139ba5750858301515b5f19600386901b1c1916600185901b178555610cba565b5f85815260208120601f198616915b828110156139ff578886015182559484019460019091019084016139e0565b5085821015613a1c57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61010060ff8c16835263ffffffff808c1660208501526001600160a01b03808c166040860152818b166060860152808a166080860152508760a08501528160c0850152613a7d8285018789613800565b925080851660e085015250509a9950505050505050505050565b5f60208284031215613aa7575f80fd5b815161311481613136565b63ffffffff8181168382160190808211156124615761246161371a565b5f8085851115613add575f80fd5b83861115613ae9575f80fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613b1e5780818660040360031b1b83161692505b505092915050565b5f805f805f805f60e0888a031215613b3c575f80fd5b8735613b4781612fa2565b96506020880135613b5781612fa2565b9550604088013594506060880135935060808801356131a181613136565b5f805f805f805f80610100898b031215613b8d575f80fd5b8835613b9881612fa2565b97506020890135613ba881612fa2565b965060408901359550606089013594506080890135613bc681612fee565b935060a0890135613bd681613136565b979a969950949793969295929450505060c08201359160e0013590565b600181815b80851115613c2d57815f1904821115613c1357613c1361371a565b80851615613c2057918102915b93841c9390800290613bf8565b509250929050565b5f82613c43575060016106ca565b81613c4f57505f6106ca565b8160018114613c655760028114613c6f57613c8b565b60019150506106ca565b60ff841115613c8057613c8061371a565b50506001821b6106ca565b5060208310610133831016604e8410600b8410161715613cae575081810a6106ca565b613cb88383613bf3565b805f1904821115613ccb57613ccb61371a565b029392505050565b5f6131148383613c35565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215613d02575f80fd5b815167ffffffffffffffff811115613d18575f80fd5b8201601f81018413613d28575f80fd5b8051613d366132e1826132ad565b818152856020838501011115613d4a575f80fd5b613d5b8260208301602086016130b5565b95945050505050565b5f60208284031215613d74575f80fd5b815161311481612fee56fe6101006040523480156200001257600080fd5b5060405162001b6638038062001b6683398101604081905262000035916200028d565b82826003620000458382620003a1565b506004620000548282620003a1565b50503360c0525060ff811660e052466080819052620000739062000080565b60a052506200046d915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620000ad6200012e565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6060600380546200013f9062000312565b80601f01602080910402602001604051908101604052809291908181526020018280546200016d9062000312565b8015620001be5780601f106200019257610100808354040283529160200191620001be565b820191906000526020600020905b815481529060010190602001808311620001a057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f057600080fd5b81516001600160401b03808211156200020d576200020d620001c8565b604051601f8301601f19908116603f01168101908282118183101715620002385762000238620001c8565b816040528381526020925086838588010111156200025557600080fd5b600091505b838210156200027957858201830151818301840152908201906200025a565b600093810190920192909252949350505050565b600080600060608486031215620002a357600080fd5b83516001600160401b0380821115620002bb57600080fd5b620002c987838801620001de565b94506020860151915080821115620002e057600080fd5b50620002ef86828701620001de565b925050604084015160ff811681146200030757600080fd5b809150509250925092565b600181811c908216806200032757607f821691505b6020821081036200034857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039c57600081815260208120601f850160051c81016020861015620003775750805b601f850160051c820191505b81811015620003985782815560010162000383565b5050505b505050565b81516001600160401b03811115620003bd57620003bd620001c8565b620003d581620003ce845462000312565b846200034e565b602080601f8311600181146200040d5760008415620003f45750858301515b600019600386901b1c1916600185901b17855562000398565b600085815260208120601f198616915b828110156200043e578886015182559484019460019091019084016200041d565b50858210156200045d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516116aa620004bc6000396000610237015260008181610307015281816105c001526106a70152600061053a015260008181610379015261050401526116aa6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806370a08231116100d8578063a457c2d71161008c578063d505accf11610066578063d505accf1461039b578063dd62ed3e146103ae578063ffa1ad74146103f457600080fd5b8063a457c2d71461034e578063a9059cbb14610361578063cd0d00961461037457600080fd5b806395d89b41116100bd57806395d89b41146102e75780639dc29fac146102ef578063a3c573eb1461030257600080fd5b806370a08231146102915780637ecebe00146102c757600080fd5b806330adf81f1161012f5780633644e515116101145780633644e51514610261578063395093511461026957806340c10f191461027c57600080fd5b806330adf81f14610209578063313ce5671461023057600080fd5b806318160ddd1161016057806318160ddd146101bd57806320606b70146101cf57806323b872dd146101f657600080fd5b806306fdde031461017c578063095ea7b31461019a575b600080fd5b610184610430565b60405161019191906113e4565b60405180910390f35b6101ad6101a8366004611479565b6104c2565b6040519015158152602001610191565b6002545b604051908152602001610191565b6101c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6101ad6102043660046114a3565b6104dc565b6101c17f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610191565b6101c1610500565b6101ad610277366004611479565b61055c565b61028f61028a366004611479565b6105a8565b005b6101c161029f3660046114df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101c16102d53660046114df565b60056020526000908152604090205481565b610184610680565b61028f6102fd366004611479565b61068f565b6103297f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101ad61035c366004611479565b61075e565b6101ad61036f366004611479565b61082f565b6101c17f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103a9366004611501565b61083d565b6101c16103bc366004611574565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101846040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b60606003805461043f906115a7565b80601f016020809104026020016040519081016040528092919081815260200182805461046b906115a7565b80156104b85780601f1061048d576101008083540402835291602001916104b8565b820191906000526020600020905b81548152906001019060200180831161049b57829003601f168201915b5050505050905090565b6000336104d0818585610b73565b60019150505b92915050565b6000336104ea858285610d27565b6104f5858585610dfe565b506001949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610537576105324661106d565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104d090829086906105a3908790611629565b610b73565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084015b60405180910390fd5b61067c8282611135565b5050565b60606004805461043f906115a7565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d427269646765000000000000000000000000000000006064820152608401610669565b61067c8282611228565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610822576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610669565b6104f58286868403610b73565b6000336104d0818585610dfe565b834211156108cc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f546f6b656e577261707065643a3a7065726d69743a204578706972656420706560448201527f726d6974000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a9190866109268361163c565b9091555060408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610991610500565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610a55573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610ad057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f546f6b656e577261707065643a3a7065726d69743a20496e76616c696420736960448201527f676e6174757265000000000000000000000000000000000000000000000000006064820152608401610669565b610b678a8a8a610b73565b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316610c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610df85781811015610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610669565b610df88484848403610b73565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610df8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611098610430565b8051602091820120604080518082018252600181527f310000000000000000000000000000000000000000000000000000000000000090840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b73ffffffffffffffffffffffffffffffffffffffff82166111b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610669565b80600260008282546111c49190611629565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166112cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610d1a565b600060208083528351808285015260005b81811015611411578581018301518582016040015282016113f5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461147457600080fd5b919050565b6000806040838503121561148c57600080fd5b61149583611450565b946020939093013593505050565b6000806000606084860312156114b857600080fd5b6114c184611450565b92506114cf60208501611450565b9150604084013590509250925092565b6000602082840312156114f157600080fd5b6114fa82611450565b9392505050565b600080600080600080600060e0888a03121561151c57600080fd5b61152588611450565b965061153360208901611450565b95506040880135945060608801359350608088013560ff8116811461155757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561158757600080fd5b61159083611450565b915061159e60208401611450565b90509250929050565b600181811c908216806115bb57607f821691505b6020821081036115f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104d6576104d66115fa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361166d5761166d6115fa565b506001019056fea26469706673582212208d88fee561cff7120d381c345cfc534cef8229a272dc5809d4bbb685ad67141164736f6c63430008110033a2646970667358221220432f6d6b4446edbe1f73c19fd2115454d5c35d8b03b98a74fd46724151d7672264736f6c63430008140033" }, { "contractName": "PolygonZkEVMBridge proxy", "balance": "340282366920938463463374607431768211455", "nonce": "1", - "address": "0xCca6ECD73932e49633B9307e1aa0fC174525F424", - "bytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b61009036600461086f565b610135565b61006b6100a336600461088a565b61017f565b3480156100b457600080fd5b506100bd6101f3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b61010136600461086f565b610231565b34801561011257600080fd5b506100bd61025e565b61012361028c565b61013361012e610363565b61036d565b565b61013d610391565b73ffffffffffffffffffffffffffffffffffffffff16330361017757610174816040518060200160405280600081525060006103d1565b50565b61017461011b565b610187610391565b73ffffffffffffffffffffffffffffffffffffffff1633036101eb576101e68383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506103d1915050565b505050565b6101e661011b565b60006101fd610391565b73ffffffffffffffffffffffffffffffffffffffff16330361022657610221610363565b905090565b61022e61011b565b90565b610239610391565b73ffffffffffffffffffffffffffffffffffffffff16330361017757610174816103fc565b6000610268610391565b73ffffffffffffffffffffffffffffffffffffffff16330361022657610221610391565b610294610391565b73ffffffffffffffffffffffffffffffffffffffff163303610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b600061022161045d565b3660008037600080366000845af43d6000803e80801561038c573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6103da83610485565b6000825111806103e75750805b156101e6576103f683836104d2565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610425610391565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a1610174816104fe565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103b5565b61048e8161060a565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606104f7838360405180606001604052806027815260200161099f602791396106d5565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff81166105a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161035a565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b73ffffffffffffffffffffffffffffffffffffffff81163b6106ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161035a565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105c4565b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516106ff9190610931565b600060405180830381855af49150503d806000811461073a576040519150601f19603f3d011682016040523d82523d6000602084013e61073f565b606091505b50915091506107508683838761075a565b9695505050505050565b606083156107f05782516000036107e95773ffffffffffffffffffffffffffffffffffffffff85163b6107e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161035a565b50816107fa565b6107fa8383610802565b949350505050565b8151156108125781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161035a919061094d565b803573ffffffffffffffffffffffffffffffffffffffff8116811461086a57600080fd5b919050565b60006020828403121561088157600080fd5b6104f782610846565b60008060006040848603121561089f57600080fd5b6108a884610846565b9250602084013567ffffffffffffffff808211156108c557600080fd5b818601915086601f8301126108d957600080fd5b8135818111156108e857600080fd5b8760208285010111156108fa57600080fd5b6020830194508093505050509250925092565b60005b83811015610928578181015183820152602001610910565b50506000910152565b6000825161094381846020870161090d565b9190910192915050565b602081526000825180602084015261096c81604085016020870161090d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220701a0c26bdd76686e63fc3c65e4f28a20ba3ecc8a60246733c0627e679c9804e64736f6c63430008140033", + "address": "0xFe12ABaa190Ef0c8638Ee0ba9F828BF41368Ca0E", + "bytecode": "0x60806040526004361061005d575f3560e01c80635c60da1b116100425780635c60da1b146100a65780638f283970146100e3578063f851a440146101025761006c565b80633659cfe6146100745780634f1ef286146100935761006c565b3661006c5761006a610116565b005b61006a610116565b34801561007f575f80fd5b5061006a61008e366004610854565b610130565b61006a6100a136600461086d565b610178565b3480156100b1575f80fd5b506100ba6101eb565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ee575f80fd5b5061006a6100fd366004610854565b610228565b34801561010d575f80fd5b506100ba610255565b61011e610282565b61012e610129610359565b610362565b565b610138610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d8160405180602001604052805f8152505f6103bf565b50565b61016d610116565b610180610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101e3576101de8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250600192506103bf915050565b505050565b6101de610116565b5f6101f4610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610359565b905090565b610225610116565b90565b610230610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d816103e9565b5f61025e610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610380565b61028a610380565b73ffffffffffffffffffffffffffffffffffffffff16330361012e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b5f61021861044a565b365f80375f80365f845af43d5f803e80801561037c573d5ff35b3d5ffd5b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6103c883610471565b5f825111806103d45750805b156101de576103e383836104bd565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610412610380565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161016d816104e9565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103a3565b61047a816105f5565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606104e28383604051806060016040528060278152602001610977602791396106c0565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff811661058c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610350565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b73ffffffffffffffffffffffffffffffffffffffff81163b610699576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610350565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105af565b60605f808573ffffffffffffffffffffffffffffffffffffffff16856040516106e9919061090b565b5f60405180830381855af49150503d805f8114610721576040519150601f19603f3d011682016040523d82523d5f602084013e610726565b606091505b509150915061073786838387610741565b9695505050505050565b606083156107d65782515f036107cf5773ffffffffffffffffffffffffffffffffffffffff85163b6107cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610350565b50816107e0565b6107e083836107e8565b949350505050565b8151156107f85781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103509190610926565b803573ffffffffffffffffffffffffffffffffffffffff8116811461084f575f80fd5b919050565b5f60208284031215610864575f80fd5b6104e28261082c565b5f805f6040848603121561087f575f80fd5b6108888461082c565b9250602084013567ffffffffffffffff808211156108a4575f80fd5b818601915086601f8301126108b7575f80fd5b8135818111156108c5575f80fd5b8760208285010111156108d6575f80fd5b6020830194508093505050509250925092565b5f5b838110156109035781810151838201526020016108eb565b50505f910152565b5f825161091c8184602087016108e9565b9190910192915050565b602081525f82518060208401526109448160408501602087016108e9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202ac98acbfbb3d3ac1b74050e18c4e76db25a3ff2801ec69bf85d0c61414d502b64736f6c63430008140033", "storage": { - "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000e34fe58dda5b8c6d547e4857e987633aa86a5e90", - "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x00000000000000000000000012864938eadb26501034339667cabfb3d7045cd2" + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000fadb60b5059e31614e02083ff6c021a24c31c891", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000608484d3e94fc775e3dcb06b0b48486c60a315e6" } }, { @@ -52,7 +52,7 @@ "balance": "0", "nonce": "1", "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "bytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806301fd904414610051578063257b36321461006d57806333d6247d1461008d578063a3c573eb146100a2575b600080fd5b61005a60015481565b6040519081526020015b60405180910390f35b61005a61007b366004610162565b60006020819052908152604090205481565b6100a061009b366004610162565b6100ee565b005b6100c97f000000000000000000000000cca6ecd73932e49633b9307e1aa0fc174525f42481565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610064565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cca6ecd73932e49633b9307e1aa0fc174525f424161461015d576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b60006020828403121561017457600080fd5b503591905056fea2646970667358221220ea2171e2c85c8bff947affc409ef6fc6a8fe82fb8c174ddeda988651e595d66564736f6c63430008140033" + "bytecode": "0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c806301fd90441461004e578063257b36321461006a57806333d6247d14610089578063a3c573eb1461009e575b5f80fd5b61005760015481565b6040519081526020015b60405180910390f35b61005761007836600461015e565b5f6020819052908152604090205481565b61009c61009736600461015e565b6100ea565b005b6100c57f000000000000000000000000fe12abaa190ef0c8638ee0ba9f828bf41368ca0e81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610061565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000fe12abaa190ef0c8638ee0ba9f828bf41368ca0e1614610159576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b5f6020828403121561016e575f80fd5b503591905056fea26469706673582212205108c6c4f924146b736832a1bdf696e20d900450207b7452462368d150f2c71c64736f6c63430008140033" }, { "contractName": "PolygonZkEVMGlobalExitRootL2 proxy", @@ -61,7 +61,7 @@ "address": "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa", "bytecode": "0x60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033", "storage": { - "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000e34fe58dda5b8c6d547e4857e987633aa86a5e90", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000fadb60b5059e31614e02083ff6c021a24c31c891", "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9" } }, @@ -70,7 +70,7 @@ "balance": "0", "nonce": "1", "address": "0x0165878A594ca255338adfa4d48449f69242Eb8F", - "bytecode": "0x6080604052600436106101c65760003560e01c806364d62353116100f7578063b1c5f42711610095578063d547741f11610064578063d547741f14610661578063e38335e514610681578063f23a6e6114610694578063f27a0c92146106d957600080fd5b8063b1c5f427146105af578063bc197c81146105cf578063c4d252f514610614578063d45c44351461063457600080fd5b80638f61f4f5116100d15780638f61f4f5146104e157806391d1485414610515578063a217fddf14610566578063b08e51c01461057b57600080fd5b806364d62353146104815780638065657f146104a15780638f2a0bb0146104c157600080fd5b8063248a9ca31161016457806331d507501161013e57806331d50750146103c857806336568abe146103e85780633a6aae7214610408578063584b153e1461046157600080fd5b8063248a9ca3146103475780632ab0f529146103775780632f2ff15d146103a857600080fd5b80630d3cf6fc116101a05780630d3cf6fc1461026b578063134008d31461029f57806313bc9f20146102b2578063150b7a02146102d257600080fd5b806301d5062a146101d257806301ffc9a7146101f457806307bd02651461022957600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506101f26101ed366004611c52565b6106ee565b005b34801561020057600080fd5b5061021461020f366004611cc7565b610783565b60405190151581526020015b60405180910390f35b34801561023557600080fd5b5061025d7fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610220565b34801561027757600080fd5b5061025d7f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101f26102ad366004611d09565b6107df565b3480156102be57600080fd5b506102146102cd366004611d75565b6108d7565b3480156102de57600080fd5b506103166102ed366004611e9a565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610220565b34801561035357600080fd5b5061025d610362366004611d75565b60009081526020819052604090206001015490565b34801561038357600080fd5b50610214610392366004611d75565b6000908152600160208190526040909120541490565b3480156103b457600080fd5b506101f26103c3366004611f02565b6108fd565b3480156103d457600080fd5b506102146103e3366004611d75565b610927565b3480156103f457600080fd5b506101f2610403366004611f02565b610940565b34801561041457600080fd5b5061043c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610220565b34801561046d57600080fd5b5061021461047c366004611d75565b6109f8565b34801561048d57600080fd5b506101f261049c366004611d75565b610a0e565b3480156104ad57600080fd5b5061025d6104bc366004611d09565b610ade565b3480156104cd57600080fd5b506101f26104dc366004611f73565b610b1d565b3480156104ed57600080fd5b5061025d7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b34801561052157600080fd5b50610214610530366004611f02565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561057257600080fd5b5061025d600081565b34801561058757600080fd5b5061025d7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b3480156105bb57600080fd5b5061025d6105ca366004612025565b610d4f565b3480156105db57600080fd5b506103166105ea36600461214e565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b34801561062057600080fd5b506101f261062f366004611d75565b610d94565b34801561064057600080fd5b5061025d61064f366004611d75565b60009081526001602052604090205490565b34801561066d57600080fd5b506101f261067c366004611f02565b610e8f565b6101f261068f366004612025565b610eb4565b3480156106a057600080fd5b506103166106af3660046121f8565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106e557600080fd5b5061025d611161565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc161071881611244565b6000610728898989898989610ade565b90506107348184611251565b6000817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a604051610770969594939291906122a6565b60405180910390a3505050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107d957506107d98261139e565b92915050565b600080527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661085c5761085c8133611435565b600061086c888888888888610ade565b905061087881856114ed565b6108848888888861162a565b6000817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a6040516108bc94939291906122f1565b60405180910390a36108cd8161172e565b5050505050505050565b6000818152600160205260408120546001811180156108f65750428111155b9392505050565b60008281526020819052604090206001015461091881611244565b61092283836117d7565b505050565b60008181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109f482826118c7565b5050565b6000818152600160208190526040822054610939565b333014610a9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109e1565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b6000868686868686604051602001610afb969594939291906122a6565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b4781611244565b888714610bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b888514610c65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b6000610c778b8b8b8b8b8b8b8b610d4f565b9050610c838184611251565b60005b8a811015610d415780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610cc357610cc3612331565b9050602002016020810190610cd89190612360565b8d8d86818110610cea57610cea612331565b905060200201358c8c87818110610d0357610d03612331565b9050602002810190610d15919061237b565b8c8b604051610d29969594939291906122a6565b60405180910390a3610d3a8161240f565b9050610c86565b505050505050505050505050565b60008888888888888888604051602001610d709897969594939291906124f7565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610dbe81611244565b610dc7826109f8565b610e53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109e1565b6000828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b600082815260208190526040902060010154610eaa81611244565b61092283836118c7565b600080527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610f3157610f318133611435565b878614610fc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b87841461104f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b60006110618a8a8a8a8a8a8a8a610d4f565b905061106d81856114ed565b60005b8981101561114b5760008b8b8381811061108c5761108c612331565b90506020020160208101906110a19190612360565b905060008a8a848181106110b7576110b7612331565b9050602002013590503660008a8a868181106110d5576110d5612331565b90506020028101906110e7919061237b565b915091506110f78484848461162a565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588686868660405161112e94939291906122f1565b60405180910390a350505050806111449061240f565b9050611070565b506111558161172e565b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161580159061123257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa15801561120e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123291906125be565b1561123d5750600090565b5060025490565b61124e8133611435565b50565b61125a82610927565b156112e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109e1565b6112ef611161565b81101561137e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109e1565b61138881426125e0565b6000928352600160205260409092209190915550565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107d957507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107d9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109f4576114738161197e565b61147e83602061199d565b60405160200161148f929190612617565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109e191600401612698565b6114f6826108d7565b611582576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109e1565b80158061159e5750600081815260016020819052604090912054145b6109f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109e1565b60008473ffffffffffffffffffffffffffffffffffffffff168484846040516116549291906126e9565b60006040518083038185875af1925050503d8060008114611691576040519150601f19603f3d011682016040523d82523d6000602084013e611696565b606091505b5050905080611727576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109e1565b5050505050565b611737816108d7565b6117c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109e1565b600090815260016020819052604090912055565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109f45760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556118693390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109f45760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107d973ffffffffffffffffffffffffffffffffffffffff831660145b606060006119ac8360026126f9565b6119b79060026125e0565b67ffffffffffffffff8111156119cf576119cf611d8e565b6040519080825280601f01601f1916602001820160405280156119f9576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611a3057611a30612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a9357611a93612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000611acf8460026126f9565b611ada9060016125e0565b90505b6001811115611b77577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611b1b57611b1b612331565b1a60f81b828281518110611b3157611b31612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93611b7081612710565b9050611add565b5083156108f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109e1565b803573ffffffffffffffffffffffffffffffffffffffff81168114611c0457600080fd5b919050565b60008083601f840112611c1b57600080fd5b50813567ffffffffffffffff811115611c3357600080fd5b602083019150836020828501011115611c4b57600080fd5b9250929050565b600080600080600080600060c0888a031215611c6d57600080fd5b611c7688611be0565b965060208801359550604088013567ffffffffffffffff811115611c9957600080fd5b611ca58a828b01611c09565b989b979a50986060810135976080820135975060a09091013595509350505050565b600060208284031215611cd957600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108f657600080fd5b60008060008060008060a08789031215611d2257600080fd5b611d2b87611be0565b955060208701359450604087013567ffffffffffffffff811115611d4e57600080fd5b611d5a89828a01611c09565b979a9699509760608101359660809091013595509350505050565b600060208284031215611d8757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611e0457611e04611d8e565b604052919050565b600082601f830112611e1d57600080fd5b813567ffffffffffffffff811115611e3757611e37611d8e565b611e6860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611dbd565b818152846020838601011115611e7d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611eb057600080fd5b611eb985611be0565b9350611ec760208601611be0565b925060408501359150606085013567ffffffffffffffff811115611eea57600080fd5b611ef687828801611e0c565b91505092959194509250565b60008060408385031215611f1557600080fd5b82359150611f2560208401611be0565b90509250929050565b60008083601f840112611f4057600080fd5b50813567ffffffffffffffff811115611f5857600080fd5b6020830191508360208260051b8501011115611c4b57600080fd5b600080600080600080600080600060c08a8c031215611f9157600080fd5b893567ffffffffffffffff80821115611fa957600080fd5b611fb58d838e01611f2e565b909b50995060208c0135915080821115611fce57600080fd5b611fda8d838e01611f2e565b909950975060408c0135915080821115611ff357600080fd5b506120008c828d01611f2e565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b60008060008060008060008060a0898b03121561204157600080fd5b883567ffffffffffffffff8082111561205957600080fd5b6120658c838d01611f2e565b909a50985060208b013591508082111561207e57600080fd5b61208a8c838d01611f2e565b909850965060408b01359150808211156120a357600080fd5b506120b08b828c01611f2e565b999c989b509699959896976060870135966080013595509350505050565b600082601f8301126120df57600080fd5b8135602067ffffffffffffffff8211156120fb576120fb611d8e565b8160051b61210a828201611dbd565b928352848101820192828101908785111561212457600080fd5b83870192505b848310156121435782358252918301919083019061212a565b979650505050505050565b600080600080600060a0868803121561216657600080fd5b61216f86611be0565b945061217d60208701611be0565b9350604086013567ffffffffffffffff8082111561219a57600080fd5b6121a689838a016120ce565b945060608801359150808211156121bc57600080fd5b6121c889838a016120ce565b935060808801359150808211156121de57600080fd5b506121eb88828901611e0c565b9150509295509295909350565b600080600080600060a0868803121561221057600080fd5b61221986611be0565b945061222760208701611be0565b93506040860135925060608601359150608086013567ffffffffffffffff81111561225157600080fd5b6121eb88828901611e0c565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a0604082015260006122dc60a08301868861225d565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015260606040820152600061232760608301848661225d565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561237257600080fd5b6108f682611be0565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126123b057600080fd5b83018035915067ffffffffffffffff8211156123cb57600080fd5b602001915036819003821315611c4b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612440576124406123e0565b5060010190565b81835260006020808501808196508560051b810191508460005b878110156124ea57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126124a057600080fd5b8701858101903567ffffffffffffffff8111156124bc57600080fd5b8036038213156124cb57600080fd5b6124d686828461225d565b9a87019a9550505090840190600101612461565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156125455773ffffffffffffffffffffffffffffffffffffffff61253084611be0565b1682526020928301929091019060010161250a565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89111561257e57600080fd5b8860051b9150818a602083013701828103602090810160408501526125a69082018789612447565b60608401959095525050608001529695505050505050565b6000602082840312156125d057600080fd5b815180151581146108f657600080fd5b808201808211156107d9576107d96123e0565b60005b8381101561260e5781810151838201526020016125f6565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161264f8160178501602088016125f3565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161268c8160288401602088016125f3565b01602801949350505050565b60208152600082518060208401526126b78160408501602087016125f3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b8183823760009101908152919050565b80820281158282048414176107d9576107d96123e0565b60008161271f5761271f6123e0565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea264697066735822122048ac459f9165e9eaa91bead23625fe941931ad2332a61820c2a6d1dcd92c218164736f6c63430008140033", + "bytecode": "0x6080604052600436106101bd575f3560e01c806364d62353116100f2578063b1c5f42711610092578063d547741f11610062578063d547741f1461063a578063e38335e514610659578063f23a6e611461066c578063f27a0c92146106b0575f80fd5b8063b1c5f4271461058d578063bc197c81146105ac578063c4d252f5146105f0578063d45c44351461060f575f80fd5b80638f61f4f5116100cd5780638f61f4f5146104c557806391d14854146104f8578063a217fddf14610547578063b08e51c01461055a575f80fd5b806364d62353146104685780638065657f146104875780638f2a0bb0146104a6575f80fd5b8063248a9ca31161015d57806331d507501161013857806331d50750146103b357806336568abe146103d25780633a6aae72146103f1578063584b153e14610449575f80fd5b8063248a9ca3146103375780632ab0f529146103655780632f2ff15d14610394575f80fd5b80630d3cf6fc116101985780630d3cf6fc1461025e578063134008d31461029157806313bc9f20146102a4578063150b7a02146102c3575f80fd5b806301d5062a146101c857806301ffc9a7146101e957806307bd02651461021d575f80fd5b366101c457005b5f80fd5b3480156101d3575f80fd5b506101e76101e2366004611bf6565b6106c4565b005b3480156101f4575f80fd5b50610208610203366004611c65565b610757565b60405190151581526020015b60405180910390f35b348015610228575f80fd5b506102507fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610214565b348015610269575f80fd5b506102507f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101e761029f366004611ca4565b6107b2565b3480156102af575f80fd5b506102086102be366004611d0b565b6108a7565b3480156102ce575f80fd5b506103066102dd366004611e28565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610214565b348015610342575f80fd5b50610250610351366004611d0b565b5f9081526020819052604090206001015490565b348015610370575f80fd5b5061020861037f366004611d0b565b5f908152600160208190526040909120541490565b34801561039f575f80fd5b506101e76103ae366004611e8c565b6108cc565b3480156103be575f80fd5b506102086103cd366004611d0b565b6108f5565b3480156103dd575f80fd5b506101e76103ec366004611e8c565b61090d565b3480156103fc575f80fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b348015610454575f80fd5b50610208610463366004611d0b565b6109c5565b348015610473575f80fd5b506101e7610482366004611d0b565b6109da565b348015610492575f80fd5b506102506104a1366004611ca4565b610aaa565b3480156104b1575f80fd5b506101e76104c0366004611ef7565b610ae8565b3480156104d0575f80fd5b506102507fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b348015610503575f80fd5b50610208610512366004611e8c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610552575f80fd5b506102505f81565b348015610565575f80fd5b506102507ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b348015610598575f80fd5b506102506105a7366004611fa0565b610d18565b3480156105b7575f80fd5b506103066105c63660046120be565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b3480156105fb575f80fd5b506101e761060a366004611d0b565b610d5c565b34801561061a575f80fd5b50610250610629366004611d0b565b5f9081526001602052604090205490565b348015610645575f80fd5b506101e7610654366004611e8c565b610e56565b6101e7610667366004611fa0565b610e7a565b348015610677575f80fd5b50610306610686366004612161565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106bb575f80fd5b50610250611121565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc16106ee81611200565b5f6106fd898989898989610aaa565b9050610709818461120d565b5f817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a60405161074496959493929190612208565b60405180910390a3505050505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107ac57506107ac82611359565b92915050565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661082e5761082e81336113ef565b5f61083d888888888888610aaa565b905061084981856114a6565b610855888888886115e2565b5f817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a60405161088c9493929190612252565b60405180910390a361089d816116e2565b5050505050505050565b5f818152600160205260408120546001811180156108c55750428111155b9392505050565b5f828152602081905260409020600101546108e681611200565b6108f0838361178a565b505050565b5f8181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109c18282611878565b5050565b5f818152600160208190526040822054610906565b333014610a69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109ae565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b5f868686868686604051602001610ac696959493929190612208565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b1281611200565b888714610ba1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b888514610c30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f610c418b8b8b8b8b8b8b8b610d18565b9050610c4d818461120d565b5f5b8a811015610d0a5780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610c8c57610c8c612291565b9050602002016020810190610ca191906122be565b8d8d86818110610cb357610cb3612291565b905060200201358c8c87818110610ccc57610ccc612291565b9050602002810190610cde91906122d7565b8c8b604051610cf296959493929190612208565b60405180910390a3610d0381612365565b9050610c4f565b505050505050505050505050565b5f8888888888888888604051602001610d38989796959493929190612447565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610d8681611200565b610d8f826109c5565b610e1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109ae565b5f828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b5f82815260208190526040902060010154610e7081611200565b6108f08383611878565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610ef657610ef681336113ef565b878614610f85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b878414611014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f6110258a8a8a8a8a8a8a8a610d18565b905061103181856114a6565b5f5b8981101561110b575f8b8b8381811061104e5761104e612291565b905060200201602081019061106391906122be565b90505f8a8a8481811061107857611078612291565b905060200201359050365f8a8a8681811061109557611095612291565b90506020028101906110a791906122d7565b915091506110b7848484846115e2565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b58868686866040516110ee9493929190612252565b60405180910390a3505050508061110490612365565b9050611033565b50611115816116e2565b50505050505050505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16158015906111ef57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef919061250c565b156111f957505f90565b5060025490565b61120a81336113ef565b50565b611216826108f5565b156112a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109ae565b6112ab611121565b81101561133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109ae565b611344814261252b565b5f928352600160205260409092209190915550565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107ac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107ac565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c15761142c8161192d565b61143783602061194c565b604051602001611448929190612560565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109ae916004016125e0565b6114af826108a7565b61153b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b80158061155657505f81815260016020819052604090912054145b6109c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f8473ffffffffffffffffffffffffffffffffffffffff1684848460405161160b929190612630565b5f6040518083038185875af1925050503d805f8114611645576040519150601f19603f3d011682016040523d82523d5f602084013e61164a565b606091505b50509050806116db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109ae565b5050505050565b6116eb816108a7565b611777576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b5f90815260016020819052604090912055565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561181a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107ac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61195a83600261263f565b61196590600261252b565b67ffffffffffffffff81111561197d5761197d611d22565b6040519080825280601f01601f1916602001820160405280156119a7576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106119dd576119dd612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a3f57611a3f612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f611a7984600261263f565b611a8490600161252b565b90505b6001811115611b20577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611ac557611ac5612291565b1a60f81b828281518110611adb57611adb612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c93611b1981612656565b9050611a87565b5083156108c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109ae565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bac575f80fd5b919050565b5f8083601f840112611bc1575f80fd5b50813567ffffffffffffffff811115611bd8575f80fd5b602083019150836020828501011115611bef575f80fd5b9250929050565b5f805f805f805f60c0888a031215611c0c575f80fd5b611c1588611b89565b965060208801359550604088013567ffffffffffffffff811115611c37575f80fd5b611c438a828b01611bb1565b989b979a50986060810135976080820135975060a09091013595509350505050565b5f60208284031215611c75575f80fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108c5575f80fd5b5f805f805f8060a08789031215611cb9575f80fd5b611cc287611b89565b955060208701359450604087013567ffffffffffffffff811115611ce4575f80fd5b611cf089828a01611bb1565b979a9699509760608101359660809091013595509350505050565b5f60208284031215611d1b575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d9657611d96611d22565b604052919050565b5f82601f830112611dad575f80fd5b813567ffffffffffffffff811115611dc757611dc7611d22565b611df860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d4f565b818152846020838601011115611e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215611e3b575f80fd5b611e4485611b89565b9350611e5260208601611b89565b925060408501359150606085013567ffffffffffffffff811115611e74575f80fd5b611e8087828801611d9e565b91505092959194509250565b5f8060408385031215611e9d575f80fd5b82359150611ead60208401611b89565b90509250929050565b5f8083601f840112611ec6575f80fd5b50813567ffffffffffffffff811115611edd575f80fd5b6020830191508360208260051b8501011115611bef575f80fd5b5f805f805f805f805f60c08a8c031215611f0f575f80fd5b893567ffffffffffffffff80821115611f26575f80fd5b611f328d838e01611eb6565b909b50995060208c0135915080821115611f4a575f80fd5b611f568d838e01611eb6565b909950975060408c0135915080821115611f6e575f80fd5b50611f7b8c828d01611eb6565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b5f805f805f805f8060a0898b031215611fb7575f80fd5b883567ffffffffffffffff80821115611fce575f80fd5b611fda8c838d01611eb6565b909a50985060208b0135915080821115611ff2575f80fd5b611ffe8c838d01611eb6565b909850965060408b0135915080821115612016575f80fd5b506120238b828c01611eb6565b999c989b509699959896976060870135966080013595509350505050565b5f82601f830112612050575f80fd5b8135602067ffffffffffffffff82111561206c5761206c611d22565b8160051b61207b828201611d4f565b9283528481018201928281019087851115612094575f80fd5b83870192505b848310156120b35782358252918301919083019061209a565b979650505050505050565b5f805f805f60a086880312156120d2575f80fd5b6120db86611b89565b94506120e960208701611b89565b9350604086013567ffffffffffffffff80821115612105575f80fd5b61211189838a01612041565b94506060880135915080821115612126575f80fd5b61213289838a01612041565b93506080880135915080821115612147575f80fd5b5061215488828901611d9e565b9150509295509295909350565b5f805f805f60a08688031215612175575f80fd5b61217e86611b89565b945061218c60208701611b89565b93506040860135925060608601359150608086013567ffffffffffffffff8111156121b5575f80fd5b61215488828901611d9e565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a060408201525f61223d60a0830186886121c1565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f6122876060830184866121c1565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156122ce575f80fd5b6108c582611b89565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261230a575f80fd5b83018035915067ffffffffffffffff821115612324575f80fd5b602001915036819003821315611bef575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361239557612395612338565b5060010190565b8183525f6020808501808196508560051b81019150845f5b8781101561243a57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126123f2575f80fd5b8701858101903567ffffffffffffffff81111561240d575f80fd5b80360382131561241b575f80fd5b6124268682846121c1565b9a87019a95505050908401906001016123b4565b5091979650505050505050565b60a080825281018890525f8960c08301825b8b8110156124945773ffffffffffffffffffffffffffffffffffffffff61247f84611b89565b16825260209283019290910190600101612459565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156124cc575f80fd5b8860051b9150818a602083013701828103602090810160408501526124f4908201878961239c565b60608401959095525050608001529695505050505050565b5f6020828403121561251c575f80fd5b815180151581146108c5575f80fd5b808201808211156107ac576107ac612338565b5f5b83811015612558578181015183820152602001612540565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f835161259781601785016020880161253e565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516125d481602884016020880161253e565b01602801949350505050565b602081525f82518060208401526125fe81604085016020870161253e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b818382375f9101908152919050565b80820281158282048414176107ac576107ac612338565b5f8161266457612664612338565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220e28ae7494480ab1c619fd775dc5ff665588c808a910d66178a982c2e7c76a1e664736f6c63430008140033", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000e10", "0xaedcc9e7897c0d335bdc5d92fe3a8b4f23727fe558cd1c19f332b28716a30559": "0x0000000000000000000000000000000000000000000000000000000000000001", @@ -88,7 +88,7 @@ "accountName": "keyless Deployer", "balance": "0", "nonce": "1", - "address": "0x28BB4e66addE1f042B77E04cf7D3784C1dcDBbA3" + "address": "0x694AB5383a002a4796f95530c14Cf0C25ec3EA03" }, { "accountName": "deployer", diff --git a/docs/running_local.md b/docs/running_local.md index 1fd926bea8..49a4eb1a98 100644 --- a/docs/running_local.md +++ b/docs/running_local.md @@ -192,7 +192,7 @@ To configure your Metamask to use your local environment, follow these steps: | Address | Description | |---|---| | 0x8dAF17A20c9DBA35f005b6324F493785D239719d | Polygon ZKEVM | -| 0x40E0576c0A7dff9dc460B29ba73e79aBf73dD2a9 | Polygon Bridge | +| 0xFe12ABaa190Ef0c8638Ee0ba9F828BF41368Ca0E | Polygon Bridge | | 0x5FbDB2315678afecb367f032d93F642f64180aa3 | Pol token | | 0x8A791620dd6260079BF849Dc5567aDC3F2FdC318 | Polygon GlobalExitRootManager | | 0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e | Polygon RollupManager | diff --git a/etherman/etherman.go b/etherman/etherman.go index 060782dd07..6f609fccc1 100644 --- a/etherman/etherman.go +++ b/etherman/etherman.go @@ -262,7 +262,7 @@ func NewClient(cfg Config, l1Config L1Config) (*Client, error) { rollupID, err := rollupManager.RollupAddressToID(&bind.CallOpts{Pending: false}, l1Config.ZkEVMAddr) if err != nil { log.Debugf("error rollupManager.RollupAddressToID(%s). Error: %w", l1Config.RollupManagerAddr, err) - // TODO return error after the upgrade + return nil, err } log.Debug("rollupID: ", rollupID) @@ -1512,7 +1512,7 @@ func (etherMan *Client) forceSequencedBatchesEvent(ctx context.Context, vLog typ if err != nil { return err } - // TODO completar los datos de forcedBlockHas, forcedGer y forcedTimestamp + // TODO complete data forcedBlockHash, forcedGer y forcedTimestamp // Read the tx for this batch. tx, err := etherMan.EthClient.TransactionInBlock(ctx, vLog.BlockHash, vLog.TxIndex) diff --git a/jsonrpc/endpoints_eth.go b/jsonrpc/endpoints_eth.go index 22fee88874..8231cab78b 100644 --- a/jsonrpc/endpoints_eth.go +++ b/jsonrpc/endpoints_eth.go @@ -68,8 +68,6 @@ func (e *EthEndpoints) Call(arg *types.TxArgs, blockArg *types.BlockNumberOrHash return e.txMan.NewDbTxScope(e.state, func(ctx context.Context, dbTx pgx.Tx) (interface{}, types.Error) { if arg == nil { return RPCErrorResponse(types.InvalidParamsErrorCode, "missing value for required argument 0", nil, false) - } else if blockArg == nil { - return RPCErrorResponse(types.InvalidParamsErrorCode, "missing value for required argument 1", nil, false) } block, respErr := e.getBlockByArg(ctx, blockArg, dbTx) if respErr != nil { @@ -113,6 +111,9 @@ func (e *EthEndpoints) Call(arg *types.TxArgs, blockArg *types.BlockNumberOrHash if result.Reverted() { data := make([]byte, len(result.ReturnValue)) copy(data, result.ReturnValue) + if len(data) == 0 { + return nil, types.NewRPCError(types.DefaultErrorCode, result.Err.Error()) + } return nil, types.NewRPCErrorWithData(types.RevertedErrorCode, result.Err.Error(), data) } else if result.Failed() { return nil, types.NewRPCError(types.DefaultErrorCode, result.Err.Error()) @@ -191,6 +192,9 @@ func (e *EthEndpoints) EstimateGas(arg *types.TxArgs, blockArg *types.BlockNumbe if errors.Is(err, runtime.ErrExecutionReverted) { data := make([]byte, len(returnValue)) copy(data, returnValue) + if len(data) == 0 { + return nil, types.NewRPCError(types.DefaultErrorCode, err.Error()) + } return nil, types.NewRPCErrorWithData(types.RevertedErrorCode, err.Error(), data) } else if err != nil { return nil, types.NewRPCError(types.DefaultErrorCode, err.Error()) diff --git a/jsonrpc/endpoints_eth_test.go b/jsonrpc/endpoints_eth_test.go index 33f4b1ec9c..69291429d0 100644 --- a/jsonrpc/endpoints_eth_test.go +++ b/jsonrpc/endpoints_eth_test.go @@ -503,7 +503,7 @@ func TestCall(t *testing.T) { latest, }, expectedResult: nil, - expectedError: types.NewRPCError(types.RevertedErrorCode, "execution reverted"), + expectedError: types.NewRPCError(types.DefaultErrorCode, "execution reverted"), setupMocks: func(c Config, m *mocksWrapper, testCase *testCase) { nonce := uint64(7) m.DbTx.On("Rollback", context.Background()).Return(nil).Once() diff --git a/synchronizer/common/syncinterfaces/etherman.go b/synchronizer/common/syncinterfaces/etherman.go index 24e5dbda69..3d5959ade2 100644 --- a/synchronizer/common/syncinterfaces/etherman.go +++ b/synchronizer/common/syncinterfaces/etherman.go @@ -18,6 +18,7 @@ type EthermanFullInterface interface { GetTrustedSequencerURL() (string, error) VerifyGenBlockNumber(ctx context.Context, genBlockNumber uint64) (bool, error) GetLatestVerifiedBatchNum() (uint64, error) + GetFinalizedBlockNumber(ctx context.Context) (uint64, error) } type EthermanGetLatestBatchNumber interface { diff --git a/synchronizer/common/syncinterfaces/mocks/etherman_full_interface.go b/synchronizer/common/syncinterfaces/mocks/etherman_full_interface.go index fe6e6c3df6..a904419575 100644 --- a/synchronizer/common/syncinterfaces/mocks/etherman_full_interface.go +++ b/synchronizer/common/syncinterfaces/mocks/etherman_full_interface.go @@ -87,6 +87,62 @@ func (_c *EthermanFullInterface_EthBlockByNumber_Call) RunAndReturn(run func(con return _c } +// GetFinalizedBlockNumber provides a mock function with given fields: ctx +func (_m *EthermanFullInterface) GetFinalizedBlockNumber(ctx context.Context) (uint64, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetFinalizedBlockNumber") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthermanFullInterface_GetFinalizedBlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFinalizedBlockNumber' +type EthermanFullInterface_GetFinalizedBlockNumber_Call struct { + *mock.Call +} + +// GetFinalizedBlockNumber is a helper method to define mock.On call +// - ctx context.Context +func (_e *EthermanFullInterface_Expecter) GetFinalizedBlockNumber(ctx interface{}) *EthermanFullInterface_GetFinalizedBlockNumber_Call { + return &EthermanFullInterface_GetFinalizedBlockNumber_Call{Call: _e.mock.On("GetFinalizedBlockNumber", ctx)} +} + +func (_c *EthermanFullInterface_GetFinalizedBlockNumber_Call) Run(run func(ctx context.Context)) *EthermanFullInterface_GetFinalizedBlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthermanFullInterface_GetFinalizedBlockNumber_Call) Return(_a0 uint64, _a1 error) *EthermanFullInterface_GetFinalizedBlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthermanFullInterface_GetFinalizedBlockNumber_Call) RunAndReturn(run func(context.Context) (uint64, error)) *EthermanFullInterface_GetFinalizedBlockNumber_Call { + _c.Call.Return(run) + return _c +} + // GetLatestBatchNumber provides a mock function with given fields: func (_m *EthermanFullInterface) GetLatestBatchNumber() (uint64, error) { ret := _m.Called() diff --git a/synchronizer/common/syncinterfaces/mocks/zkevm_client_ethereum_compatible_l2_block_getter.go b/synchronizer/common/syncinterfaces/mocks/zkevm_client_ethereum_compatible_l2_block_getter.go new file mode 100644 index 0000000000..58c2af0dff --- /dev/null +++ b/synchronizer/common/syncinterfaces/mocks/zkevm_client_ethereum_compatible_l2_block_getter.go @@ -0,0 +1,98 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_syncinterfaces + +import ( + context "context" + big "math/big" + + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" +) + +// ZKEVMClientEthereumCompatibleL2BlockGetter is an autogenerated mock type for the ZKEVMClientEthereumCompatibleL2BlockGetter type +type ZKEVMClientEthereumCompatibleL2BlockGetter struct { + mock.Mock +} + +type ZKEVMClientEthereumCompatibleL2BlockGetter_Expecter struct { + mock *mock.Mock +} + +func (_m *ZKEVMClientEthereumCompatibleL2BlockGetter) EXPECT() *ZKEVMClientEthereumCompatibleL2BlockGetter_Expecter { + return &ZKEVMClientEthereumCompatibleL2BlockGetter_Expecter{mock: &_m.Mock} +} + +// BlockByNumber provides a mock function with given fields: ctx, number +func (_m *ZKEVMClientEthereumCompatibleL2BlockGetter) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { + ret := _m.Called(ctx, number) + + if len(ret) == 0 { + panic("no return value specified for BlockByNumber") + } + + var r0 *types.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Block, error)); ok { + return rf(ctx, number) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) *types.Block); ok { + r0 = rf(ctx, number) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, number) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockByNumber' +type ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call struct { + *mock.Call +} + +// BlockByNumber is a helper method to define mock.On call +// - ctx context.Context +// - number *big.Int +func (_e *ZKEVMClientEthereumCompatibleL2BlockGetter_Expecter) BlockByNumber(ctx interface{}, number interface{}) *ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call { + return &ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call{Call: _e.mock.On("BlockByNumber", ctx, number)} +} + +func (_c *ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call) Run(run func(ctx context.Context, number *big.Int)) *ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*big.Int)) + }) + return _c +} + +func (_c *ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call) Return(_a0 *types.Block, _a1 error) *ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call) RunAndReturn(run func(context.Context, *big.Int) (*types.Block, error)) *ZKEVMClientEthereumCompatibleL2BlockGetter_BlockByNumber_Call { + _c.Call.Return(run) + return _c +} + +// NewZKEVMClientEthereumCompatibleL2BlockGetter creates a new instance of ZKEVMClientEthereumCompatibleL2BlockGetter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewZKEVMClientEthereumCompatibleL2BlockGetter(t interface { + mock.TestingT + Cleanup(func()) +}) *ZKEVMClientEthereumCompatibleL2BlockGetter { + mock := &ZKEVMClientEthereumCompatibleL2BlockGetter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 5e468813a5..33cf49a7ee 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -165,7 +165,7 @@ func NewSynchronizer( res.l1EventProcessors = defaultsL1EventProcessors(res, l1checkerL2Blocks) switch cfg.L1SynchronizationMode { case ParallelMode: - log.Info("L1SynchronizationMode is parallel") + log.Fatal("L1SynchronizationMode is parallel. Not yet suported, please use sequential mode to sync") res.l1SyncOrchestration = newL1SyncParallel(ctx, cfg, etherManForL1, res, runInDevelopmentMode) case SequentialMode: log.Info("L1SynchronizationMode is sequential") @@ -492,7 +492,7 @@ func sanityCheckForGenesisBlockRollupInfo(blocks []etherman.Block, order map[com // lastEthBlockSynced -> last block synced in the db func (s *ClientSynchronizer) syncBlocksParallel(lastEthBlockSynced *state.Block) (*state.Block, error) { // This function will read events fromBlockNum to latestEthBlock. Check reorg to be sure that everything is ok. - block, err := s.checkReorg(lastEthBlockSynced) + block, err := s.newCheckReorg(lastEthBlockSynced, nil) if err != nil { log.Errorf("error checking reorgs. Retrying... Err: %v", err) return lastEthBlockSynced, fmt.Errorf("error checking reorgs") @@ -522,7 +522,7 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc lastKnownBlock := header.Number // This function will read events fromBlockNum to latestEthBlock. Check reorg to be sure that everything is ok. - block, err := s.checkReorg(lastEthBlockSynced) + block, err := s.newCheckReorg(lastEthBlockSynced, nil) if err != nil { log.Errorf("error checking reorgs. Retrying... Err: %v", err) return lastEthBlockSynced, fmt.Errorf("error checking reorgs") @@ -538,7 +538,7 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc var fromBlock uint64 if lastEthBlockSynced.BlockNumber > 0 { - fromBlock = lastEthBlockSynced.BlockNumber + 1 + fromBlock = lastEthBlockSynced.BlockNumber } for { @@ -560,8 +560,39 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc return lastEthBlockSynced, err } + var initBlockReceived *etherman.Block + if len(blocks) != 0 { + initBlockReceived = &blocks[0] + // First position of the array must be deleted + blocks = removeBlockElement(blocks, 0) + } else { + // Reorg detected + log.Infof("Reorg detected in block %d while querying GetRollupInfoByBlockRange. Rolling back to at least the previous block", fromBlock) + prevBlock, err := s.state.GetPreviousBlock(s.ctx, 1, nil) + if errors.Is(err, state.ErrNotFound) { + log.Warn("error checking reorg: previous block not found in db: ", err) + prevBlock = &state.Block{} + } else if err != nil { + log.Error("error getting previousBlock from db. Error: ", err) + return lastEthBlockSynced, err + } + blockReorged, err := s.newCheckReorg(prevBlock, nil) + if err != nil { + log.Error("error checking reorgs in previous blocks. Error: ", err) + return lastEthBlockSynced, err + } + if blockReorged == nil { + blockReorged = prevBlock + } + err = s.resetState(blockReorged.BlockNumber) + if err != nil { + log.Errorf("error resetting the state to a previous block. Retrying... Err: %v", err) + return lastEthBlockSynced, fmt.Errorf("error resetting the state to a previous block") + } + return blockReorged, nil + } // Check reorg again to be sure that the chain has not changed between the previous checkReorg and the call GetRollupInfoByBlockRange - block, err := s.checkReorg(lastEthBlockSynced) + block, err := s.newCheckReorg(lastEthBlockSynced, initBlockReceived) if err != nil { log.Errorf("error checking reorgs. Retrying... Err: %v", err) return lastEthBlockSynced, fmt.Errorf("error checking reorgs") @@ -589,47 +620,35 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc ReceivedAt: blocks[len(blocks)-1].ReceivedAt, } for i := range blocks { - log.Debug("Position: ", i, ". BlockNumber: ", blocks[i].BlockNumber, ". BlockHash: ", blocks[i].BlockHash) + log.Info("Position: ", i, ". New block. BlockNumber: ", blocks[i].BlockNumber, ". BlockHash: ", blocks[i].BlockHash) } } - fromBlock = toBlock + 1 if lastKnownBlock.Cmp(new(big.Int).SetUint64(toBlock)) < 1 { waitDuration = s.cfg.SyncInterval.Duration break } - if len(blocks) == 0 { // If there is no events in the checked blocks range and lastKnownBlock > fromBlock. - // Store the latest block of the block range. Get block info and process the block - fb, err := s.etherMan.EthBlockByNumber(s.ctx, toBlock) - if err != nil { - return lastEthBlockSynced, err - } - b := etherman.Block{ - BlockNumber: fb.NumberU64(), - BlockHash: fb.Hash(), - ParentHash: fb.ParentHash(), - ReceivedAt: time.Unix(int64(fb.Time()), 0), - } - err = s.ProcessBlockRange([]etherman.Block{b}, order) - if err != nil { - return lastEthBlockSynced, err - } - block := state.Block{ - BlockNumber: fb.NumberU64(), - BlockHash: fb.Hash(), - ParentHash: fb.ParentHash(), - ReceivedAt: time.Unix(int64(fb.Time()), 0), - } - lastEthBlockSynced = &block - log.Debug("Storing empty block. BlockNumber: ", b.BlockNumber, ". BlockHash: ", b.BlockHash) - } + + fromBlock = toBlock } return lastEthBlockSynced, nil } +func removeBlockElement(slice []etherman.Block, s int) []etherman.Block { + ret := make([]etherman.Block, 0) + ret = append(ret, slice[:s]...) + return append(ret, slice[s+1:]...) +} + // ProcessBlockRange process the L1 events and stores the information in the db func (s *ClientSynchronizer) ProcessBlockRange(blocks []etherman.Block, order map[common.Hash][]etherman.Order) error { + // Check the latest finalized block in L1 + finalizedBlockNumber, err := s.etherMan.GetFinalizedBlockNumber(s.ctx) + if err != nil { + log.Errorf("error getting finalized block number in L1. Error: %v", err) + return err + } // New info has to be included into the db using the state for i := range blocks { // Begin db transaction @@ -644,6 +663,9 @@ func (s *ClientSynchronizer) ProcessBlockRange(blocks []etherman.Block, order ma ParentHash: blocks[i].ParentHash, ReceivedAt: blocks[i].ReceivedAt, } + if blocks[i].BlockNumber <= finalizedBlockNumber { + b.Checked = true + } // Add block information err = s.state.AddBlock(s.ctx, &b, dbTx) if err != nil { @@ -664,7 +686,7 @@ func (s *ClientSynchronizer) ProcessBlockRange(blocks []etherman.Block, order ma log.Debug("EventOrder: ", element.Name, ". Batch Sequence: ", batchSequence, "forkId: ", forkId) } else { forkId = s.state.GetForkIDByBlockNumber(blocks[i].BlockNumber) - log.Debug("EventOrder: ", element.Name, ". BlockNumber: ", blocks[i].BlockNumber, "forkId: ", forkId) + log.Debug("EventOrder: ", element.Name, ". BlockNumber: ", blocks[i].BlockNumber, ". forkId: ", forkId) } forkIdTyped := actions.ForkIdType(forkId) // Process event received from l1 @@ -765,7 +787,8 @@ If hash or hash parent don't match, reorg detected and the function will return must be reverted. Then, check the previous ethereum block synced, get block info from the blockchain and check hash and has parent. This operation has to be done until a match is found. */ -func (s *ClientSynchronizer) checkReorg(latestBlock *state.Block) (*state.Block, error) { +// TODO This function will be deprecated +func (s *ClientSynchronizer) oldCheckReorg(latestBlock *state.Block) (*state.Block, error) { //nolint:unused // This function only needs to worry about reorgs if some of the reorganized blocks contained rollup info. latestEthBlockSynced := *latestBlock reorgedBlock := *latestBlock @@ -835,6 +858,89 @@ func (s *ClientSynchronizer) checkReorg(latestBlock *state.Block) (*state.Block, return nil, nil } +func (s *ClientSynchronizer) newCheckReorg(latestStoredBlock *state.Block, syncedBlock *etherman.Block) (*state.Block, error) { + // This function only needs to worry about reorgs if some of the reorganized blocks contained rollup info. + latestStoredEthBlock := *latestStoredBlock + reorgedBlock := *latestStoredBlock + var depth uint64 + block := syncedBlock + for { + if block == nil { + log.Infof("[checkReorg function] Checking Block %d in L1", reorgedBlock.BlockNumber) + b, err := s.etherMan.EthBlockByNumber(s.ctx, reorgedBlock.BlockNumber) + if err != nil { + log.Errorf("error getting latest block synced from blockchain. Block: %d, error: %v", reorgedBlock.BlockNumber, err) + return nil, err + } + block = ðerman.Block{ + BlockNumber: b.Number().Uint64(), + BlockHash: b.Hash(), + ParentHash: b.ParentHash(), + } + } else { + log.Infof("[checkReorg function] Using block %d from GetRollupInfoByBlockRange", block.BlockNumber) + } + log.Infof("[checkReorg function] BlockNumber: %d BlockHash got from L1 provider: %s", block.BlockNumber, block.BlockHash.String()) + log.Infof("[checkReorg function] reorgedBlockNumber: %d reorgedBlockHash already synced: %s", reorgedBlock.BlockNumber, reorgedBlock.BlockHash.String()) + if block.BlockNumber != reorgedBlock.BlockNumber { + err := fmt.Errorf("wrong ethereum block retrieved from blockchain. Block numbers don't match. BlockNumber stored: %d. BlockNumber retrieved: %d", + reorgedBlock.BlockNumber, block.BlockNumber) + log.Error("error: ", err) + return nil, err + } + // Compare hashes + if (block.BlockHash != reorgedBlock.BlockHash || block.ParentHash != reorgedBlock.ParentHash) && reorgedBlock.BlockNumber > s.genesis.BlockNumber { + log.Infof("checkReorg: Bad block %d hashOk %t parentHashOk %t", reorgedBlock.BlockNumber, block.BlockHash == reorgedBlock.BlockHash, block.ParentHash == reorgedBlock.ParentHash) + log.Debug("[checkReorg function] => latestBlockNumber: ", reorgedBlock.BlockNumber) + log.Debug("[checkReorg function] => latestBlockHash: ", reorgedBlock.BlockHash) + log.Debug("[checkReorg function] => latestBlockHashParent: ", reorgedBlock.ParentHash) + log.Debug("[checkReorg function] => BlockNumber: ", reorgedBlock.BlockNumber, block.BlockNumber) + log.Debug("[checkReorg function] => BlockHash: ", block.BlockHash) + log.Debug("[checkReorg function] => BlockHashParent: ", block.ParentHash) + depth++ + log.Debug("REORG: Looking for the latest correct ethereum block. Depth: ", depth) + // Reorg detected. Getting previous block + dbTx, err := s.state.BeginStateTransaction(s.ctx) + if err != nil { + log.Errorf("error creating db transaction to get prevoius blocks") + return nil, err + } + lb, err := s.state.GetPreviousBlock(s.ctx, depth, dbTx) + errC := dbTx.Commit(s.ctx) + if errC != nil { + log.Errorf("error committing dbTx, err: %v", errC) + rollbackErr := dbTx.Rollback(s.ctx) + if rollbackErr != nil { + log.Errorf("error rolling back state. RollbackErr: %v", rollbackErr) + return nil, rollbackErr + } + log.Errorf("error committing dbTx, err: %v", errC) + return nil, errC + } + if errors.Is(err, state.ErrNotFound) { + log.Warn("error checking reorg: previous block not found in db. Reorg reached the genesis block: %v.Genesis block can't be reorged, using genesis block as starting point. Error: %v", reorgedBlock, err) + return &reorgedBlock, nil + } else if err != nil { + log.Error("error getting previousBlock from db. Error: ", err) + return nil, err + } + reorgedBlock = *lb + } else { + log.Debugf("checkReorg: Block %d hashOk %t parentHashOk %t", reorgedBlock.BlockNumber, block.BlockHash == reorgedBlock.BlockHash, block.ParentHash == reorgedBlock.ParentHash) + break + } + // This forces to get the block from L1 in the next iteration of the loop + block = nil + } + if latestStoredEthBlock.BlockHash != reorgedBlock.BlockHash { + latestStoredBlock = &reorgedBlock + log.Info("Reorg detected in block: ", latestStoredEthBlock.BlockNumber, " last block OK: ", latestStoredBlock.BlockNumber) + return latestStoredBlock, nil + } + log.Debugf("No reorg detected in block: %d. BlockHash: %s", latestStoredEthBlock.BlockNumber, latestStoredEthBlock.BlockHash.String()) + return nil, nil +} + // Stop function stops the synchronizer func (s *ClientSynchronizer) Stop() { s.cancelCtx() diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index 38cc155780..98ab184de6 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -2,6 +2,7 @@ package synchronizer import ( context "context" + "math" "math/big" "testing" "time" @@ -154,9 +155,12 @@ func TestForcedBatchEtrog(t *testing.T) { Run(func(args mock.Arguments) { ctx := args[0].(context.Context) parentHash := common.HexToHash("0x111") - ethHeader := ðTypes.Header{Number: big.NewInt(1), ParentHash: parentHash} - ethBlock := ethTypes.NewBlockWithHeader(ethHeader) - lastBlock := &state.Block{BlockHash: ethBlock.Hash(), BlockNumber: ethBlock.Number().Uint64()} + ethHeader0 := ðTypes.Header{Number: big.NewInt(0), ParentHash: parentHash} + ethBlock0 := ethTypes.NewBlockWithHeader(ethHeader0) + ethHeader1 := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash()} + ethBlock1 := ethTypes.NewBlockWithHeader(ethHeader1) + lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} + lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} m.State. On("GetForkIDByBatchNumber", mock.Anything). @@ -164,7 +168,7 @@ func TestForcedBatchEtrog(t *testing.T) { Maybe() m.State. On("GetLastBlock", ctx, m.DbTx). - Return(lastBlock, nil). + Return(lastBlock0, nil). Once() m.State. @@ -200,14 +204,14 @@ func TestForcedBatchEtrog(t *testing.T) { Return(nil) m.Etherman. - On("EthBlockByNumber", ctx, lastBlock.BlockNumber). - Return(ethBlock, nil). + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). Once() n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. On("HeaderByNumber", mock.Anything, n). - Return(ethHeader, nil). + Return(ethHeader1, nil). Once() t := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC) @@ -226,7 +230,7 @@ func TestForcedBatchEtrog(t *testing.T) { } forceb := []etherman.ForcedBatch{{ - BlockNumber: lastBlock.BlockNumber, + BlockNumber: lastBlock1.BlockNumber, ForcedBatchNumber: 1, Sequencer: sequencedBatch.Coinbase, GlobalExitRoot: sequencedBatch.PolygonRollupBaseEtrogBatchData.ForcedGlobalExitRoot, @@ -234,16 +238,21 @@ func TestForcedBatchEtrog(t *testing.T) { ForcedAt: time.Unix(int64(sequencedBatch.PolygonRollupBaseEtrogBatchData.ForcedTimestamp), 0), }} - ethermanBlock := etherman.Block{ + ethermanBlock0 := etherman.Block{ + BlockNumber: 0, + ReceivedAt: t, + BlockHash: ethBlock0.Hash(), + } + ethermanBlock1 := etherman.Block{ BlockNumber: 1, ReceivedAt: t, - BlockHash: ethBlock.Hash(), + BlockHash: ethBlock1.Hash(), SequencedBatches: [][]etherman.SequencedBatch{{sequencedBatch}}, ForcedBatches: forceb, } - blocks := []etherman.Block{ethermanBlock} + blocks := []etherman.Block{ethermanBlock0, ethermanBlock1} order := map[common.Hash][]etherman.Order{ - ethBlock.Hash(): { + ethBlock1.Hash(): { { Name: etherman.ForcedBatchesOrder, Pos: 0, @@ -255,21 +264,16 @@ func TestForcedBatchEtrog(t *testing.T) { }, } - fromBlock := ethBlock.NumberU64() + 1 + fromBlock := ethBlock0.NumberU64() toBlock := fromBlock + cfg.SyncChunkSize - if toBlock > ethHeader.Number.Uint64() { - toBlock = ethHeader.Number.Uint64() + if toBlock > ethBlock1.NumberU64() { + toBlock = ethBlock1.NumberU64() } m.Etherman. On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). Return(blocks, order, nil). Once() - m.Etherman. - On("EthBlockByNumber", ctx, lastBlock.BlockNumber). - Return(ethBlock, nil). - Once() - m.ZKEVMClient. On("BatchNumber", ctx). Return(uint64(1), nil) @@ -280,10 +284,11 @@ func TestForcedBatchEtrog(t *testing.T) { Once() stateBlock := &state.Block{ - BlockNumber: ethermanBlock.BlockNumber, - BlockHash: ethermanBlock.BlockHash, - ParentHash: ethermanBlock.ParentHash, - ReceivedAt: ethermanBlock.ReceivedAt, + BlockNumber: ethermanBlock1.BlockNumber, + BlockHash: ethermanBlock1.BlockHash, + ParentHash: ethermanBlock1.ParentHash, + ReceivedAt: ethermanBlock1.ReceivedAt, + Checked: true, } executionResponse := executor.ProcessBatchResponseV2{ @@ -295,13 +300,18 @@ func TestForcedBatchEtrog(t *testing.T) { Return(&executionResponse, nil). Times(1) + m.Etherman. + On("GetFinalizedBlockNumber", ctx). + Return(ethBlock1.NumberU64(), nil). + Once() + m.State. On("AddBlock", ctx, stateBlock, m.DbTx). Return(nil). Once() fb := []state.ForcedBatch{{ - BlockNumber: lastBlock.BlockNumber, + BlockNumber: lastBlock1.BlockNumber, ForcedBatchNumber: 1, Sequencer: sequencedBatch.Coinbase, GlobalExitRoot: sequencedBatch.PolygonRollupBaseEtrogBatchData.ForcedGlobalExitRoot, @@ -336,7 +346,7 @@ func TestForcedBatchEtrog(t *testing.T) { BatchNumber: sequencedBatch.BatchNumber, TxHash: sequencedBatch.TxHash, Coinbase: sequencedBatch.Coinbase, - BlockNumber: ethermanBlock.BlockNumber, + BlockNumber: ethermanBlock1.BlockNumber, TimestampBatchEtrog: &t, L1InfoRoot: &forcedGER, } @@ -409,21 +419,20 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { Run(func(args mock.Arguments) { ctx := args[0].(context.Context) parentHash := common.HexToHash("0x111") - ethHeader := ðTypes.Header{Number: big.NewInt(1), ParentHash: parentHash} - ethBlock := ethTypes.NewBlockWithHeader(ethHeader) - lastBlock := &state.Block{BlockHash: ethBlock.Hash(), BlockNumber: ethBlock.Number().Uint64()} + ethHeader0 := ðTypes.Header{Number: big.NewInt(0), ParentHash: parentHash} + ethBlock0 := ethTypes.NewBlockWithHeader(ethHeader0) + ethHeader1 := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash()} + ethBlock1 := ethTypes.NewBlockWithHeader(ethHeader1) + lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} + lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} m.State. On("GetForkIDByBatchNumber", mock.Anything). Return(uint64(1), nil). Maybe() - m.State. - On("GetForkIDByBlockNumber", mock.Anything). - Return(uint64(1), nil). - Maybe() m.State. On("GetLastBlock", ctx, m.DbTx). - Return(lastBlock, nil). + Return(lastBlock0, nil). Once() m.State. @@ -461,15 +470,15 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { Return(nil). Once() + n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. - On("EthBlockByNumber", ctx, lastBlock.BlockNumber). - Return(ethBlock, nil). + On("HeaderByNumber", ctx, n). + Return(ethHeader1, nil). Once() - n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. - On("HeaderByNumber", ctx, n). - Return(ethHeader, nil). + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). Once() sequencedForceBatch := etherman.SequencedForceBatch{ @@ -485,7 +494,7 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { } forceb := []etherman.ForcedBatch{{ - BlockNumber: lastBlock.BlockNumber, + BlockNumber: lastBlock1.BlockNumber, ForcedBatchNumber: 1, Sequencer: sequencedForceBatch.Coinbase, GlobalExitRoot: sequencedForceBatch.PolygonRollupBaseEtrogBatchData.ForcedGlobalExitRoot, @@ -493,14 +502,21 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { ForcedAt: time.Unix(int64(sequencedForceBatch.PolygonRollupBaseEtrogBatchData.ForcedTimestamp), 0), }} - ethermanBlock := etherman.Block{ - BlockHash: ethBlock.Hash(), + ethermanBlock0 := etherman.Block{ + BlockNumber: ethBlock0.NumberU64(), + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + } + ethermanBlock1 := etherman.Block{ + BlockNumber: ethBlock1.NumberU64(), + BlockHash: ethBlock1.Hash(), + ParentHash: ethBlock1.ParentHash(), SequencedForceBatches: [][]etherman.SequencedForceBatch{{sequencedForceBatch}}, ForcedBatches: forceb, } - blocks := []etherman.Block{ethermanBlock} + blocks := []etherman.Block{ethermanBlock0, ethermanBlock1} order := map[common.Hash][]etherman.Order{ - ethBlock.Hash(): { + ethBlock1.Hash(): { { Name: etherman.ForcedBatchesOrder, Pos: 0, @@ -512,10 +528,10 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { }, } - fromBlock := ethBlock.NumberU64() + 1 + fromBlock := ethBlock0.NumberU64() toBlock := fromBlock + cfg.SyncChunkSize - if toBlock > ethHeader.Number.Uint64() { - toBlock = ethHeader.Number.Uint64() + if toBlock > ethBlock1.NumberU64() { + toBlock = ethBlock1.NumberU64() } m.Etherman. On("GetRollupInfoByBlockRange", ctx, fromBlock, &toBlock). @@ -523,8 +539,8 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { Once() m.Etherman. - On("EthBlockByNumber", ctx, lastBlock.BlockNumber). - Return(ethBlock, nil). + On("GetFinalizedBlockNumber", ctx). + Return(ethBlock1.NumberU64(), nil). Once() m.State. @@ -533,10 +549,11 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { Once() stateBlock := &state.Block{ - BlockNumber: ethermanBlock.BlockNumber, - BlockHash: ethermanBlock.BlockHash, - ParentHash: ethermanBlock.ParentHash, - ReceivedAt: ethermanBlock.ReceivedAt, + BlockNumber: ethermanBlock1.BlockNumber, + BlockHash: ethermanBlock1.BlockHash, + ParentHash: ethermanBlock1.ParentHash, + ReceivedAt: ethermanBlock1.ReceivedAt, + Checked: true, } m.State. @@ -544,8 +561,13 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { Return(nil). Once() + m.State. + On("GetForkIDByBlockNumber", stateBlock.BlockNumber). + Return(uint64(9), nil). + Once() + fb := []state.ForcedBatch{{ - BlockNumber: lastBlock.BlockNumber, + BlockNumber: lastBlock1.BlockNumber, ForcedBatchNumber: 1, Sequencer: sequencedForceBatch.Coinbase, GlobalExitRoot: sequencedForceBatch.PolygonRollupBaseEtrogBatchData.ForcedGlobalExitRoot, @@ -577,7 +599,7 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { processingContext := state.ProcessingContext{ BatchNumber: sequencedForceBatch.BatchNumber, Coinbase: sequencedForceBatch.Coinbase, - Timestamp: ethBlock.ReceivedAt, + Timestamp: ethBlock1.ReceivedAt, GlobalExitRoot: sequencedForceBatch.PolygonRollupBaseEtrogBatchData.ForcedGlobalExitRoot, ForcedBatchNum: &f, BatchL2Data: &sequencedForceBatch.PolygonRollupBaseEtrogBatchData.Transactions, @@ -592,7 +614,7 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { TxHash: sequencedForceBatch.TxHash, Coinbase: sequencedForceBatch.Coinbase, SequencerAddr: sequencedForceBatch.Coinbase, - BlockNumber: ethermanBlock.BlockNumber, + BlockNumber: ethermanBlock1.BlockNumber, } m.State. @@ -616,7 +638,10 @@ func TestSequenceForcedBatchIncaberry(t *testing.T) { m.DbTx. On("Commit", ctx). - Run(func(args mock.Arguments) { sync.Stop() }). + Run(func(args mock.Arguments) { + sync.Stop() + ctx.Done() + }). Return(nil). Once() }). @@ -890,3 +915,1029 @@ func expectedCallsForsyncTrustedState(t *testing.T, m *mocks, sync *ClientSynchr Return(nil). Once() } + +func TestReorg(t *testing.T) { + genesis := state.Genesis{ + BlockNumber: uint64(0), + } + cfg := Config{ + SyncInterval: cfgTypes.Duration{Duration: 1 * time.Second}, + SyncChunkSize: 3, + L1SynchronizationMode: SequentialMode, + SyncBlockProtection: "latest", + } + + m := mocks{ + Etherman: mock_syncinterfaces.NewEthermanFullInterface(t), + State: mock_syncinterfaces.NewStateFullInterface(t), + Pool: mock_syncinterfaces.NewPoolInterface(t), + DbTx: syncMocks.NewDbTxMock(t), + ZKEVMClient: mock_syncinterfaces.NewZKEVMClientInterface(t), + EthTxManager: mock_syncinterfaces.NewEthTxManager(t), + } + ethermanForL1 := []syncinterfaces.EthermanFullInterface{m.Etherman} + sync, err := NewSynchronizer(false, m.Etherman, ethermanForL1, m.State, m.Pool, m.EthTxManager, m.ZKEVMClient, m.zkEVMClientEthereumCompatible, nil, genesis, cfg, false) + require.NoError(t, err) + + // state preparation + ctxMatchBy := mock.MatchedBy(func(ctx context.Context) bool { return ctx != nil }) + forkIdInterval := state.ForkIDInterval{ + ForkId: 9, + FromBatchNumber: 0, + ToBatchNumber: math.MaxUint64, + } + m.State.EXPECT().GetForkIDInMemory(uint64(9)).Return(&forkIdInterval) + + m.State. + On("BeginStateTransaction", ctxMatchBy). + Run(func(args mock.Arguments) { + ctx := args[0].(context.Context) + parentHash := common.HexToHash("0x111") + ethHeader0 := ðTypes.Header{Number: big.NewInt(0), ParentHash: parentHash} + ethBlock0 := ethTypes.NewBlockWithHeader(ethHeader0) + ethHeader1bis := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash(), Time: 10, GasUsed: 20, Root: common.HexToHash("0x234")} + ethBlock1bis := ethTypes.NewBlockWithHeader(ethHeader1bis) + ethHeader2bis := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1bis.Hash()} + ethBlock2bis := ethTypes.NewBlockWithHeader(ethHeader2bis) + ethHeader3bis := ðTypes.Header{Number: big.NewInt(3), ParentHash: ethBlock2bis.Hash()} + ethBlock3bis := ethTypes.NewBlockWithHeader(ethHeader3bis) + ethHeader1 := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash()} + ethBlock1 := ethTypes.NewBlockWithHeader(ethHeader1) + ethHeader2 := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1.Hash()} + ethBlock2 := ethTypes.NewBlockWithHeader(ethHeader2) + ethHeader3 := ðTypes.Header{Number: big.NewInt(3), ParentHash: ethBlock2.Hash()} + ethBlock3 := ethTypes.NewBlockWithHeader(ethHeader3) + + lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} + lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} + + m.State. + On("GetForkIDByBatchNumber", mock.Anything). + Return(uint64(9), nil). + Maybe() + m.State. + On("GetLastBlock", ctx, m.DbTx). + Return(lastBlock1, nil). + Once() + + m.State. + On("GetLastBatchNumber", ctx, m.DbTx). + Return(uint64(10), nil). + Once() + + m.State. + On("SetInitSyncBatch", ctx, uint64(10), m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("GetLatestBatchNumber"). + Return(uint64(10), nil) + + var nilDbTx pgx.Tx + m.State. + On("GetLastBatchNumber", ctx, nilDbTx). + Return(uint64(10), nil) + + m.Etherman. + On("GetLatestVerifiedBatchNum"). + Return(uint64(10), nil) + + m.State. + On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). + Return(nil) + + n := big.NewInt(rpc.LatestBlockNumber.Int64()) + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader3bis, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1, nil). + Once() + + ti := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC) + + ethermanBlock1bis := etherman.Block{ + BlockNumber: 1, + ReceivedAt: ti, + BlockHash: ethBlock1bis.Hash(), + ParentHash: ethBlock1bis.ParentHash(), + } + ethermanBlock2bis := etherman.Block{ + BlockNumber: 2, + ReceivedAt: ti, + BlockHash: ethBlock2bis.Hash(), + ParentHash: ethBlock2bis.ParentHash(), + } + blocks := []etherman.Block{ethermanBlock1bis, ethermanBlock2bis} + order := map[common.Hash][]etherman.Order{} + + fromBlock := ethBlock1.NumberU64() + toBlock := fromBlock + cfg.SyncChunkSize + if toBlock > ethBlock3.NumberU64() { + toBlock = ethBlock3.NumberU64() + } + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + var depth uint64 = 1 + stateBlock0 := &state.Block{ + BlockNumber: ethBlock0.NumberU64(), + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + ReceivedAt: ti, + } + m.State. + On("GetPreviousBlock", ctx, depth, m.DbTx). + Return(stateBlock0, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + m.State. + On("Reset", ctx, ethBlock0.NumberU64(), m.DbTx). + Return(nil). + Once() + + m.EthTxManager. + On("Reorg", ctx, ethBlock0.NumberU64()+1, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader3bis, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + ethermanBlock0 := etherman.Block{ + BlockNumber: 0, + ReceivedAt: ti, + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + } + ethermanBlock3bis := etherman.Block{ + BlockNumber: 3, + ReceivedAt: ti, + BlockHash: ethBlock3bis.Hash(), + ParentHash: ethBlock3bis.ParentHash(), + } + fromBlock = 0 + blocks2 := []etherman.Block{ethermanBlock0, ethermanBlock1bis, ethermanBlock2bis, ethermanBlock3bis} + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks2, order, nil). + Once() + + m.Etherman. + On("GetFinalizedBlockNumber", ctx). + Return(ethBlock2bis.NumberU64(), nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock1bis := &state.Block{ + BlockNumber: ethermanBlock1bis.BlockNumber, + BlockHash: ethermanBlock1bis.BlockHash, + ParentHash: ethermanBlock1bis.ParentHash, + ReceivedAt: ethermanBlock1bis.ReceivedAt, + Checked: true, + } + m.State. + On("AddBlock", ctx, stateBlock1bis, m.DbTx). + Return(nil). + Once() + + m.State. + On("GetStoredFlushID", ctx). + Return(uint64(1), cProverIDExecution, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock2bis := &state.Block{ + BlockNumber: ethermanBlock2bis.BlockNumber, + BlockHash: ethermanBlock2bis.BlockHash, + ParentHash: ethermanBlock2bis.ParentHash, + ReceivedAt: ethermanBlock2bis.ReceivedAt, + Checked: true, + } + m.State. + On("AddBlock", ctx, stateBlock2bis, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock3bis := &state.Block{ + BlockNumber: ethermanBlock3bis.BlockNumber, + BlockHash: ethermanBlock3bis.BlockHash, + ParentHash: ethermanBlock3bis.ParentHash, + ReceivedAt: ethermanBlock3bis.ReceivedAt, + Checked: false, + } + m.State. + On("AddBlock", ctx, stateBlock3bis, m.DbTx). + Return(nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil) + + m.DbTx. + On("Commit", ctx). + Run(func(args mock.Arguments) { + sync.Stop() + ctx.Done() + }). + Return(nil). + Once() + }). + Return(m.DbTx, nil). + Once() + + err = sync.Sync() + require.NoError(t, err) +} + +func TestLatestSyncedBlockEmpty(t *testing.T) { + genesis := state.Genesis{ + BlockNumber: uint64(0), + } + cfg := Config{ + SyncInterval: cfgTypes.Duration{Duration: 1 * time.Second}, + SyncChunkSize: 3, + L1SynchronizationMode: SequentialMode, + SyncBlockProtection: "latest", + } + + m := mocks{ + Etherman: mock_syncinterfaces.NewEthermanFullInterface(t), + State: mock_syncinterfaces.NewStateFullInterface(t), + Pool: mock_syncinterfaces.NewPoolInterface(t), + DbTx: syncMocks.NewDbTxMock(t), + ZKEVMClient: mock_syncinterfaces.NewZKEVMClientInterface(t), + EthTxManager: mock_syncinterfaces.NewEthTxManager(t), + } + ethermanForL1 := []syncinterfaces.EthermanFullInterface{m.Etherman} + sync, err := NewSynchronizer(false, m.Etherman, ethermanForL1, m.State, m.Pool, m.EthTxManager, m.ZKEVMClient, m.zkEVMClientEthereumCompatible, nil, genesis, cfg, false) + require.NoError(t, err) + + // state preparation + ctxMatchBy := mock.MatchedBy(func(ctx context.Context) bool { return ctx != nil }) + forkIdInterval := state.ForkIDInterval{ + ForkId: 9, + FromBatchNumber: 0, + ToBatchNumber: math.MaxUint64, + } + m.State.EXPECT().GetForkIDInMemory(uint64(9)).Return(&forkIdInterval) + + m.State. + On("BeginStateTransaction", ctxMatchBy). + Run(func(args mock.Arguments) { + ctx := args[0].(context.Context) + parentHash := common.HexToHash("0x111") + ethHeader0 := ðTypes.Header{Number: big.NewInt(0), ParentHash: parentHash} + ethBlock0 := ethTypes.NewBlockWithHeader(ethHeader0) + ethHeader1 := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash()} + ethBlock1 := ethTypes.NewBlockWithHeader(ethHeader1) + ethHeader2 := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1.Hash()} + ethBlock2 := ethTypes.NewBlockWithHeader(ethHeader2) + ethHeader3 := ðTypes.Header{Number: big.NewInt(3), ParentHash: ethBlock2.Hash()} + ethBlock3 := ethTypes.NewBlockWithHeader(ethHeader3) + + lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} + lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} + + m.State. + On("GetForkIDByBatchNumber", mock.Anything). + Return(uint64(9), nil). + Maybe() + m.State. + On("GetLastBlock", ctx, m.DbTx). + Return(lastBlock1, nil). + Once() + + m.State. + On("GetLastBatchNumber", ctx, m.DbTx). + Return(uint64(10), nil). + Once() + + m.State. + On("SetInitSyncBatch", ctx, uint64(10), m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("GetLatestBatchNumber"). + Return(uint64(10), nil) + + var nilDbTx pgx.Tx + m.State. + On("GetLastBatchNumber", ctx, nilDbTx). + Return(uint64(10), nil) + + m.Etherman. + On("GetLatestVerifiedBatchNum"). + Return(uint64(10), nil) + + m.State. + On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). + Return(nil) + + n := big.NewInt(rpc.LatestBlockNumber.Int64()) + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader3, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1, nil). + Once() + + blocks := []etherman.Block{} + order := map[common.Hash][]etherman.Order{} + + fromBlock := ethBlock1.NumberU64() + toBlock := fromBlock + cfg.SyncChunkSize + if toBlock > ethBlock3.NumberU64() { + toBlock = ethBlock3.NumberU64() + } + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + ti := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC) + var depth uint64 = 1 + stateBlock0 := &state.Block{ + BlockNumber: ethBlock0.NumberU64(), + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + ReceivedAt: ti, + } + m.State. + On("GetPreviousBlock", ctx, depth, nil). + Return(stateBlock0, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + m.State. + On("Reset", ctx, ethBlock0.NumberU64(), m.DbTx). + Return(nil). + Once() + + m.EthTxManager. + On("Reorg", ctx, ethBlock0.NumberU64()+1, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader3, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + ethermanBlock0 := etherman.Block{ + BlockNumber: 0, + ReceivedAt: ti, + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + } + blocks = []etherman.Block{ethermanBlock0} + fromBlock = 0 + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.Etherman. + On("GetFinalizedBlockNumber", ctx). + Return(ethBlock3.NumberU64(), nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Run(func(args mock.Arguments) { + sync.Stop() + ctx.Done() + }). + Return(uint64(1), nil). + Once() + }). + Return(m.DbTx, nil). + Once() + + err = sync.Sync() + require.NoError(t, err) +} + +func TestRegularReorg(t *testing.T) { + genesis := state.Genesis{ + BlockNumber: uint64(0), + } + cfg := Config{ + SyncInterval: cfgTypes.Duration{Duration: 1 * time.Second}, + SyncChunkSize: 3, + L1SynchronizationMode: SequentialMode, + SyncBlockProtection: "latest", + } + + m := mocks{ + Etherman: mock_syncinterfaces.NewEthermanFullInterface(t), + State: mock_syncinterfaces.NewStateFullInterface(t), + Pool: mock_syncinterfaces.NewPoolInterface(t), + DbTx: syncMocks.NewDbTxMock(t), + ZKEVMClient: mock_syncinterfaces.NewZKEVMClientInterface(t), + EthTxManager: mock_syncinterfaces.NewEthTxManager(t), + } + ethermanForL1 := []syncinterfaces.EthermanFullInterface{m.Etherman} + sync, err := NewSynchronizer(false, m.Etherman, ethermanForL1, m.State, m.Pool, m.EthTxManager, m.ZKEVMClient, m.zkEVMClientEthereumCompatible, nil, genesis, cfg, false) + require.NoError(t, err) + + // state preparation + ctxMatchBy := mock.MatchedBy(func(ctx context.Context) bool { return ctx != nil }) + forkIdInterval := state.ForkIDInterval{ + ForkId: 9, + FromBatchNumber: 0, + ToBatchNumber: math.MaxUint64, + } + m.State.EXPECT().GetForkIDInMemory(uint64(9)).Return(&forkIdInterval) + + m.State. + On("BeginStateTransaction", ctxMatchBy). + Run(func(args mock.Arguments) { + ctx := args[0].(context.Context) + parentHash := common.HexToHash("0x111") + ethHeader0 := ðTypes.Header{Number: big.NewInt(0), ParentHash: parentHash} + ethBlock0 := ethTypes.NewBlockWithHeader(ethHeader0) + ethHeader1bis := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash(), Time: 10, GasUsed: 20, Root: common.HexToHash("0x234")} + ethBlock1bis := ethTypes.NewBlockWithHeader(ethHeader1bis) + ethHeader2bis := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1bis.Hash()} + ethBlock2bis := ethTypes.NewBlockWithHeader(ethHeader2bis) + ethHeader1 := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash()} + ethBlock1 := ethTypes.NewBlockWithHeader(ethHeader1) + ethHeader2 := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1.Hash()} + ethBlock2 := ethTypes.NewBlockWithHeader(ethHeader2) + + lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} + lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil) + + m.State. + On("GetForkIDByBatchNumber", mock.Anything). + Return(uint64(9), nil). + Maybe() + m.State. + On("GetLastBlock", ctx, m.DbTx). + Return(lastBlock1, nil). + Once() + + m.State. + On("GetLastBatchNumber", ctx, m.DbTx). + Return(uint64(10), nil). + Once() + + m.State. + On("SetInitSyncBatch", ctx, uint64(10), m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("GetLatestBatchNumber"). + Return(uint64(10), nil) + + var nilDbTx pgx.Tx + m.State. + On("GetLastBatchNumber", ctx, nilDbTx). + Return(uint64(10), nil) + + m.Etherman. + On("GetLatestVerifiedBatchNum"). + Return(uint64(10), nil) + + m.State. + On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). + Return(nil) + + n := big.NewInt(rpc.LatestBlockNumber.Int64()) + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader2bis, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1bis, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + ti := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC) + var depth uint64 = 1 + stateBlock0 := &state.Block{ + BlockNumber: ethBlock0.NumberU64(), + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + ReceivedAt: ti, + } + m.State. + On("GetPreviousBlock", ctx, depth, m.DbTx). + Return(stateBlock0, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + m.State. + On("Reset", ctx, ethBlock0.NumberU64(), m.DbTx). + Return(nil). + Once() + + m.EthTxManager. + On("Reorg", ctx, ethBlock0.NumberU64()+1, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader2bis, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + ethermanBlock0 := etherman.Block{ + BlockNumber: 0, + ReceivedAt: ti, + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + } + ethermanBlock1bis := etherman.Block{ + BlockNumber: 1, + ReceivedAt: ti, + BlockHash: ethBlock1bis.Hash(), + ParentHash: ethBlock1bis.ParentHash(), + } + ethermanBlock2bis := etherman.Block{ + BlockNumber: 2, + ReceivedAt: ti, + BlockHash: ethBlock2bis.Hash(), + ParentHash: ethBlock2bis.ParentHash(), + } + blocks := []etherman.Block{ethermanBlock0, ethermanBlock1bis, ethermanBlock2bis} + order := map[common.Hash][]etherman.Order{} + + fromBlock := ethBlock0.NumberU64() + toBlock := fromBlock + cfg.SyncChunkSize + if toBlock > ethBlock2.NumberU64() { + toBlock = ethBlock2.NumberU64() + } + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.Etherman. + On("GetFinalizedBlockNumber", ctx). + Return(ethBlock2bis.NumberU64(), nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock1bis := &state.Block{ + BlockNumber: ethermanBlock1bis.BlockNumber, + BlockHash: ethermanBlock1bis.BlockHash, + ParentHash: ethermanBlock1bis.ParentHash, + ReceivedAt: ethermanBlock1bis.ReceivedAt, + Checked: true, + } + m.State. + On("AddBlock", ctx, stateBlock1bis, m.DbTx). + Return(nil). + Once() + + m.State. + On("GetStoredFlushID", ctx). + Return(uint64(1), cProverIDExecution, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock2bis := &state.Block{ + BlockNumber: ethermanBlock2bis.BlockNumber, + BlockHash: ethermanBlock2bis.BlockHash, + ParentHash: ethermanBlock2bis.ParentHash, + ReceivedAt: ethermanBlock2bis.ReceivedAt, + Checked: true, + } + m.State. + On("AddBlock", ctx, stateBlock2bis, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Run(func(args mock.Arguments) { + sync.Stop() + ctx.Done() + }). + Return(nil). + Once() + }). + Return(m.DbTx, nil). + Once() + + err = sync.Sync() + require.NoError(t, err) +} + +func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) { + genesis := state.Genesis{ + BlockNumber: uint64(0), + } + cfg := Config{ + SyncInterval: cfgTypes.Duration{Duration: 1 * time.Second}, + SyncChunkSize: 3, + L1SynchronizationMode: SequentialMode, + SyncBlockProtection: "latest", + } + + m := mocks{ + Etherman: mock_syncinterfaces.NewEthermanFullInterface(t), + State: mock_syncinterfaces.NewStateFullInterface(t), + Pool: mock_syncinterfaces.NewPoolInterface(t), + DbTx: syncMocks.NewDbTxMock(t), + ZKEVMClient: mock_syncinterfaces.NewZKEVMClientInterface(t), + EthTxManager: mock_syncinterfaces.NewEthTxManager(t), + } + ethermanForL1 := []syncinterfaces.EthermanFullInterface{m.Etherman} + sync, err := NewSynchronizer(false, m.Etherman, ethermanForL1, m.State, m.Pool, m.EthTxManager, m.ZKEVMClient, m.zkEVMClientEthereumCompatible, nil, genesis, cfg, false) + require.NoError(t, err) + + // state preparation + ctxMatchBy := mock.MatchedBy(func(ctx context.Context) bool { return ctx != nil }) + forkIdInterval := state.ForkIDInterval{ + ForkId: 9, + FromBatchNumber: 0, + ToBatchNumber: math.MaxUint64, + } + m.State.EXPECT().GetForkIDInMemory(uint64(9)).Return(&forkIdInterval) + + m.State. + On("BeginStateTransaction", ctxMatchBy). + Run(func(args mock.Arguments) { + ctx := args[0].(context.Context) + parentHash := common.HexToHash("0x111") + ethHeader0 := ðTypes.Header{Number: big.NewInt(0), ParentHash: parentHash} + ethBlock0 := ethTypes.NewBlockWithHeader(ethHeader0) + ethHeader1 := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash()} + ethBlock1 := ethTypes.NewBlockWithHeader(ethHeader1) + ethHeader1bis := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash(), Time: 0, GasUsed: 10} + ethBlock1bis := ethTypes.NewBlockWithHeader(ethHeader1bis) + ethHeader2 := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1.Hash()} + ethBlock2 := ethTypes.NewBlockWithHeader(ethHeader2) + ethHeader3 := ðTypes.Header{Number: big.NewInt(3), ParentHash: ethBlock2.Hash()} + ethBlock3 := ethTypes.NewBlockWithHeader(ethHeader3) + + lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} + lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} + lastBlock2 := &state.Block{BlockHash: ethBlock2.Hash(), BlockNumber: ethBlock2.Number().Uint64(), ParentHash: ethBlock2.ParentHash()} + + m.State. + On("GetForkIDByBatchNumber", mock.Anything). + Return(uint64(9), nil). + Maybe() + m.State. + On("GetLastBlock", ctx, m.DbTx). + Return(lastBlock2, nil). + Once() + + m.State. + On("GetLastBatchNumber", ctx, m.DbTx). + Return(uint64(10), nil). + Once() + + m.State. + On("SetInitSyncBatch", ctx, uint64(10), m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("GetLatestBatchNumber"). + Return(uint64(10), nil) + + var nilDbTx pgx.Tx + m.State. + On("GetLastBatchNumber", ctx, nilDbTx). + Return(uint64(10), nil) + + m.Etherman. + On("GetLatestVerifiedBatchNum"). + Return(uint64(10), nil) + + m.State. + On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). + Return(nil) + + n := big.NewInt(rpc.LatestBlockNumber.Int64()) + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader3, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock2.BlockNumber). + Return(ethBlock2, nil). + Once() + + blocks := []etherman.Block{} + order := map[common.Hash][]etherman.Order{} + + fromBlock := ethBlock2.NumberU64() + toBlock := fromBlock + cfg.SyncChunkSize + if toBlock > ethBlock3.NumberU64() { + toBlock = ethBlock3.NumberU64() + } + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + ti := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC) + var depth uint64 = 1 + stateBlock1 := &state.Block{ + BlockNumber: ethBlock1.NumberU64(), + BlockHash: ethBlock1.Hash(), + ParentHash: ethBlock1.ParentHash(), + ReceivedAt: ti, + } + m.State. + On("GetPreviousBlock", ctx, depth, nil). + Return(stateBlock1, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1bis, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock0 := &state.Block{ + BlockNumber: ethBlock0.NumberU64(), + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + ReceivedAt: ti, + } + m.State. + On("GetPreviousBlock", ctx, depth, m.DbTx). + Return(stateBlock0, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + m.State. + On("Reset", ctx, ethBlock0.NumberU64(), m.DbTx). + Return(nil). + Once() + + m.EthTxManager. + On("Reorg", ctx, ethBlock0.NumberU64()+1, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader3, nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + ethermanBlock0 := etherman.Block{ + BlockNumber: 0, + ReceivedAt: ti, + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + } + ethermanBlock1bis := etherman.Block{ + BlockNumber: 1, + ReceivedAt: ti, + BlockHash: ethBlock1.Hash(), + ParentHash: ethBlock1.ParentHash(), + } + blocks = []etherman.Block{ethermanBlock0, ethermanBlock1bis} + fromBlock = 0 + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.Etherman. + On("GetFinalizedBlockNumber", ctx). + Return(ethBlock3.NumberU64(), nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock1bis := &state.Block{ + BlockNumber: ethermanBlock1bis.BlockNumber, + BlockHash: ethermanBlock1bis.BlockHash, + ParentHash: ethermanBlock1bis.ParentHash, + ReceivedAt: ethermanBlock1bis.ReceivedAt, + Checked: true, + } + m.State. + On("AddBlock", ctx, stateBlock1bis, m.DbTx). + Return(nil). + Once() + + m.State. + On("GetStoredFlushID", ctx). + Return(uint64(1), cProverIDExecution, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Run(func(args mock.Arguments) { + sync.Stop() + ctx.Done() + }). + Return(uint64(1), nil). + Once() + }). + Return(m.DbTx, nil). + Once() + + err = sync.Sync() + require.NoError(t, err) +} diff --git a/test/config/test.genesis.config.json b/test/config/test.genesis.config.json index 9744f7b920..3c2db9d886 100644 --- a/test/config/test.genesis.config.json +++ b/test/config/test.genesis.config.json @@ -6,95 +6,95 @@ "polTokenAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3", "polygonZkEVMGlobalExitRootAddress": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" }, - "genesisBlockNumber": 67, - "root": "0xcc9ec17819f4ac7f282949ca8c379c4d3ee1b8b7908c51b9b405b6319af67b32", - "genesis": [ - { - "contractName": "PolygonZkEVMDeployer", - "balance": "0", - "nonce": "4", - "address": "0x51dbd54FCCb6b3A07738fd3E156D588e71f79973", - "bytecode": "0x6080604052600436106100705760003560e01c8063715018a61161004e578063715018a6146100e65780638da5cb5b146100fb578063e11ae6cb14610126578063f2fde38b1461013957600080fd5b80632b79805a146100755780634a94d4871461008a5780636d07dbf81461009d575b600080fd5b610088610083366004610927565b610159565b005b6100886100983660046109c7565b6101cb565b3480156100a957600080fd5b506100bd6100b8366004610a1e565b61020d565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b50610088610220565b34801561010757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100bd565b610088610134366004610a40565b610234565b34801561014557600080fd5b50610088610154366004610a90565b61029b565b610161610357565b600061016e8585856103d8565b905061017a8183610537565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a15050505050565b6101d3610357565b6101de83838361057b565b506040517f25adb19089b6a549831a273acdf7908cff8b7ee5f551f8d1d37996cf01c5df5b90600090a1505050565b600061021983836105a9565b9392505050565b610228610357565b61023260006105b6565b565b61023c610357565b60006102498484846103d8565b60405173ffffffffffffffffffffffffffffffffffffffff821681529091507fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a150505050565b6102a3610357565b73ffffffffffffffffffffffffffffffffffffffff811661034b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610354816105b6565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610232576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610342565b600083471015610444576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610342565b81516000036104af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610342565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610342565b6060610219838360006040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c6564000081525061062b565b60606105a1848484604051806060016040528060298152602001610b3d6029913961062b565b949350505050565b6000610219838330610744565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060824710156106bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610342565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516106e69190610acf565b60006040518083038185875af1925050503d8060008114610723576040519150601f19603f3d011682016040523d82523d6000602084013e610728565b606091505b50915091506107398783838761076e565b979650505050505050565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b606083156108045782516000036107fd5773ffffffffffffffffffffffffffffffffffffffff85163b6107fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610342565b50816105a1565b6105a183838151156108195781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103429190610aeb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261088d57600080fd5b813567ffffffffffffffff808211156108a8576108a861084d565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156108ee576108ee61084d565b8160405283815286602085880101111561090757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806080858703121561093d57600080fd5b8435935060208501359250604085013567ffffffffffffffff8082111561096357600080fd5b61096f8883890161087c565b9350606087013591508082111561098557600080fd5b506109928782880161087c565b91505092959194509250565b803573ffffffffffffffffffffffffffffffffffffffff811681146109c257600080fd5b919050565b6000806000606084860312156109dc57600080fd5b6109e58461099e565b9250602084013567ffffffffffffffff811115610a0157600080fd5b610a0d8682870161087c565b925050604084013590509250925092565b60008060408385031215610a3157600080fd5b50508035926020909101359150565b600080600060608486031215610a5557600080fd5b8335925060208401359150604084013567ffffffffffffffff811115610a7a57600080fd5b610a868682870161087c565b9150509250925092565b600060208284031215610aa257600080fd5b6102198261099e565b60005b83811015610ac6578181015183820152602001610aae565b50506000910152565b60008251610ae1818460208701610aab565b9190910192915050565b6020815260008251806020840152610b0a816040850160208701610aab565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220964619cee0e0baf94c6f8763f013be157da5d54c89e5cff4a8caf4266e13f13a64736f6c63430008140033", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266" - } - }, - { - "contractName": "ProxyAdmin", - "balance": "0", - "nonce": "1", - "address": "0xe34Fe58DDa5b8c6D547E4857E987633aa86a5e90", - "bytecode": "0x60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461012b57806399a88ec41461013e578063f2fde38b1461015e578063f3b7dead1461017e57600080fd5b8063204e1c7a14610080578063715018a6146100c95780637eff275e146100e05780638da5cb5b14610100575b600080fd5b34801561008c57600080fd5b506100a061009b366004610608565b61019e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d557600080fd5b506100de610255565b005b3480156100ec57600080fd5b506100de6100fb36600461062c565b610269565b34801561010c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100a0565b6100de610139366004610694565b6102f7565b34801561014a57600080fd5b506100de61015936600461062c565b61038c565b34801561016a57600080fd5b506100de610179366004610608565b6103e8565b34801561018a57600080fd5b506100a0610199366004610608565b6104a4565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b600060405180830381855afa9150503d8060008114610225576040519150601f19603f3d011682016040523d82523d6000602084013e61022a565b606091505b50915091508161023957600080fd5b8080602001905181019061024d9190610788565b949350505050565b61025d6104f0565b6102676000610571565b565b6102716104f0565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b600060405180830381600087803b1580156102db57600080fd5b505af11580156102ef573d6000803e3d6000fd5b505050505050565b6102ff6104f0565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef28690349061035590869086906004016107a5565b6000604051808303818588803b15801561036e57600080fd5b505af1158015610382573d6000803e3d6000fd5b5050505050505050565b6103946104f0565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102c1565b6103f06104f0565b73ffffffffffffffffffffffffffffffffffffffff8116610498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6104a181610571565b50565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b60005473ffffffffffffffffffffffffffffffffffffffff163314610267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161048f565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff811681146104a157600080fd5b60006020828403121561061a57600080fd5b8135610625816105e6565b9392505050565b6000806040838503121561063f57600080fd5b823561064a816105e6565b9150602083013561065a816105e6565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156106a957600080fd5b83356106b4816105e6565b925060208401356106c4816105e6565b9150604084013567ffffffffffffffff808211156106e157600080fd5b818601915086601f8301126106f557600080fd5b81358181111561070757610707610665565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561074d5761074d610665565b8160405282815289602084870101111561076657600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561079a57600080fd5b8151610625816105e6565b73ffffffffffffffffffffffffffffffffffffffff8316815260006020604081840152835180604085015260005b818110156107ef578581018301518582016060015282016107d3565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050939250505056fea2646970667358221220c9867ffac53151bdb1305d8f5e3e883cd83e5270c7ec09cdc24e837b2e65239064736f6c63430008140033", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f" - } - }, - { - "contractName": "PolygonZkEVMBridge implementation", - "balance": "0", - "nonce": "1", - "address": "0x493732fB136a380920C390a85fc27d79C7b70756", - "bytecode": "0x6080604052600436106101a35760003560e01c806383f24403116100e2578063ccaa2d1111610085578063ccaa2d1114610511578063cd58657914610531578063d02103ca14610544578063dbc169761461056b578063ee25560b14610580578063f5efcd79146105ad578063f811bff7146105cd578063fb570834146105ed57600080fd5b806383f244031461040b5780638ed7e3f21461042b578063aaa13cc21461044b578063b8b284d01461046b578063bab161bf1461048b578063be5831c7146104ad578063c00f14ab146104d1578063cc461632146104f157600080fd5b80633cbc795b1161014a5780633cbc795b146102fd5780633e197043146103365780634b2f336d146103565780635ca1e165146103765780637843298b1461038b57806379e2cf97146103ab57806381b1c174146103c057806383c43a55146103f657600080fd5b806315064c96146101a85780632072f6c5146101d757806322e95f2c146101ee578063240ff3781461021b57806327aef4e81461022e5780632dfdf0b514610250578063318aee3d146102745780633c351e10146102dd575b600080fd5b3480156101b457600080fd5b506068546101c29060ff1681565b60405190151581526020015b60405180910390f35b3480156101e357600080fd5b506101ec61060d565b005b3480156101fa57600080fd5b5061020e610209366004612b65565b610642565b6040516101ce9190612b9c565b6101ec610229366004612c06565b610693565b34801561023a57600080fd5b50610243610703565b6040516101ce9190612ccf565b34801561025c57600080fd5b5061026660535481565b6040519081526020016101ce565b34801561028057600080fd5b506102b961028f366004612ce9565b606b6020526000908152604090205463ffffffff811690600160201b90046001600160a01b031682565b6040805163ffffffff90931683526001600160a01b039091166020830152016101ce565b3480156102e957600080fd5b50606d5461020e906001600160a01b031681565b34801561030957600080fd5b50606d5461032190600160a01b900463ffffffff1681565b60405163ffffffff90911681526020016101ce565b34801561034257600080fd5b50610266610351366004612d15565b610791565b34801561036257600080fd5b50606f5461020e906001600160a01b031681565b34801561038257600080fd5b5061026661081e565b34801561039757600080fd5b5061020e6103a6366004612d94565b6108fb565b3480156103b757600080fd5b506101ec610925565b3480156103cc57600080fd5b5061020e6103db366004612ddd565b606a602052600090815260409020546001600160a01b031681565b34801561040257600080fd5b50610243610946565b34801561041757600080fd5b50610266610426366004612e08565b610965565b34801561043757600080fd5b50606c5461020e906001600160a01b031681565b34801561045757600080fd5b5061020e610466366004612f12565b610a3b565b34801561047757600080fd5b506101ec610486366004612fad565b610b3d565b34801561049757600080fd5b5060685461032190610100900463ffffffff1681565b3480156104b957600080fd5b5060685461032190600160c81b900463ffffffff1681565b3480156104dd57600080fd5b506102436104ec366004612ce9565b610c04565b3480156104fd57600080fd5b506101c261050c36600461302f565b610c49565b34801561051d57600080fd5b506101ec61052c366004613062565b610cd2565b6101ec61053f36600461314d565b6111c7565b34801561055057600080fd5b5060685461020e90600160281b90046001600160a01b031681565b34801561057757600080fd5b506101ec611621565b34801561058c57600080fd5b5061026661059b366004612ddd565b60696020526000908152604090205481565b3480156105b957600080fd5b506101ec6105c8366004613062565b611654565b3480156105d957600080fd5b506101ec6105e83660046131e2565b6118ef565b3480156105f957600080fd5b506101c261060836600461328a565b611b62565b606c546001600160a01b0316331461063857604051631736745960e31b815260040160405180910390fd5b610640611b7a565b565b6000606a6000848460405160200161065b9291906132d2565b60408051601f19818403018152918152815160209283012083529082019290925201600020546001600160a01b031690505b92915050565b60685460ff16156106b757604051630bc011ff60e21b815260040160405180910390fd5b34158015906106d05750606f546001600160a01b031615155b156106ee576040516301bd897160e61b815260040160405180910390fd5b6106fc858534868686611bd6565b5050505050565b606e8054610710906132fc565b80601f016020809104026020016040519081016040528092919081815260200182805461073c906132fc565b80156107895780601f1061075e57610100808354040283529160200191610789565b820191906000526020600020905b81548152906001019060200180831161076c57829003601f168201915b505050505081565b6040516001600160f81b031960f889901b1660208201526001600160e01b031960e088811b821660218401526001600160601b0319606089811b821660258601529188901b909216603984015285901b16603d8201526051810183905260718101829052600090609101604051602081830303815290604052805190602001209050979650505050505050565b605354600090819081805b60208110156108f2578083901c600116600103610886576033816020811061085357610853613336565b015460408051602081019290925281018590526060016040516020818303038152906040528051906020012093506108b3565b60408051602081018690529081018390526060016040516020818303038152906040528051906020012093505b604080516020810184905290810183905260600160405160208183030381529060405280519060200120915080806108ea90613362565b915050610829565b50919392505050565b600061091d848461090b85611ca0565b61091486611d5f565b61046687611e17565b949350505050565b605354606854600160c81b900463ffffffff16101561064057610640611ecf565b60405180611ba00160405280611b668152602001613a7a611b66913981565b600083815b6020811015610a3257600163ffffffff8516821c811690036109d55784816020811061099857610998613336565b6020020135826040516020016109b8929190918252602082015260400190565b604051602081830303815290604052805190602001209150610a20565b818582602081106109e8576109e8613336565b6020020135604051602001610a07929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b80610a2a81613362565b91505061096a565b50949350505050565b6000808686604051602001610a519291906132d2565b604051602081830303815290604052805190602001209050600060ff60f81b308360405180611ba00160405280611b668152602001613a7a611b669139898989604051602001610aa39392919061337b565b60408051601f1981840301815290829052610ac192916020016133b4565b60405160208183030381529060405280519060200120604051602001610b1994939291906001600160f81b031994909416845260609290921b6001600160601b03191660018401526015830152603582015260550190565b60408051808303601f19018152919052805160209091012098975050505050505050565b60685460ff1615610b6157604051630bc011ff60e21b815260040160405180910390fd5b606f546001600160a01b0316610b8a5760405163dde3cda760e01b815260040160405180910390fd5b606f54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610bbc90339088906004016133e3565b600060405180830381600087803b158015610bd657600080fd5b505af1158015610bea573d6000803e3d6000fd5b50505050610bfc868686868686611bd6565b505050505050565b6060610c0f82611ca0565b610c1883611d5f565b610c2184611e17565b604051602001610c339392919061337b565b6040516020818303038152906040529050919050565b6068546000908190610100900463ffffffff16158015610c6f575063ffffffff83166001145b15610c81575063ffffffff8316610ca8565b610c95600160201b63ffffffff85166133fc565b610ca59063ffffffff8616613413565b90505b600881901c600090815260696020526040902054600160ff9092169190911b908116149392505050565b60685460ff1615610cf657604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff8681166101009092041614610d26576040516302caf51760e11b815260040160405180910390fd5b610d5a8c8c8c8c8c610d5560008e8e8e8e8e8e8e604051610d48929190613426565b6040518091039020610791565b611f68565b6001600160a01b038616610e9257606f546001600160a01b0316610e295760006001600160a01b03851684825b6040519080825280601f01601f191660200182016040528015610db1576020820181803683370190505b50604051610dbf9190613436565b60006040518083038185875af1925050503d8060008114610dfc576040519150601f19603f3d011682016040523d82523d6000602084013e610e01565b606091505b5050905080610e2357604051630ce8f45160e31b815260040160405180910390fd5b5061117a565b606f546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610e5b90879087906004016133e3565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b5050505061117a565b606d546001600160a01b038781169116148015610ec05750606d5463ffffffff888116600160a01b90920416145b15610ed85760006001600160a01b0385168482610d87565b60685463ffffffff610100909104811690881603610f0957610f046001600160a01b03871685856120c7565b61117a565b60008787604051602001610f1e9291906132d2565b60408051601f1981840301815291815281516020928301206000818152606a9093529120549091506001600160a01b031680611116576000610f968386868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061212292505050565b6040516340c10f1960e01b81529091506001600160a01b038216906340c10f1990610fc7908a908a906004016133e3565b600060405180830381600087803b158015610fe157600080fd5b505af1158015610ff5573d6000803e3d6000fd5b5050505080606a600085815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060405180604001604052808b63ffffffff1681526020018a6001600160a01b0316815250606b6000836001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f490e59a1701b938786ac72570a1efeac994a3dbe96e2e883e19e902ace6e6a398a8a83888860405161110895949392919061347b565b60405180910390a150611177565b6040516340c10f1960e01b81526001600160a01b038216906340c10f199061114490899089906004016133e3565b600060405180830381600087803b15801561115e57600080fd5b505af1158015611172573d6000803e3d6000fd5b505050505b50505b7f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d8a888887876040516111b19594939291906134b4565b60405180910390a1505050505050505050505050565b60685460ff16156111eb57604051630bc011ff60e21b815260040160405180910390fd5b6111f361219e565b60685463ffffffff610100909104811690881603611224576040516302caf51760e11b815260040160405180910390fd5b6000806060876001600160a01b03881661130a578834146112585760405163b89240f560e01b815260040160405180910390fd5b606d54606e80546001600160a01b0383169650600160a01b90920463ffffffff16945090611285906132fc565b80601f01602080910402602001604051908101604052809291908181526020018280546112b1906132fc565b80156112fe5780601f106112d3576101008083540402835291602001916112fe565b820191906000526020600020905b8154815290600101906020018083116112e157829003601f168201915b50505050509150611596565b34156113295760405163798ee6f160e01b815260040160405180910390fd5b606f546001600160a01b03908116908916036113a457604051632770a7eb60e21b81526001600160a01b03891690639dc29fac9061136d9033908d906004016133e3565b600060405180830381600087803b15801561138757600080fd5b505af115801561139b573d6000803e3d6000fd5b50505050611596565b6001600160a01b038089166000908152606b602090815260409182902082518084019093525463ffffffff81168352600160201b9004909216918101829052901561145c57604051632770a7eb60e21b81526001600160a01b038a1690639dc29fac906114179033908e906004016133e3565b600060405180830381600087803b15801561143157600080fd5b505af1158015611445573d6000803e3d6000fd5b505050508060200151945080600001519350611589565b851561146e5761146e898b89896121f7565b6040516370a0823160e01b81526000906001600160a01b038b16906370a082319061149d903090600401612b9c565b602060405180830381865afa1580156114ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114de91906134e6565b90506114f56001600160a01b038b1633308e61253d565b6040516370a0823160e01b81526000906001600160a01b038c16906370a0823190611524903090600401612b9c565b602060405180830381865afa158015611541573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156591906134e6565b905061157182826134ff565b6068548c9850610100900463ffffffff169650935050505b61159289610c04565b9250505b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b600084868e8e86886053546040516115d6989796959493929190613512565b60405180910390a16115fd6115f8600085878f8f878980519060200120610791565b612575565b861561160b5761160b611ecf565b5050505061161860018055565b50505050505050565b606c546001600160a01b0316331461164c57604051631736745960e31b815260040160405180910390fd5b610640612660565b60685460ff161561167857604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff86811661010090920416146116a8576040516302caf51760e11b815260040160405180910390fd5b6116ca8c8c8c8c8c610d5560018e8e8e8e8e8e8e604051610d48929190613426565b606f546000906001600160a01b031661178157846001600160a01b031684888a86866040516024016116ff949392919061357d565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b179052516117349190613436565b60006040518083038185875af1925050503d8060008114611771576040519150601f19603f3d011682016040523d82523d6000602084013e611776565b606091505b505080915050611883565b606f546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906117b390889088906004016133e3565b600060405180830381600087803b1580156117cd57600080fd5b505af11580156117e1573d6000803e3d6000fd5b50505050846001600160a01b031687898585604051602401611806949392919061357d565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161183b9190613436565b6000604051808303816000865af19150503d8060008114611878576040519150601f19603f3d011682016040523d82523d6000602084013e61187d565b606091505b50909150505b806118a1576040516337e391c360e01b815260040160405180910390fd5b7f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d8b898988886040516118d89594939291906134b4565b60405180910390a150505050505050505050505050565b600054610100900460ff161580801561190f5750600054600160ff909116105b806119295750303b158015611929575060005460ff166001145b6119915760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156119b4576000805461ff0019166101001790555b60688054610100600160c81b03191661010063ffffffff8a160265010000000000600160c81b03191617600160281b6001600160a01b038781169190910291909117909155606c80546001600160a01b0319168583161790558616611a3d5763ffffffff851615611a3857604051630d43a60960e11b815260040160405180910390fd5b611b0c565b606d805463ffffffff8716600160a01b026001600160c01b03199091166001600160a01b03891617179055606e611a7483826135fe565b50611aeb6000801b6012604051602001611ad791906060808252600d908201526c2bb930b83832b21022ba3432b960991b608082015260a060208201819052600490820152630ae8aa8960e31b60c082015260ff91909116604082015260e00190565b604051602081830303815290604052612122565b606f80546001600160a01b0319166001600160a01b03929092169190911790555b611b146126b8565b8015611618576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b600081611b70868686610965565b1495945050505050565b60685460ff1615611b9e57604051630bc011ff60e21b815260040160405180910390fd5b6068805460ff191660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a549790600090a1565b60685463ffffffff610100909104811690871603611c07576040516302caf51760e11b815260040160405180910390fd5b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b6001606860019054906101000a900463ffffffff16338989898888605354604051611c5b999897969594939291906136bd565b60405180910390a1611c926115f86001606860019054906101000a900463ffffffff16338a8a8a8989604051610d48929190613426565b8215610bfc57610bfc611ecf565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b179052905160609160009182916001600160a01b03861691611ce79190613436565b600060405180830381855afa9150503d8060008114611d22576040519150601f19603f3d011682016040523d82523d6000602084013e611d27565b606091505b509150915081611d5657604051806040016040528060078152602001664e4f5f4e414d4560c81b81525061091d565b61091d816126e7565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b179052905160609160009182916001600160a01b03861691611da69190613436565b600060405180830381855afa9150503d8060008114611de1576040519150601f19603f3d011682016040523d82523d6000602084013e611de6565b606091505b509150915081611d5657604051806040016040528060098152602001681393d7d4d6535093d360ba1b81525061091d565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b1790529051600091829182916001600160a01b03861691611e5d9190613436565b600060405180830381855afa9150503d8060008114611e98576040519150601f19603f3d011682016040523d82523d6000602084013e611e9d565b606091505b5091509150818015611eb0575080516020145b611ebb57601261091d565b8080602001905181019061091d919061372a565b6053546068805463ffffffff909216600160c81b0263ffffffff60c81b1990921691909117908190556001600160a01b03600160281b909104166333d6247d611f1661081e565b6040518263ffffffff1660e01b8152600401611f3491815260200190565b600060405180830381600087803b158015611f4e57600080fd5b505af1158015611f62573d6000803e3d6000fd5b50505050565b606854604080516020808201879052818301869052825180830384018152606083019384905280519101206312bd9b1960e11b9092526064810191909152600091600160281b90046001600160a01b03169063257b3632906084016020604051808303816000875af1158015611fe2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200691906134e6565b90508060000361202857604051622f6fad60e01b815260040160405180910390fd5b600080600160401b87161561206857869150612046848a8489611b62565b612063576040516338105f3b60e21b815260040160405180910390fd5b6120b2565b602087901c612078816001613747565b915087925061209361208b868c86610965565b8a8389611b62565b6120b0576040516338105f3b60e21b815260040160405180910390fd5b505b6120bc8282612875565b505050505050505050565b61211d8363a9059cbb60e01b84846040516024016120e69291906133e3565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261291d565b505050565b60008060405180611ba00160405280611b668152602001613a7a611b669139836040516020016121539291906133b4565b6040516020818303038152906040529050838151602083016000f591506001600160a01b038216612197576040516305f7d84960e51b815260040160405180910390fd5b5092915050565b6002600154036121f05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611988565b6002600155565b60006122066004828486613764565b61220f9161378e565b9050632afa533160e01b6001600160e01b03198216016123a357600080808080808061223e896004818d613764565b81019061224b91906137be565b9650965096509650965096509650336001600160a01b0316876001600160a01b03161461228b5760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03861630146122b45760405163750643af60e01b815260040160405180910390fd5b8a85146122d4576040516303fffc4b60e01b815260040160405180910390fd5b604080516001600160a01b0389811660248301528881166044830152606482018890526084820187905260ff861660a483015260c4820185905260e48083018590528351808403909101815261010490920183526020820180516001600160e01b031663d505accf60e01b1790529151918e16916123529190613436565b6000604051808303816000865af19150503d806000811461238f576040519150601f19603f3d011682016040523d82523d6000602084013e612394565b606091505b505050505050505050506106fc565b6001600160e01b031981166323f2ebc360e21b146123d457604051637141605d60e11b815260040160405180910390fd5b6000808080808080806123ea8a6004818e613764565b8101906123f79190613812565b97509750975097509750975097509750336001600160a01b0316886001600160a01b0316146124395760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03871630146124625760405163750643af60e01b815260040160405180910390fd5b604080516001600160a01b038a811660248301528981166044830152606482018990526084820188905286151560a483015260ff861660c483015260e482018590526101048083018590528351808403909101815261012490920183526020820180516001600160e01b03166323f2ebc360e21b1790529151918f16916124e99190613436565b6000604051808303816000865af19150503d8060008114612526576040519150601f19603f3d011682016040523d82523d6000602084013e61252b565b606091505b50505050505050505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611f629085906323b872dd60e01b906084016120e6565b80600161258460206002613979565b61258e91906134ff565b605354106125af576040516377ae67b360e11b815260040160405180910390fd5b60006053600081546125c090613362565b9182905550905060005b6020811015612651578082901c6001166001036125fd5782603382602081106125f5576125f5613336565b015550505050565b6033816020811061261057612610613336565b01546040805160208101929092528101849052606001604051602081830303815290604052805190602001209250808061264990613362565b9150506125ca565b5061211d613985565b60018055565b60685460ff1661268357604051635386698160e01b815260040160405180910390fd5b6068805460ff191690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b390600090a1565b600054610100900460ff166126df5760405162461bcd60e51b81526004016119889061399b565b6106406129ef565b60606040825110612706578180602001905181019061068d91906139e6565b81516020036128425760005b602081108015612741575082818151811061272f5761272f613336565b01602001516001600160f81b03191615155b15612758578061275081613362565b915050612712565b806000036127905750506040805180820190915260128152714e4f545f56414c49445f454e434f44494e4760701b6020820152919050565b6000816001600160401b038111156127aa576127aa612e47565b6040519080825280601f01601f1916602001820160405280156127d4576020820181803683370190505b50905060005b8281101561283a578481815181106127f4576127f4613336565b602001015160f81c60f81b82828151811061281157612811613336565b60200101906001600160f81b031916908160001a9053508061283281613362565b9150506127da565b509392505050565b50506040805180820190915260128152714e4f545f56414c49445f454e434f44494e4760701b602082015290565b919050565b606854600090610100900463ffffffff16158015612899575063ffffffff82166001145b156128ab575063ffffffff82166128d2565b6128bf600160201b63ffffffff84166133fc565b6128cf9063ffffffff8516613413565b90505b600881901c60008181526069602052604081208054600160ff861690811b9182189283905592909190818316900361161857604051630c8d9eab60e31b815260040160405180910390fd5b6000612972826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612a169092919063ffffffff16565b80519091501561211d57808060200190518101906129909190613a5c565b61211d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611988565b600054610100900460ff1661265a5760405162461bcd60e51b81526004016119889061399b565b606061091d848460008585600080866001600160a01b03168587604051612a3d9190613436565b60006040518083038185875af1925050503d8060008114612a7a576040519150601f19603f3d011682016040523d82523d6000602084013e612a7f565b606091505b5091509150612a9087838387612a9b565b979650505050505050565b60608315612b0a578251600003612b03576001600160a01b0385163b612b035760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611988565b508161091d565b61091d8383815115612b1f5781518083602001fd5b8060405162461bcd60e51b81526004016119889190612ccf565b803563ffffffff8116811461287057600080fd5b6001600160a01b0381168114612b6257600080fd5b50565b60008060408385031215612b7857600080fd5b612b8183612b39565b91506020830135612b9181612b4d565b809150509250929050565b6001600160a01b0391909116815260200190565b8015158114612b6257600080fd5b60008083601f840112612bd057600080fd5b5081356001600160401b03811115612be757600080fd5b602083019150836020828501011115612bff57600080fd5b9250929050565b600080600080600060808688031215612c1e57600080fd5b612c2786612b39565b94506020860135612c3781612b4d565b93506040860135612c4781612bb0565b925060608601356001600160401b03811115612c6257600080fd5b612c6e88828901612bbe565b969995985093965092949392505050565b60005b83811015612c9a578181015183820152602001612c82565b50506000910152565b60008151808452612cbb816020860160208601612c7f565b601f01601f19169290920160200192915050565b602081526000612ce26020830184612ca3565b9392505050565b600060208284031215612cfb57600080fd5b8135612ce281612b4d565b60ff81168114612b6257600080fd5b600080600080600080600060e0888a031215612d3057600080fd5b8735612d3b81612d06565b9650612d4960208901612b39565b95506040880135612d5981612b4d565b9450612d6760608901612b39565b93506080880135612d7781612b4d565b9699959850939692959460a0840135945060c09093013592915050565b600080600060608486031215612da957600080fd5b612db284612b39565b92506020840135612dc281612b4d565b91506040840135612dd281612b4d565b809150509250925092565b600060208284031215612def57600080fd5b5035919050565b80610400810183101561068d57600080fd5b60008060006104408486031215612e1e57600080fd5b83359250612e2f8560208601612df6565b9150612e3e6104208501612b39565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612e8557612e85612e47565b604052919050565b60006001600160401b03821115612ea657612ea6612e47565b50601f01601f191660200190565b6000612ec7612ec284612e8d565b612e5d565b9050828152838383011115612edb57600080fd5b828260208301376000602084830101529392505050565b600082601f830112612f0357600080fd5b612ce283833560208501612eb4565b600080600080600060a08688031215612f2a57600080fd5b612f3386612b39565b94506020860135612f4381612b4d565b935060408601356001600160401b0380821115612f5f57600080fd5b612f6b89838a01612ef2565b94506060880135915080821115612f8157600080fd5b50612f8e88828901612ef2565b9250506080860135612f9f81612d06565b809150509295509295909350565b60008060008060008060a08789031215612fc657600080fd5b612fcf87612b39565b95506020870135612fdf81612b4d565b9450604087013593506060870135612ff681612bb0565b925060808701356001600160401b0381111561301157600080fd5b61301d89828a01612bbe565b979a9699509497509295939492505050565b6000806040838503121561304257600080fd5b61304b83612b39565b915061305960208401612b39565b90509250929050565b6000806000806000806000806000806000806109208d8f03121561308557600080fd5b61308f8e8e612df6565b9b5061309f8e6104008f01612df6565b9a506108008d013599506108208d013598506108408d013597506130c66108608e01612b39565b96506130d66108808e0135612b4d565b6108808d013595506130eb6108a08e01612b39565b94506130fb6108c08e0135612b4d565b6108c08d013593506108e08d013592506001600160401b036109008e0135111561312457600080fd5b6131358e6109008f01358f01612bbe565b81935080925050509295989b509295989b509295989b565b600080600080600080600060c0888a03121561316857600080fd5b61317188612b39565b9650602088013561318181612b4d565b955060408801359450606088013561319881612b4d565b935060808801356131a881612bb0565b925060a08801356001600160401b038111156131c357600080fd5b6131cf8a828b01612bbe565b989b979a50959850939692959293505050565b60008060008060008060c087890312156131fb57600080fd5b61320487612b39565b9550602087013561321481612b4d565b945061322260408801612b39565b9350606087013561323281612b4d565b9250608087013561324281612b4d565b915060a08701356001600160401b0381111561325d57600080fd5b8701601f8101891361326e57600080fd5b61327d89823560208401612eb4565b9150509295509295509295565b60008060008061046085870312156132a157600080fd5b843593506132b28660208701612df6565b92506132c16104208601612b39565b939692955092936104400135925050565b60e09290921b6001600160e01b031916825260601b6001600160601b031916600482015260180190565b600181811c9082168061331057607f821691505b60208210810361333057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016133745761337461334c565b5060010190565b60608152600061338e6060830186612ca3565b82810360208401526133a08186612ca3565b91505060ff83166040830152949350505050565b600083516133c6818460208801612c7f565b8351908301906133da818360208801612c7f565b01949350505050565b6001600160a01b03929092168252602082015260400190565b808202811582820484141761068d5761068d61334c565b8082018082111561068d5761068d61334c565b8183823760009101908152919050565b60008251613448818460208701612c7f565b9190910192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b63ffffffff861681526001600160a01b03858116602083015284166040820152608060608201819052600090612a909083018486613452565b94855263ffffffff9390931660208501526001600160a01b039182166040850152166060830152608082015260a00190565b6000602082840312156134f857600080fd5b5051919050565b8181038181111561068d5761068d61334c565b60ff8916815263ffffffff88811660208301526001600160a01b03888116604084015287821660608401528616608083015260a0820185905261010060c0830181905260009161356484830187612ca3565b925080851660e085015250509998505050505050505050565b6001600160a01b038516815263ffffffff841660208201526060604082018190526000906135ae9083018486613452565b9695505050505050565b601f82111561211d57600081815260208120601f850160051c810160208610156135df5750805b601f850160051c820191505b81811015610bfc578281556001016135eb565b81516001600160401b0381111561361757613617612e47565b61362b8161362584546132fc565b846135b8565b602080601f83116001811461366057600084156136485750858301515b600019600386901b1c1916600185901b178555610bfc565b600085815260208120601f198616915b8281101561368f57888601518255948401946001909101908401613670565b50858210156136ad5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60ff8a16815263ffffffff89811660208301526001600160a01b03898116604084015288821660608401528716608083015260a0820186905261010060c083018190526000916137108483018789613452565b925080851660e085015250509a9950505050505050505050565b60006020828403121561373c57600080fd5b8151612ce281612d06565b63ffffffff8181168382160190808211156121975761219761334c565b6000808585111561377457600080fd5b8386111561378157600080fd5b5050820193919092039150565b6001600160e01b031981358181169160048510156137b65780818660040360031b1b83161692505b505092915050565b600080600080600080600060e0888a0312156137d957600080fd5b87356137e481612b4d565b965060208801356137f481612b4d565b955060408801359450606088013593506080880135612d7781612d06565b600080600080600080600080610100898b03121561382f57600080fd5b883561383a81612b4d565b9750602089013561384a81612b4d565b96506040890135955060608901359450608089013561386881612bb0565b935060a089013561387881612d06565b979a969950949793969295929450505060c08201359160e0013590565b600181815b808511156138d05781600019048211156138b6576138b661334c565b808516156138c357918102915b93841c939080029061389a565b509250929050565b6000826138e75750600161068d565b816138f45750600061068d565b816001811461390a576002811461391457613930565b600191505061068d565b60ff8411156139255761392561334c565b50506001821b61068d565b5060208310610133831016604e8410600b8410161715613953575081810a61068d565b61395d8383613895565b80600019048211156139715761397161334c565b029392505050565b6000612ce283836138d8565b634e487b7160e01b600052600160045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000602082840312156139f857600080fd5b81516001600160401b03811115613a0e57600080fd5b8201601f81018413613a1f57600080fd5b8051613a2d612ec282612e8d565b818152856020838501011115613a4257600080fd5b613a53826020830160208601612c7f565b95945050505050565b600060208284031215613a6e57600080fd5b8151612ce281612bb056fe6101006040523480156200001257600080fd5b5060405162001b6638038062001b6683398101604081905262000035916200028d565b82826003620000458382620003a1565b506004620000548282620003a1565b50503360c0525060ff811660e052466080819052620000739062000080565b60a052506200046d915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620000ad6200012e565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6060600380546200013f9062000312565b80601f01602080910402602001604051908101604052809291908181526020018280546200016d9062000312565b8015620001be5780601f106200019257610100808354040283529160200191620001be565b820191906000526020600020905b815481529060010190602001808311620001a057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f057600080fd5b81516001600160401b03808211156200020d576200020d620001c8565b604051601f8301601f19908116603f01168101908282118183101715620002385762000238620001c8565b816040528381526020925086838588010111156200025557600080fd5b600091505b838210156200027957858201830151818301840152908201906200025a565b600093810190920192909252949350505050565b600080600060608486031215620002a357600080fd5b83516001600160401b0380821115620002bb57600080fd5b620002c987838801620001de565b94506020860151915080821115620002e057600080fd5b50620002ef86828701620001de565b925050604084015160ff811681146200030757600080fd5b809150509250925092565b600181811c908216806200032757607f821691505b6020821081036200034857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039c57600081815260208120601f850160051c81016020861015620003775750805b601f850160051c820191505b81811015620003985782815560010162000383565b5050505b505050565b81516001600160401b03811115620003bd57620003bd620001c8565b620003d581620003ce845462000312565b846200034e565b602080601f8311600181146200040d5760008415620003f45750858301515b600019600386901b1c1916600185901b17855562000398565b600085815260208120601f198616915b828110156200043e578886015182559484019460019091019084016200041d565b50858210156200045d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516116aa620004bc6000396000610237015260008181610307015281816105c001526106a70152600061053a015260008181610379015261050401526116aa6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806370a08231116100d8578063a457c2d71161008c578063d505accf11610066578063d505accf1461039b578063dd62ed3e146103ae578063ffa1ad74146103f457600080fd5b8063a457c2d71461034e578063a9059cbb14610361578063cd0d00961461037457600080fd5b806395d89b41116100bd57806395d89b41146102e75780639dc29fac146102ef578063a3c573eb1461030257600080fd5b806370a08231146102915780637ecebe00146102c757600080fd5b806330adf81f1161012f5780633644e515116101145780633644e51514610261578063395093511461026957806340c10f191461027c57600080fd5b806330adf81f14610209578063313ce5671461023057600080fd5b806318160ddd1161016057806318160ddd146101bd57806320606b70146101cf57806323b872dd146101f657600080fd5b806306fdde031461017c578063095ea7b31461019a575b600080fd5b610184610430565b60405161019191906113e4565b60405180910390f35b6101ad6101a8366004611479565b6104c2565b6040519015158152602001610191565b6002545b604051908152602001610191565b6101c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6101ad6102043660046114a3565b6104dc565b6101c17f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610191565b6101c1610500565b6101ad610277366004611479565b61055c565b61028f61028a366004611479565b6105a8565b005b6101c161029f3660046114df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101c16102d53660046114df565b60056020526000908152604090205481565b610184610680565b61028f6102fd366004611479565b61068f565b6103297f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101ad61035c366004611479565b61075e565b6101ad61036f366004611479565b61082f565b6101c17f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103a9366004611501565b61083d565b6101c16103bc366004611574565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101846040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b60606003805461043f906115a7565b80601f016020809104026020016040519081016040528092919081815260200182805461046b906115a7565b80156104b85780601f1061048d576101008083540402835291602001916104b8565b820191906000526020600020905b81548152906001019060200180831161049b57829003601f168201915b5050505050905090565b6000336104d0818585610b73565b60019150505b92915050565b6000336104ea858285610d27565b6104f5858585610dfe565b506001949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610537576105324661106d565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104d090829086906105a3908790611629565b610b73565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084015b60405180910390fd5b61067c8282611135565b5050565b60606004805461043f906115a7565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d427269646765000000000000000000000000000000006064820152608401610669565b61067c8282611228565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610822576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610669565b6104f58286868403610b73565b6000336104d0818585610dfe565b834211156108cc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f546f6b656e577261707065643a3a7065726d69743a204578706972656420706560448201527f726d6974000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a9190866109268361163c565b9091555060408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610991610500565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610a55573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610ad057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f546f6b656e577261707065643a3a7065726d69743a20496e76616c696420736960448201527f676e6174757265000000000000000000000000000000000000000000000000006064820152608401610669565b610b678a8a8a610b73565b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316610c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610df85781811015610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610669565b610df88484848403610b73565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610df8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611098610430565b8051602091820120604080518082018252600181527f310000000000000000000000000000000000000000000000000000000000000090840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b73ffffffffffffffffffffffffffffffffffffffff82166111b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610669565b80600260008282546111c49190611629565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166112cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610d1a565b600060208083528351808285015260005b81811015611411578581018301518582016040015282016113f5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461147457600080fd5b919050565b6000806040838503121561148c57600080fd5b61149583611450565b946020939093013593505050565b6000806000606084860312156114b857600080fd5b6114c184611450565b92506114cf60208501611450565b9150604084013590509250925092565b6000602082840312156114f157600080fd5b6114fa82611450565b9392505050565b600080600080600080600060e0888a03121561151c57600080fd5b61152588611450565b965061153360208901611450565b95506040880135945060608801359350608088013560ff8116811461155757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561158757600080fd5b61159083611450565b915061159e60208401611450565b90509250929050565b600181811c908216806115bb57607f821691505b6020821081036115f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104d6576104d66115fa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361166d5761166d6115fa565b506001019056fea26469706673582212208d88fee561cff7120d381c345cfc534cef8229a272dc5809d4bbb685ad67141164736f6c63430008110033a2646970667358221220914f18d5b241f0d10b2ebc814aadeee338ad60bad704683e414dad415cb2e14d64736f6c63430008140033" - }, - { - "contractName": "PolygonZkEVMBridge proxy", - "balance": "340282366920938463463374607431768211455", - "nonce": "1", - "address": "0xB7098a13a48EcE087d3DA15b2D28eCE0f89819B8", - "bytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b61009036600461086f565b610135565b61006b6100a336600461088a565b61017f565b3480156100b457600080fd5b506100bd6101f3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b61010136600461086f565b610231565b34801561011257600080fd5b506100bd61025e565b61012361028c565b61013361012e610363565b61036d565b565b61013d610391565b73ffffffffffffffffffffffffffffffffffffffff16330361017757610174816040518060200160405280600081525060006103d1565b50565b61017461011b565b610187610391565b73ffffffffffffffffffffffffffffffffffffffff1633036101eb576101e68383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506103d1915050565b505050565b6101e661011b565b60006101fd610391565b73ffffffffffffffffffffffffffffffffffffffff16330361022657610221610363565b905090565b61022e61011b565b90565b610239610391565b73ffffffffffffffffffffffffffffffffffffffff16330361017757610174816103fc565b6000610268610391565b73ffffffffffffffffffffffffffffffffffffffff16330361022657610221610391565b610294610391565b73ffffffffffffffffffffffffffffffffffffffff163303610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b600061022161045d565b3660008037600080366000845af43d6000803e80801561038c573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6103da83610485565b6000825111806103e75750805b156101e6576103f683836104d2565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610425610391565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a1610174816104fe565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103b5565b61048e8161060a565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606104f7838360405180606001604052806027815260200161099f602791396106d5565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff81166105a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161035a565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b73ffffffffffffffffffffffffffffffffffffffff81163b6106ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161035a565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105c4565b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516106ff9190610931565b600060405180830381855af49150503d806000811461073a576040519150601f19603f3d011682016040523d82523d6000602084013e61073f565b606091505b50915091506107508683838761075a565b9695505050505050565b606083156107f05782516000036107e95773ffffffffffffffffffffffffffffffffffffffff85163b6107e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161035a565b50816107fa565b6107fa8383610802565b949350505050565b8151156108125781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161035a919061094d565b803573ffffffffffffffffffffffffffffffffffffffff8116811461086a57600080fd5b919050565b60006020828403121561088157600080fd5b6104f782610846565b60008060006040848603121561089f57600080fd5b6108a884610846565b9250602084013567ffffffffffffffff808211156108c557600080fd5b818601915086601f8301126108d957600080fd5b8135818111156108e857600080fd5b8760208285010111156108fa57600080fd5b6020830194508093505050509250925092565b60005b83811015610928578181015183820152602001610910565b50506000910152565b6000825161094381846020870161090d565b9190910192915050565b602081526000825180602084015261096c81604085016020870161090d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220701a0c26bdd76686e63fc3c65e4f28a20ba3ecc8a60246733c0627e679c9804e64736f6c63430008140033", - "storage": { - "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000e34fe58dda5b8c6d547e4857e987633aa86a5e90", - "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000493732fb136a380920c390a85fc27d79c7b70756" - } - }, - { - "contractName": "PolygonZkEVMGlobalExitRootL2 implementation", - "balance": "0", - "nonce": "1", - "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "bytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806301fd904414610051578063257b36321461006d57806333d6247d1461008d578063a3c573eb146100a2575b600080fd5b61005a60015481565b6040519081526020015b60405180910390f35b61005a61007b366004610162565b60006020819052908152604090205481565b6100a061009b366004610162565b6100ee565b005b6100c97f000000000000000000000000b7098a13a48ece087d3da15b2d28ece0f89819b881565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610064565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b7098a13a48ece087d3da15b2d28ece0f89819b8161461015d576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b60006020828403121561017457600080fd5b503591905056fea2646970667358221220ea2171e2c85c8bff947affc409ef6fc6a8fe82fb8c174ddeda988651e595d66564736f6c63430008140033" - }, - { - "contractName": "PolygonZkEVMGlobalExitRootL2 proxy", - "balance": "0", - "nonce": "1", - "address": "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa", - "bytecode": "0x60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033", - "storage": { - "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000e34fe58dda5b8c6d547e4857e987633aa86a5e90", - "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9" - } - }, - { - "contractName": "PolygonZkEVMTimelock", - "balance": "0", - "nonce": "1", - "address": "0x0165878A594ca255338adfa4d48449f69242Eb8F", - "bytecode": "0x6080604052600436106101c65760003560e01c806364d62353116100f7578063b1c5f42711610095578063d547741f11610064578063d547741f14610661578063e38335e514610681578063f23a6e6114610694578063f27a0c92146106d957600080fd5b8063b1c5f427146105af578063bc197c81146105cf578063c4d252f514610614578063d45c44351461063457600080fd5b80638f61f4f5116100d15780638f61f4f5146104e157806391d1485414610515578063a217fddf14610566578063b08e51c01461057b57600080fd5b806364d62353146104815780638065657f146104a15780638f2a0bb0146104c157600080fd5b8063248a9ca31161016457806331d507501161013e57806331d50750146103c857806336568abe146103e85780633a6aae7214610408578063584b153e1461046157600080fd5b8063248a9ca3146103475780632ab0f529146103775780632f2ff15d146103a857600080fd5b80630d3cf6fc116101a05780630d3cf6fc1461026b578063134008d31461029f57806313bc9f20146102b2578063150b7a02146102d257600080fd5b806301d5062a146101d257806301ffc9a7146101f457806307bd02651461022957600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506101f26101ed366004611c52565b6106ee565b005b34801561020057600080fd5b5061021461020f366004611cc7565b610783565b60405190151581526020015b60405180910390f35b34801561023557600080fd5b5061025d7fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610220565b34801561027757600080fd5b5061025d7f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101f26102ad366004611d09565b6107df565b3480156102be57600080fd5b506102146102cd366004611d75565b6108d7565b3480156102de57600080fd5b506103166102ed366004611e9a565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610220565b34801561035357600080fd5b5061025d610362366004611d75565b60009081526020819052604090206001015490565b34801561038357600080fd5b50610214610392366004611d75565b6000908152600160208190526040909120541490565b3480156103b457600080fd5b506101f26103c3366004611f02565b6108fd565b3480156103d457600080fd5b506102146103e3366004611d75565b610927565b3480156103f457600080fd5b506101f2610403366004611f02565b610940565b34801561041457600080fd5b5061043c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610220565b34801561046d57600080fd5b5061021461047c366004611d75565b6109f8565b34801561048d57600080fd5b506101f261049c366004611d75565b610a0e565b3480156104ad57600080fd5b5061025d6104bc366004611d09565b610ade565b3480156104cd57600080fd5b506101f26104dc366004611f73565b610b1d565b3480156104ed57600080fd5b5061025d7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b34801561052157600080fd5b50610214610530366004611f02565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561057257600080fd5b5061025d600081565b34801561058757600080fd5b5061025d7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b3480156105bb57600080fd5b5061025d6105ca366004612025565b610d4f565b3480156105db57600080fd5b506103166105ea36600461214e565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b34801561062057600080fd5b506101f261062f366004611d75565b610d94565b34801561064057600080fd5b5061025d61064f366004611d75565b60009081526001602052604090205490565b34801561066d57600080fd5b506101f261067c366004611f02565b610e8f565b6101f261068f366004612025565b610eb4565b3480156106a057600080fd5b506103166106af3660046121f8565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106e557600080fd5b5061025d611161565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc161071881611244565b6000610728898989898989610ade565b90506107348184611251565b6000817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a604051610770969594939291906122a6565b60405180910390a3505050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107d957506107d98261139e565b92915050565b600080527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661085c5761085c8133611435565b600061086c888888888888610ade565b905061087881856114ed565b6108848888888861162a565b6000817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a6040516108bc94939291906122f1565b60405180910390a36108cd8161172e565b5050505050505050565b6000818152600160205260408120546001811180156108f65750428111155b9392505050565b60008281526020819052604090206001015461091881611244565b61092283836117d7565b505050565b60008181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109f482826118c7565b5050565b6000818152600160208190526040822054610939565b333014610a9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109e1565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b6000868686868686604051602001610afb969594939291906122a6565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b4781611244565b888714610bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b888514610c65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b6000610c778b8b8b8b8b8b8b8b610d4f565b9050610c838184611251565b60005b8a811015610d415780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610cc357610cc3612331565b9050602002016020810190610cd89190612360565b8d8d86818110610cea57610cea612331565b905060200201358c8c87818110610d0357610d03612331565b9050602002810190610d15919061237b565b8c8b604051610d29969594939291906122a6565b60405180910390a3610d3a8161240f565b9050610c86565b505050505050505050505050565b60008888888888888888604051602001610d709897969594939291906124f7565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610dbe81611244565b610dc7826109f8565b610e53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109e1565b6000828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b600082815260208190526040902060010154610eaa81611244565b61092283836118c7565b600080527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610f3157610f318133611435565b878614610fc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b87841461104f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b60006110618a8a8a8a8a8a8a8a610d4f565b905061106d81856114ed565b60005b8981101561114b5760008b8b8381811061108c5761108c612331565b90506020020160208101906110a19190612360565b905060008a8a848181106110b7576110b7612331565b9050602002013590503660008a8a868181106110d5576110d5612331565b90506020028101906110e7919061237b565b915091506110f78484848461162a565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588686868660405161112e94939291906122f1565b60405180910390a350505050806111449061240f565b9050611070565b506111558161172e565b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161580159061123257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa15801561120e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123291906125be565b1561123d5750600090565b5060025490565b61124e8133611435565b50565b61125a82610927565b156112e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109e1565b6112ef611161565b81101561137e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109e1565b61138881426125e0565b6000928352600160205260409092209190915550565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107d957507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107d9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109f4576114738161197e565b61147e83602061199d565b60405160200161148f929190612617565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109e191600401612698565b6114f6826108d7565b611582576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109e1565b80158061159e5750600081815260016020819052604090912054145b6109f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109e1565b60008473ffffffffffffffffffffffffffffffffffffffff168484846040516116549291906126e9565b60006040518083038185875af1925050503d8060008114611691576040519150601f19603f3d011682016040523d82523d6000602084013e611696565b606091505b5050905080611727576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109e1565b5050505050565b611737816108d7565b6117c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109e1565b600090815260016020819052604090912055565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109f45760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556118693390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109f45760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107d973ffffffffffffffffffffffffffffffffffffffff831660145b606060006119ac8360026126f9565b6119b79060026125e0565b67ffffffffffffffff8111156119cf576119cf611d8e565b6040519080825280601f01601f1916602001820160405280156119f9576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611a3057611a30612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a9357611a93612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000611acf8460026126f9565b611ada9060016125e0565b90505b6001811115611b77577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611b1b57611b1b612331565b1a60f81b828281518110611b3157611b31612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93611b7081612710565b9050611add565b5083156108f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109e1565b803573ffffffffffffffffffffffffffffffffffffffff81168114611c0457600080fd5b919050565b60008083601f840112611c1b57600080fd5b50813567ffffffffffffffff811115611c3357600080fd5b602083019150836020828501011115611c4b57600080fd5b9250929050565b600080600080600080600060c0888a031215611c6d57600080fd5b611c7688611be0565b965060208801359550604088013567ffffffffffffffff811115611c9957600080fd5b611ca58a828b01611c09565b989b979a50986060810135976080820135975060a09091013595509350505050565b600060208284031215611cd957600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108f657600080fd5b60008060008060008060a08789031215611d2257600080fd5b611d2b87611be0565b955060208701359450604087013567ffffffffffffffff811115611d4e57600080fd5b611d5a89828a01611c09565b979a9699509760608101359660809091013595509350505050565b600060208284031215611d8757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611e0457611e04611d8e565b604052919050565b600082601f830112611e1d57600080fd5b813567ffffffffffffffff811115611e3757611e37611d8e565b611e6860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611dbd565b818152846020838601011115611e7d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611eb057600080fd5b611eb985611be0565b9350611ec760208601611be0565b925060408501359150606085013567ffffffffffffffff811115611eea57600080fd5b611ef687828801611e0c565b91505092959194509250565b60008060408385031215611f1557600080fd5b82359150611f2560208401611be0565b90509250929050565b60008083601f840112611f4057600080fd5b50813567ffffffffffffffff811115611f5857600080fd5b6020830191508360208260051b8501011115611c4b57600080fd5b600080600080600080600080600060c08a8c031215611f9157600080fd5b893567ffffffffffffffff80821115611fa957600080fd5b611fb58d838e01611f2e565b909b50995060208c0135915080821115611fce57600080fd5b611fda8d838e01611f2e565b909950975060408c0135915080821115611ff357600080fd5b506120008c828d01611f2e565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b60008060008060008060008060a0898b03121561204157600080fd5b883567ffffffffffffffff8082111561205957600080fd5b6120658c838d01611f2e565b909a50985060208b013591508082111561207e57600080fd5b61208a8c838d01611f2e565b909850965060408b01359150808211156120a357600080fd5b506120b08b828c01611f2e565b999c989b509699959896976060870135966080013595509350505050565b600082601f8301126120df57600080fd5b8135602067ffffffffffffffff8211156120fb576120fb611d8e565b8160051b61210a828201611dbd565b928352848101820192828101908785111561212457600080fd5b83870192505b848310156121435782358252918301919083019061212a565b979650505050505050565b600080600080600060a0868803121561216657600080fd5b61216f86611be0565b945061217d60208701611be0565b9350604086013567ffffffffffffffff8082111561219a57600080fd5b6121a689838a016120ce565b945060608801359150808211156121bc57600080fd5b6121c889838a016120ce565b935060808801359150808211156121de57600080fd5b506121eb88828901611e0c565b9150509295509295909350565b600080600080600060a0868803121561221057600080fd5b61221986611be0565b945061222760208701611be0565b93506040860135925060608601359150608086013567ffffffffffffffff81111561225157600080fd5b6121eb88828901611e0c565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a0604082015260006122dc60a08301868861225d565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015260606040820152600061232760608301848661225d565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561237257600080fd5b6108f682611be0565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126123b057600080fd5b83018035915067ffffffffffffffff8211156123cb57600080fd5b602001915036819003821315611c4b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612440576124406123e0565b5060010190565b81835260006020808501808196508560051b810191508460005b878110156124ea57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126124a057600080fd5b8701858101903567ffffffffffffffff8111156124bc57600080fd5b8036038213156124cb57600080fd5b6124d686828461225d565b9a87019a9550505090840190600101612461565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156125455773ffffffffffffffffffffffffffffffffffffffff61253084611be0565b1682526020928301929091019060010161250a565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89111561257e57600080fd5b8860051b9150818a602083013701828103602090810160408501526125a69082018789612447565b60608401959095525050608001529695505050505050565b6000602082840312156125d057600080fd5b815180151581146108f657600080fd5b808201808211156107d9576107d96123e0565b60005b8381101561260e5781810151838201526020016125f6565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161264f8160178501602088016125f3565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161268c8160288401602088016125f3565b01602801949350505050565b60208152600082518060208401526126b78160408501602087016125f3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b8183823760009101908152919050565b80820281158282048414176107d9576107d96123e0565b60008161271f5761271f6123e0565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220c474c39da3523b28ebfa5fd66c05b42d6ddcc4a57055483bdda32888b366016164736f6c63430008140033", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000e10", - "0xaedcc9e7897c0d335bdc5d92fe3a8b4f23727fe558cd1c19f332b28716a30559": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0xf5e61edb9c9cc6bfbae4463e9a2b1dd6ac3b44ddef38f18016e56ba0363910d9": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x64494413541ff93b31aa309254e3fed72a7456e9845988b915b4c7a7ceba8814": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", - "0x60b9d94c75b7b3f721925089391e4644cd890cb5e6466f9596dfbd2c54e0b280": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x3412d5605ac6cd444957cedb533e5dacad6378b4bc819ebe3652188a665066d6": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", - "0x4b63b79f1e338a49559dcd3193ac9eecc50d0f275d24e97cc8c319e5a31a8bd0": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0xdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d706a": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", - "0x800d5dfe4bba53eedee06cd4546a27da8de00f12db83f56062976d4493fda899": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0xc3ad33e20b0c56a223ad5104fff154aa010f8715b9c981fd38fdc60a4d1a52fc": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5" - } - }, - { - "accountName": "keyless Deployer", - "balance": "0", - "nonce": "1", - "address": "0x28BB4e66addE1f042B77E04cf7D3784C1dcDBbA3" - }, - { - "accountName": "deployer", - "balance": "100000000000000000000000", - "nonce": "8", - "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" - } - ] - } \ No newline at end of file + "genesisBlockNumber": 136, + "root": "0x489e44072604e671274ea693d5309e797fb37a3e0d91e5b0f04639c251c05332", + "genesis": [ + { + "contractName": "PolygonZkEVMDeployer", + "balance": "0", + "nonce": "4", + "address": "0xFbD07134824dDEa24E4ae414c18ecbFa98169A24", + "bytecode": "0x60806040526004361061006e575f3560e01c8063715018a61161004c578063715018a6146100e25780638da5cb5b146100f6578063e11ae6cb1461011f578063f2fde38b14610132575f80fd5b80632b79805a146100725780634a94d487146100875780636d07dbf81461009a575b5f80fd5b610085610080366004610908565b610151565b005b6100856100953660046109a2565b6101c2565b3480156100a5575f80fd5b506100b96100b43660046109f5565b610203565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ed575f80fd5b50610085610215565b348015610101575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166100b9565b61008561012d366004610a15565b610228565b34801561013d575f80fd5b5061008561014c366004610a61565b61028e565b61015961034a565b5f6101658585856103ca565b90506101718183610527565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a15050505050565b6101ca61034a565b6101d583838361056a565b506040517f25adb19089b6a549831a273acdf7908cff8b7ee5f551f8d1d37996cf01c5df5b905f90a1505050565b5f61020e8383610598565b9392505050565b61021d61034a565b6102265f6105a4565b565b61023061034a565b5f61023c8484846103ca565b60405173ffffffffffffffffffffffffffffffffffffffff821681529091507fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a150505050565b61029661034a565b73ffffffffffffffffffffffffffffffffffffffff811661033e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610347816105a4565b50565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610226576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610335565b5f83471015610435576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610335565b81515f0361049f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610335565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff811661020e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610335565b606061020e83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250610618565b6060610590848484604051806060016040528060298152602001610b0860299139610618565b949350505050565b5f61020e83833061072d565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060824710156106aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610335565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516106d29190610a9c565b5f6040518083038185875af1925050503d805f811461070c576040519150601f19603f3d011682016040523d82523d5f602084013e610711565b606091505b509150915061072287838387610756565b979650505050505050565b5f604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b606083156107eb5782515f036107e45773ffffffffffffffffffffffffffffffffffffffff85163b6107e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610335565b5081610590565b61059083838151156108005781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103359190610ab7565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112610870575f80fd5b813567ffffffffffffffff8082111561088b5761088b610834565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156108d1576108d1610834565b816040528381528660208588010111156108e9575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f805f806080858703121561091b575f80fd5b8435935060208501359250604085013567ffffffffffffffff80821115610940575f80fd5b61094c88838901610861565b93506060870135915080821115610961575f80fd5b5061096e87828801610861565b91505092959194509250565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099d575f80fd5b919050565b5f805f606084860312156109b4575f80fd5b6109bd8461097a565b9250602084013567ffffffffffffffff8111156109d8575f80fd5b6109e486828701610861565b925050604084013590509250925092565b5f8060408385031215610a06575f80fd5b50508035926020909101359150565b5f805f60608486031215610a27575f80fd5b8335925060208401359150604084013567ffffffffffffffff811115610a4b575f80fd5b610a5786828701610861565b9150509250925092565b5f60208284031215610a71575f80fd5b61020e8261097a565b5f5b83811015610a94578181015183820152602001610a7c565b50505f910152565b5f8251610aad818460208701610a7a565b9190910192915050565b602081525f8251806020840152610ad5816040850160208701610a7a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220330b94dc698c4d290bf55c23f13b473cde6a6bae0030cb902de18af54e35839f64736f6c63430008140033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266" + } + }, + { + "contractName": "ProxyAdmin", + "balance": "0", + "nonce": "1", + "address": "0xfADB60b5059e31614e02083fF6C021a24C31c891", + "bytecode": "0x608060405260043610610079575f3560e01c80639623609d1161004c5780639623609d1461012357806399a88ec414610136578063f2fde38b14610155578063f3b7dead14610174575f80fd5b8063204e1c7a1461007d578063715018a6146100c55780637eff275e146100db5780638da5cb5b146100fa575b5f80fd5b348015610088575f80fd5b5061009c6100973660046105e8565b610193565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d0575f80fd5b506100d9610244565b005b3480156100e6575f80fd5b506100d96100f536600461060a565b610257565b348015610105575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff1661009c565b6100d961013136600461066e565b6102e0565b348015610141575f80fd5b506100d961015036600461060a565b610371565b348015610160575f80fd5b506100d961016f3660046105e8565b6103cd565b34801561017f575f80fd5b5061009c61018e3660046105e8565b610489565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b5f60405180830381855afa9150503d805f8114610215576040519150601f19603f3d011682016040523d82523d5f602084013e61021a565b606091505b509150915081610228575f80fd5b8080602001905181019061023c919061075b565b949350505050565b61024c6104d3565b6102555f610553565b565b61025f6104d3565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b5f604051808303815f87803b1580156102c6575f80fd5b505af11580156102d8573d5f803e3d5ffd5b505050505050565b6102e86104d3565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef28690349061033e9086908690600401610776565b5f604051808303818588803b158015610355575f80fd5b505af1158015610367573d5f803e3d5ffd5b5050505050505050565b6103796104d3565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102af565b6103d56104d3565b73ffffffffffffffffffffffffffffffffffffffff811661047d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61048681610553565b50565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610255576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610474565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81168114610486575f80fd5b5f602082840312156105f8575f80fd5b8135610603816105c7565b9392505050565b5f806040838503121561061b575f80fd5b8235610626816105c7565b91506020830135610636816105c7565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f805f60608486031215610680575f80fd5b833561068b816105c7565b9250602084013561069b816105c7565b9150604084013567ffffffffffffffff808211156106b7575f80fd5b818601915086601f8301126106ca575f80fd5b8135818111156106dc576106dc610641565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561072257610722610641565b8160405282815289602084870101111561073a575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f6020828403121561076b575f80fd5b8151610603816105c7565b73ffffffffffffffffffffffffffffffffffffffff831681525f602060408184015283518060408501525f5b818110156107be578581018301518582016060015282016107a2565b505f6060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050939250505056fea26469706673582212203083a4ccc2e42eed60bd19037f2efa77ed086dc7a5403f75bebb995dcba2221c64736f6c63430008140033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f" + } + }, + { + "contractName": "PolygonZkEVMBridge implementation", + "balance": "0", + "nonce": "1", + "address": "0x608484d3e94Fc775E3dCb06B0B48486c60A315e6", + "bytecode": "0x6080604052600436106101db575f3560e01c806383f24403116100fd578063ccaa2d1111610092578063ee25560b11610062578063ee25560b146105a9578063f5efcd79146105d4578063f811bff7146105f3578063fb57083414610612575f80fd5b8063ccaa2d111461053b578063cd5865791461055a578063d02103ca1461056d578063dbc1697614610595575f80fd5b8063bab161bf116100cd578063bab161bf146104b9578063be5831c7146104da578063c00f14ab146104fd578063cc4616321461051c575f80fd5b806383f244031461043d5780638ed7e3f21461045c578063aaa13cc21461047b578063b8b284d01461049a575f80fd5b80633cbc795b116101735780637843298b116101435780637843298b146103c257806379e2cf97146103e157806381b1c174146103f557806383c43a5514610429575f80fd5b80633cbc795b146103385780633e197043146103705780634b2f336d1461038f5780635ca1e165146103ae575f80fd5b806327aef4e8116101ae57806327aef4e81461026d5780632dfdf0b51461028e578063318aee3d146102b15780633c351e1014610319575f80fd5b806315064c96146101df5780632072f6c51461020d57806322e95f2c14610223578063240ff3781461025a575b5f80fd5b3480156101ea575f80fd5b506068546101f89060ff1681565b60405190151581526020015b60405180910390f35b348015610218575f80fd5b50610221610631565b005b34801561022e575f80fd5b5061024261023d366004612fb9565b610666565b6040516001600160a01b039091168152602001610204565b610221610268366004613040565b6106d0565b348015610278575f80fd5b50610281610759565b6040516102049190613102565b348015610299575f80fd5b506102a360535481565b604051908152602001610204565b3480156102bc575f80fd5b506102f56102cb36600461311b565b606b6020525f908152604090205463ffffffff81169064010000000090046001600160a01b031682565b6040805163ffffffff90931683526001600160a01b03909116602083015201610204565b348015610324575f80fd5b50606d54610242906001600160a01b031681565b348015610343575f80fd5b50606d5461035b90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610204565b34801561037b575f80fd5b506102a361038a366004613144565b6107e5565b34801561039a575f80fd5b50606f54610242906001600160a01b031681565b3480156103b9575f80fd5b506102a361088e565b3480156103cd575f80fd5b506102426103dc3660046131be565b61096a565b3480156103ec575f80fd5b50610221610993565b348015610400575f80fd5b5061024261040f366004613204565b606a6020525f90815260409020546001600160a01b031681565b348015610434575f80fd5b506102816109b4565b348015610448575f80fd5b506102a361045736600461322c565b6109d3565b348015610467575f80fd5b50606c54610242906001600160a01b031681565b348015610486575f80fd5b5061024261049536600461332d565b610aa8565b3480156104a5575f80fd5b506102216104b43660046133c3565b610be7565b3480156104c4575f80fd5b5060685461035b90610100900463ffffffff1681565b3480156104e5575f80fd5b5060685461035b90600160c81b900463ffffffff1681565b348015610508575f80fd5b5061028161051736600461311b565b610cc2565b348015610527575f80fd5b506101f8610536366004613441565b610d07565b348015610546575f80fd5b50610221610555366004613472565b610d8f565b610221610568366004613556565b6112c0565b348015610578575f80fd5b50606854610242906501000000000090046001600160a01b031681565b3480156105a0575f80fd5b5061022161172c565b3480156105b4575f80fd5b506102a36105c3366004613204565b60696020525f908152604090205481565b3480156105df575f80fd5b506102216105ee366004613472565b61175f565b3480156105fe575f80fd5b5061022161060d3660046135e6565b611a25565b34801561061d575f80fd5b506101f861062c366004613689565b611d40565b606c546001600160a01b0316331461065c57604051631736745960e31b815260040160405180910390fd5b610664611d57565b565b6040805160e084901b6001600160e01b031916602080830191909152606084901b6bffffffffffffffffffffffff1916602483015282516018818403018152603890920183528151918101919091205f908152606a90915220546001600160a01b03165b92915050565b60685460ff16156106f457604051630bc011ff60e21b815260040160405180910390fd5b341580159061070d5750606f546001600160a01b031615155b15610744576040517f6f625c4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610752858534868686611db2565b5050505050565b606e8054610766906136ce565b80601f0160208091040260200160405190810160405280929190818152602001828054610792906136ce565b80156107dd5780601f106107b4576101008083540402835291602001916107dd565b820191905f5260205f20905b8154815290600101906020018083116107c057829003601f168201915b505050505081565b6040517fff0000000000000000000000000000000000000000000000000000000000000060f889901b1660208201526001600160e01b031960e088811b821660218401526bffffffffffffffffffffffff19606089811b821660258601529188901b909216603984015285901b16603d82015260518101839052607181018290525f90609101604051602081830303815290604052805190602001209050979650505050505050565b6053545f90819081805b6020811015610961578083901c6001166001036108f557603381602081106108c2576108c2613706565b01546040805160208101929092528101859052606001604051602081830303815290604052805190602001209350610922565b60408051602081018690529081018390526060016040516020818303038152906040528051906020012093505b604080516020810184905290810183905260600160405160208183030381529060405280519060200120915080806109599061372e565b915050610898565b50919392505050565b5f61098b848461097985611e7c565b61098286611f66565b61049587612047565b949350505050565b605354606854600160c81b900463ffffffff16101561066457610664612114565b60405180611ba00160405280611b668152602001613d80611b66913981565b5f83815b6020811015610a9f57600163ffffffff8516821c81169003610a4257848160208110610a0557610a05613706565b602002013582604051602001610a25929190918252602082015260400190565b604051602081830303815290604052805190602001209150610a8d565b81858260208110610a5557610a55613706565b6020020135604051602001610a74929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b80610a978161372e565b9150506109d7565b50949350505050565b6040516001600160e01b031960e087901b1660208201526bffffffffffffffffffffffff19606086901b1660248201525f9081906038016040516020818303038152906040528051906020012090505f60ff60f81b308360405180611ba00160405280611b668152602001613d80611b669139898989604051602001610b3093929190613746565b60408051601f1981840301815290829052610b4e929160200161377e565b60405160208183030381529060405280519060200120604051602001610bc394939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051808303601f19018152919052805160209091012098975050505050505050565b60685460ff1615610c0b57604051630bc011ff60e21b815260040160405180910390fd5b606f546001600160a01b0316610c4d576040517fdde3cda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f54604051632770a7eb60e21b8152336004820152602481018690526001600160a01b0390911690639dc29fac906044015f604051808303815f87803b158015610c96575f80fd5b505af1158015610ca8573d5f803e3d5ffd5b50505050610cba868686868686611db2565b505050505050565b6060610ccd82611e7c565b610cd683611f66565b610cdf84612047565b604051602001610cf193929190613746565b6040516020818303038152906040529050919050565b6068545f908190610100900463ffffffff16158015610d2c575063ffffffff83166001145b15610d3e575063ffffffff8316610d66565b610d5364010000000063ffffffff85166137ac565b610d639063ffffffff86166137c3565b90505b600881901c5f90815260696020526040902054600160ff9092169190911b908116149392505050565b60685460ff1615610db357604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff8681166101009092041614610de3576040516302caf51760e11b815260040160405180910390fd5b610e168c8c8c8c8c610e115f8e8e8e8e8e8e8e604051610e049291906137d6565b60405180910390206107e5565b6121c2565b6001600160a01b038616610f6057606f546001600160a01b0316610efa575f6001600160a01b03851684825b6040519080825280601f01601f191660200182016040528015610e6c576020820181803683370190505b50604051610e7a91906137e5565b5f6040518083038185875af1925050503d805f8114610eb4576040519150601f19603f3d011682016040523d82523d5f602084013e610eb9565b606091505b5050905080610ef4576040517f6747a28800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611256565b606f546040516340c10f1960e01b81526001600160a01b03868116600483015260248201869052909116906340c10f19906044015f604051808303815f87803b158015610f45575f80fd5b505af1158015610f57573d5f803e3d5ffd5b50505050611256565b606d546001600160a01b038781169116148015610f8e5750606d5463ffffffff888116600160a01b90920416145b15610fa5575f6001600160a01b0385168482610e42565b60685463ffffffff610100909104811690881603610fd657610fd16001600160a01b0387168585612354565b611256565b6040516001600160e01b031960e089901b1660208201526bffffffffffffffffffffffff19606088901b1660248201525f9060380160408051601f1981840301815291815281516020928301205f818152606a9093529120549091506001600160a01b0316806111f5575f6110808386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506123d592505050565b6040516340c10f1960e01b81526001600160a01b03898116600483015260248201899052919250908216906340c10f19906044015f604051808303815f87803b1580156110cb575f80fd5b505af11580156110dd573d5f803e3d5ffd5b5050505080606a5f8581526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060405180604001604052808b63ffffffff1681526020018a6001600160a01b0316815250606b5f836001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548163ffffffff021916908363ffffffff1602179055506020820151815f0160046101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f490e59a1701b938786ac72570a1efeac994a3dbe96e2e883e19e902ace6e6a398a8a8388886040516111e7959493929190613828565b60405180910390a150611253565b6040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f19906044015f604051808303815f87803b15801561123c575f80fd5b505af115801561124e573d5f803e3d5ffd5b505050505b50505b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b60685460ff16156112e457604051630bc011ff60e21b815260040160405180910390fd5b6112ec612468565b60685463ffffffff61010090910481169088160361131d576040516302caf51760e11b815260040160405180910390fd5b5f806060876001600160a01b03881661141957883414611369576040517fb89240f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606d54606e80546001600160a01b0383169650600160a01b90920463ffffffff16945090611396906136ce565b80601f01602080910402602001604051908101604052809291908181526020018280546113c2906136ce565b801561140d5780601f106113e45761010080835404028352916020019161140d565b820191905f5260205f20905b8154815290600101906020018083116113f057829003601f168201915b505050505091506116a3565b3415611451576040517f798ee6f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546001600160a01b03908116908916036114c757604051632770a7eb60e21b8152336004820152602481018a90526001600160a01b03891690639dc29fac906044015f604051808303815f87803b1580156114ac575f80fd5b505af11580156114be573d5f803e3d5ffd5b505050506116a3565b6001600160a01b038089165f908152606b602090815260409182902082518084019093525463ffffffff811683526401000000009004909216918101829052901561157957604051632770a7eb60e21b8152336004820152602481018b90526001600160a01b038a1690639dc29fac906044015f604051808303815f87803b158015611551575f80fd5b505af1158015611563573d5f803e3d5ffd5b5050505080602001519450805f01519350611696565b851561158b5761158b898b89896124c1565b6040516370a0823160e01b81523060048201525f906001600160a01b038b16906370a0823190602401602060405180830381865afa1580156115cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f39190613860565b905061160a6001600160a01b038b1633308e612860565b6040516370a0823160e01b81523060048201525f906001600160a01b038c16906370a0823190602401602060405180830381865afa15801561164e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116729190613860565b905061167e8282613877565b6068548c9850610100900463ffffffff169650935050505b61169f89610cc2565b9250505b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b5f84868e8e86886053546040516116e298979695949392919061388a565b60405180910390a16117086117035f85878f8f8789805190602001206107e5565b6128b1565b861561171657611716612114565b5050505061172360018055565b50505050505050565b606c546001600160a01b0316331461175757604051631736745960e31b815260040160405180910390fd5b6106646129b2565b60685460ff161561178357604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff86811661010090920416146117b3576040516302caf51760e11b815260040160405180910390fd5b6117d58c8c8c8c8c610e1160018e8e8e8e8e8e8e604051610e049291906137d6565b606f545f906001600160a01b031661188857846001600160a01b031684888a868660405160240161180994939291906138f3565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161183e91906137e5565b5f6040518083038185875af1925050503d805f8114611878576040519150601f19603f3d011682016040523d82523d5f602084013e61187d565b606091505b505080915050611983565b606f546040516340c10f1960e01b81526001600160a01b03878116600483015260248201879052909116906340c10f19906044015f604051808303815f87803b1580156118d3575f80fd5b505af11580156118e5573d5f803e3d5ffd5b50505050846001600160a01b03168789858560405160240161190a94939291906138f3565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161193f91906137e5565b5f604051808303815f865af19150503d805f8114611978576040519150601f19603f3d011682016040523d82523d5f602084013e61197d565b606091505b50909150505b806119ba576040517f37e391c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518c815263ffffffff8a1660208201526001600160a01b0389811682840152871660608201526080810186905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a150505050505050505050505050565b5f54610100900460ff1615808015611a4357505f54600160ff909116105b80611a5c5750303b158015611a5c57505f5460ff166001145b611ad35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f805460ff191660011790558015611af4575f805461ff0019166101001790555b606880547fffffffffffffff000000000000000000000000000000000000000000000000ff1661010063ffffffff8a16027fffffffffffffff0000000000000000000000000000000000000000ffffffffff1617650100000000006001600160a01b038781169190910291909117909155606c805473ffffffffffffffffffffffffffffffffffffffff19168583161790558616611bcf5763ffffffff851615611bca576040517f1a874c1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ceb565b606d805463ffffffff8716600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009091166001600160a01b03891617179055606e611c1e8382613970565b50611cbd5f801b6012604051602001611ca991906060808252600d908201527f5772617070656420457468657200000000000000000000000000000000000000608082015260a0602082018190526004908201527f574554480000000000000000000000000000000000000000000000000000000060c082015260ff91909116604082015260e00190565b6040516020818303038152906040526123d5565b606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555b611cf3612a22565b8015611723575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b5f81611d4d8686866109d3565b1495945050505050565b60685460ff1615611d7b57604051630bc011ff60e21b815260040160405180910390fd5b6068805460ff191660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a5497905f90a1565b60685463ffffffff610100909104811690871603611de3576040516302caf51760e11b815260040160405180910390fd5b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b6001606860019054906101000a900463ffffffff16338989898888605354604051611e3799989796959493929190613a2c565b60405180910390a1611e6e6117036001606860019054906101000a900463ffffffff16338a8a8a8989604051610e049291906137d6565b8215610cba57610cba612114565b60408051600481526024810182526020810180516001600160e01b03167f06fdde030000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611edb91906137e5565b5f60405180830381855afa9150503d805f8114611f13576040519150601f19603f3d011682016040523d82523d5f602084013e611f18565b606091505b509150915081611f5d576040518060400160405280600781526020017f4e4f5f4e414d450000000000000000000000000000000000000000000000000081525061098b565b61098b81612a94565b60408051600481526024810182526020810180516001600160e01b03167f95d89b410000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611fc591906137e5565b5f60405180830381855afa9150503d805f8114611ffd576040519150601f19603f3d011682016040523d82523d5f602084013e612002565b606091505b509150915081611f5d576040518060400160405280600981526020017f4e4f5f53594d424f4c000000000000000000000000000000000000000000000081525061098b565b60408051600481526024810182526020810180516001600160e01b03167f313ce5670000000000000000000000000000000000000000000000000000000017905290515f91829182916001600160a01b038616916120a591906137e5565b5f60405180830381855afa9150503d805f81146120dd576040519150601f19603f3d011682016040523d82523d5f602084013e6120e2565b606091505b50915091508180156120f5575080516020145b61210057601261098b565b8080602001905181019061098b9190613a97565b6053546068805463ffffffff909216600160c81b027fffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117908190556001600160a01b0365010000000000909104166333d6247d61217561088e565b6040518263ffffffff1660e01b815260040161219391815260200190565b5f604051808303815f87803b1580156121aa575f80fd5b505af11580156121bc573d5f803e3d5ffd5b50505050565b606854604080516020808201879052818301869052825180830384018152606083019384905280519101207f257b36320000000000000000000000000000000000000000000000000000000090925260648101919091525f916501000000000090046001600160a01b03169063257b3632906084016020604051808303815f875af1158015612253573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122779190613860565b9050805f036122b1576040517e2f6fad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80680100000000000000008716156122f5578691506122d3848a8489611d40565b6122f0576040516338105f3b60e21b815260040160405180910390fd5b61233f565b602087901c612305816001613ab2565b9150879250612320612318868c866109d3565b8a8389611d40565b61233d576040516338105f3b60e21b815260040160405180910390fd5b505b6123498282612c64565b505050505050505050565b6040516001600160a01b0383166024820152604481018290526123d09084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612d24565b505050565b5f8060405180611ba00160405280611b668152602001613d80611b6691398360405160200161240592919061377e565b6040516020818303038152906040529050838151602083015ff591506001600160a01b038216612461576040517fbefb092000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092915050565b6002600154036124ba5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611aca565b6002600155565b5f6124cf6004828486613acf565b6124d891613af6565b90507f2afa5331000000000000000000000000000000000000000000000000000000006001600160e01b03198216016126b2575f80808080808061251f896004818d613acf565b81019061252c9190613b26565b9650965096509650965096509650336001600160a01b0316876001600160a01b03161461256c5760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03861630146125955760405163750643af60e01b815260040160405180910390fd5b8a85146125ce576040517f03fffc4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b0389811660248301528881166044830152606482018890526084820187905260ff861660a483015260c4820185905260e48083018590528351808403909101815261010490920183526020820180516001600160e01b03167fd505accf000000000000000000000000000000000000000000000000000000001790529151918e169161266591906137e5565b5f604051808303815f865af19150503d805f811461269e576040519150601f19603f3d011682016040523d82523d5f602084013e6126a3565b606091505b50505050505050505050610752565b6001600160e01b031981166323f2ebc360e21b146126fc576040517fe282c0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f808080808080806127118a6004818e613acf565b81019061271e9190613b75565b97509750975097509750975097509750336001600160a01b0316886001600160a01b0316146127605760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03871630146127895760405163750643af60e01b815260040160405180910390fd5b604080516001600160a01b038a811660248301528981166044830152606482018990526084820188905286151560a483015260ff861660c483015260e482018590526101048083018590528351808403909101815261012490920183526020820180516001600160e01b03166323f2ebc360e21b1790529151918f169161281091906137e5565b5f604051808303815f865af19150503d805f8114612849576040519150601f19603f3d011682016040523d82523d5f602084013e61284e565b606091505b50505050505050505050505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526121bc9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612399565b8060016128c060206002613cd3565b6128ca9190613877565b60535410612904576040517fef5ccf6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60535f81546129139061372e565b918290555090505f5b60208110156129a3578082901c60011660010361294f57826033826020811061294757612947613706565b015550505050565b6033816020811061296257612962613706565b01546040805160208101929092528101849052606001604051602081830303815290604052805190602001209250808061299b9061372e565b91505061291c565b506123d0613cde565b60018055565b60685460ff166129ee576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6068805460ff191690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b3905f90a1565b5f54610100900460ff16612a8c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611aca565b610664612e08565b60606040825110612ab357818060200190518101906106ca9190613cf2565b8151602003612c26575f5b602081108015612b055750828181518110612adb57612adb613706565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612b1c5780612b148161372e565b915050612abe565b805f03612b5e57505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b5f8167ffffffffffffffff811115612b7857612b78613268565b6040519080825280601f01601f191660200182016040528015612ba2576020820181803683370190505b5090505f5b82811015612c1e57848181518110612bc157612bc1613706565b602001015160f81c60f81b828281518110612bde57612bde613706565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535080612c168161372e565b915050612ba7565b509392505050565b505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b919050565b6068545f90610100900463ffffffff16158015612c87575063ffffffff82166001145b15612c99575063ffffffff8216612cc1565b612cae64010000000063ffffffff84166137ac565b612cbe9063ffffffff85166137c3565b90505b600881901c5f8181526069602052604081208054600160ff861690811b91821892839055929091908183169003611723576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612d78826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e729092919063ffffffff16565b8051909150156123d05780806020019051810190612d969190613d64565b6123d05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611aca565b5f54610100900460ff166129ac5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611aca565b606061098b84845f85855f80866001600160a01b03168587604051612e9791906137e5565b5f6040518083038185875af1925050503d805f8114612ed1576040519150601f19603f3d011682016040523d82523d5f602084013e612ed6565b606091505b5091509150612ee787838387612ef2565b979650505050505050565b60608315612f605782515f03612f59576001600160a01b0385163b612f595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611aca565b508161098b565b61098b8383815115612f755781518083602001fd5b8060405162461bcd60e51b8152600401611aca9190613102565b803563ffffffff81168114612c5f575f80fd5b6001600160a01b0381168114612fb6575f80fd5b50565b5f8060408385031215612fca575f80fd5b612fd383612f8f565b91506020830135612fe381612fa2565b809150509250929050565b8015158114612fb6575f80fd5b5f8083601f84011261300b575f80fd5b50813567ffffffffffffffff811115613022575f80fd5b602083019150836020828501011115613039575f80fd5b9250929050565b5f805f805f60808688031215613054575f80fd5b61305d86612f8f565b9450602086013561306d81612fa2565b9350604086013561307d81612fee565b9250606086013567ffffffffffffffff811115613098575f80fd5b6130a488828901612ffb565b969995985093965092949392505050565b5f5b838110156130cf5781810151838201526020016130b7565b50505f910152565b5f81518084526130ee8160208601602086016130b5565b601f01601f19169290920160200192915050565b602081525f61311460208301846130d7565b9392505050565b5f6020828403121561312b575f80fd5b813561311481612fa2565b60ff81168114612fb6575f80fd5b5f805f805f805f60e0888a03121561315a575f80fd5b873561316581613136565b965061317360208901612f8f565b9550604088013561318381612fa2565b945061319160608901612f8f565b935060808801356131a181612fa2565b9699959850939692959460a0840135945060c09093013592915050565b5f805f606084860312156131d0575f80fd5b6131d984612f8f565b925060208401356131e981612fa2565b915060408401356131f981612fa2565b809150509250925092565b5f60208284031215613214575f80fd5b5035919050565b8061040081018310156106ca575f80fd5b5f805f610440848603121561323f575f80fd5b83359250613250856020860161321b565b915061325f6104208501612f8f565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156132a5576132a5613268565b604052919050565b5f67ffffffffffffffff8211156132c6576132c6613268565b50601f01601f191660200190565b5f6132e66132e1846132ad565b61327c565b90508281528383830111156132f9575f80fd5b828260208301375f602084830101529392505050565b5f82601f83011261331e575f80fd5b613114838335602085016132d4565b5f805f805f60a08688031215613341575f80fd5b61334a86612f8f565b9450602086013561335a81612fa2565b9350604086013567ffffffffffffffff80821115613376575f80fd5b61338289838a0161330f565b94506060880135915080821115613397575f80fd5b506133a48882890161330f565b92505060808601356133b581613136565b809150509295509295909350565b5f805f805f8060a087890312156133d8575f80fd5b6133e187612f8f565b955060208701356133f181612fa2565b945060408701359350606087013561340881612fee565b9250608087013567ffffffffffffffff811115613423575f80fd5b61342f89828a01612ffb565b979a9699509497509295939492505050565b5f8060408385031215613452575f80fd5b61345b83612f8f565b915061346960208401612f8f565b90509250929050565b5f805f805f805f805f805f806109208d8f03121561348e575f80fd5b6134988e8e61321b565b9b506134a88e6104008f0161321b565b9a506108008d013599506108208d013598506108408d013597506134cf6108608e01612f8f565b96506134df6108808e0135612fa2565b6108808d013595506134f46108a08e01612f8f565b94506135046108c08e0135612fa2565b6108c08d013593506108e08d0135925067ffffffffffffffff6109008e0135111561352d575f80fd5b61353e8e6109008f01358f01612ffb565b81935080925050509295989b509295989b509295989b565b5f805f805f805f60c0888a03121561356c575f80fd5b61357588612f8f565b9650602088013561358581612fa2565b955060408801359450606088013561359c81612fa2565b935060808801356135ac81612fee565b925060a088013567ffffffffffffffff8111156135c7575f80fd5b6135d38a828b01612ffb565b989b979a50959850939692959293505050565b5f805f805f8060c087890312156135fb575f80fd5b61360487612f8f565b9550602087013561361481612fa2565b945061362260408801612f8f565b9350606087013561363281612fa2565b9250608087013561364281612fa2565b915060a087013567ffffffffffffffff81111561365d575f80fd5b8701601f8101891361366d575f80fd5b61367c898235602084016132d4565b9150509295509295509295565b5f805f80610460858703121561369d575f80fd5b843593506136ae866020870161321b565b92506136bd6104208601612f8f565b939692955092936104400135925050565b600181811c908216806136e257607f821691505b60208210810361370057634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161373f5761373f61371a565b5060010190565b606081525f61375860608301866130d7565b828103602084015261376a81866130d7565b91505060ff83166040830152949350505050565b5f835161378f8184602088016130b5565b8351908301906137a38183602088016130b5565b01949350505050565b80820281158282048414176106ca576106ca61371a565b808201808211156106ca576106ca61371a565b818382375f9101908152919050565b5f82516137f68184602087016130b5565b9190910192915050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b63ffffffff861681525f6001600160a01b03808716602084015280861660408401525060806060830152612ee7608083018486613800565b5f60208284031215613870575f80fd5b5051919050565b818103818111156106ca576106ca61371a565b5f61010060ff8b16835263ffffffff808b1660208501526001600160a01b03808b166040860152818a1660608601528089166080860152508660a08501528160c08501526138da828501876130d7565b925080851660e085015250509998505050505050505050565b6001600160a01b038516815263ffffffff84166020820152606060408201525f613921606083018486613800565b9695505050505050565b601f8211156123d0575f81815260208120601f850160051c810160208610156139515750805b601f850160051c820191505b81811015610cba5782815560010161395d565b815167ffffffffffffffff81111561398a5761398a613268565b61399e8161399884546136ce565b8461392b565b602080601f8311600181146139d1575f84156139ba5750858301515b5f19600386901b1c1916600185901b178555610cba565b5f85815260208120601f198616915b828110156139ff578886015182559484019460019091019084016139e0565b5085821015613a1c57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61010060ff8c16835263ffffffff808c1660208501526001600160a01b03808c166040860152818b166060860152808a166080860152508760a08501528160c0850152613a7d8285018789613800565b925080851660e085015250509a9950505050505050505050565b5f60208284031215613aa7575f80fd5b815161311481613136565b63ffffffff8181168382160190808211156124615761246161371a565b5f8085851115613add575f80fd5b83861115613ae9575f80fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613b1e5780818660040360031b1b83161692505b505092915050565b5f805f805f805f60e0888a031215613b3c575f80fd5b8735613b4781612fa2565b96506020880135613b5781612fa2565b9550604088013594506060880135935060808801356131a181613136565b5f805f805f805f80610100898b031215613b8d575f80fd5b8835613b9881612fa2565b97506020890135613ba881612fa2565b965060408901359550606089013594506080890135613bc681612fee565b935060a0890135613bd681613136565b979a969950949793969295929450505060c08201359160e0013590565b600181815b80851115613c2d57815f1904821115613c1357613c1361371a565b80851615613c2057918102915b93841c9390800290613bf8565b509250929050565b5f82613c43575060016106ca565b81613c4f57505f6106ca565b8160018114613c655760028114613c6f57613c8b565b60019150506106ca565b60ff841115613c8057613c8061371a565b50506001821b6106ca565b5060208310610133831016604e8410600b8410161715613cae575081810a6106ca565b613cb88383613bf3565b805f1904821115613ccb57613ccb61371a565b029392505050565b5f6131148383613c35565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215613d02575f80fd5b815167ffffffffffffffff811115613d18575f80fd5b8201601f81018413613d28575f80fd5b8051613d366132e1826132ad565b818152856020838501011115613d4a575f80fd5b613d5b8260208301602086016130b5565b95945050505050565b5f60208284031215613d74575f80fd5b815161311481612fee56fe6101006040523480156200001257600080fd5b5060405162001b6638038062001b6683398101604081905262000035916200028d565b82826003620000458382620003a1565b506004620000548282620003a1565b50503360c0525060ff811660e052466080819052620000739062000080565b60a052506200046d915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620000ad6200012e565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6060600380546200013f9062000312565b80601f01602080910402602001604051908101604052809291908181526020018280546200016d9062000312565b8015620001be5780601f106200019257610100808354040283529160200191620001be565b820191906000526020600020905b815481529060010190602001808311620001a057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f057600080fd5b81516001600160401b03808211156200020d576200020d620001c8565b604051601f8301601f19908116603f01168101908282118183101715620002385762000238620001c8565b816040528381526020925086838588010111156200025557600080fd5b600091505b838210156200027957858201830151818301840152908201906200025a565b600093810190920192909252949350505050565b600080600060608486031215620002a357600080fd5b83516001600160401b0380821115620002bb57600080fd5b620002c987838801620001de565b94506020860151915080821115620002e057600080fd5b50620002ef86828701620001de565b925050604084015160ff811681146200030757600080fd5b809150509250925092565b600181811c908216806200032757607f821691505b6020821081036200034857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039c57600081815260208120601f850160051c81016020861015620003775750805b601f850160051c820191505b81811015620003985782815560010162000383565b5050505b505050565b81516001600160401b03811115620003bd57620003bd620001c8565b620003d581620003ce845462000312565b846200034e565b602080601f8311600181146200040d5760008415620003f45750858301515b600019600386901b1c1916600185901b17855562000398565b600085815260208120601f198616915b828110156200043e578886015182559484019460019091019084016200041d565b50858210156200045d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516116aa620004bc6000396000610237015260008181610307015281816105c001526106a70152600061053a015260008181610379015261050401526116aa6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806370a08231116100d8578063a457c2d71161008c578063d505accf11610066578063d505accf1461039b578063dd62ed3e146103ae578063ffa1ad74146103f457600080fd5b8063a457c2d71461034e578063a9059cbb14610361578063cd0d00961461037457600080fd5b806395d89b41116100bd57806395d89b41146102e75780639dc29fac146102ef578063a3c573eb1461030257600080fd5b806370a08231146102915780637ecebe00146102c757600080fd5b806330adf81f1161012f5780633644e515116101145780633644e51514610261578063395093511461026957806340c10f191461027c57600080fd5b806330adf81f14610209578063313ce5671461023057600080fd5b806318160ddd1161016057806318160ddd146101bd57806320606b70146101cf57806323b872dd146101f657600080fd5b806306fdde031461017c578063095ea7b31461019a575b600080fd5b610184610430565b60405161019191906113e4565b60405180910390f35b6101ad6101a8366004611479565b6104c2565b6040519015158152602001610191565b6002545b604051908152602001610191565b6101c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6101ad6102043660046114a3565b6104dc565b6101c17f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610191565b6101c1610500565b6101ad610277366004611479565b61055c565b61028f61028a366004611479565b6105a8565b005b6101c161029f3660046114df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101c16102d53660046114df565b60056020526000908152604090205481565b610184610680565b61028f6102fd366004611479565b61068f565b6103297f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101ad61035c366004611479565b61075e565b6101ad61036f366004611479565b61082f565b6101c17f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103a9366004611501565b61083d565b6101c16103bc366004611574565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101846040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b60606003805461043f906115a7565b80601f016020809104026020016040519081016040528092919081815260200182805461046b906115a7565b80156104b85780601f1061048d576101008083540402835291602001916104b8565b820191906000526020600020905b81548152906001019060200180831161049b57829003601f168201915b5050505050905090565b6000336104d0818585610b73565b60019150505b92915050565b6000336104ea858285610d27565b6104f5858585610dfe565b506001949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610537576105324661106d565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104d090829086906105a3908790611629565b610b73565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084015b60405180910390fd5b61067c8282611135565b5050565b60606004805461043f906115a7565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d427269646765000000000000000000000000000000006064820152608401610669565b61067c8282611228565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610822576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610669565b6104f58286868403610b73565b6000336104d0818585610dfe565b834211156108cc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f546f6b656e577261707065643a3a7065726d69743a204578706972656420706560448201527f726d6974000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a9190866109268361163c565b9091555060408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610991610500565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610a55573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610ad057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f546f6b656e577261707065643a3a7065726d69743a20496e76616c696420736960448201527f676e6174757265000000000000000000000000000000000000000000000000006064820152608401610669565b610b678a8a8a610b73565b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316610c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610df85781811015610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610669565b610df88484848403610b73565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610df8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611098610430565b8051602091820120604080518082018252600181527f310000000000000000000000000000000000000000000000000000000000000090840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b73ffffffffffffffffffffffffffffffffffffffff82166111b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610669565b80600260008282546111c49190611629565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166112cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610d1a565b600060208083528351808285015260005b81811015611411578581018301518582016040015282016113f5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461147457600080fd5b919050565b6000806040838503121561148c57600080fd5b61149583611450565b946020939093013593505050565b6000806000606084860312156114b857600080fd5b6114c184611450565b92506114cf60208501611450565b9150604084013590509250925092565b6000602082840312156114f157600080fd5b6114fa82611450565b9392505050565b600080600080600080600060e0888a03121561151c57600080fd5b61152588611450565b965061153360208901611450565b95506040880135945060608801359350608088013560ff8116811461155757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561158757600080fd5b61159083611450565b915061159e60208401611450565b90509250929050565b600181811c908216806115bb57607f821691505b6020821081036115f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104d6576104d66115fa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361166d5761166d6115fa565b506001019056fea26469706673582212208d88fee561cff7120d381c345cfc534cef8229a272dc5809d4bbb685ad67141164736f6c63430008110033a2646970667358221220432f6d6b4446edbe1f73c19fd2115454d5c35d8b03b98a74fd46724151d7672264736f6c63430008140033" + }, + { + "contractName": "PolygonZkEVMBridge proxy", + "balance": "340282366920938463463374607431768211455", + "nonce": "1", + "address": "0xFe12ABaa190Ef0c8638Ee0ba9F828BF41368Ca0E", + "bytecode": "0x60806040526004361061005d575f3560e01c80635c60da1b116100425780635c60da1b146100a65780638f283970146100e3578063f851a440146101025761006c565b80633659cfe6146100745780634f1ef286146100935761006c565b3661006c5761006a610116565b005b61006a610116565b34801561007f575f80fd5b5061006a61008e366004610854565b610130565b61006a6100a136600461086d565b610178565b3480156100b1575f80fd5b506100ba6101eb565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ee575f80fd5b5061006a6100fd366004610854565b610228565b34801561010d575f80fd5b506100ba610255565b61011e610282565b61012e610129610359565b610362565b565b610138610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d8160405180602001604052805f8152505f6103bf565b50565b61016d610116565b610180610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101e3576101de8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250600192506103bf915050565b505050565b6101de610116565b5f6101f4610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610359565b905090565b610225610116565b90565b610230610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d816103e9565b5f61025e610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610380565b61028a610380565b73ffffffffffffffffffffffffffffffffffffffff16330361012e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b5f61021861044a565b365f80375f80365f845af43d5f803e80801561037c573d5ff35b3d5ffd5b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6103c883610471565b5f825111806103d45750805b156101de576103e383836104bd565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610412610380565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161016d816104e9565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103a3565b61047a816105f5565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606104e28383604051806060016040528060278152602001610977602791396106c0565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff811661058c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610350565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b73ffffffffffffffffffffffffffffffffffffffff81163b610699576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610350565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105af565b60605f808573ffffffffffffffffffffffffffffffffffffffff16856040516106e9919061090b565b5f60405180830381855af49150503d805f8114610721576040519150601f19603f3d011682016040523d82523d5f602084013e610726565b606091505b509150915061073786838387610741565b9695505050505050565b606083156107d65782515f036107cf5773ffffffffffffffffffffffffffffffffffffffff85163b6107cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610350565b50816107e0565b6107e083836107e8565b949350505050565b8151156107f85781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103509190610926565b803573ffffffffffffffffffffffffffffffffffffffff8116811461084f575f80fd5b919050565b5f60208284031215610864575f80fd5b6104e28261082c565b5f805f6040848603121561087f575f80fd5b6108888461082c565b9250602084013567ffffffffffffffff808211156108a4575f80fd5b818601915086601f8301126108b7575f80fd5b8135818111156108c5575f80fd5b8760208285010111156108d6575f80fd5b6020830194508093505050509250925092565b5f5b838110156109035781810151838201526020016108eb565b50505f910152565b5f825161091c8184602087016108e9565b9190910192915050565b602081525f82518060208401526109448160408501602087016108e9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202ac98acbfbb3d3ac1b74050e18c4e76db25a3ff2801ec69bf85d0c61414d502b64736f6c63430008140033", + "storage": { + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000fadb60b5059e31614e02083ff6c021a24c31c891", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000608484d3e94fc775e3dcb06b0b48486c60a315e6" + } + }, + { + "contractName": "PolygonZkEVMGlobalExitRootL2 implementation", + "balance": "0", + "nonce": "1", + "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + "bytecode": "0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c806301fd90441461004e578063257b36321461006a57806333d6247d14610089578063a3c573eb1461009e575b5f80fd5b61005760015481565b6040519081526020015b60405180910390f35b61005761007836600461015e565b5f6020819052908152604090205481565b61009c61009736600461015e565b6100ea565b005b6100c57f000000000000000000000000fe12abaa190ef0c8638ee0ba9f828bf41368ca0e81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610061565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000fe12abaa190ef0c8638ee0ba9f828bf41368ca0e1614610159576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b5f6020828403121561016e575f80fd5b503591905056fea26469706673582212205108c6c4f924146b736832a1bdf696e20d900450207b7452462368d150f2c71c64736f6c63430008140033" + }, + { + "contractName": "PolygonZkEVMGlobalExitRootL2 proxy", + "balance": "0", + "nonce": "1", + "address": "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa", + "bytecode": "0x60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033", + "storage": { + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000fadb60b5059e31614e02083ff6c021a24c31c891", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c9" + } + }, + { + "contractName": "PolygonZkEVMTimelock", + "balance": "0", + "nonce": "1", + "address": "0x0165878A594ca255338adfa4d48449f69242Eb8F", + "bytecode": "0x6080604052600436106101bd575f3560e01c806364d62353116100f2578063b1c5f42711610092578063d547741f11610062578063d547741f1461063a578063e38335e514610659578063f23a6e611461066c578063f27a0c92146106b0575f80fd5b8063b1c5f4271461058d578063bc197c81146105ac578063c4d252f5146105f0578063d45c44351461060f575f80fd5b80638f61f4f5116100cd5780638f61f4f5146104c557806391d14854146104f8578063a217fddf14610547578063b08e51c01461055a575f80fd5b806364d62353146104685780638065657f146104875780638f2a0bb0146104a6575f80fd5b8063248a9ca31161015d57806331d507501161013857806331d50750146103b357806336568abe146103d25780633a6aae72146103f1578063584b153e14610449575f80fd5b8063248a9ca3146103375780632ab0f529146103655780632f2ff15d14610394575f80fd5b80630d3cf6fc116101985780630d3cf6fc1461025e578063134008d31461029157806313bc9f20146102a4578063150b7a02146102c3575f80fd5b806301d5062a146101c857806301ffc9a7146101e957806307bd02651461021d575f80fd5b366101c457005b5f80fd5b3480156101d3575f80fd5b506101e76101e2366004611bf6565b6106c4565b005b3480156101f4575f80fd5b50610208610203366004611c65565b610757565b60405190151581526020015b60405180910390f35b348015610228575f80fd5b506102507fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610214565b348015610269575f80fd5b506102507f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101e761029f366004611ca4565b6107b2565b3480156102af575f80fd5b506102086102be366004611d0b565b6108a7565b3480156102ce575f80fd5b506103066102dd366004611e28565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610214565b348015610342575f80fd5b50610250610351366004611d0b565b5f9081526020819052604090206001015490565b348015610370575f80fd5b5061020861037f366004611d0b565b5f908152600160208190526040909120541490565b34801561039f575f80fd5b506101e76103ae366004611e8c565b6108cc565b3480156103be575f80fd5b506102086103cd366004611d0b565b6108f5565b3480156103dd575f80fd5b506101e76103ec366004611e8c565b61090d565b3480156103fc575f80fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b348015610454575f80fd5b50610208610463366004611d0b565b6109c5565b348015610473575f80fd5b506101e7610482366004611d0b565b6109da565b348015610492575f80fd5b506102506104a1366004611ca4565b610aaa565b3480156104b1575f80fd5b506101e76104c0366004611ef7565b610ae8565b3480156104d0575f80fd5b506102507fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b348015610503575f80fd5b50610208610512366004611e8c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610552575f80fd5b506102505f81565b348015610565575f80fd5b506102507ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b348015610598575f80fd5b506102506105a7366004611fa0565b610d18565b3480156105b7575f80fd5b506103066105c63660046120be565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b3480156105fb575f80fd5b506101e761060a366004611d0b565b610d5c565b34801561061a575f80fd5b50610250610629366004611d0b565b5f9081526001602052604090205490565b348015610645575f80fd5b506101e7610654366004611e8c565b610e56565b6101e7610667366004611fa0565b610e7a565b348015610677575f80fd5b50610306610686366004612161565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106bb575f80fd5b50610250611121565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc16106ee81611200565b5f6106fd898989898989610aaa565b9050610709818461120d565b5f817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a60405161074496959493929190612208565b60405180910390a3505050505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107ac57506107ac82611359565b92915050565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661082e5761082e81336113ef565b5f61083d888888888888610aaa565b905061084981856114a6565b610855888888886115e2565b5f817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a60405161088c9493929190612252565b60405180910390a361089d816116e2565b5050505050505050565b5f818152600160205260408120546001811180156108c55750428111155b9392505050565b5f828152602081905260409020600101546108e681611200565b6108f0838361178a565b505050565b5f8181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109c18282611878565b5050565b5f818152600160208190526040822054610906565b333014610a69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109ae565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b5f868686868686604051602001610ac696959493929190612208565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b1281611200565b888714610ba1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b888514610c30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f610c418b8b8b8b8b8b8b8b610d18565b9050610c4d818461120d565b5f5b8a811015610d0a5780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610c8c57610c8c612291565b9050602002016020810190610ca191906122be565b8d8d86818110610cb357610cb3612291565b905060200201358c8c87818110610ccc57610ccc612291565b9050602002810190610cde91906122d7565b8c8b604051610cf296959493929190612208565b60405180910390a3610d0381612365565b9050610c4f565b505050505050505050505050565b5f8888888888888888604051602001610d38989796959493929190612447565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610d8681611200565b610d8f826109c5565b610e1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109ae565b5f828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b5f82815260208190526040902060010154610e7081611200565b6108f08383611878565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610ef657610ef681336113ef565b878614610f85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b878414611014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f6110258a8a8a8a8a8a8a8a610d18565b905061103181856114a6565b5f5b8981101561110b575f8b8b8381811061104e5761104e612291565b905060200201602081019061106391906122be565b90505f8a8a8481811061107857611078612291565b905060200201359050365f8a8a8681811061109557611095612291565b90506020028101906110a791906122d7565b915091506110b7848484846115e2565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b58868686866040516110ee9493929190612252565b60405180910390a3505050508061110490612365565b9050611033565b50611115816116e2565b50505050505050505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16158015906111ef57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef919061250c565b156111f957505f90565b5060025490565b61120a81336113ef565b50565b611216826108f5565b156112a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109ae565b6112ab611121565b81101561133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109ae565b611344814261252b565b5f928352600160205260409092209190915550565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107ac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107ac565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c15761142c8161192d565b61143783602061194c565b604051602001611448929190612560565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109ae916004016125e0565b6114af826108a7565b61153b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b80158061155657505f81815260016020819052604090912054145b6109c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f8473ffffffffffffffffffffffffffffffffffffffff1684848460405161160b929190612630565b5f6040518083038185875af1925050503d805f8114611645576040519150601f19603f3d011682016040523d82523d5f602084013e61164a565b606091505b50509050806116db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109ae565b5050505050565b6116eb816108a7565b611777576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b5f90815260016020819052604090912055565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561181a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107ac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61195a83600261263f565b61196590600261252b565b67ffffffffffffffff81111561197d5761197d611d22565b6040519080825280601f01601f1916602001820160405280156119a7576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106119dd576119dd612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a3f57611a3f612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f611a7984600261263f565b611a8490600161252b565b90505b6001811115611b20577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611ac557611ac5612291565b1a60f81b828281518110611adb57611adb612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c93611b1981612656565b9050611a87565b5083156108c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109ae565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bac575f80fd5b919050565b5f8083601f840112611bc1575f80fd5b50813567ffffffffffffffff811115611bd8575f80fd5b602083019150836020828501011115611bef575f80fd5b9250929050565b5f805f805f805f60c0888a031215611c0c575f80fd5b611c1588611b89565b965060208801359550604088013567ffffffffffffffff811115611c37575f80fd5b611c438a828b01611bb1565b989b979a50986060810135976080820135975060a09091013595509350505050565b5f60208284031215611c75575f80fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108c5575f80fd5b5f805f805f8060a08789031215611cb9575f80fd5b611cc287611b89565b955060208701359450604087013567ffffffffffffffff811115611ce4575f80fd5b611cf089828a01611bb1565b979a9699509760608101359660809091013595509350505050565b5f60208284031215611d1b575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d9657611d96611d22565b604052919050565b5f82601f830112611dad575f80fd5b813567ffffffffffffffff811115611dc757611dc7611d22565b611df860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d4f565b818152846020838601011115611e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215611e3b575f80fd5b611e4485611b89565b9350611e5260208601611b89565b925060408501359150606085013567ffffffffffffffff811115611e74575f80fd5b611e8087828801611d9e565b91505092959194509250565b5f8060408385031215611e9d575f80fd5b82359150611ead60208401611b89565b90509250929050565b5f8083601f840112611ec6575f80fd5b50813567ffffffffffffffff811115611edd575f80fd5b6020830191508360208260051b8501011115611bef575f80fd5b5f805f805f805f805f60c08a8c031215611f0f575f80fd5b893567ffffffffffffffff80821115611f26575f80fd5b611f328d838e01611eb6565b909b50995060208c0135915080821115611f4a575f80fd5b611f568d838e01611eb6565b909950975060408c0135915080821115611f6e575f80fd5b50611f7b8c828d01611eb6565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b5f805f805f805f8060a0898b031215611fb7575f80fd5b883567ffffffffffffffff80821115611fce575f80fd5b611fda8c838d01611eb6565b909a50985060208b0135915080821115611ff2575f80fd5b611ffe8c838d01611eb6565b909850965060408b0135915080821115612016575f80fd5b506120238b828c01611eb6565b999c989b509699959896976060870135966080013595509350505050565b5f82601f830112612050575f80fd5b8135602067ffffffffffffffff82111561206c5761206c611d22565b8160051b61207b828201611d4f565b9283528481018201928281019087851115612094575f80fd5b83870192505b848310156120b35782358252918301919083019061209a565b979650505050505050565b5f805f805f60a086880312156120d2575f80fd5b6120db86611b89565b94506120e960208701611b89565b9350604086013567ffffffffffffffff80821115612105575f80fd5b61211189838a01612041565b94506060880135915080821115612126575f80fd5b61213289838a01612041565b93506080880135915080821115612147575f80fd5b5061215488828901611d9e565b9150509295509295909350565b5f805f805f60a08688031215612175575f80fd5b61217e86611b89565b945061218c60208701611b89565b93506040860135925060608601359150608086013567ffffffffffffffff8111156121b5575f80fd5b61215488828901611d9e565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a060408201525f61223d60a0830186886121c1565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f6122876060830184866121c1565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156122ce575f80fd5b6108c582611b89565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261230a575f80fd5b83018035915067ffffffffffffffff821115612324575f80fd5b602001915036819003821315611bef575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361239557612395612338565b5060010190565b8183525f6020808501808196508560051b81019150845f5b8781101561243a57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126123f2575f80fd5b8701858101903567ffffffffffffffff81111561240d575f80fd5b80360382131561241b575f80fd5b6124268682846121c1565b9a87019a95505050908401906001016123b4565b5091979650505050505050565b60a080825281018890525f8960c08301825b8b8110156124945773ffffffffffffffffffffffffffffffffffffffff61247f84611b89565b16825260209283019290910190600101612459565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156124cc575f80fd5b8860051b9150818a602083013701828103602090810160408501526124f4908201878961239c565b60608401959095525050608001529695505050505050565b5f6020828403121561251c575f80fd5b815180151581146108c5575f80fd5b808201808211156107ac576107ac612338565b5f5b83811015612558578181015183820152602001612540565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f835161259781601785016020880161253e565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516125d481602884016020880161253e565b01602801949350505050565b602081525f82518060208401526125fe81604085016020870161253e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b818382375f9101908152919050565b80820281158282048414176107ac576107ac612338565b5f8161266457612664612338565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220e28ae7494480ab1c619fd775dc5ff665588c808a910d66178a982c2e7c76a1e664736f6c63430008140033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000e10", + "0xaedcc9e7897c0d335bdc5d92fe3a8b4f23727fe558cd1c19f332b28716a30559": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xf5e61edb9c9cc6bfbae4463e9a2b1dd6ac3b44ddef38f18016e56ba0363910d9": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x64494413541ff93b31aa309254e3fed72a7456e9845988b915b4c7a7ceba8814": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", + "0x60b9d94c75b7b3f721925089391e4644cd890cb5e6466f9596dfbd2c54e0b280": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x3412d5605ac6cd444957cedb533e5dacad6378b4bc819ebe3652188a665066d6": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", + "0x4b63b79f1e338a49559dcd3193ac9eecc50d0f275d24e97cc8c319e5a31a8bd0": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d706a": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5", + "0x800d5dfe4bba53eedee06cd4546a27da8de00f12db83f56062976d4493fda899": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xc3ad33e20b0c56a223ad5104fff154aa010f8715b9c981fd38fdc60a4d1a52fc": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5" + } + }, + { + "accountName": "keyless Deployer", + "balance": "0", + "nonce": "1", + "address": "0x694AB5383a002a4796f95530c14Cf0C25ec3EA03" + }, + { + "accountName": "deployer", + "balance": "100000000000000000000000", + "nonce": "8", + "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + } + ] +} \ No newline at end of file diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 4cee07a09d..08dbc93431 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -453,7 +453,7 @@ services: zkevm-mock-l1-network: container_name: zkevm-mock-l1-network - image: hermeznetwork/geth-zkevm-contracts:v2.1.3-fork.8-geth1.12.0 + image: hermeznetwork/geth-zkevm-contracts:elderberry-fork.9-geth1.13.11 ports: - 8545:8545 - 8546:8546 diff --git a/test/e2e/jsonrpc2_test.go b/test/e2e/jsonrpc2_test.go index b2a3a2598f..fcd883a956 100644 --- a/test/e2e/jsonrpc2_test.go +++ b/test/e2e/jsonrpc2_test.go @@ -456,22 +456,27 @@ func TestCallMissingParameters(t *testing.T) { expectedError: types.ErrorObject{Code: types.InvalidParamsErrorCode, Message: "missing value for required argument 0"}, }, { - name: "params has only first parameter", - params: []interface{}{map[string]interface{}{"value": "0x1"}}, - expectedError: types.ErrorObject{Code: types.InvalidParamsErrorCode, Message: "missing value for required argument 1"}, + name: "params has only first parameter", + params: []interface{}{map[string]interface{}{"value": "0x1", "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92267"}}, }, } for _, network := range networks { - log.Infof("Network %s", network.Name) - for _, testCase := range testCases { + t.Logf("Network %s", network.Name) + for tc, testCase := range testCases { + t.Logf("testCase %d", tc) t.Run(network.Name+testCase.name, func(t *testing.T) { response, err := client.JSONRPCCall(network.URL, "eth_call", testCase.params...) require.NoError(t, err) - require.NotNil(t, response.Error) - require.Nil(t, response.Result) - require.Equal(t, testCase.expectedError.Code, response.Error.Code) - require.Equal(t, testCase.expectedError.Message, response.Error.Message) + if (testCase.expectedError != types.ErrorObject{}) { + require.NotNil(t, response.Error) + require.Nil(t, response.Result) + require.Equal(t, testCase.expectedError.Code, response.Error.Code) + require.Equal(t, testCase.expectedError.Message, response.Error.Message) + } else { + require.Nil(t, response.Error) + require.NotNil(t, response.Result) + } }) } } @@ -620,24 +625,39 @@ func TestEstimateGas(t *testing.T) { txToMsg, err := sc.Increment(auth) require.NoError(t, err) - // add funds to address 0x000...001 used in the test - nonce, err := ethereumClient.NonceAt(ctx, auth.From, nil) - require.NoError(t, err) - value := big.NewInt(1000) - require.NoError(t, err) - tx = ethTypes.NewTx(ðTypes.LegacyTx{ - Nonce: nonce, - To: state.Ptr(common.HexToAddress("0x1")), - Value: value, - Gas: 24000, - GasPrice: gasPrice, - }) - signedTx, err := auth.Signer(auth.From, tx) - require.NoError(t, err) - err = ethereumClient.SendTransaction(ctx, signedTx) - require.NoError(t, err) - err = operations.WaitTxToBeMined(ctx, ethereumClient, signedTx, operations.DefaultTimeoutTxToBeMined) - require.NoError(t, err) + // addresses the test needs to have balance + addressesToAddBalance := map[common.Address]*big.Int{ + // add funds to address 0x111...111 which is the default address + // when estimating TXs without specifying the sender + common.HexToAddress("0x1111111111111111111111111111111111111111"): big.NewInt(3000000000000000), + + // add funds to address 0x000...001 + common.HexToAddress("0x1"): big.NewInt(1000), + } + + for addr, value := range addressesToAddBalance { + nonce, err := ethereumClient.NonceAt(ctx, auth.From, nil) + require.NoError(t, err) + value := value + require.NoError(t, err) + tx = ethTypes.NewTx(ðTypes.LegacyTx{ + Nonce: nonce, + To: state.Ptr(addr), + Value: value, + Gas: 24000, + GasPrice: gasPrice, + }) + signedTx, err := auth.Signer(auth.From, tx) + require.NoError(t, err) + err = ethereumClient.SendTransaction(ctx, signedTx) + require.NoError(t, err) + err = operations.WaitTxToBeMined(ctx, ethereumClient, signedTx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + balance, err := ethereumClient.BalanceAt(ctx, addr, nil) + require.NoError(t, err) + log.Debugf("%v balance: %v", addr.String(), balance.String()) + } type testCase struct { name string @@ -670,19 +690,15 @@ func TestEstimateGas(t *testing.T) { name: "with gasPrice set and without from address", address: nil, setGasPrice: true, - expectedError: types.NewRPCError(-32000, "gas required exceeds allowance"), + expectedError: nil, + }, + { + name: "with gasPrice and value set and address with enough balance", + address: state.Ptr(auth.From), + value: state.Ptr(int64(1)), + setGasPrice: true, + expectedError: types.NewRPCError(-32000, "execution reverted"), }, - // TODO: This test is failing due to geth bug - // we can uncomment it when updating geth version - // on l1 image, it's returning error code -32000 when - // it should be returning error code 3 due to execution message - // { - // name: "with gasPrice and value set and address with enough balance", - // address: state.Ptr(auth.From), - // value: state.Ptr(int64(1)), - // setGasPrice: true, - // expectedError: types.NewRPCError(3, "execution reverted"), - // }, { name: "with gasPrice and value set and address without enough balance", address: state.Ptr(common.HexToAddress("0x1")), @@ -697,13 +713,21 @@ func TestEstimateGas(t *testing.T) { setGasPrice: true, expectedError: types.NewRPCError(-32000, "insufficient funds for transfer"), }, - { - name: "with gasPrice and value set and without from address", - address: nil, - value: state.Ptr(int64(-1)), - setGasPrice: true, - expectedError: types.NewRPCError(-32000, "insufficient funds for transfer"), - }, + // TODO = Review the test below in future versions of geth. + // + // Geth is returning -32000, "insufficient funds for transfer" + // zkEVM is returning 3, "execution reverted" + // + // Since the tx has value, the method increment is not payable + // and the default account has balance, the tx should revert + // + // { + // name: "with gasPrice and value set and without from address", + // address: nil, + // value: state.Ptr(int64(-1)), + // setGasPrice: true, + // expectedError: types.NewRPCError(-32000, "insufficient funds for transfer"), + // }, { name: "without gasPrice set and address with enough balance", address: state.Ptr(auth.From), @@ -746,7 +770,6 @@ func TestEstimateGas(t *testing.T) { if testCase.value != nil { v := *testCase.value if v == -1 { //set the value as acc balance + 1 to force overflow - msg.Value = common.Big0.Add(balance, common.Big1) } else { msg.Value = big.NewInt(0).SetInt64(v) From b1e688466dddc247eeb58d41428c564e6313853b Mon Sep 17 00:00:00 2001 From: agnusmor <100322135+agnusmor@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:30:03 +0200 Subject: [PATCH 04/23] Fix adding tx that matches with tx that is being processed (#3559) * fix adding tx that matches (same addr and nonce) tx that is being processing * fix generate mocks * fix updateCurrentNonceBalance --- sequencer/addrqueue.go | 4 ++++ sequencer/finalizer.go | 4 ++-- sequencer/worker.go | 20 ++++++++++++++++++++ test/Makefile | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/sequencer/addrqueue.go b/sequencer/addrqueue.go index 177521c449..9c0d8d996e 100644 --- a/sequencer/addrqueue.go +++ b/sequencer/addrqueue.go @@ -211,6 +211,10 @@ func (a *addrQueue) updateCurrentNonceBalance(nonce *uint64, balance *big.Int) ( if oldReadyTx != nil && oldReadyTx.Nonce > a.currentNonce { log.Infof("set readyTx %s as notReadyTx from addrQueue %s", oldReadyTx.HashStr, a.fromStr) a.notReadyTxs[oldReadyTx.Nonce] = oldReadyTx + } else if oldReadyTx != nil { // if oldReadyTx doesn't have a valid nonce then we add it to the txsToDelete + reason := runtime.ErrIntrinsicInvalidNonce.Error() + oldReadyTx.FailedReason = &reason + txsToDelete = append(txsToDelete, oldReadyTx) } return a.readyTx, oldReadyTx, txsToDelete diff --git a/sequencer/finalizer.go b/sequencer/finalizer.go index 305b809240..64c28604ce 100644 --- a/sequencer/finalizer.go +++ b/sequencer/finalizer.go @@ -345,8 +345,8 @@ func (f *finalizer) checkL1InfoTreeUpdate(ctx context.Context) { if firstL1InfoRootUpdate || l1InfoRoot.L1InfoTreeIndex > f.lastL1InfoTree.L1InfoTreeIndex { log.Infof("received new l1InfoRoot %s, index: %d, l1Block: %d", l1InfoRoot.L1InfoTreeRoot, l1InfoRoot.L1InfoTreeIndex, l1InfoRoot.BlockNumber) - // Check if new l1InfoRoot is valid. We skip it if l1InfoRoot.BlockNumber == 0 (empty tree) - if l1InfoRoot.BlockNumber > 0 { + // Check if new l1InfoRoot is valid. We skip it if l1InfoTreeIndex is 0 (it's a special case) + if l1InfoRoot.L1InfoTreeIndex > 0 { valid, err := f.checkValidL1InfoRoot(ctx, l1InfoRoot) if err != nil { log.Errorf("error validating new l1InfoRoot, index: %d, error: %v", l1InfoRoot.L1InfoTreeIndex, err) diff --git a/sequencer/worker.go b/sequencer/worker.go index a99f956fed..0d0b378872 100644 --- a/sequencer/worker.go +++ b/sequencer/worker.go @@ -23,6 +23,7 @@ type Worker struct { state stateInterface batchConstraints state.BatchConstraintsCfg readyTxsCond *timeoutCond + wipTx *TxTracker } // NewWorker creates an init a worker @@ -60,6 +61,12 @@ func (w *Worker) AddTxTracker(ctx context.Context, tx *TxTracker) (replacedTx *T return nil, pool.ErrOutOfCounters } + if (w.wipTx != nil) && (w.wipTx.FromStr == tx.FromStr) && (w.wipTx.Nonce == tx.Nonce) { + log.Infof("adding tx %s (nonce %d) from address %s that matches current processing tx %s (nonce %d), rejecting it as duplicated nonce", tx.Hash, tx.Nonce, tx.From, w.wipTx.Hash, w.wipTx.Nonce) + w.workerMutex.Unlock() + return nil, ErrDuplicatedNonce + } + addr, found := w.pool[tx.FromStr] if !found { // Unlock the worker to let execute other worker functions while creating the new AddrQueue @@ -174,6 +181,8 @@ func (w *Worker) MoveTxToNotReady(txHash common.Hash, from common.Address, actua defer w.workerMutex.Unlock() log.Debugf("move tx %s to notReady (from: %s, actualNonce: %d, actualBalance: %s)", txHash.String(), from.String(), actualNonce, actualBalance.String()) + w.resetWipTx(txHash) + addrQueue, found := w.pool[from.String()] if found { // Sanity check. The txHash must be the readyTx @@ -195,6 +204,8 @@ func (w *Worker) DeleteTx(txHash common.Hash, addr common.Address) { w.workerMutex.Lock() defer w.workerMutex.Unlock() + w.resetWipTx(txHash) + addrQueue, found := w.pool[addr.String()] if found { deletedReadyTx := addrQueue.deleteTx(txHash) @@ -293,6 +304,8 @@ func (w *Worker) GetBestFittingTx(resources state.BatchResources) (*TxTracker, e w.workerMutex.Lock() defer w.workerMutex.Unlock() + w.wipTx = nil + if w.txSortedList.len() == 0 { return nil, ErrTransactionsListEmpty } @@ -342,6 +355,7 @@ func (w *Worker) GetBestFittingTx(resources state.BatchResources) (*TxTracker, e if foundAt != -1 { log.Debugf("best fitting tx %s found at index %d with gasPrice %d", tx.HashStr, foundAt, tx.GasPrice) + w.wipTx = tx return tx, nil } else { return nil, ErrNoFittingTransaction @@ -382,3 +396,9 @@ func (w *Worker) addTxToSortedList(readyTx *TxTracker) { w.readyTxsCond.L.Unlock() } } + +func (w *Worker) resetWipTx(txHash common.Hash) { + if (w.wipTx != nil) && (w.wipTx.Hash == txHash) { + w.wipTx = nil + } +} diff --git a/test/Makefile b/test/Makefile index 306cb71c98..a2afd00d70 100644 --- a/test/Makefile +++ b/test/Makefile @@ -669,7 +669,7 @@ generate-mocks-sequencer: ## Generates mocks for sequencer , using mockery tool 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=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=../sequencer --output=../sequencer --outpkg=sequencer --inpackage --structname=EthermanMock --filename=mock_etherman.go .PHONY: generate-mocks-sequencesender generate-mocks-sequencesender: ## Generates mocks for sequencesender , using mockery tool From 9f7361d6f1886e3096d8fed518f1657fc7b3c42a Mon Sep 17 00:00:00 2001 From: Joan Esteban <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 16 Apr 2024 11:01:40 +0200 Subject: [PATCH 05/23] synchronizer: check l1blocks (#3546) * wip * run on background L1block checker * fix lint and documentation * fix conflict * add unittest * more unittest * fix lint * increase timeout for async unittest * fix unittest * rename GetResponse for GetResult and fix uniitest * add a second gorutines for check the newest blocks * more unittest * add unittest and run also preCheck on launch * by default Precheck from FINALIZED and SAFE * fix unittest, apply PR comments * changes suggested by ARR552 in integration method * fix documentation * import new network-l1-mock from PR#3553 * import new network-l1-mock from PR#3553 * import new network-l1-mock from PR#3553 * import new network-l1-mock from PR#3553 * fix unittest * fix PR comments * fix error * checkReorgAndExecuteReset can't be call with lastEthBlockSynced=nil * add parentHash to error * fix error * merge 3553 fix unittest * fix unittest * fix wrong merge * adapt parallel reorg detection to flow * fix unit tests * fix log * allow use sync parallel mode --------- Co-authored-by: Alonso --- config/default.go | 8 + docs/config-file/node-config-doc.html | 2 +- docs/config-file/node-config-doc.md | 165 ++++++++-- docs/config-file/node-config-schema.json | 51 +++ state/interfaces.go | 2 + state/mocks/mock_storage.go | 121 +++++++ state/pgstatestorage/block.go | 49 +++ state/pgstatestorage/pgstatestorage_test.go | 21 ++ synchronizer/common/reorg_error.go | 44 +++ .../syncinterfaces/async_l1_block_checker.go | 40 +++ .../common/syncinterfaces/etherman.go | 3 +- .../mocks/async_l1_block_checker.go | 196 ++++++++++++ .../mocks/l1_block_checker_integrator.go | 176 +++++++++++ .../mocks/state_full_interface.go | 181 +++++++++++ synchronizer/common/syncinterfaces/state.go | 3 + synchronizer/config.go | 32 ++ synchronizer/l1_check_block/async.go | 183 +++++++++++ synchronizer/l1_check_block/async_test.go | 138 ++++++++ synchronizer/l1_check_block/check_l1block.go | 146 +++++++++ .../l1_check_block/check_l1block_test.go | 128 ++++++++ synchronizer/l1_check_block/common.go | 5 + synchronizer/l1_check_block/integration.go | 205 ++++++++++++ .../l1_check_block/integration_test.go | 298 ++++++++++++++++++ .../l1_check_block/mocks/l1_block_checker.go | 82 +++++ .../l1_check_block/mocks/l1_requester.go | 98 ++++++ .../mocks/safe_l1_block_number_fetcher.go | 139 ++++++++ .../state_for_l1_block_checker_integration.go | 100 ++++++ .../l1_check_block/mocks/state_interfacer.go | 149 +++++++++ .../mocks/state_pre_check_interfacer.go | 101 ++++++ .../mocks/sync_check_reorger.go | 111 +++++++ .../l1_check_block/pre_check_l1block.go | 139 ++++++++ .../l1_check_block/pre_check_l1block_test.go | 144 +++++++++ synchronizer/l1_check_block/safe_l1_block.go | 120 +++++++ .../l1_check_block/safe_l1_block_test.go | 113 +++++++ .../l1_rollup_info_consumer.go | 14 +- synchronizer/synchronizer.go | 284 ++++++++++------- synchronizer/synchronizer_test.go | 115 +++++-- test/Makefile | 3 + test/e2e/jsonrpc2_test.go | 5 +- 39 files changed, 3754 insertions(+), 160 deletions(-) create mode 100644 synchronizer/common/reorg_error.go create mode 100644 synchronizer/common/syncinterfaces/async_l1_block_checker.go create mode 100644 synchronizer/common/syncinterfaces/mocks/async_l1_block_checker.go create mode 100644 synchronizer/common/syncinterfaces/mocks/l1_block_checker_integrator.go create mode 100644 synchronizer/l1_check_block/async.go create mode 100644 synchronizer/l1_check_block/async_test.go create mode 100644 synchronizer/l1_check_block/check_l1block.go create mode 100644 synchronizer/l1_check_block/check_l1block_test.go create mode 100644 synchronizer/l1_check_block/common.go create mode 100644 synchronizer/l1_check_block/integration.go create mode 100644 synchronizer/l1_check_block/integration_test.go create mode 100644 synchronizer/l1_check_block/mocks/l1_block_checker.go create mode 100644 synchronizer/l1_check_block/mocks/l1_requester.go create mode 100644 synchronizer/l1_check_block/mocks/safe_l1_block_number_fetcher.go create mode 100644 synchronizer/l1_check_block/mocks/state_for_l1_block_checker_integration.go create mode 100644 synchronizer/l1_check_block/mocks/state_interfacer.go create mode 100644 synchronizer/l1_check_block/mocks/state_pre_check_interfacer.go create mode 100644 synchronizer/l1_check_block/mocks/sync_check_reorger.go create mode 100644 synchronizer/l1_check_block/pre_check_l1block.go create mode 100644 synchronizer/l1_check_block/pre_check_l1block_test.go create mode 100644 synchronizer/l1_check_block/safe_l1_block.go create mode 100644 synchronizer/l1_check_block/safe_l1_block_test.go diff --git a/config/default.go b/config/default.go index a8971263ca..3f8a12407c 100644 --- a/config/default.go +++ b/config/default.go @@ -106,6 +106,14 @@ SyncBlockProtection = "safe" # latest, finalized, safe L1SynchronizationMode = "sequential" L1SyncCheckL2BlockHash = true L1SyncCheckL2BlockNumberhModulus = 30 + [Synchronizer.L1BlockCheck] + Enable = true + L1SafeBlockPoint = "finalized" + L1SafeBlockOffset = 0 + ForceCheckBeforeStart = true + PreCheckEnable = true + L1PreSafeBlockPoint = "safe" + L1PreSafeBlockOffset = 0 [Synchronizer.L1ParallelSynchronization] MaxClients = 10 MaxPendingNoProcessedBlocks = 25 diff --git a/docs/config-file/node-config-doc.html b/docs/config-file/node-config-doc.html index 9122c48735..99a31fd86e 100644 --- a/docs/config-file/node-config-doc.html +++ b/docs/config-file/node-config-doc.html @@ -16,7 +16,7 @@
"300ms"
 

Default: 500Type: number

MaxRequestsPerIPAndSecond defines how much requests a single IP can
send within a single second


Default: ""Type: string

SequencerNodeURI is used allow Non-Sequencer nodes
to relay transactions to the Sequencer node


Default: 0Type: integer

MaxCumulativeGasUsed is the max gas allowed per batch


WebSockets configuration
Default: trueType: boolean

Enabled defines if the WebSocket requests are enabled or disabled


Default: "0.0.0.0"Type: string

Host defines the network adapter that will be used to serve the WS requests


Default: 8546Type: integer

Port defines the port to serve the endpoints via WS


Default: 104857600Type: integer

ReadLimit defines the maximum size of a message read from the client (in bytes)


Default: trueType: boolean

EnableL2SuggestedGasPricePolling enables polling of the L2 gas price to block tx in the RPC with lower gas price.


Default: falseType: boolean

BatchRequestsEnabled defines if the Batch requests are enabled or disabled


Default: 20Type: integer

BatchRequestsLimit defines the limit of requests that can be incorporated into each batch request


Type: array of integer

L2Coinbase defines which address is going to receive the fees

Must contain a minimum of 20 items

Must contain a maximum of 20 items

Each item of this array must be:


Default: 10000Type: integer

MaxLogsCount is a configuration to set the max number of logs that can be returned
in a single call to the state, if zero it means no limit


Default: 10000Type: integer

MaxLogsBlockRange is a configuration to set the max range for block number when querying TXs
logs in a single call to the state, if zero it means no limit


Default: 60000Type: integer

MaxNativeBlockHashBlockRange is a configuration to set the max range for block number when querying
native block hashes in a single call to the state, if zero it means no limit


Default: trueType: boolean

EnableHttpLog allows the user to enable or disable the logs related to the HTTP
requests to be captured by the server.


ZKCountersLimits defines the ZK Counter limits
Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Configuration of service `Syncrhonizer`. For this service is also really important the value of `IsTrustedSequencer` because depending of this values is going to ask to a trusted node for trusted transactions or not
Default: "1s"Type: string

SyncInterval is the delay interval between reading new rollup information


Examples:

"1m"
 
"300ms"
-

Default: 100Type: integer

SyncChunkSize is the number of blocks to sync on each chunk


Default: ""Type: string

TrustedSequencerURL is the rpc url to connect and sync the trusted state


Default: "safe"Type: string

SyncBlockProtection specify the state to sync (lastest, finalized or safe)


Default: trueType: boolean

L1SyncCheckL2BlockHash if is true when a batch is closed is force to check L2Block hash against trustedNode (only apply for permissionless)


Default: 30Type: integer

L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check
a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...)


Default: "sequential"Type: enum (of string)

L1SynchronizationMode define how to synchronize with L1:
- parallel: Request data to L1 in parallel, and process sequentially. The advantage is that executor is not blocked waiting for L1 data
- sequential: Request data to L1 and execute

Must be one of:

  • "sequential"
  • "parallel"

L1ParallelSynchronization Configuration for parallel mode (if L1SynchronizationMode equal to 'parallel')
Default: 10Type: integer

MaxClients Number of clients used to synchronize with L1


Default: 25Type: integer

MaxPendingNoProcessedBlocks Size of the buffer used to store rollup information from L1, must be >= to NumberOfEthereumClientsToSync
sugested twice of NumberOfParallelOfEthereumClients


Default: "5s"Type: string

RequestLastBlockPeriod is the time to wait to request the
last block to L1 to known if we need to retrieve more data.
This value only apply when the system is synchronized


Examples:

"1m"
+

Default: 100Type: integer

SyncChunkSize is the number of blocks to sync on each chunk


Default: ""Type: string

TrustedSequencerURL is the rpc url to connect and sync the trusted state


Default: "safe"Type: string

SyncBlockProtection specify the state to sync (lastest, finalized or safe)


Default: trueType: boolean

L1SyncCheckL2BlockHash if is true when a batch is closed is force to check L2Block hash against trustedNode (only apply for permissionless)


Default: 30Type: integer

L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check
a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...)


Default: trueType: boolean

Enable if is true then the check l1 Block Hash is active


Default: "finalized"Type: enum (of string)

L1SafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest

Must be one of:

  • "finalized"
  • "safe"
  • "latest"

Default: 0Type: integer

L1SafeBlockOffset is the offset to add to L1SafeBlockPoint as a safe point
it can be positive or negative
Example: L1SafeBlockPoint= finalized, L1SafeBlockOffset= -10, then the safe block ten blocks before the finalized block


Default: trueType: boolean

ForceCheckBeforeStart if is true then the first time the system is started it will force to check all pending blocks


Default: trueType: boolean

PreCheckEnable if is true then the pre-check is active, will check blocks between L1SafeBlock and L1PreSafeBlock


Default: "safe"Type: enum (of string)

L1PreSafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest

Must be one of:

  • "finalized"
  • "safe"
  • "latest"

Default: 0Type: integer

L1PreSafeBlockOffset is the offset to add to L1PreSafeBlockPoint as a safe point
it can be positive or negative
Example: L1PreSafeBlockPoint= finalized, L1PreSafeBlockOffset= -10, then the safe block ten blocks before the finalized block


Default: "sequential"Type: enum (of string)

L1SynchronizationMode define how to synchronize with L1:
- parallel: Request data to L1 in parallel, and process sequentially. The advantage is that executor is not blocked waiting for L1 data
- sequential: Request data to L1 and execute

Must be one of:

  • "sequential"
  • "parallel"

L1ParallelSynchronization Configuration for parallel mode (if L1SynchronizationMode equal to 'parallel')
Default: 10Type: integer

MaxClients Number of clients used to synchronize with L1


Default: 25Type: integer

MaxPendingNoProcessedBlocks Size of the buffer used to store rollup information from L1, must be >= to NumberOfEthereumClientsToSync
sugested twice of NumberOfParallelOfEthereumClients


Default: "5s"Type: string

RequestLastBlockPeriod is the time to wait to request the
last block to L1 to known if we need to retrieve more data.
This value only apply when the system is synchronized


Examples:

"1m"
 
"300ms"
 

Consumer Configuration for the consumer of rollup information from L1
Default: "5s"Type: string

AceptableInacctivityTime is the expected maximum time that the consumer
could wait until new data is produced. If the time is greater it emmit a log to warn about
that. The idea is keep working the consumer as much as possible, so if the producer is not
fast enought then you could increse the number of parallel clients to sync with L1


Examples:

"1m"
 
"300ms"
diff --git a/docs/config-file/node-config-doc.md b/docs/config-file/node-config-doc.md
index 23619596c8..9a94f41ced 100644
--- a/docs/config-file/node-config-doc.md
+++ b/docs/config-file/node-config-doc.md
@@ -1342,6 +1342,7 @@ because depending of this values is going to ask to a trusted node for trusted t
 | - [SyncBlockProtection](#Synchronizer_SyncBlockProtection )                           | No      | string           | No         | -          | SyncBlockProtection specify the state to sync (lastest, finalized or safe)                                                                                                                                                                              |
 | - [L1SyncCheckL2BlockHash](#Synchronizer_L1SyncCheckL2BlockHash )                     | No      | boolean          | No         | -          | L1SyncCheckL2BlockHash if is true when a batch is closed is force to check  L2Block hash against trustedNode (only apply for permissionless)                                                                                                            |
 | - [L1SyncCheckL2BlockNumberhModulus](#Synchronizer_L1SyncCheckL2BlockNumberhModulus ) | No      | integer          | No         | -          | L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check
a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...) | +| - [L1BlockCheck](#Synchronizer_L1BlockCheck ) | No | object | No | - | - | | - [L1SynchronizationMode](#Synchronizer_L1SynchronizationMode ) | No | enum (of string) | No | - | L1SynchronizationMode define how to synchronize with L1:
- parallel: Request data to L1 in parallel, and process sequentially. The advantage is that executor is not blocked waiting for L1 data
- sequential: Request data to L1 and execute | | - [L1ParallelSynchronization](#Synchronizer_L1ParallelSynchronization ) | No | object | No | - | L1ParallelSynchronization Configuration for parallel mode (if L1SynchronizationMode equal to 'parallel') | | - [L2Synchronization](#Synchronizer_L2Synchronization ) | No | object | No | - | L2Synchronization Configuration for L2 synchronization | @@ -1443,7 +1444,135 @@ a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...) L1SyncCheckL2BlockNumberhModulus=30 ``` -### 9.7. `Synchronizer.L1SynchronizationMode` +### 9.7. `[Synchronizer.L1BlockCheck]` + +**Type:** : `object` + +| Property | Pattern | Type | Deprecated | Definition | Title/Description | +| ---------------------------------------------------------------------------- | ------- | ---------------- | ---------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| - [Enable](#Synchronizer_L1BlockCheck_Enable ) | No | boolean | No | - | Enable if is true then the check l1 Block Hash is active | +| - [L1SafeBlockPoint](#Synchronizer_L1BlockCheck_L1SafeBlockPoint ) | No | enum (of string) | No | - | L1SafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest | +| - [L1SafeBlockOffset](#Synchronizer_L1BlockCheck_L1SafeBlockOffset ) | No | integer | No | - | L1SafeBlockOffset is the offset to add to L1SafeBlockPoint as a safe point
it can be positive or negative
Example: L1SafeBlockPoint= finalized, L1SafeBlockOffset= -10, then the safe block ten blocks before the finalized block | +| - [ForceCheckBeforeStart](#Synchronizer_L1BlockCheck_ForceCheckBeforeStart ) | No | boolean | No | - | ForceCheckBeforeStart if is true then the first time the system is started it will force to check all pending blocks | +| - [PreCheckEnable](#Synchronizer_L1BlockCheck_PreCheckEnable ) | No | boolean | No | - | PreCheckEnable if is true then the pre-check is active, will check blocks between L1SafeBlock and L1PreSafeBlock | +| - [L1PreSafeBlockPoint](#Synchronizer_L1BlockCheck_L1PreSafeBlockPoint ) | No | enum (of string) | No | - | L1PreSafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest | +| - [L1PreSafeBlockOffset](#Synchronizer_L1BlockCheck_L1PreSafeBlockOffset ) | No | integer | No | - | L1PreSafeBlockOffset is the offset to add to L1PreSafeBlockPoint as a safe point
it can be positive or negative
Example: L1PreSafeBlockPoint= finalized, L1PreSafeBlockOffset= -10, then the safe block ten blocks before the finalized block | + +#### 9.7.1. `Synchronizer.L1BlockCheck.Enable` + +**Type:** : `boolean` + +**Default:** `true` + +**Description:** Enable if is true then the check l1 Block Hash is active + +**Example setting the default value** (true): +``` +[Synchronizer.L1BlockCheck] +Enable=true +``` + +#### 9.7.2. `Synchronizer.L1BlockCheck.L1SafeBlockPoint` + +**Type:** : `enum (of string)` + +**Default:** `"finalized"` + +**Description:** L1SafeBlockPoint is the point that a block is considered safe enough to be checked +it can be: finalized, safe,pending or latest + +**Example setting the default value** ("finalized"): +``` +[Synchronizer.L1BlockCheck] +L1SafeBlockPoint="finalized" +``` + +Must be one of: +* "finalized" +* "safe" +* "latest" + +#### 9.7.3. `Synchronizer.L1BlockCheck.L1SafeBlockOffset` + +**Type:** : `integer` + +**Default:** `0` + +**Description:** L1SafeBlockOffset is the offset to add to L1SafeBlockPoint as a safe point +it can be positive or negative +Example: L1SafeBlockPoint= finalized, L1SafeBlockOffset= -10, then the safe block ten blocks before the finalized block + +**Example setting the default value** (0): +``` +[Synchronizer.L1BlockCheck] +L1SafeBlockOffset=0 +``` + +#### 9.7.4. `Synchronizer.L1BlockCheck.ForceCheckBeforeStart` + +**Type:** : `boolean` + +**Default:** `true` + +**Description:** ForceCheckBeforeStart if is true then the first time the system is started it will force to check all pending blocks + +**Example setting the default value** (true): +``` +[Synchronizer.L1BlockCheck] +ForceCheckBeforeStart=true +``` + +#### 9.7.5. `Synchronizer.L1BlockCheck.PreCheckEnable` + +**Type:** : `boolean` + +**Default:** `true` + +**Description:** PreCheckEnable if is true then the pre-check is active, will check blocks between L1SafeBlock and L1PreSafeBlock + +**Example setting the default value** (true): +``` +[Synchronizer.L1BlockCheck] +PreCheckEnable=true +``` + +#### 9.7.6. `Synchronizer.L1BlockCheck.L1PreSafeBlockPoint` + +**Type:** : `enum (of string)` + +**Default:** `"safe"` + +**Description:** L1PreSafeBlockPoint is the point that a block is considered safe enough to be checked +it can be: finalized, safe,pending or latest + +**Example setting the default value** ("safe"): +``` +[Synchronizer.L1BlockCheck] +L1PreSafeBlockPoint="safe" +``` + +Must be one of: +* "finalized" +* "safe" +* "latest" + +#### 9.7.7. `Synchronizer.L1BlockCheck.L1PreSafeBlockOffset` + +**Type:** : `integer` + +**Default:** `0` + +**Description:** L1PreSafeBlockOffset is the offset to add to L1PreSafeBlockPoint as a safe point +it can be positive or negative +Example: L1PreSafeBlockPoint= finalized, L1PreSafeBlockOffset= -10, then the safe block ten blocks before the finalized block + +**Example setting the default value** (0): +``` +[Synchronizer.L1BlockCheck] +L1PreSafeBlockOffset=0 +``` + +### 9.8. `Synchronizer.L1SynchronizationMode` **Type:** : `enum (of string)` @@ -1463,7 +1592,7 @@ Must be one of: * "sequential" * "parallel" -### 9.8. `[Synchronizer.L1ParallelSynchronization]` +### 9.9. `[Synchronizer.L1ParallelSynchronization]` **Type:** : `object` **Description:** L1ParallelSynchronization Configuration for parallel mode (if L1SynchronizationMode equal to 'parallel') @@ -1481,7 +1610,7 @@ Must be one of: | - [RollupInfoRetriesSpacing](#Synchronizer_L1ParallelSynchronization_RollupInfoRetriesSpacing ) | No | string | No | - | Duration | | - [FallbackToSequentialModeOnSynchronized](#Synchronizer_L1ParallelSynchronization_FallbackToSequentialModeOnSynchronized ) | No | boolean | No | - | FallbackToSequentialModeOnSynchronized if true switch to sequential mode if the system is synchronized | -#### 9.8.1. `Synchronizer.L1ParallelSynchronization.MaxClients` +#### 9.9.1. `Synchronizer.L1ParallelSynchronization.MaxClients` **Type:** : `integer` @@ -1495,7 +1624,7 @@ Must be one of: MaxClients=10 ``` -#### 9.8.2. `Synchronizer.L1ParallelSynchronization.MaxPendingNoProcessedBlocks` +#### 9.9.2. `Synchronizer.L1ParallelSynchronization.MaxPendingNoProcessedBlocks` **Type:** : `integer` @@ -1510,7 +1639,7 @@ sugested twice of NumberOfParallelOfEthereumClients MaxPendingNoProcessedBlocks=25 ``` -#### 9.8.3. `Synchronizer.L1ParallelSynchronization.RequestLastBlockPeriod` +#### 9.9.3. `Synchronizer.L1ParallelSynchronization.RequestLastBlockPeriod` **Title:** Duration @@ -1538,7 +1667,7 @@ This value only apply when the system is synchronized RequestLastBlockPeriod="5s" ``` -#### 9.8.4. `[Synchronizer.L1ParallelSynchronization.PerformanceWarning]` +#### 9.9.4. `[Synchronizer.L1ParallelSynchronization.PerformanceWarning]` **Type:** : `object` **Description:** Consumer Configuration for the consumer of rollup information from L1 @@ -1548,7 +1677,7 @@ RequestLastBlockPeriod="5s" | - [AceptableInacctivityTime](#Synchronizer_L1ParallelSynchronization_PerformanceWarning_AceptableInacctivityTime ) | No | string | No | - | Duration | | - [ApplyAfterNumRollupReceived](#Synchronizer_L1ParallelSynchronization_PerformanceWarning_ApplyAfterNumRollupReceived ) | No | integer | No | - | ApplyAfterNumRollupReceived is the number of iterations to
start checking the time waiting for new rollup info data | -##### 9.8.4.1. `Synchronizer.L1ParallelSynchronization.PerformanceWarning.AceptableInacctivityTime` +##### 9.9.4.1. `Synchronizer.L1ParallelSynchronization.PerformanceWarning.AceptableInacctivityTime` **Title:** Duration @@ -1577,7 +1706,7 @@ fast enought then you could increse the number of parallel clients to sync with AceptableInacctivityTime="5s" ``` -##### 9.8.4.2. `Synchronizer.L1ParallelSynchronization.PerformanceWarning.ApplyAfterNumRollupReceived` +##### 9.9.4.2. `Synchronizer.L1ParallelSynchronization.PerformanceWarning.ApplyAfterNumRollupReceived` **Type:** : `integer` @@ -1592,7 +1721,7 @@ start checking the time waiting for new rollup info data ApplyAfterNumRollupReceived=10 ``` -#### 9.8.5. `Synchronizer.L1ParallelSynchronization.RequestLastBlockTimeout` +#### 9.9.5. `Synchronizer.L1ParallelSynchronization.RequestLastBlockTimeout` **Title:** Duration @@ -1618,7 +1747,7 @@ ApplyAfterNumRollupReceived=10 RequestLastBlockTimeout="5s" ``` -#### 9.8.6. `Synchronizer.L1ParallelSynchronization.RequestLastBlockMaxRetries` +#### 9.9.6. `Synchronizer.L1ParallelSynchronization.RequestLastBlockMaxRetries` **Type:** : `integer` @@ -1632,7 +1761,7 @@ RequestLastBlockTimeout="5s" RequestLastBlockMaxRetries=3 ``` -#### 9.8.7. `Synchronizer.L1ParallelSynchronization.StatisticsPeriod` +#### 9.9.7. `Synchronizer.L1ParallelSynchronization.StatisticsPeriod` **Title:** Duration @@ -1658,7 +1787,7 @@ RequestLastBlockMaxRetries=3 StatisticsPeriod="5m0s" ``` -#### 9.8.8. `Synchronizer.L1ParallelSynchronization.TimeOutMainLoop` +#### 9.9.8. `Synchronizer.L1ParallelSynchronization.TimeOutMainLoop` **Title:** Duration @@ -1684,7 +1813,7 @@ StatisticsPeriod="5m0s" TimeOutMainLoop="5m0s" ``` -#### 9.8.9. `Synchronizer.L1ParallelSynchronization.RollupInfoRetriesSpacing` +#### 9.9.9. `Synchronizer.L1ParallelSynchronization.RollupInfoRetriesSpacing` **Title:** Duration @@ -1710,7 +1839,7 @@ TimeOutMainLoop="5m0s" RollupInfoRetriesSpacing="5s" ``` -#### 9.8.10. `Synchronizer.L1ParallelSynchronization.FallbackToSequentialModeOnSynchronized` +#### 9.9.10. `Synchronizer.L1ParallelSynchronization.FallbackToSequentialModeOnSynchronized` **Type:** : `boolean` @@ -1724,7 +1853,7 @@ RollupInfoRetriesSpacing="5s" FallbackToSequentialModeOnSynchronized=false ``` -### 9.9. `[Synchronizer.L2Synchronization]` +### 9.10. `[Synchronizer.L2Synchronization]` **Type:** : `object` **Description:** L2Synchronization Configuration for L2 synchronization @@ -1735,7 +1864,7 @@ FallbackToSequentialModeOnSynchronized=false | - [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.9.1. `Synchronizer.L2Synchronization.AcceptEmptyClosedBatches` +#### 9.10.1. `Synchronizer.L2Synchronization.AcceptEmptyClosedBatches` **Type:** : `boolean` @@ -1750,7 +1879,7 @@ if true, the synchronizer will accept empty batches and process them. AcceptEmptyClosedBatches=false ``` -#### 9.9.2. `Synchronizer.L2Synchronization.ReprocessFullBatchOnClose` +#### 9.10.2. `Synchronizer.L2Synchronization.ReprocessFullBatchOnClose` **Type:** : `boolean` @@ -1764,7 +1893,7 @@ AcceptEmptyClosedBatches=false ReprocessFullBatchOnClose=false ``` -#### 9.9.3. `Synchronizer.L2Synchronization.CheckLastL2BlockHashOnCloseBatch` +#### 9.10.3. `Synchronizer.L2Synchronization.CheckLastL2BlockHashOnCloseBatch` **Type:** : `boolean` diff --git a/docs/config-file/node-config-schema.json b/docs/config-file/node-config-schema.json index 1c93ea4b3c..504c330f35 100644 --- a/docs/config-file/node-config-schema.json +++ b/docs/config-file/node-config-schema.json @@ -532,6 +532,57 @@ "description": "L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check\na modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...)", "default": 30 }, + "L1BlockCheck": { + "properties": { + "Enable": { + "type": "boolean", + "description": "Enable if is true then the check l1 Block Hash is active", + "default": true + }, + "L1SafeBlockPoint": { + "type": "string", + "enum": [ + "finalized", + "safe", + "latest" + ], + "description": "L1SafeBlockPoint is the point that a block is considered safe enough to be checked\nit can be: finalized, safe,pending or latest", + "default": "finalized" + }, + "L1SafeBlockOffset": { + "type": "integer", + "description": "L1SafeBlockOffset is the offset to add to L1SafeBlockPoint as a safe point\nit can be positive or negative\nExample: L1SafeBlockPoint= finalized, L1SafeBlockOffset= -10, then the safe block ten blocks before the finalized block", + "default": 0 + }, + "ForceCheckBeforeStart": { + "type": "boolean", + "description": "ForceCheckBeforeStart if is true then the first time the system is started it will force to check all pending blocks", + "default": true + }, + "PreCheckEnable": { + "type": "boolean", + "description": "PreCheckEnable if is true then the pre-check is active, will check blocks between L1SafeBlock and L1PreSafeBlock", + "default": true + }, + "L1PreSafeBlockPoint": { + "type": "string", + "enum": [ + "finalized", + "safe", + "latest" + ], + "description": "L1PreSafeBlockPoint is the point that a block is considered safe enough to be checked\nit can be: finalized, safe,pending or latest", + "default": "safe" + }, + "L1PreSafeBlockOffset": { + "type": "integer", + "description": "L1PreSafeBlockOffset is the offset to add to L1PreSafeBlockPoint as a safe point\nit can be positive or negative\nExample: L1PreSafeBlockPoint= finalized, L1PreSafeBlockOffset= -10, then the safe block ten blocks before the finalized block", + "default": 0 + } + }, + "additionalProperties": false, + "type": "object" + }, "L1SynchronizationMode": { "type": "string", "enum": [ diff --git a/state/interfaces.go b/state/interfaces.go index dfde07d8ce..cc1f0127a9 100644 --- a/state/interfaces.go +++ b/state/interfaces.go @@ -25,6 +25,7 @@ type storage interface { GetLastBlock(ctx context.Context, dbTx pgx.Tx) (*Block, error) GetPreviousBlock(ctx context.Context, offset uint64, dbTx pgx.Tx) (*Block, error) GetFirstUncheckedBlock(ctx context.Context, fromBlockNumber uint64, dbTx pgx.Tx) (*Block, error) + GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*Block, error) UpdateCheckedBlockByNumber(ctx context.Context, blockNumber uint64, newCheckedStatus bool, dbTx pgx.Tx) error AddGlobalExitRoot(ctx context.Context, exitRoot *GlobalExitRoot, dbTx pgx.Tx) error GetLatestGlobalExitRoot(ctx context.Context, maxBlockNumber uint64, dbTx pgx.Tx) (GlobalExitRoot, time.Time, error) @@ -161,4 +162,5 @@ type storage interface { UpdateBatchAsChecked(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) error GetNotCheckedBatches(ctx context.Context, dbTx pgx.Tx) ([]*Batch, error) GetLastL2BlockByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*L2Block, error) + GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*Block, error) } diff --git a/state/mocks/mock_storage.go b/state/mocks/mock_storage.go index 2b03479dee..27964e0247 100644 --- a/state/mocks/mock_storage.go +++ b/state/mocks/mock_storage.go @@ -5549,6 +5549,66 @@ func (_c *StorageMock_GetPreviousBlock_Call) RunAndReturn(run func(context.Conte return _c } +// GetPreviousBlockToBlockNumber provides a mock function with given fields: ctx, blockNumber, dbTx +func (_m *StorageMock) GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) { + ret := _m.Called(ctx, blockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetPreviousBlockToBlockNumber") + } + + var r0 *state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) (*state.Block, error)); ok { + return rf(ctx, blockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) *state.Block); ok { + r0 = rf(ctx, blockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, blockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StorageMock_GetPreviousBlockToBlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPreviousBlockToBlockNumber' +type StorageMock_GetPreviousBlockToBlockNumber_Call struct { + *mock.Call +} + +// GetPreviousBlockToBlockNumber is a helper method to define mock.On call +// - ctx context.Context +// - blockNumber uint64 +// - dbTx pgx.Tx +func (_e *StorageMock_Expecter) GetPreviousBlockToBlockNumber(ctx interface{}, blockNumber interface{}, dbTx interface{}) *StorageMock_GetPreviousBlockToBlockNumber_Call { + return &StorageMock_GetPreviousBlockToBlockNumber_Call{Call: _e.mock.On("GetPreviousBlockToBlockNumber", ctx, blockNumber, dbTx)} +} + +func (_c *StorageMock_GetPreviousBlockToBlockNumber_Call) Run(run func(ctx context.Context, blockNumber uint64, dbTx pgx.Tx)) *StorageMock_GetPreviousBlockToBlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(pgx.Tx)) + }) + return _c +} + +func (_c *StorageMock_GetPreviousBlockToBlockNumber_Call) Return(_a0 *state.Block, _a1 error) *StorageMock_GetPreviousBlockToBlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StorageMock_GetPreviousBlockToBlockNumber_Call) RunAndReturn(run func(context.Context, uint64, pgx.Tx) (*state.Block, error)) *StorageMock_GetPreviousBlockToBlockNumber_Call { + _c.Call.Return(run) + return _c +} + // GetProcessingContext provides a mock function with given fields: ctx, batchNumber, dbTx func (_m *StorageMock) GetProcessingContext(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.ProcessingContext, error) { ret := _m.Called(ctx, batchNumber, dbTx) @@ -6832,6 +6892,67 @@ func (_c *StorageMock_GetTxsOlderThanNL1BlocksUntilTxHash_Call) RunAndReturn(run return _c } +// GetUncheckedBlocks provides a mock function with given fields: ctx, fromBlockNumber, toBlockNumber, dbTx +func (_m *StorageMock) GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*state.Block, error) { + ret := _m.Called(ctx, fromBlockNumber, toBlockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetUncheckedBlocks") + } + + var r0 []*state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, pgx.Tx) ([]*state.Block, error)); ok { + return rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, pgx.Tx) []*state.Block); ok { + r0 = rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StorageMock_GetUncheckedBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUncheckedBlocks' +type StorageMock_GetUncheckedBlocks_Call struct { + *mock.Call +} + +// GetUncheckedBlocks is a helper method to define mock.On call +// - ctx context.Context +// - fromBlockNumber uint64 +// - toBlockNumber uint64 +// - dbTx pgx.Tx +func (_e *StorageMock_Expecter) GetUncheckedBlocks(ctx interface{}, fromBlockNumber interface{}, toBlockNumber interface{}, dbTx interface{}) *StorageMock_GetUncheckedBlocks_Call { + return &StorageMock_GetUncheckedBlocks_Call{Call: _e.mock.On("GetUncheckedBlocks", ctx, fromBlockNumber, toBlockNumber, dbTx)} +} + +func (_c *StorageMock_GetUncheckedBlocks_Call) Run(run func(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx)) *StorageMock_GetUncheckedBlocks_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(uint64), args[3].(pgx.Tx)) + }) + return _c +} + +func (_c *StorageMock_GetUncheckedBlocks_Call) Return(_a0 []*state.Block, _a1 error) *StorageMock_GetUncheckedBlocks_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StorageMock_GetUncheckedBlocks_Call) RunAndReturn(run func(context.Context, uint64, uint64, pgx.Tx) ([]*state.Block, error)) *StorageMock_GetUncheckedBlocks_Call { + _c.Call.Return(run) + return _c +} + // GetVerifiedBatch provides a mock function with given fields: ctx, batchNumber, dbTx func (_m *StorageMock) GetVerifiedBatch(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.VerifiedBatch, error) { ret := _m.Called(ctx, batchNumber, dbTx) diff --git a/state/pgstatestorage/block.go b/state/pgstatestorage/block.go index 768b384df1..7c657a6e3b 100644 --- a/state/pgstatestorage/block.go +++ b/state/pgstatestorage/block.go @@ -63,6 +63,35 @@ func (p *PostgresStorage) GetFirstUncheckedBlock(ctx context.Context, fromBlockN return &block, err } +func (p *PostgresStorage) GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*state.Block, error) { + const getUncheckedBlocksSQL = "SELECT block_num, block_hash, parent_hash, received_at, checked FROM state.block WHERE block_num>=$1 AND block_num<=$2 AND checked=false ORDER BY block_num" + + q := p.getExecQuerier(dbTx) + + rows, err := q.Query(ctx, getUncheckedBlocksSQL, fromBlockNumber, toBlockNumber) + if err != nil { + return nil, err + } + defer rows.Close() + + var blocks []*state.Block + for rows.Next() { + var ( + blockHash string + parentHash string + block state.Block + ) + err := rows.Scan(&block.BlockNumber, &blockHash, &parentHash, &block.ReceivedAt, &block.Checked) + if err != nil { + return nil, err + } + block.BlockHash = common.HexToHash(blockHash) + block.ParentHash = common.HexToHash(parentHash) + blocks = append(blocks, &block) + } + return blocks, nil +} + // GetPreviousBlock gets the offset previous L1 block respect to latest. func (p *PostgresStorage) GetPreviousBlock(ctx context.Context, offset uint64, dbTx pgx.Tx) (*state.Block, error) { var ( @@ -83,6 +112,26 @@ func (p *PostgresStorage) GetPreviousBlock(ctx context.Context, offset uint64, d return &block, err } +// GetPreviousBlockToBlockNumber gets the previous L1 block respect blockNumber. +func (p *PostgresStorage) GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) { + var ( + blockHash string + parentHash string + block state.Block + ) + const getPreviousBlockSQL = "SELECT block_num, block_hash, parent_hash, received_at,checked FROM state.block WHERE block_num < $1 ORDER BY block_num DESC LIMIT 1 " + + q := p.getExecQuerier(dbTx) + + err := q.QueryRow(ctx, getPreviousBlockSQL, blockNumber).Scan(&block.BlockNumber, &blockHash, &parentHash, &block.ReceivedAt, &block.Checked) + if errors.Is(err, pgx.ErrNoRows) { + return nil, state.ErrNotFound + } + block.BlockHash = common.HexToHash(blockHash) + block.ParentHash = common.HexToHash(parentHash) + return &block, err +} + // GetBlockByNumber returns the L1 block with the given number. func (p *PostgresStorage) GetBlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) { var ( diff --git a/state/pgstatestorage/pgstatestorage_test.go b/state/pgstatestorage/pgstatestorage_test.go index 416b21b47b..9c8a178dd0 100644 --- a/state/pgstatestorage/pgstatestorage_test.go +++ b/state/pgstatestorage/pgstatestorage_test.go @@ -1687,3 +1687,24 @@ func TestUpdateCheckedBlockByNumber(t *testing.T) { require.NoError(t, err) require.False(t, b1.Checked) } + +func TestGetUncheckedBlocks(t *testing.T) { + var err error + blockNumber := uint64(61001) + err = testState.AddBlock(context.Background(), &state.Block{BlockNumber: blockNumber, Checked: true}, nil) + require.NoError(t, err) + err = testState.AddBlock(context.Background(), &state.Block{BlockNumber: blockNumber + 1, Checked: false}, nil) + require.NoError(t, err) + err = testState.AddBlock(context.Background(), &state.Block{BlockNumber: blockNumber + 2, Checked: true}, nil) + require.NoError(t, err) + err = testState.AddBlock(context.Background(), &state.Block{BlockNumber: blockNumber + 3, Checked: false}, nil) + require.NoError(t, err) + err = testState.AddBlock(context.Background(), &state.Block{BlockNumber: blockNumber + 4, Checked: false}, nil) + require.NoError(t, err) + + blocks, err := testState.GetUncheckedBlocks(context.Background(), blockNumber, blockNumber+3, nil) + require.NoError(t, err) + require.Equal(t, 2, len(blocks)) + require.Equal(t, uint64(blockNumber+1), blocks[0].BlockNumber) + require.Equal(t, uint64(blockNumber+3), blocks[1].BlockNumber) +} diff --git a/synchronizer/common/reorg_error.go b/synchronizer/common/reorg_error.go new file mode 100644 index 0000000000..e60dcfb22c --- /dev/null +++ b/synchronizer/common/reorg_error.go @@ -0,0 +1,44 @@ +package common + +import "fmt" + +// ReorgError is an error that is raised when a reorg is detected +type ReorgError struct { + // BlockNumber is the block number that caused the reorg + BlockNumber uint64 + Err error +} + +// NewReorgError creates a new ReorgError +func NewReorgError(blockNumber uint64, err error) *ReorgError { + return &ReorgError{ + BlockNumber: blockNumber, + Err: err, + } +} + +func (e *ReorgError) Error() string { + return fmt.Sprintf("%s blockNumber: %d", e.Err.Error(), e.BlockNumber) +} + +// IsReorgError checks if an error is a ReorgError +func IsReorgError(err error) bool { + _, ok := err.(*ReorgError) + return ok +} + +// GetReorgErrorBlockNumber returns the block number that caused the reorg +func GetReorgErrorBlockNumber(err error) uint64 { + if reorgErr, ok := err.(*ReorgError); ok { + return reorgErr.BlockNumber + } + return 0 +} + +// GetReorgError returns the error that caused the reorg +func GetReorgError(err error) error { + if reorgErr, ok := err.(*ReorgError); ok { + return reorgErr.Err + } + return nil +} diff --git a/synchronizer/common/syncinterfaces/async_l1_block_checker.go b/synchronizer/common/syncinterfaces/async_l1_block_checker.go new file mode 100644 index 0000000000..b95903901a --- /dev/null +++ b/synchronizer/common/syncinterfaces/async_l1_block_checker.go @@ -0,0 +1,40 @@ +package syncinterfaces + +import ( + "context" + "fmt" + + "github.com/0xPolygonHermez/zkevm-node/state" +) + +type IterationResult struct { + Err error + ReorgDetected bool + BlockNumber uint64 + ReorgMessage string +} + +func (ir *IterationResult) String() string { + if ir.Err == nil { + if ir.ReorgDetected { + return fmt.Sprintf("IterationResult{ReorgDetected: %v, BlockNumber: %d ReorgMessage:%s}", ir.ReorgDetected, ir.BlockNumber, ir.ReorgMessage) + } else { + return "IterationResult{None}" + } + } else { + return fmt.Sprintf("IterationResult{Err: %s, ReorgDetected: %v, BlockNumber: %d ReorgMessage:%s}", ir.Err.Error(), ir.ReorgDetected, ir.BlockNumber, ir.ReorgMessage) + } +} + +type AsyncL1BlockChecker interface { + Run(ctx context.Context, onFinish func()) + RunSynchronous(ctx context.Context) IterationResult + Stop() + GetResult() *IterationResult +} + +type L1BlockCheckerIntegrator interface { + OnStart(ctx context.Context) error + OnResetState(ctx context.Context) + CheckReorgWrapper(ctx context.Context, reorgFirstBlockOk *state.Block, errReportedByReorgFunc error) (*state.Block, error) +} diff --git a/synchronizer/common/syncinterfaces/etherman.go b/synchronizer/common/syncinterfaces/etherman.go index 3d5959ade2..fdbdd669f8 100644 --- a/synchronizer/common/syncinterfaces/etherman.go +++ b/synchronizer/common/syncinterfaces/etherman.go @@ -14,10 +14,11 @@ type EthermanFullInterface interface { HeaderByNumber(ctx context.Context, number *big.Int) (*ethTypes.Header, error) GetRollupInfoByBlockRange(ctx context.Context, fromBlock uint64, toBlock *uint64) ([]etherman.Block, map[common.Hash][]etherman.Order, error) EthBlockByNumber(ctx context.Context, blockNumber uint64) (*ethTypes.Block, error) - GetLatestBatchNumber() (uint64, error) GetTrustedSequencerURL() (string, error) VerifyGenBlockNumber(ctx context.Context, genBlockNumber uint64) (bool, error) GetLatestVerifiedBatchNum() (uint64, error) + + EthermanGetLatestBatchNumber GetFinalizedBlockNumber(ctx context.Context) (uint64, error) } diff --git a/synchronizer/common/syncinterfaces/mocks/async_l1_block_checker.go b/synchronizer/common/syncinterfaces/mocks/async_l1_block_checker.go new file mode 100644 index 0000000000..67b38de348 --- /dev/null +++ b/synchronizer/common/syncinterfaces/mocks/async_l1_block_checker.go @@ -0,0 +1,196 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_syncinterfaces + +import ( + context "context" + + syncinterfaces "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces" + mock "github.com/stretchr/testify/mock" +) + +// AsyncL1BlockChecker is an autogenerated mock type for the AsyncL1BlockChecker type +type AsyncL1BlockChecker struct { + mock.Mock +} + +type AsyncL1BlockChecker_Expecter struct { + mock *mock.Mock +} + +func (_m *AsyncL1BlockChecker) EXPECT() *AsyncL1BlockChecker_Expecter { + return &AsyncL1BlockChecker_Expecter{mock: &_m.Mock} +} + +// GetResult provides a mock function with given fields: +func (_m *AsyncL1BlockChecker) GetResult() *syncinterfaces.IterationResult { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetResult") + } + + var r0 *syncinterfaces.IterationResult + if rf, ok := ret.Get(0).(func() *syncinterfaces.IterationResult); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*syncinterfaces.IterationResult) + } + } + + return r0 +} + +// AsyncL1BlockChecker_GetResult_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetResult' +type AsyncL1BlockChecker_GetResult_Call struct { + *mock.Call +} + +// GetResult is a helper method to define mock.On call +func (_e *AsyncL1BlockChecker_Expecter) GetResult() *AsyncL1BlockChecker_GetResult_Call { + return &AsyncL1BlockChecker_GetResult_Call{Call: _e.mock.On("GetResult")} +} + +func (_c *AsyncL1BlockChecker_GetResult_Call) Run(run func()) *AsyncL1BlockChecker_GetResult_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *AsyncL1BlockChecker_GetResult_Call) Return(_a0 *syncinterfaces.IterationResult) *AsyncL1BlockChecker_GetResult_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AsyncL1BlockChecker_GetResult_Call) RunAndReturn(run func() *syncinterfaces.IterationResult) *AsyncL1BlockChecker_GetResult_Call { + _c.Call.Return(run) + return _c +} + +// Run provides a mock function with given fields: ctx, onFinish +func (_m *AsyncL1BlockChecker) Run(ctx context.Context, onFinish func()) { + _m.Called(ctx, onFinish) +} + +// AsyncL1BlockChecker_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run' +type AsyncL1BlockChecker_Run_Call struct { + *mock.Call +} + +// Run is a helper method to define mock.On call +// - ctx context.Context +// - onFinish func() +func (_e *AsyncL1BlockChecker_Expecter) Run(ctx interface{}, onFinish interface{}) *AsyncL1BlockChecker_Run_Call { + return &AsyncL1BlockChecker_Run_Call{Call: _e.mock.On("Run", ctx, onFinish)} +} + +func (_c *AsyncL1BlockChecker_Run_Call) Run(run func(ctx context.Context, onFinish func())) *AsyncL1BlockChecker_Run_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(func())) + }) + return _c +} + +func (_c *AsyncL1BlockChecker_Run_Call) Return() *AsyncL1BlockChecker_Run_Call { + _c.Call.Return() + return _c +} + +func (_c *AsyncL1BlockChecker_Run_Call) RunAndReturn(run func(context.Context, func())) *AsyncL1BlockChecker_Run_Call { + _c.Call.Return(run) + return _c +} + +// RunSynchronous provides a mock function with given fields: ctx +func (_m *AsyncL1BlockChecker) RunSynchronous(ctx context.Context) syncinterfaces.IterationResult { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for RunSynchronous") + } + + var r0 syncinterfaces.IterationResult + if rf, ok := ret.Get(0).(func(context.Context) syncinterfaces.IterationResult); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(syncinterfaces.IterationResult) + } + + return r0 +} + +// AsyncL1BlockChecker_RunSynchronous_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RunSynchronous' +type AsyncL1BlockChecker_RunSynchronous_Call struct { + *mock.Call +} + +// RunSynchronous is a helper method to define mock.On call +// - ctx context.Context +func (_e *AsyncL1BlockChecker_Expecter) RunSynchronous(ctx interface{}) *AsyncL1BlockChecker_RunSynchronous_Call { + return &AsyncL1BlockChecker_RunSynchronous_Call{Call: _e.mock.On("RunSynchronous", ctx)} +} + +func (_c *AsyncL1BlockChecker_RunSynchronous_Call) Run(run func(ctx context.Context)) *AsyncL1BlockChecker_RunSynchronous_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *AsyncL1BlockChecker_RunSynchronous_Call) Return(_a0 syncinterfaces.IterationResult) *AsyncL1BlockChecker_RunSynchronous_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *AsyncL1BlockChecker_RunSynchronous_Call) RunAndReturn(run func(context.Context) syncinterfaces.IterationResult) *AsyncL1BlockChecker_RunSynchronous_Call { + _c.Call.Return(run) + return _c +} + +// Stop provides a mock function with given fields: +func (_m *AsyncL1BlockChecker) Stop() { + _m.Called() +} + +// AsyncL1BlockChecker_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop' +type AsyncL1BlockChecker_Stop_Call struct { + *mock.Call +} + +// Stop is a helper method to define mock.On call +func (_e *AsyncL1BlockChecker_Expecter) Stop() *AsyncL1BlockChecker_Stop_Call { + return &AsyncL1BlockChecker_Stop_Call{Call: _e.mock.On("Stop")} +} + +func (_c *AsyncL1BlockChecker_Stop_Call) Run(run func()) *AsyncL1BlockChecker_Stop_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *AsyncL1BlockChecker_Stop_Call) Return() *AsyncL1BlockChecker_Stop_Call { + _c.Call.Return() + return _c +} + +func (_c *AsyncL1BlockChecker_Stop_Call) RunAndReturn(run func()) *AsyncL1BlockChecker_Stop_Call { + _c.Call.Return(run) + return _c +} + +// NewAsyncL1BlockChecker creates a new instance of AsyncL1BlockChecker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewAsyncL1BlockChecker(t interface { + mock.TestingT + Cleanup(func()) +}) *AsyncL1BlockChecker { + mock := &AsyncL1BlockChecker{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/common/syncinterfaces/mocks/l1_block_checker_integrator.go b/synchronizer/common/syncinterfaces/mocks/l1_block_checker_integrator.go new file mode 100644 index 0000000000..0248874f26 --- /dev/null +++ b/synchronizer/common/syncinterfaces/mocks/l1_block_checker_integrator.go @@ -0,0 +1,176 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_syncinterfaces + +import ( + context "context" + + state "github.com/0xPolygonHermez/zkevm-node/state" + mock "github.com/stretchr/testify/mock" +) + +// L1BlockCheckerIntegrator is an autogenerated mock type for the L1BlockCheckerIntegrator type +type L1BlockCheckerIntegrator struct { + mock.Mock +} + +type L1BlockCheckerIntegrator_Expecter struct { + mock *mock.Mock +} + +func (_m *L1BlockCheckerIntegrator) EXPECT() *L1BlockCheckerIntegrator_Expecter { + return &L1BlockCheckerIntegrator_Expecter{mock: &_m.Mock} +} + +// CheckReorgWrapper provides a mock function with given fields: ctx, reorgFirstBlockOk, errReportedByReorgFunc +func (_m *L1BlockCheckerIntegrator) CheckReorgWrapper(ctx context.Context, reorgFirstBlockOk *state.Block, errReportedByReorgFunc error) (*state.Block, error) { + ret := _m.Called(ctx, reorgFirstBlockOk, errReportedByReorgFunc) + + if len(ret) == 0 { + panic("no return value specified for CheckReorgWrapper") + } + + var r0 *state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *state.Block, error) (*state.Block, error)); ok { + return rf(ctx, reorgFirstBlockOk, errReportedByReorgFunc) + } + if rf, ok := ret.Get(0).(func(context.Context, *state.Block, error) *state.Block); ok { + r0 = rf(ctx, reorgFirstBlockOk, errReportedByReorgFunc) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *state.Block, error) error); ok { + r1 = rf(ctx, reorgFirstBlockOk, errReportedByReorgFunc) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L1BlockCheckerIntegrator_CheckReorgWrapper_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckReorgWrapper' +type L1BlockCheckerIntegrator_CheckReorgWrapper_Call struct { + *mock.Call +} + +// CheckReorgWrapper is a helper method to define mock.On call +// - ctx context.Context +// - reorgFirstBlockOk *state.Block +// - errReportedByReorgFunc error +func (_e *L1BlockCheckerIntegrator_Expecter) CheckReorgWrapper(ctx interface{}, reorgFirstBlockOk interface{}, errReportedByReorgFunc interface{}) *L1BlockCheckerIntegrator_CheckReorgWrapper_Call { + return &L1BlockCheckerIntegrator_CheckReorgWrapper_Call{Call: _e.mock.On("CheckReorgWrapper", ctx, reorgFirstBlockOk, errReportedByReorgFunc)} +} + +func (_c *L1BlockCheckerIntegrator_CheckReorgWrapper_Call) Run(run func(ctx context.Context, reorgFirstBlockOk *state.Block, errReportedByReorgFunc error)) *L1BlockCheckerIntegrator_CheckReorgWrapper_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*state.Block), args[2].(error)) + }) + return _c +} + +func (_c *L1BlockCheckerIntegrator_CheckReorgWrapper_Call) Return(_a0 *state.Block, _a1 error) *L1BlockCheckerIntegrator_CheckReorgWrapper_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L1BlockCheckerIntegrator_CheckReorgWrapper_Call) RunAndReturn(run func(context.Context, *state.Block, error) (*state.Block, error)) *L1BlockCheckerIntegrator_CheckReorgWrapper_Call { + _c.Call.Return(run) + return _c +} + +// OnResetState provides a mock function with given fields: ctx +func (_m *L1BlockCheckerIntegrator) OnResetState(ctx context.Context) { + _m.Called(ctx) +} + +// L1BlockCheckerIntegrator_OnResetState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnResetState' +type L1BlockCheckerIntegrator_OnResetState_Call struct { + *mock.Call +} + +// OnResetState is a helper method to define mock.On call +// - ctx context.Context +func (_e *L1BlockCheckerIntegrator_Expecter) OnResetState(ctx interface{}) *L1BlockCheckerIntegrator_OnResetState_Call { + return &L1BlockCheckerIntegrator_OnResetState_Call{Call: _e.mock.On("OnResetState", ctx)} +} + +func (_c *L1BlockCheckerIntegrator_OnResetState_Call) Run(run func(ctx context.Context)) *L1BlockCheckerIntegrator_OnResetState_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *L1BlockCheckerIntegrator_OnResetState_Call) Return() *L1BlockCheckerIntegrator_OnResetState_Call { + _c.Call.Return() + return _c +} + +func (_c *L1BlockCheckerIntegrator_OnResetState_Call) RunAndReturn(run func(context.Context)) *L1BlockCheckerIntegrator_OnResetState_Call { + _c.Call.Return(run) + return _c +} + +// OnStart provides a mock function with given fields: ctx +func (_m *L1BlockCheckerIntegrator) OnStart(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for OnStart") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// L1BlockCheckerIntegrator_OnStart_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnStart' +type L1BlockCheckerIntegrator_OnStart_Call struct { + *mock.Call +} + +// OnStart is a helper method to define mock.On call +// - ctx context.Context +func (_e *L1BlockCheckerIntegrator_Expecter) OnStart(ctx interface{}) *L1BlockCheckerIntegrator_OnStart_Call { + return &L1BlockCheckerIntegrator_OnStart_Call{Call: _e.mock.On("OnStart", ctx)} +} + +func (_c *L1BlockCheckerIntegrator_OnStart_Call) Run(run func(ctx context.Context)) *L1BlockCheckerIntegrator_OnStart_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *L1BlockCheckerIntegrator_OnStart_Call) Return(_a0 error) *L1BlockCheckerIntegrator_OnStart_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *L1BlockCheckerIntegrator_OnStart_Call) RunAndReturn(run func(context.Context) error) *L1BlockCheckerIntegrator_OnStart_Call { + _c.Call.Return(run) + return _c +} + +// NewL1BlockCheckerIntegrator creates a new instance of L1BlockCheckerIntegrator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewL1BlockCheckerIntegrator(t interface { + mock.TestingT + Cleanup(func()) +}) *L1BlockCheckerIntegrator { + mock := &L1BlockCheckerIntegrator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go index f4790bc695..fa570dbe7f 100644 --- a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go +++ b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go @@ -821,6 +821,66 @@ func (_c *StateFullInterface_GetBatchByNumber_Call) RunAndReturn(run func(contex return _c } +// GetBlockByNumber provides a mock function with given fields: ctx, blockNumber, dbTx +func (_m *StateFullInterface) GetBlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) { + ret := _m.Called(ctx, blockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetBlockByNumber") + } + + var r0 *state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) (*state.Block, error)); ok { + return rf(ctx, blockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) *state.Block); ok { + r0 = rf(ctx, blockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, blockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StateFullInterface_GetBlockByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlockByNumber' +type StateFullInterface_GetBlockByNumber_Call struct { + *mock.Call +} + +// GetBlockByNumber is a helper method to define mock.On call +// - ctx context.Context +// - blockNumber uint64 +// - dbTx pgx.Tx +func (_e *StateFullInterface_Expecter) GetBlockByNumber(ctx interface{}, blockNumber interface{}, dbTx interface{}) *StateFullInterface_GetBlockByNumber_Call { + return &StateFullInterface_GetBlockByNumber_Call{Call: _e.mock.On("GetBlockByNumber", ctx, blockNumber, dbTx)} +} + +func (_c *StateFullInterface_GetBlockByNumber_Call) Run(run func(ctx context.Context, blockNumber uint64, dbTx pgx.Tx)) *StateFullInterface_GetBlockByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(pgx.Tx)) + }) + return _c +} + +func (_c *StateFullInterface_GetBlockByNumber_Call) Return(_a0 *state.Block, _a1 error) *StateFullInterface_GetBlockByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StateFullInterface_GetBlockByNumber_Call) RunAndReturn(run func(context.Context, uint64, pgx.Tx) (*state.Block, error)) *StateFullInterface_GetBlockByNumber_Call { + _c.Call.Return(run) + return _c +} + // GetExitRootByGlobalExitRoot provides a mock function with given fields: ctx, ger, dbTx func (_m *StateFullInterface) GetExitRootByGlobalExitRoot(ctx context.Context, ger common.Hash, dbTx pgx.Tx) (*state.GlobalExitRoot, error) { ret := _m.Called(ctx, ger, dbTx) @@ -1805,6 +1865,66 @@ func (_c *StateFullInterface_GetPreviousBlock_Call) RunAndReturn(run func(contex return _c } +// GetPreviousBlockToBlockNumber provides a mock function with given fields: ctx, blockNumber, dbTx +func (_m *StateFullInterface) GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) { + ret := _m.Called(ctx, blockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetPreviousBlockToBlockNumber") + } + + var r0 *state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) (*state.Block, error)); ok { + return rf(ctx, blockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) *state.Block); ok { + r0 = rf(ctx, blockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, blockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StateFullInterface_GetPreviousBlockToBlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPreviousBlockToBlockNumber' +type StateFullInterface_GetPreviousBlockToBlockNumber_Call struct { + *mock.Call +} + +// GetPreviousBlockToBlockNumber is a helper method to define mock.On call +// - ctx context.Context +// - blockNumber uint64 +// - dbTx pgx.Tx +func (_e *StateFullInterface_Expecter) GetPreviousBlockToBlockNumber(ctx interface{}, blockNumber interface{}, dbTx interface{}) *StateFullInterface_GetPreviousBlockToBlockNumber_Call { + return &StateFullInterface_GetPreviousBlockToBlockNumber_Call{Call: _e.mock.On("GetPreviousBlockToBlockNumber", ctx, blockNumber, dbTx)} +} + +func (_c *StateFullInterface_GetPreviousBlockToBlockNumber_Call) Run(run func(ctx context.Context, blockNumber uint64, dbTx pgx.Tx)) *StateFullInterface_GetPreviousBlockToBlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(pgx.Tx)) + }) + return _c +} + +func (_c *StateFullInterface_GetPreviousBlockToBlockNumber_Call) Return(_a0 *state.Block, _a1 error) *StateFullInterface_GetPreviousBlockToBlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StateFullInterface_GetPreviousBlockToBlockNumber_Call) RunAndReturn(run func(context.Context, uint64, pgx.Tx) (*state.Block, error)) *StateFullInterface_GetPreviousBlockToBlockNumber_Call { + _c.Call.Return(run) + return _c +} + // GetReorgedTransactions provides a mock function with given fields: ctx, batchNumber, dbTx func (_m *StateFullInterface) GetReorgedTransactions(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) ([]*types.Transaction, error) { ret := _m.Called(ctx, batchNumber, dbTx) @@ -1988,6 +2108,67 @@ func (_c *StateFullInterface_GetStoredFlushID_Call) RunAndReturn(run func(contex return _c } +// GetUncheckedBlocks provides a mock function with given fields: ctx, fromBlockNumber, toBlockNumber, dbTx +func (_m *StateFullInterface) GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*state.Block, error) { + ret := _m.Called(ctx, fromBlockNumber, toBlockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetUncheckedBlocks") + } + + var r0 []*state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, pgx.Tx) ([]*state.Block, error)); ok { + return rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, pgx.Tx) []*state.Block); ok { + r0 = rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StateFullInterface_GetUncheckedBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUncheckedBlocks' +type StateFullInterface_GetUncheckedBlocks_Call struct { + *mock.Call +} + +// GetUncheckedBlocks is a helper method to define mock.On call +// - ctx context.Context +// - fromBlockNumber uint64 +// - toBlockNumber uint64 +// - dbTx pgx.Tx +func (_e *StateFullInterface_Expecter) GetUncheckedBlocks(ctx interface{}, fromBlockNumber interface{}, toBlockNumber interface{}, dbTx interface{}) *StateFullInterface_GetUncheckedBlocks_Call { + return &StateFullInterface_GetUncheckedBlocks_Call{Call: _e.mock.On("GetUncheckedBlocks", ctx, fromBlockNumber, toBlockNumber, dbTx)} +} + +func (_c *StateFullInterface_GetUncheckedBlocks_Call) Run(run func(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx)) *StateFullInterface_GetUncheckedBlocks_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(uint64), args[3].(pgx.Tx)) + }) + return _c +} + +func (_c *StateFullInterface_GetUncheckedBlocks_Call) Return(_a0 []*state.Block, _a1 error) *StateFullInterface_GetUncheckedBlocks_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StateFullInterface_GetUncheckedBlocks_Call) RunAndReturn(run func(context.Context, uint64, uint64, pgx.Tx) ([]*state.Block, error)) *StateFullInterface_GetUncheckedBlocks_Call { + _c.Call.Return(run) + return _c +} + // OpenBatch provides a mock function with given fields: ctx, processingContext, dbTx func (_m *StateFullInterface) OpenBatch(ctx context.Context, processingContext state.ProcessingContext, dbTx pgx.Tx) error { ret := _m.Called(ctx, processingContext, dbTx) diff --git a/synchronizer/common/syncinterfaces/state.go b/synchronizer/common/syncinterfaces/state.go index 0aff583319..cafae4104e 100644 --- a/synchronizer/common/syncinterfaces/state.go +++ b/synchronizer/common/syncinterfaces/state.go @@ -28,6 +28,7 @@ type StateFullInterface interface { AddForcedBatch(ctx context.Context, forcedBatch *state.ForcedBatch, dbTx pgx.Tx) error AddBlock(ctx context.Context, block *state.Block, dbTx pgx.Tx) error Reset(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) error + GetBlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) GetPreviousBlock(ctx context.Context, offset uint64, dbTx pgx.Tx) (*state.Block, error) GetFirstUncheckedBlock(ctx context.Context, fromBlockNumber uint64, dbTx pgx.Tx) (*state.Block, error) UpdateCheckedBlockByNumber(ctx context.Context, blockNumber uint64, newCheckedStatus bool, dbTx pgx.Tx) error @@ -75,4 +76,6 @@ type StateFullInterface interface { UpdateForkIDBlockNumber(ctx context.Context, forkdID uint64, newBlockNumber uint64, updateMemCache bool, dbTx pgx.Tx) error GetLastL2BlockNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error) GetL2BlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.L2Block, error) + GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*state.Block, error) + GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) } diff --git a/synchronizer/config.go b/synchronizer/config.go index 0f7d822a60..ef51d41308 100644 --- a/synchronizer/config.go +++ b/synchronizer/config.go @@ -1,6 +1,8 @@ package synchronizer import ( + "fmt" + "github.com/0xPolygonHermez/zkevm-node/config/types" "github.com/0xPolygonHermez/zkevm-node/synchronizer/l2_sync" ) @@ -22,6 +24,7 @@ type Config struct { // a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...) L1SyncCheckL2BlockNumberhModulus uint64 `mapstructure:"L1SyncCheckL2BlockNumberhModulus"` + L1BlockCheck L1BlockCheckConfig `mapstructure:"L1BlockCheck"` // L1SynchronizationMode define how to synchronize with L1: // - parallel: Request data to L1 in parallel, and process sequentially. The advantage is that executor is not blocked waiting for L1 data // - sequential: Request data to L1 and execute @@ -32,6 +35,35 @@ type Config struct { L2Synchronization l2_sync.Config `mapstructure:"L2Synchronization"` } +// L1BlockCheckConfig Configuration for L1 Block Checker +type L1BlockCheckConfig struct { + // Enable if is true then the check l1 Block Hash is active + Enable bool `mapstructure:"Enable"` + // L1SafeBlockPoint is the point that a block is considered safe enough to be checked + // it can be: finalized, safe,pending or latest + L1SafeBlockPoint string `mapstructure:"L1SafeBlockPoint" jsonschema:"enum=finalized,enum=safe, enum=pending,enum=latest"` + // L1SafeBlockOffset is the offset to add to L1SafeBlockPoint as a safe point + // it can be positive or negative + // Example: L1SafeBlockPoint= finalized, L1SafeBlockOffset= -10, then the safe block ten blocks before the finalized block + L1SafeBlockOffset int `mapstructure:"L1SafeBlockOffset"` + // ForceCheckBeforeStart if is true then the first time the system is started it will force to check all pending blocks + ForceCheckBeforeStart bool `mapstructure:"ForceCheckBeforeStart"` + + // PreCheckEnable if is true then the pre-check is active, will check blocks between L1SafeBlock and L1PreSafeBlock + PreCheckEnable bool `mapstructure:"PreCheckEnable"` + // L1PreSafeBlockPoint is the point that a block is considered safe enough to be checked + // it can be: finalized, safe,pending or latest + L1PreSafeBlockPoint string `mapstructure:"L1PreSafeBlockPoint" jsonschema:"enum=finalized,enum=safe, enum=pending,enum=latest"` + // L1PreSafeBlockOffset is the offset to add to L1PreSafeBlockPoint as a safe point + // it can be positive or negative + // Example: L1PreSafeBlockPoint= finalized, L1PreSafeBlockOffset= -10, then the safe block ten blocks before the finalized block + L1PreSafeBlockOffset int `mapstructure:"L1PreSafeBlockOffset"` +} + +func (c *L1BlockCheckConfig) String() string { + return fmt.Sprintf("Enable: %v, L1SafeBlockPoint: %s, L1SafeBlockOffset: %d, ForceCheckBeforeStart: %v", c.Enable, c.L1SafeBlockPoint, c.L1SafeBlockOffset, c.ForceCheckBeforeStart) +} + // L1ParallelSynchronizationConfig Configuration for parallel mode (if UL1SynchronizationMode equal to 'parallel') type L1ParallelSynchronizationConfig struct { // MaxClients Number of clients used to synchronize with L1 diff --git a/synchronizer/l1_check_block/async.go b/synchronizer/l1_check_block/async.go new file mode 100644 index 0000000000..4a2a45d924 --- /dev/null +++ b/synchronizer/l1_check_block/async.go @@ -0,0 +1,183 @@ +package l1_check_block + +import ( + "context" + "sync" + "time" + + "github.com/0xPolygonHermez/zkevm-node/log" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces" +) + +// L1BlockChecker is an interface that defines the method to check L1 blocks +type L1BlockChecker interface { + Step(ctx context.Context) error +} + +const ( + defaultPeriodTime = time.Second +) + +// AsyncCheck is a wrapper for L1BlockChecker to become asynchronous +type AsyncCheck struct { + checker L1BlockChecker + mutex sync.Mutex + lastResult *syncinterfaces.IterationResult + onFinishCall func() + periodTime time.Duration + // Wg is a wait group to wait for the result + Wg sync.WaitGroup + ctx context.Context + cancelCtx context.CancelFunc + isRunning bool +} + +// NewAsyncCheck creates a new AsyncCheck +func NewAsyncCheck(checker L1BlockChecker) *AsyncCheck { + return &AsyncCheck{ + checker: checker, + periodTime: defaultPeriodTime, + } +} + +// SetPeriodTime sets the period time between relaunch checker.Step +func (a *AsyncCheck) SetPeriodTime(periodTime time.Duration) { + a.periodTime = periodTime +} + +// Run is a method that starts the async check +func (a *AsyncCheck) Run(ctx context.Context, onFinish func()) { + a.mutex.Lock() + defer a.mutex.Unlock() + a.onFinishCall = onFinish + if a.isRunning { + log.Infof("%s L1BlockChecker: already running, changing onFinish call", logPrefix) + return + } + a.lastResult = nil + a.ctx, a.cancelCtx = context.WithCancel(ctx) + a.launchChecker(a.ctx) +} + +// Stop is a method that stops the async check +func (a *AsyncCheck) Stop() { + a.cancelCtx() + a.Wg.Wait() +} + +// RunSynchronous is a method that forces the check to be synchronous before starting the async check +func (a *AsyncCheck) RunSynchronous(ctx context.Context) syncinterfaces.IterationResult { + return a.executeIteration(ctx) +} + +// GetResult returns the last result of the check: +// - Nil -> still running +// - Not nil -> finished, and this is the result. You must call again Run to start a new check +func (a *AsyncCheck) GetResult() *syncinterfaces.IterationResult { + a.mutex.Lock() + defer a.mutex.Unlock() + return a.lastResult +} + +// https://stackoverflow.com/questions/32840687/timeout-for-waitgroup-wait +// waitTimeout waits for the waitgroup for the specified max timeout. +// Returns true if waiting timed out. +func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { + c := make(chan struct{}) + go func() { + defer close(c) + wg.Wait() + }() + select { + case <-c: + return false // completed normally + case <-time.After(timeout): + return true // timed out + } +} + +// GetResultBlockingUntilAvailable wait the time specific in timeout, if reach timeout returns current +// result, if not, wait until the result is available. +// if timeout is 0, it waits indefinitely +func (a *AsyncCheck) GetResultBlockingUntilAvailable(timeout time.Duration) *syncinterfaces.IterationResult { + if timeout == 0 { + a.Wg.Wait() + } else { + waitTimeout(&a.Wg, timeout) + } + return a.GetResult() +} + +func (a *AsyncCheck) setResult(result syncinterfaces.IterationResult) { + a.mutex.Lock() + defer a.mutex.Unlock() + a.lastResult = &result +} + +func (a *AsyncCheck) launchChecker(ctx context.Context) { + // add waitGroup to wait for a result + a.Wg.Add(1) + a.isRunning = true + go func() { + log.Infof("%s L1BlockChecker: starting background process", logPrefix) + for { + result := a.step(ctx) + if result != nil { + a.setResult(*result) + // Result is set wg is done + break + } + } + log.Infof("%s L1BlockChecker: finished background process", logPrefix) + a.Wg.Done() + a.mutex.Lock() + onFinishCall := a.onFinishCall + a.isRunning = false + a.mutex.Unlock() + // call onFinish function with no mutex + if onFinishCall != nil { + onFinishCall() + } + }() +} + +// step is a method that executes until executeItertion +// returns an error or a reorg +func (a *AsyncCheck) step(ctx context.Context) *syncinterfaces.IterationResult { + select { + case <-ctx.Done(): + log.Debugf("%s L1BlockChecker: context done", logPrefix) + return &syncinterfaces.IterationResult{Err: ctx.Err()} + default: + result := a.executeIteration(ctx) + if result.ReorgDetected { + return &result + } + log.Debugf("%s L1BlockChecker:returned %s waiting %s to relaunch", logPrefix, result.String(), a.periodTime) + time.Sleep(a.periodTime) + } + return nil +} + +// executeIteration executes a single iteration of the checker +func (a *AsyncCheck) executeIteration(ctx context.Context) syncinterfaces.IterationResult { + res := syncinterfaces.IterationResult{} + log.Debugf("%s calling checker.Step(...)", logPrefix) + res.Err = a.checker.Step(ctx) + log.Debugf("%s returned checker.Step(...) %w", logPrefix, res.Err) + if res.Err != nil { + log.Errorf("%s Fail check L1 Blocks: %w", logPrefix, res.Err) + if common.IsReorgError(res.Err) { + // log error + blockNumber := common.GetReorgErrorBlockNumber(res.Err) + log.Infof("%s Reorg detected at block %d", logPrefix, blockNumber) + // It keeps blocked until the channel is read + res.BlockNumber = blockNumber + res.ReorgDetected = true + res.ReorgMessage = res.Err.Error() + res.Err = nil + } + } + return res +} diff --git a/synchronizer/l1_check_block/async_test.go b/synchronizer/l1_check_block/async_test.go new file mode 100644 index 0000000000..21358b1c8f --- /dev/null +++ b/synchronizer/l1_check_block/async_test.go @@ -0,0 +1,138 @@ +package l1_check_block_test + +import ( + "context" + "fmt" + "sync" + "testing" + "time" + + "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block" + "github.com/stretchr/testify/require" +) + +var ( + errGenericToTestAsync = fmt.Errorf("error_async") + errReorgToTestAsync = common.NewReorgError(uint64(1234), fmt.Errorf("fake reorg to test")) + timeoutContextForAsyncTests = time.Second +) + +type mockChecker struct { + Wg *sync.WaitGroup + ErrorsToReturn []error +} + +func (m *mockChecker) Step(ctx context.Context) error { + defer m.Wg.Done() + err := m.ErrorsToReturn[0] + if len(m.ErrorsToReturn) > 0 { + m.ErrorsToReturn = m.ErrorsToReturn[1:] + } + return err +} + +// If checker.step() returns ok, the async object will relaunch the call +func TestAsyncRelaunchCheckerUntilReorgDetected(t *testing.T) { + mockChecker := &mockChecker{ErrorsToReturn: []error{nil, nil, errGenericToTestAsync, errReorgToTestAsync}, Wg: &sync.WaitGroup{}} + sut := l1_check_block.NewAsyncCheck(mockChecker) + sut.SetPeriodTime(0) + ctx, cancel := context.WithTimeout(context.Background(), timeoutContextForAsyncTests) + defer cancel() + mockChecker.Wg.Add(4) + + sut.Run(ctx, nil) + + mockChecker.Wg.Wait() + result := sut.GetResultBlockingUntilAvailable(0) + require.NotNil(t, result) + require.Equal(t, uint64(1234), result.BlockNumber) + require.Equal(t, true, result.ReorgDetected) + require.Equal(t, nil, result.Err) +} + +func TestAsyncGetResultIsNilUntilStops(t *testing.T) { + mockChecker := &mockChecker{ErrorsToReturn: []error{nil, nil, errGenericToTestAsync, errReorgToTestAsync}, Wg: &sync.WaitGroup{}} + sut := l1_check_block.NewAsyncCheck(mockChecker) + sut.SetPeriodTime(0) + ctx, cancel := context.WithTimeout(context.Background(), timeoutContextForAsyncTests) + defer cancel() + mockChecker.Wg.Add(4) + require.Nil(t, sut.GetResult(), "before start result is Nil") + + sut.Run(ctx, nil) + + require.Nil(t, sut.GetResult(), "after start result is Nil") + mockChecker.Wg.Wait() + result := sut.GetResultBlockingUntilAvailable(0) + require.NotNil(t, result) +} + +// RunSynchronous it returns the first result, doesnt mind if a reorg or not +func TestAsyncGRunSynchronousReturnTheFirstResult(t *testing.T) { + mockChecker := &mockChecker{ErrorsToReturn: []error{errGenericToTestAsync}, Wg: &sync.WaitGroup{}} + sut := l1_check_block.NewAsyncCheck(mockChecker) + sut.SetPeriodTime(0) + ctx, cancel := context.WithTimeout(context.Background(), timeoutContextForAsyncTests) + defer cancel() + mockChecker.Wg.Add(1) + + result := sut.RunSynchronous(ctx) + + require.NotNil(t, result) + require.Equal(t, uint64(0), result.BlockNumber) + require.Equal(t, false, result.ReorgDetected) + require.Equal(t, errGenericToTestAsync, result.Err) +} + +func TestAsyncGRunSynchronousDontAffectGetResult(t *testing.T) { + mockChecker := &mockChecker{ErrorsToReturn: []error{errGenericToTestAsync}, Wg: &sync.WaitGroup{}} + sut := l1_check_block.NewAsyncCheck(mockChecker) + sut.SetPeriodTime(0) + ctx, cancel := context.WithTimeout(context.Background(), timeoutContextForAsyncTests) + defer cancel() + mockChecker.Wg.Add(1) + + result := sut.RunSynchronous(ctx) + + require.NotNil(t, result) + require.Nil(t, sut.GetResult()) +} + +func TestAsyncStop(t *testing.T) { + mockChecker := &mockChecker{ErrorsToReturn: []error{nil, nil, errGenericToTestAsync, errReorgToTestAsync}, Wg: &sync.WaitGroup{}} + sut := l1_check_block.NewAsyncCheck(mockChecker) + sut.SetPeriodTime(0) + ctx, cancel := context.WithTimeout(context.Background(), timeoutContextForAsyncTests) + defer cancel() + require.Nil(t, sut.GetResult(), "before start result is Nil") + mockChecker.Wg.Add(4) + sut.Run(ctx, nil) + sut.Stop() + sut.Stop() + + result := sut.GetResultBlockingUntilAvailable(0) + require.NotNil(t, result) + mockChecker.Wg = &sync.WaitGroup{} + mockChecker.Wg.Add(4) + mockChecker.ErrorsToReturn = []error{nil, nil, errGenericToTestAsync, errReorgToTestAsync} + sut.Run(ctx, nil) + mockChecker.Wg.Wait() + result = sut.GetResultBlockingUntilAvailable(0) + require.NotNil(t, result) +} + +func TestAsyncMultipleRun(t *testing.T) { + mockChecker := &mockChecker{ErrorsToReturn: []error{nil, nil, errGenericToTestAsync, errReorgToTestAsync}, Wg: &sync.WaitGroup{}} + sut := l1_check_block.NewAsyncCheck(mockChecker) + sut.SetPeriodTime(0) + ctx, cancel := context.WithTimeout(context.Background(), timeoutContextForAsyncTests) + defer cancel() + require.Nil(t, sut.GetResult(), "before start result is Nil") + mockChecker.Wg.Add(4) + sut.Run(ctx, nil) + sut.Run(ctx, nil) + sut.Run(ctx, nil) + result := sut.GetResultBlockingUntilAvailable(0) + require.NotNil(t, result) +} diff --git a/synchronizer/l1_check_block/check_l1block.go b/synchronizer/l1_check_block/check_l1block.go new file mode 100644 index 0000000000..cd1204c5b3 --- /dev/null +++ b/synchronizer/l1_check_block/check_l1block.go @@ -0,0 +1,146 @@ +package l1_check_block + +import ( + "context" + "errors" + "fmt" + "math/big" + "time" + + "github.com/0xPolygonHermez/zkevm-node/log" + "github.com/0xPolygonHermez/zkevm-node/state" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/jackc/pgx/v4" +) + +// This object check old L1block to double-check that the L1block hash is correct +// - Get first not checked block +// - Get last block on L1 (safe/finalized/ or minus -n) + +// L1Requester is an interface for GETH client +type L1Requester interface { + HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) +} + +// StateInterfacer is an interface for the state +type StateInterfacer interface { + GetFirstUncheckedBlock(ctx context.Context, fromBlockNumber uint64, dbTx pgx.Tx) (*state.Block, error) + UpdateCheckedBlockByNumber(ctx context.Context, blockNumber uint64, newCheckedStatus bool, dbTx pgx.Tx) error +} + +// SafeL1BlockNumberFetcher is an interface for fetching the L1 block number reference point (safe, finalized,...) +type SafeL1BlockNumberFetcher interface { + GetSafeBlockNumber(ctx context.Context, l1Client L1Requester) (uint64, error) + Description() string +} + +// CheckL1BlockHash is a struct that implements a checker of L1Block hash +type CheckL1BlockHash struct { + L1Client L1Requester + State StateInterfacer + SafeBlockNumberFetcher SafeL1BlockNumberFetcher +} + +// NewCheckL1BlockHash creates a new CheckL1BlockHash +func NewCheckL1BlockHash(l1Client L1Requester, state StateInterfacer, safeBlockNumberFetcher SafeL1BlockNumberFetcher) *CheckL1BlockHash { + return &CheckL1BlockHash{ + L1Client: l1Client, + State: state, + SafeBlockNumberFetcher: safeBlockNumberFetcher, + } +} + +// Name is a method that returns the name of the checker +func (p *CheckL1BlockHash) Name() string { + return logPrefix + " main_checker: " +} + +// Step is a method that checks the L1 block hash, run until all blocks are checked and returns +func (p *CheckL1BlockHash) Step(ctx context.Context) error { + stateBlock, err := p.State.GetFirstUncheckedBlock(ctx, uint64(0), nil) + if errors.Is(err, state.ErrNotFound) { + log.Debugf("%s: No unchecked blocks to check", p.Name()) + return nil + } + if err != nil { + return err + } + if stateBlock == nil { + log.Warnf("%s: function CheckL1Block receive a nil pointer", p.Name()) + return nil + } + safeBlockNumber, err := p.SafeBlockNumberFetcher.GetSafeBlockNumber(ctx, p.L1Client) + if err != nil { + return err + } + log.Debugf("%s: checking from block (%s) %d first block to check: %d....", p.Name(), p.SafeBlockNumberFetcher.Description(), safeBlockNumber, stateBlock.BlockNumber) + return p.doAllBlocks(ctx, *stateBlock, safeBlockNumber) +} + +func (p *CheckL1BlockHash) doAllBlocks(ctx context.Context, firstStateBlock state.Block, safeBlockNumber uint64) error { + var err error + startTime := time.Now() + stateBlock := &firstStateBlock + numBlocksChecked := 0 + for { + lastStateBlockNumber := stateBlock.BlockNumber + if stateBlock.BlockNumber > safeBlockNumber { + log.Debugf("%s: block %d to check is not still safe enough (%s) %d ", p.Name(), stateBlock.BlockNumber, p.SafeBlockNumberFetcher.Description(), safeBlockNumber, logPrefix) + return nil + } + err = p.doBlock(ctx, stateBlock) + if err != nil { + return err + } + numBlocksChecked++ + stateBlock, err = p.State.GetFirstUncheckedBlock(ctx, lastStateBlockNumber, nil) + if errors.Is(err, state.ErrNotFound) { + diff := time.Since(startTime) + log.Infof("%s: checked all blocks (%d) (using as safe Block Point(%s): %d) time:%s", p.Name(), numBlocksChecked, p.SafeBlockNumberFetcher.Description(), safeBlockNumber, diff) + return nil + } + } +} + +func (p *CheckL1BlockHash) doBlock(ctx context.Context, stateBlock *state.Block) error { + err := CheckBlockHash(ctx, stateBlock, p.L1Client, p.Name()) + if err != nil { + return err + } + log.Infof("%s: L1Block: %d hash: %s is correct marking as checked", p.Name(), stateBlock.BlockNumber, + stateBlock.BlockHash.String()) + err = p.State.UpdateCheckedBlockByNumber(ctx, stateBlock.BlockNumber, true, nil) + if err != nil { + log.Errorf("%s: Error updating block %d as checked. err: %s", p.Name(), stateBlock.BlockNumber, err.Error()) + return err + } + return nil +} + +// CheckBlockHash is a method that checks the L1 block hash +func CheckBlockHash(ctx context.Context, stateBlock *state.Block, L1Client L1Requester, checkerName string) error { + if stateBlock == nil { + log.Warn("%s function CheckL1Block receive a nil pointer", checkerName) + return nil + } + l1Block, err := L1Client.HeaderByNumber(ctx, big.NewInt(int64(stateBlock.BlockNumber))) + if err != nil { + return err + } + if l1Block == nil { + err = fmt.Errorf("%s request of block: %d to L1 returns a nil", checkerName, stateBlock.BlockNumber) + log.Error(err.Error()) + return err + } + if l1Block.Hash() != stateBlock.BlockHash { + msg := fmt.Sprintf("%s Reorg detected at block %d l1Block.Hash=%s != stateBlock.Hash=%s. ", checkerName, stateBlock.BlockNumber, + l1Block.Hash().String(), stateBlock.BlockHash.String()) + if l1Block.ParentHash != stateBlock.ParentHash { + msg += fmt.Sprintf(" ParentHash are also different. l1Block.ParentHash=%s != stateBlock.ParentHash=%s", l1Block.ParentHash.String(), stateBlock.ParentHash.String()) + } + log.Errorf(msg) + return common.NewReorgError(stateBlock.BlockNumber, fmt.Errorf(msg)) + } + return nil +} diff --git a/synchronizer/l1_check_block/check_l1block_test.go b/synchronizer/l1_check_block/check_l1block_test.go new file mode 100644 index 0000000000..e5090140a3 --- /dev/null +++ b/synchronizer/l1_check_block/check_l1block_test.go @@ -0,0 +1,128 @@ +package l1_check_block_test + +import ( + "context" + "fmt" + "math/big" + "testing" + + "github.com/0xPolygonHermez/zkevm-node/state" + commonsync "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block" + mock_l1_check_block "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block/mocks" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +type testData struct { + mockL1Client *mock_l1_check_block.L1Requester + mockState *mock_l1_check_block.StateInterfacer + mockBlockNumberFetch *mock_l1_check_block.SafeL1BlockNumberFetcher + sut *l1_check_block.CheckL1BlockHash + ctx context.Context + stateBlock *state.Block +} + +func newTestData(t *testing.T) *testData { + mockL1Client := mock_l1_check_block.NewL1Requester(t) + mockState := mock_l1_check_block.NewStateInterfacer(t) + mockBlockNumberFetch := mock_l1_check_block.NewSafeL1BlockNumberFetcher(t) + mockBlockNumberFetch.EXPECT().Description().Return("mock").Maybe() + sut := l1_check_block.NewCheckL1BlockHash(mockL1Client, mockState, mockBlockNumberFetch) + require.NotNil(t, sut) + ctx := context.Background() + return &testData{ + mockL1Client: mockL1Client, + mockState: mockState, + mockBlockNumberFetch: mockBlockNumberFetch, + sut: sut, + ctx: ctx, + stateBlock: &state.Block{ + BlockNumber: 1234, + BlockHash: common.HexToHash("0xb07e1289b32edefd8f3c702d016fb73c81d5950b2ebc790ad9d2cb8219066b4c"), + }, + } +} + +func TestCheckL1BlockHashNoBlocksOnDB(t *testing.T) { + data := newTestData(t) + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, uint64(0), nil).Return(nil, state.ErrNotFound) + res := data.sut.Step(data.ctx) + require.NoError(t, res) +} + +func TestCheckL1BlockHashErrorGettingFirstUncheckedBlockFromDB(t *testing.T) { + data := newTestData(t) + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, uint64(0), nil).Return(nil, fmt.Errorf("error")) + res := data.sut.Step(data.ctx) + require.Error(t, res) +} + +func TestCheckL1BlockHashErrorGettingGetSafeBlockNumber(t *testing.T) { + data := newTestData(t) + + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, uint64(0), nil).Return(data.stateBlock, nil) + data.mockBlockNumberFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(0), fmt.Errorf("error")) + res := data.sut.Step(data.ctx) + require.Error(t, res) +} + +// The first block to check is below the safe point, nothing to do +func TestCheckL1BlockHashSafePointIsInFuture(t *testing.T) { + data := newTestData(t) + + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, uint64(0), nil).Return(data.stateBlock, nil) + data.mockBlockNumberFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(data.stateBlock.BlockNumber-1, nil) + + res := data.sut.Step(data.ctx) + require.NoError(t, res) +} + +func TestCheckL1BlockHashL1ClientReturnsANil(t *testing.T) { + data := newTestData(t) + + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, uint64(0), nil).Return(data.stateBlock, nil) + data.mockBlockNumberFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(data.stateBlock.BlockNumber+10, nil) + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlock.BlockNumber))).Return(nil, nil) + res := data.sut.Step(data.ctx) + require.Error(t, res) +} + +// Check a block that is OK +func TestCheckL1BlockHashMatchHashUpdateCheckMarkOnDB(t *testing.T) { + data := newTestData(t) + + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, uint64(0), nil).Return(data.stateBlock, nil) + data.mockBlockNumberFetch.EXPECT().Description().Return("mock") + data.mockBlockNumberFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(data.stateBlock.BlockNumber, nil) + l1Block := &types.Header{ + Number: big.NewInt(100), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlock.BlockNumber))).Return(l1Block, nil) + data.mockState.EXPECT().UpdateCheckedBlockByNumber(data.ctx, data.stateBlock.BlockNumber, true, nil).Return(nil) + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, mock.Anything, nil).Return(nil, state.ErrNotFound) + + res := data.sut.Step(data.ctx) + require.NoError(t, res) +} + +// The first block to check is equal to the safe point, must be processed +func TestCheckL1BlockHashMismatch(t *testing.T) { + data := newTestData(t) + + data.mockState.EXPECT().GetFirstUncheckedBlock(data.ctx, uint64(0), nil).Return(data.stateBlock, nil) + data.stateBlock.BlockHash = common.HexToHash("0x1234") // Wrong hash to trigger a mismatch + data.mockBlockNumberFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(data.stateBlock.BlockNumber, nil) + l1Block := &types.Header{ + Number: big.NewInt(100), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlock.BlockNumber))).Return(l1Block, nil) + + res := data.sut.Step(data.ctx) + require.Error(t, res) + resErr, ok := res.(*commonsync.ReorgError) + require.True(t, ok) + require.Equal(t, data.stateBlock.BlockNumber, resErr.BlockNumber) +} diff --git a/synchronizer/l1_check_block/common.go b/synchronizer/l1_check_block/common.go new file mode 100644 index 0000000000..a473c220a3 --- /dev/null +++ b/synchronizer/l1_check_block/common.go @@ -0,0 +1,5 @@ +package l1_check_block + +const ( + logPrefix = "checkL1block:" +) diff --git a/synchronizer/l1_check_block/integration.go b/synchronizer/l1_check_block/integration.go new file mode 100644 index 0000000000..82a962eb3f --- /dev/null +++ b/synchronizer/l1_check_block/integration.go @@ -0,0 +1,205 @@ +package l1_check_block + +import ( + "context" + "time" + + "github.com/0xPolygonHermez/zkevm-node/log" + "github.com/0xPolygonHermez/zkevm-node/state" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces" + "github.com/jackc/pgx/v4" +) + +// StateForL1BlockCheckerIntegration is an interface for the state +type StateForL1BlockCheckerIntegration interface { + GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) +} + +// L1BlockCheckerIntegration is a struct that integrates the L1BlockChecker with the synchronizer +type L1BlockCheckerIntegration struct { + forceCheckOnStart bool + checker syncinterfaces.AsyncL1BlockChecker + preChecker syncinterfaces.AsyncL1BlockChecker + state StateForL1BlockCheckerIntegration + sync SyncCheckReorger + timeBetweenRetries time.Duration +} + +// SyncCheckReorger is an interface that defines the methods required from Synchronizer object +type SyncCheckReorger interface { + ExecuteReorgFromMismatchBlock(blockNumber uint64, reason string) error + OnDetectedMismatchL1BlockReorg() +} + +// NewL1BlockCheckerIntegration creates a new L1BlockCheckerIntegration +func NewL1BlockCheckerIntegration(checker syncinterfaces.AsyncL1BlockChecker, preChecker syncinterfaces.AsyncL1BlockChecker, state StateForL1BlockCheckerIntegration, sync SyncCheckReorger, forceCheckOnStart bool, timeBetweenRetries time.Duration) *L1BlockCheckerIntegration { + return &L1BlockCheckerIntegration{ + forceCheckOnStart: forceCheckOnStart, + checker: checker, + preChecker: preChecker, + state: state, + sync: sync, + timeBetweenRetries: timeBetweenRetries, + } +} + +// OnStart is a method that is called before starting the synchronizer +func (v *L1BlockCheckerIntegration) OnStart(ctx context.Context) error { + if v.forceCheckOnStart { + log.Infof("%s Forcing L1BlockChecker check before start", logPrefix) + result := v.runCheckerSync(ctx, v.checker) + if result.ReorgDetected { + v.executeResult(ctx, result) + } else { + log.Infof("%s Forcing L1BlockChecker check:OK ", logPrefix) + if v.preChecker != nil { + log.Infof("%s Forcing L1BlockChecker preCheck before start", logPrefix) + result = v.runCheckerSync(ctx, v.preChecker) + if result.ReorgDetected { + v.executeResult(ctx, result) + } else { + log.Infof("%s Forcing L1BlockChecker preCheck:OK", logPrefix) + } + } + } + } + v.launch(ctx) + return nil +} + +func (v *L1BlockCheckerIntegration) runCheckerSync(ctx context.Context, checker syncinterfaces.AsyncL1BlockChecker) syncinterfaces.IterationResult { + for { + result := checker.RunSynchronous(ctx) + if result.Err == nil { + return result + } else { + time.Sleep(v.timeBetweenRetries) + } + } +} + +// OnStartL1Sync is a method that is called before starting the L1 sync +func (v *L1BlockCheckerIntegration) OnStartL1Sync(ctx context.Context) bool { + return v.checkBackgroundResult(ctx, "before start L1 sync") +} + +// OnStartL2Sync is a method that is called before starting the L2 sync +func (v *L1BlockCheckerIntegration) OnStartL2Sync(ctx context.Context) bool { + return v.checkBackgroundResult(ctx, "before start 2 sync") +} + +// OnResetState is a method that is called after a resetState +func (v *L1BlockCheckerIntegration) OnResetState(ctx context.Context) { + log.Infof("%s L1BlockChecker: after a resetState relaunch background process", logPrefix) + v.launch(ctx) +} + +// CheckReorgWrapper is a wrapper over reorg function of synchronizer. +// it checks the result of the function and the result of background process and decides which return +func (v *L1BlockCheckerIntegration) CheckReorgWrapper(ctx context.Context, reorgFirstBlockOk *state.Block, errReportedByReorgFunc error) (*state.Block, error) { + resultBackground := v.getMergedResults() + if resultBackground != nil && resultBackground.ReorgDetected { + // Background process detected a reorg, decide which return + firstOkBlockBackgroundCheck, err := v.state.GetPreviousBlockToBlockNumber(ctx, resultBackground.BlockNumber, nil) + if err != nil { + log.Warnf("%s Error getting previous block to block number where a reorg have been detected %d: %s. So we reorgFunc values", logPrefix, resultBackground.BlockNumber, err) + return reorgFirstBlockOk, errReportedByReorgFunc + } + if reorgFirstBlockOk == nil || errReportedByReorgFunc != nil { + log.Infof("%s Background checker detects bad block at block %d (first block ok %d) and regular reorg function no. Returning it", logPrefix, + resultBackground.BlockNumber, firstOkBlockBackgroundCheck.BlockNumber) + return firstOkBlockBackgroundCheck, nil + } + if firstOkBlockBackgroundCheck.BlockNumber < reorgFirstBlockOk.BlockNumber { + // Background process detected a reorg at oldest block + log.Warnf("%s Background checker detects bad block at block %d (first block ok %d) and regular reorg function first block ok: %d. Returning from %d", + logPrefix, resultBackground.BlockNumber, firstOkBlockBackgroundCheck.BlockNumber, reorgFirstBlockOk.BlockNumber, firstOkBlockBackgroundCheck.BlockNumber) + return firstOkBlockBackgroundCheck, nil + } else { + // Regular reorg function detected a reorg at oldest block + log.Warnf("%s Background checker detects bad block at block %d (first block ok %d) and regular reorg function first block ok: %d. Executing from %d", + logPrefix, resultBackground.BlockNumber, firstOkBlockBackgroundCheck.BlockNumber, reorgFirstBlockOk.BlockNumber, reorgFirstBlockOk.BlockNumber) + return reorgFirstBlockOk, errReportedByReorgFunc + } + } + if resultBackground != nil && !resultBackground.ReorgDetected { + // Relaunch checker, if there is a reorg, It is going to be relaunched after (OnResetState) + v.launch(ctx) + } + // Background process doesnt have anything to we return the regular reorg function result + return reorgFirstBlockOk, errReportedByReorgFunc +} + +func (v *L1BlockCheckerIntegration) checkBackgroundResult(ctx context.Context, positionMessage string) bool { + log.Debugf("%s Checking L1BlockChecker %s", logPrefix, positionMessage) + result := v.getMergedResults() + if result != nil { + if result.ReorgDetected { + log.Warnf("%s Checking L1BlockChecker %s: reorg detected %s", logPrefix, positionMessage, result.String()) + v.executeResult(ctx, *result) + } + v.launch(ctx) + return result.ReorgDetected + } + return false +} + +func (v *L1BlockCheckerIntegration) getMergedResults() *syncinterfaces.IterationResult { + result := v.checker.GetResult() + var preResult *syncinterfaces.IterationResult + preResult = nil + if v.preChecker != nil { + preResult = v.preChecker.GetResult() + } + if preResult == nil { + return result + } + if result == nil { + return preResult + } + // result and preResult have values + if result.ReorgDetected && preResult.ReorgDetected { + // That is the common case, checker must detect oldest blocks than preChecker + if result.BlockNumber < preResult.BlockNumber { + return result + } + return preResult + } + if preResult.ReorgDetected { + return preResult + } + return result +} + +func (v *L1BlockCheckerIntegration) onFinishChecker() { + log.Infof("%s L1BlockChecker: finished background process, calling to synchronizer", logPrefix) + // Stop both processes + v.checker.Stop() + if v.preChecker != nil { + v.preChecker.Stop() + } + v.sync.OnDetectedMismatchL1BlockReorg() +} + +func (v *L1BlockCheckerIntegration) launch(ctx context.Context) { + log.Infof("%s L1BlockChecker: starting background process...", logPrefix) + v.checker.Run(ctx, v.onFinishChecker) + if v.preChecker != nil { + log.Infof("%s L1BlockChecker: starting background precheck process...", logPrefix) + v.preChecker.Run(ctx, v.onFinishChecker) + } +} + +func (v *L1BlockCheckerIntegration) executeResult(ctx context.Context, result syncinterfaces.IterationResult) bool { + if result.ReorgDetected { + for { + err := v.sync.ExecuteReorgFromMismatchBlock(result.BlockNumber, result.ReorgMessage) + if err == nil { + return true + } + log.Errorf("%s Error executing reorg: %s", logPrefix, err) + time.Sleep(v.timeBetweenRetries) + } + } + return false +} diff --git a/synchronizer/l1_check_block/integration_test.go b/synchronizer/l1_check_block/integration_test.go new file mode 100644 index 0000000000..de79c71351 --- /dev/null +++ b/synchronizer/l1_check_block/integration_test.go @@ -0,0 +1,298 @@ +package l1_check_block_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/0xPolygonHermez/zkevm-node/state" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces" + mock_syncinterfaces "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces/mocks" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block" + mock_l1_check_block "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block/mocks" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +var ( + genericErrorToTest = fmt.Errorf("error") +) + +type testDataIntegration struct { + mockChecker *mock_syncinterfaces.AsyncL1BlockChecker + mockPreChecker *mock_syncinterfaces.AsyncL1BlockChecker + mockState *mock_l1_check_block.StateForL1BlockCheckerIntegration + mockSync *mock_l1_check_block.SyncCheckReorger + sut *l1_check_block.L1BlockCheckerIntegration + ctx context.Context + resultOk syncinterfaces.IterationResult + resultError syncinterfaces.IterationResult + resultReorg syncinterfaces.IterationResult +} + +func newDataIntegration(t *testing.T, forceCheckOnStart bool) *testDataIntegration { + return newDataIntegrationOnlyMainChecker(t, forceCheckOnStart) +} + +func newDataIntegrationWithPreChecker(t *testing.T, forceCheckOnStart bool) *testDataIntegration { + res := newDataIntegrationOnlyMainChecker(t, forceCheckOnStart) + res.mockPreChecker = mock_syncinterfaces.NewAsyncL1BlockChecker(t) + res.sut = l1_check_block.NewL1BlockCheckerIntegration(res.mockChecker, res.mockPreChecker, res.mockState, res.mockSync, forceCheckOnStart, time.Millisecond) + return res +} + +func newDataIntegrationOnlyMainChecker(t *testing.T, forceCheckOnStart bool) *testDataIntegration { + mockChecker := mock_syncinterfaces.NewAsyncL1BlockChecker(t) + mockSync := mock_l1_check_block.NewSyncCheckReorger(t) + mockState := mock_l1_check_block.NewStateForL1BlockCheckerIntegration(t) + sut := l1_check_block.NewL1BlockCheckerIntegration(mockChecker, nil, mockState, mockSync, forceCheckOnStart, time.Millisecond) + return &testDataIntegration{ + mockChecker: mockChecker, + mockPreChecker: nil, + mockSync: mockSync, + mockState: mockState, + sut: sut, + ctx: context.Background(), + resultReorg: syncinterfaces.IterationResult{ + ReorgDetected: true, + BlockNumber: 1234, + }, + resultOk: syncinterfaces.IterationResult{ + ReorgDetected: false, + }, + resultError: syncinterfaces.IterationResult{ + Err: genericErrorToTest, + ReorgDetected: false, + }, + } +} + +func TestIntegrationIfNoForceCheckOnlyLaunchBackgroudChecker(t *testing.T) { + data := newDataIntegration(t, false) + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +func TestIntegrationIfForceCheckRunsSynchronousOneTimeAndAfterLaunchBackgroudChecker(t *testing.T) { + data := newDataIntegration(t, true) + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultOk) + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +func TestIntegrationIfSyncCheckReturnsReorgExecuteIt(t *testing.T) { + data := newDataIntegration(t, true) + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultReorg) + data.mockSync.EXPECT().ExecuteReorgFromMismatchBlock(uint64(1234), "").Return(nil) + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +func TestIntegrationIfSyncCheckReturnErrorRetry(t *testing.T) { + data := newDataIntegration(t, true) + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultError).Once() + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultOk).Once() + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +func TestIntegrationIfSyncCheckReturnsReorgExecuteItAndFailsRetry(t *testing.T) { + data := newDataIntegration(t, true) + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultReorg) + data.mockSync.EXPECT().ExecuteReorgFromMismatchBlock(uint64(1234), mock.Anything).Return(genericErrorToTest).Once() + data.mockSync.EXPECT().ExecuteReorgFromMismatchBlock(uint64(1234), mock.Anything).Return(nil).Once() + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +// OnStart if check and preCheck execute both, and launch both in background +func TestIntegrationCheckAndPreCheckOnStartForceCheck(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultOk) + data.mockPreChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultOk) + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + data.mockPreChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +// OnStart if mainChecker returns reorg doesnt need to run preCheck +func TestIntegrationCheckAndPreCheckOnStartMainCheckerReturnReorg(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultReorg) + data.mockSync.EXPECT().ExecuteReorgFromMismatchBlock(uint64(1234), mock.Anything).Return(nil).Once() + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + data.mockPreChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +// If mainCheck is OK, but preCheck returns reorg, it should execute reorg +func TestIntegrationCheckAndPreCheckOnStartPreCheckerReturnReorg(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultOk) + data.mockPreChecker.EXPECT().RunSynchronous(data.ctx).Return(data.resultReorg) + data.mockSync.EXPECT().ExecuteReorgFromMismatchBlock(uint64(1234), mock.Anything).Return(nil).Once() + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + data.mockPreChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + err := data.sut.OnStart(data.ctx) + require.NoError(t, err) +} + +// The process is running on background, no results yet +func TestIntegrationCheckAndPreCheckOnOnCheckReorgRunningOnBackground(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(nil) + data.mockPreChecker.EXPECT().GetResult().Return(nil) + block, err := data.sut.CheckReorgWrapper(data.ctx, nil, nil) + require.Nil(t, block) + require.NoError(t, err) +} + +func TestIntegrationCheckAndPreCheckOnOnCheckReorgOneProcessHaveResultOK(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(&data.resultOk) + data.mockPreChecker.EXPECT().GetResult().Return(nil) + // One have been stopped, so must relaunch both + data.mockChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + data.mockPreChecker.EXPECT().Run(data.ctx, mock.Anything).Return() + block, err := data.sut.CheckReorgWrapper(data.ctx, nil, nil) + require.Nil(t, block) + require.NoError(t, err) +} + +func TestIntegrationCheckAndPreCheckOnOnCheckReorgMainCheckerReorg(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(&data.resultReorg) + data.mockPreChecker.EXPECT().GetResult().Return(nil) + data.mockState.EXPECT().GetPreviousBlockToBlockNumber(data.ctx, uint64(1234), nil).Return(&state.Block{ + BlockNumber: data.resultReorg.BlockNumber - 1, + }, nil) + // One have been stopped,but is going to be launched OnResetState call after the reset + block, err := data.sut.CheckReorgWrapper(data.ctx, nil, nil) + require.NotNil(t, block) + require.Equal(t, data.resultReorg.BlockNumber-1, block.BlockNumber) + require.NoError(t, err) +} + +func TestIntegrationCheckAndPreCheckOnOnCheckReorgPreCheckerReorg(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(nil) + data.mockPreChecker.EXPECT().GetResult().Return(&data.resultReorg) + data.mockState.EXPECT().GetPreviousBlockToBlockNumber(data.ctx, uint64(1234), nil).Return(&state.Block{ + BlockNumber: data.resultReorg.BlockNumber - 1, + }, nil) + // One have been stopped,but is going to be launched OnResetState call after the reset + + block, err := data.sut.CheckReorgWrapper(data.ctx, nil, nil) + require.NotNil(t, block) + require.Equal(t, data.resultReorg.BlockNumber-1, block.BlockNumber) + require.NoError(t, err) +} + +func TestIntegrationCheckAndPreCheckOnOnCheckReorgBothReorgWinOldest1(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + reorgMain := data.resultReorg + reorgMain.BlockNumber = 1235 + data.mockChecker.EXPECT().GetResult().Return(&reorgMain) + reorgPre := data.resultReorg + reorgPre.BlockNumber = 1236 + data.mockPreChecker.EXPECT().GetResult().Return(&reorgPre) + data.mockState.EXPECT().GetPreviousBlockToBlockNumber(data.ctx, uint64(1235), nil).Return(&state.Block{ + BlockNumber: 1234, + }, nil) + + // Both have been stopped,but is going to be launched OnResetState call after the reset + + block, err := data.sut.CheckReorgWrapper(data.ctx, nil, nil) + require.NotNil(t, block) + require.Equal(t, uint64(1234), block.BlockNumber) + require.NoError(t, err) +} + +func TestIntegrationCheckAndPreCheckOnOnCheckReorgBothReorgWinOldest2(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + reorgMain := data.resultReorg + reorgMain.BlockNumber = 1236 + data.mockChecker.EXPECT().GetResult().Return(&reorgMain) + reorgPre := data.resultReorg + reorgPre.BlockNumber = 1235 + data.mockPreChecker.EXPECT().GetResult().Return(&reorgPre) + data.mockState.EXPECT().GetPreviousBlockToBlockNumber(data.ctx, uint64(1235), nil).Return(&state.Block{ + BlockNumber: 1234, + }, nil) + // Both have been stopped,but is going to be launched OnResetState call after the reset + + block, err := data.sut.CheckReorgWrapper(data.ctx, nil, nil) + require.NotNil(t, block) + require.Equal(t, uint64(1234), block.BlockNumber) + require.NoError(t, err) +} + +func TestIntegrationCheckReorgWrapperBypassReorgFuncIfNoBackgroundData(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(nil) + data.mockPreChecker.EXPECT().GetResult().Return(nil) + reorgFuncBlock := &state.Block{ + BlockNumber: 1234, + } + reorgFuncErr := fmt.Errorf("error") + block, err := data.sut.CheckReorgWrapper(data.ctx, reorgFuncBlock, reorgFuncErr) + require.Equal(t, reorgFuncBlock, block) + require.Equal(t, reorgFuncErr, err) +} + +func TestIntegrationCheckReorgWrapperChooseOldestReorgFunc(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(nil) + data.mockPreChecker.EXPECT().GetResult().Return(&data.resultReorg) + data.mockState.EXPECT().GetPreviousBlockToBlockNumber(data.ctx, uint64(1234), nil).Return(&state.Block{ + BlockNumber: 1233, + }, nil) + + reorgFuncBlock := &state.Block{ + BlockNumber: 1230, + } + block, err := data.sut.CheckReorgWrapper(data.ctx, reorgFuncBlock, nil) + require.Equal(t, reorgFuncBlock, block) + require.NoError(t, err) +} + +func TestIntegrationCheckReorgWrapperChooseOldestBackgroundCheck(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(nil) + data.mockPreChecker.EXPECT().GetResult().Return(&data.resultReorg) + data.mockState.EXPECT().GetPreviousBlockToBlockNumber(data.ctx, uint64(1234), nil).Return(&state.Block{ + BlockNumber: 1233, + }, nil) + + reorgFuncBlock := &state.Block{ + BlockNumber: 1240, + } + block, err := data.sut.CheckReorgWrapper(data.ctx, reorgFuncBlock, nil) + require.Equal(t, uint64(1233), block.BlockNumber) + require.NoError(t, err) +} + +func TestIntegrationCheckReorgWrapperIgnoreReorgFuncIfError(t *testing.T) { + data := newDataIntegrationWithPreChecker(t, true) + data.mockChecker.EXPECT().GetResult().Return(nil) + data.mockPreChecker.EXPECT().GetResult().Return(&data.resultReorg) + data.mockState.EXPECT().GetPreviousBlockToBlockNumber(data.ctx, uint64(1234), nil).Return(&state.Block{ + BlockNumber: 1233, + }, nil) + + reorgFuncBlock := &state.Block{ + BlockNumber: 1230, + } + reorgFuncErr := fmt.Errorf("error") + block, err := data.sut.CheckReorgWrapper(data.ctx, reorgFuncBlock, reorgFuncErr) + require.Equal(t, uint64(1233), block.BlockNumber) + require.NoError(t, err) +} diff --git a/synchronizer/l1_check_block/mocks/l1_block_checker.go b/synchronizer/l1_check_block/mocks/l1_block_checker.go new file mode 100644 index 0000000000..6f0eab9acb --- /dev/null +++ b/synchronizer/l1_check_block/mocks/l1_block_checker.go @@ -0,0 +1,82 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_l1_check_block + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// L1BlockChecker is an autogenerated mock type for the L1BlockChecker type +type L1BlockChecker struct { + mock.Mock +} + +type L1BlockChecker_Expecter struct { + mock *mock.Mock +} + +func (_m *L1BlockChecker) EXPECT() *L1BlockChecker_Expecter { + return &L1BlockChecker_Expecter{mock: &_m.Mock} +} + +// Step provides a mock function with given fields: ctx +func (_m *L1BlockChecker) Step(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Step") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// L1BlockChecker_Step_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Step' +type L1BlockChecker_Step_Call struct { + *mock.Call +} + +// Step is a helper method to define mock.On call +// - ctx context.Context +func (_e *L1BlockChecker_Expecter) Step(ctx interface{}) *L1BlockChecker_Step_Call { + return &L1BlockChecker_Step_Call{Call: _e.mock.On("Step", ctx)} +} + +func (_c *L1BlockChecker_Step_Call) Run(run func(ctx context.Context)) *L1BlockChecker_Step_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *L1BlockChecker_Step_Call) Return(_a0 error) *L1BlockChecker_Step_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *L1BlockChecker_Step_Call) RunAndReturn(run func(context.Context) error) *L1BlockChecker_Step_Call { + _c.Call.Return(run) + return _c +} + +// NewL1BlockChecker creates a new instance of L1BlockChecker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewL1BlockChecker(t interface { + mock.TestingT + Cleanup(func()) +}) *L1BlockChecker { + mock := &L1BlockChecker{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/l1_check_block/mocks/l1_requester.go b/synchronizer/l1_check_block/mocks/l1_requester.go new file mode 100644 index 0000000000..713cc4a5ef --- /dev/null +++ b/synchronizer/l1_check_block/mocks/l1_requester.go @@ -0,0 +1,98 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_l1_check_block + +import ( + context "context" + big "math/big" + + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" +) + +// L1Requester is an autogenerated mock type for the L1Requester type +type L1Requester struct { + mock.Mock +} + +type L1Requester_Expecter struct { + mock *mock.Mock +} + +func (_m *L1Requester) EXPECT() *L1Requester_Expecter { + return &L1Requester_Expecter{mock: &_m.Mock} +} + +// HeaderByNumber provides a mock function with given fields: ctx, number +func (_m *L1Requester) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + ret := _m.Called(ctx, number) + + if len(ret) == 0 { + panic("no return value specified for HeaderByNumber") + } + + var r0 *types.Header + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Header, error)); ok { + return rf(ctx, number) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) *types.Header); ok { + r0 = rf(ctx, number) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Header) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, number) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L1Requester_HeaderByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeaderByNumber' +type L1Requester_HeaderByNumber_Call struct { + *mock.Call +} + +// HeaderByNumber is a helper method to define mock.On call +// - ctx context.Context +// - number *big.Int +func (_e *L1Requester_Expecter) HeaderByNumber(ctx interface{}, number interface{}) *L1Requester_HeaderByNumber_Call { + return &L1Requester_HeaderByNumber_Call{Call: _e.mock.On("HeaderByNumber", ctx, number)} +} + +func (_c *L1Requester_HeaderByNumber_Call) Run(run func(ctx context.Context, number *big.Int)) *L1Requester_HeaderByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*big.Int)) + }) + return _c +} + +func (_c *L1Requester_HeaderByNumber_Call) Return(_a0 *types.Header, _a1 error) *L1Requester_HeaderByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L1Requester_HeaderByNumber_Call) RunAndReturn(run func(context.Context, *big.Int) (*types.Header, error)) *L1Requester_HeaderByNumber_Call { + _c.Call.Return(run) + return _c +} + +// NewL1Requester creates a new instance of L1Requester. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewL1Requester(t interface { + mock.TestingT + Cleanup(func()) +}) *L1Requester { + mock := &L1Requester{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/l1_check_block/mocks/safe_l1_block_number_fetcher.go b/synchronizer/l1_check_block/mocks/safe_l1_block_number_fetcher.go new file mode 100644 index 0000000000..abb043afb4 --- /dev/null +++ b/synchronizer/l1_check_block/mocks/safe_l1_block_number_fetcher.go @@ -0,0 +1,139 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_l1_check_block + +import ( + context "context" + + l1_check_block "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block" + mock "github.com/stretchr/testify/mock" +) + +// SafeL1BlockNumberFetcher is an autogenerated mock type for the SafeL1BlockNumberFetcher type +type SafeL1BlockNumberFetcher struct { + mock.Mock +} + +type SafeL1BlockNumberFetcher_Expecter struct { + mock *mock.Mock +} + +func (_m *SafeL1BlockNumberFetcher) EXPECT() *SafeL1BlockNumberFetcher_Expecter { + return &SafeL1BlockNumberFetcher_Expecter{mock: &_m.Mock} +} + +// Description provides a mock function with given fields: +func (_m *SafeL1BlockNumberFetcher) Description() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// SafeL1BlockNumberFetcher_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type SafeL1BlockNumberFetcher_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *SafeL1BlockNumberFetcher_Expecter) Description() *SafeL1BlockNumberFetcher_Description_Call { + return &SafeL1BlockNumberFetcher_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *SafeL1BlockNumberFetcher_Description_Call) Run(run func()) *SafeL1BlockNumberFetcher_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *SafeL1BlockNumberFetcher_Description_Call) Return(_a0 string) *SafeL1BlockNumberFetcher_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *SafeL1BlockNumberFetcher_Description_Call) RunAndReturn(run func() string) *SafeL1BlockNumberFetcher_Description_Call { + _c.Call.Return(run) + return _c +} + +// GetSafeBlockNumber provides a mock function with given fields: ctx, l1Client +func (_m *SafeL1BlockNumberFetcher) GetSafeBlockNumber(ctx context.Context, l1Client l1_check_block.L1Requester) (uint64, error) { + ret := _m.Called(ctx, l1Client) + + if len(ret) == 0 { + panic("no return value specified for GetSafeBlockNumber") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, l1_check_block.L1Requester) (uint64, error)); ok { + return rf(ctx, l1Client) + } + if rf, ok := ret.Get(0).(func(context.Context, l1_check_block.L1Requester) uint64); ok { + r0 = rf(ctx, l1Client) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, l1_check_block.L1Requester) error); ok { + r1 = rf(ctx, l1Client) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSafeBlockNumber' +type SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call struct { + *mock.Call +} + +// GetSafeBlockNumber is a helper method to define mock.On call +// - ctx context.Context +// - l1Client l1_check_block.L1Requester +func (_e *SafeL1BlockNumberFetcher_Expecter) GetSafeBlockNumber(ctx interface{}, l1Client interface{}) *SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call { + return &SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call{Call: _e.mock.On("GetSafeBlockNumber", ctx, l1Client)} +} + +func (_c *SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call) Run(run func(ctx context.Context, l1Client l1_check_block.L1Requester)) *SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(l1_check_block.L1Requester)) + }) + return _c +} + +func (_c *SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call) Return(_a0 uint64, _a1 error) *SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call) RunAndReturn(run func(context.Context, l1_check_block.L1Requester) (uint64, error)) *SafeL1BlockNumberFetcher_GetSafeBlockNumber_Call { + _c.Call.Return(run) + return _c +} + +// NewSafeL1BlockNumberFetcher creates a new instance of SafeL1BlockNumberFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSafeL1BlockNumberFetcher(t interface { + mock.TestingT + Cleanup(func()) +}) *SafeL1BlockNumberFetcher { + mock := &SafeL1BlockNumberFetcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/l1_check_block/mocks/state_for_l1_block_checker_integration.go b/synchronizer/l1_check_block/mocks/state_for_l1_block_checker_integration.go new file mode 100644 index 0000000000..32fbb30b86 --- /dev/null +++ b/synchronizer/l1_check_block/mocks/state_for_l1_block_checker_integration.go @@ -0,0 +1,100 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_l1_check_block + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + pgx "github.com/jackc/pgx/v4" + + state "github.com/0xPolygonHermez/zkevm-node/state" +) + +// StateForL1BlockCheckerIntegration is an autogenerated mock type for the StateForL1BlockCheckerIntegration type +type StateForL1BlockCheckerIntegration struct { + mock.Mock +} + +type StateForL1BlockCheckerIntegration_Expecter struct { + mock *mock.Mock +} + +func (_m *StateForL1BlockCheckerIntegration) EXPECT() *StateForL1BlockCheckerIntegration_Expecter { + return &StateForL1BlockCheckerIntegration_Expecter{mock: &_m.Mock} +} + +// GetPreviousBlockToBlockNumber provides a mock function with given fields: ctx, blockNumber, dbTx +func (_m *StateForL1BlockCheckerIntegration) GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) { + ret := _m.Called(ctx, blockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetPreviousBlockToBlockNumber") + } + + var r0 *state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) (*state.Block, error)); ok { + return rf(ctx, blockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) *state.Block); ok { + r0 = rf(ctx, blockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, blockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPreviousBlockToBlockNumber' +type StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call struct { + *mock.Call +} + +// GetPreviousBlockToBlockNumber is a helper method to define mock.On call +// - ctx context.Context +// - blockNumber uint64 +// - dbTx pgx.Tx +func (_e *StateForL1BlockCheckerIntegration_Expecter) GetPreviousBlockToBlockNumber(ctx interface{}, blockNumber interface{}, dbTx interface{}) *StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call { + return &StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call{Call: _e.mock.On("GetPreviousBlockToBlockNumber", ctx, blockNumber, dbTx)} +} + +func (_c *StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call) Run(run func(ctx context.Context, blockNumber uint64, dbTx pgx.Tx)) *StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(pgx.Tx)) + }) + return _c +} + +func (_c *StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call) Return(_a0 *state.Block, _a1 error) *StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call) RunAndReturn(run func(context.Context, uint64, pgx.Tx) (*state.Block, error)) *StateForL1BlockCheckerIntegration_GetPreviousBlockToBlockNumber_Call { + _c.Call.Return(run) + return _c +} + +// NewStateForL1BlockCheckerIntegration creates a new instance of StateForL1BlockCheckerIntegration. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewStateForL1BlockCheckerIntegration(t interface { + mock.TestingT + Cleanup(func()) +}) *StateForL1BlockCheckerIntegration { + mock := &StateForL1BlockCheckerIntegration{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/l1_check_block/mocks/state_interfacer.go b/synchronizer/l1_check_block/mocks/state_interfacer.go new file mode 100644 index 0000000000..4855ba5eb1 --- /dev/null +++ b/synchronizer/l1_check_block/mocks/state_interfacer.go @@ -0,0 +1,149 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_l1_check_block + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + pgx "github.com/jackc/pgx/v4" + + state "github.com/0xPolygonHermez/zkevm-node/state" +) + +// StateInterfacer is an autogenerated mock type for the StateInterfacer type +type StateInterfacer struct { + mock.Mock +} + +type StateInterfacer_Expecter struct { + mock *mock.Mock +} + +func (_m *StateInterfacer) EXPECT() *StateInterfacer_Expecter { + return &StateInterfacer_Expecter{mock: &_m.Mock} +} + +// GetFirstUncheckedBlock provides a mock function with given fields: ctx, fromBlockNumber, dbTx +func (_m *StateInterfacer) GetFirstUncheckedBlock(ctx context.Context, fromBlockNumber uint64, dbTx pgx.Tx) (*state.Block, error) { + ret := _m.Called(ctx, fromBlockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetFirstUncheckedBlock") + } + + var r0 *state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) (*state.Block, error)); ok { + return rf(ctx, fromBlockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, pgx.Tx) *state.Block); ok { + r0 = rf(ctx, fromBlockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, fromBlockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StateInterfacer_GetFirstUncheckedBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFirstUncheckedBlock' +type StateInterfacer_GetFirstUncheckedBlock_Call struct { + *mock.Call +} + +// GetFirstUncheckedBlock is a helper method to define mock.On call +// - ctx context.Context +// - fromBlockNumber uint64 +// - dbTx pgx.Tx +func (_e *StateInterfacer_Expecter) GetFirstUncheckedBlock(ctx interface{}, fromBlockNumber interface{}, dbTx interface{}) *StateInterfacer_GetFirstUncheckedBlock_Call { + return &StateInterfacer_GetFirstUncheckedBlock_Call{Call: _e.mock.On("GetFirstUncheckedBlock", ctx, fromBlockNumber, dbTx)} +} + +func (_c *StateInterfacer_GetFirstUncheckedBlock_Call) Run(run func(ctx context.Context, fromBlockNumber uint64, dbTx pgx.Tx)) *StateInterfacer_GetFirstUncheckedBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(pgx.Tx)) + }) + return _c +} + +func (_c *StateInterfacer_GetFirstUncheckedBlock_Call) Return(_a0 *state.Block, _a1 error) *StateInterfacer_GetFirstUncheckedBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StateInterfacer_GetFirstUncheckedBlock_Call) RunAndReturn(run func(context.Context, uint64, pgx.Tx) (*state.Block, error)) *StateInterfacer_GetFirstUncheckedBlock_Call { + _c.Call.Return(run) + return _c +} + +// UpdateCheckedBlockByNumber provides a mock function with given fields: ctx, blockNumber, newCheckedStatus, dbTx +func (_m *StateInterfacer) UpdateCheckedBlockByNumber(ctx context.Context, blockNumber uint64, newCheckedStatus bool, dbTx pgx.Tx) error { + ret := _m.Called(ctx, blockNumber, newCheckedStatus, dbTx) + + if len(ret) == 0 { + panic("no return value specified for UpdateCheckedBlockByNumber") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, bool, pgx.Tx) error); ok { + r0 = rf(ctx, blockNumber, newCheckedStatus, dbTx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// StateInterfacer_UpdateCheckedBlockByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateCheckedBlockByNumber' +type StateInterfacer_UpdateCheckedBlockByNumber_Call struct { + *mock.Call +} + +// UpdateCheckedBlockByNumber is a helper method to define mock.On call +// - ctx context.Context +// - blockNumber uint64 +// - newCheckedStatus bool +// - dbTx pgx.Tx +func (_e *StateInterfacer_Expecter) UpdateCheckedBlockByNumber(ctx interface{}, blockNumber interface{}, newCheckedStatus interface{}, dbTx interface{}) *StateInterfacer_UpdateCheckedBlockByNumber_Call { + return &StateInterfacer_UpdateCheckedBlockByNumber_Call{Call: _e.mock.On("UpdateCheckedBlockByNumber", ctx, blockNumber, newCheckedStatus, dbTx)} +} + +func (_c *StateInterfacer_UpdateCheckedBlockByNumber_Call) Run(run func(ctx context.Context, blockNumber uint64, newCheckedStatus bool, dbTx pgx.Tx)) *StateInterfacer_UpdateCheckedBlockByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(bool), args[3].(pgx.Tx)) + }) + return _c +} + +func (_c *StateInterfacer_UpdateCheckedBlockByNumber_Call) Return(_a0 error) *StateInterfacer_UpdateCheckedBlockByNumber_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *StateInterfacer_UpdateCheckedBlockByNumber_Call) RunAndReturn(run func(context.Context, uint64, bool, pgx.Tx) error) *StateInterfacer_UpdateCheckedBlockByNumber_Call { + _c.Call.Return(run) + return _c +} + +// NewStateInterfacer creates a new instance of StateInterfacer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewStateInterfacer(t interface { + mock.TestingT + Cleanup(func()) +}) *StateInterfacer { + mock := &StateInterfacer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/l1_check_block/mocks/state_pre_check_interfacer.go b/synchronizer/l1_check_block/mocks/state_pre_check_interfacer.go new file mode 100644 index 0000000000..2bf5522f60 --- /dev/null +++ b/synchronizer/l1_check_block/mocks/state_pre_check_interfacer.go @@ -0,0 +1,101 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_l1_check_block + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + pgx "github.com/jackc/pgx/v4" + + state "github.com/0xPolygonHermez/zkevm-node/state" +) + +// StatePreCheckInterfacer is an autogenerated mock type for the StatePreCheckInterfacer type +type StatePreCheckInterfacer struct { + mock.Mock +} + +type StatePreCheckInterfacer_Expecter struct { + mock *mock.Mock +} + +func (_m *StatePreCheckInterfacer) EXPECT() *StatePreCheckInterfacer_Expecter { + return &StatePreCheckInterfacer_Expecter{mock: &_m.Mock} +} + +// GetUncheckedBlocks provides a mock function with given fields: ctx, fromBlockNumber, toBlockNumber, dbTx +func (_m *StatePreCheckInterfacer) GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*state.Block, error) { + ret := _m.Called(ctx, fromBlockNumber, toBlockNumber, dbTx) + + if len(ret) == 0 { + panic("no return value specified for GetUncheckedBlocks") + } + + var r0 []*state.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, pgx.Tx) ([]*state.Block, error)); ok { + return rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, pgx.Tx) []*state.Block); ok { + r0 = rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*state.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64, pgx.Tx) error); ok { + r1 = rf(ctx, fromBlockNumber, toBlockNumber, dbTx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StatePreCheckInterfacer_GetUncheckedBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUncheckedBlocks' +type StatePreCheckInterfacer_GetUncheckedBlocks_Call struct { + *mock.Call +} + +// GetUncheckedBlocks is a helper method to define mock.On call +// - ctx context.Context +// - fromBlockNumber uint64 +// - toBlockNumber uint64 +// - dbTx pgx.Tx +func (_e *StatePreCheckInterfacer_Expecter) GetUncheckedBlocks(ctx interface{}, fromBlockNumber interface{}, toBlockNumber interface{}, dbTx interface{}) *StatePreCheckInterfacer_GetUncheckedBlocks_Call { + return &StatePreCheckInterfacer_GetUncheckedBlocks_Call{Call: _e.mock.On("GetUncheckedBlocks", ctx, fromBlockNumber, toBlockNumber, dbTx)} +} + +func (_c *StatePreCheckInterfacer_GetUncheckedBlocks_Call) Run(run func(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx)) *StatePreCheckInterfacer_GetUncheckedBlocks_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(uint64), args[3].(pgx.Tx)) + }) + return _c +} + +func (_c *StatePreCheckInterfacer_GetUncheckedBlocks_Call) Return(_a0 []*state.Block, _a1 error) *StatePreCheckInterfacer_GetUncheckedBlocks_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StatePreCheckInterfacer_GetUncheckedBlocks_Call) RunAndReturn(run func(context.Context, uint64, uint64, pgx.Tx) ([]*state.Block, error)) *StatePreCheckInterfacer_GetUncheckedBlocks_Call { + _c.Call.Return(run) + return _c +} + +// NewStatePreCheckInterfacer creates a new instance of StatePreCheckInterfacer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewStatePreCheckInterfacer(t interface { + mock.TestingT + Cleanup(func()) +}) *StatePreCheckInterfacer { + mock := &StatePreCheckInterfacer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/l1_check_block/mocks/sync_check_reorger.go b/synchronizer/l1_check_block/mocks/sync_check_reorger.go new file mode 100644 index 0000000000..bffd02cb87 --- /dev/null +++ b/synchronizer/l1_check_block/mocks/sync_check_reorger.go @@ -0,0 +1,111 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_l1_check_block + +import mock "github.com/stretchr/testify/mock" + +// SyncCheckReorger is an autogenerated mock type for the SyncCheckReorger type +type SyncCheckReorger struct { + mock.Mock +} + +type SyncCheckReorger_Expecter struct { + mock *mock.Mock +} + +func (_m *SyncCheckReorger) EXPECT() *SyncCheckReorger_Expecter { + return &SyncCheckReorger_Expecter{mock: &_m.Mock} +} + +// ExecuteReorgFromMismatchBlock provides a mock function with given fields: blockNumber, reason +func (_m *SyncCheckReorger) ExecuteReorgFromMismatchBlock(blockNumber uint64, reason string) error { + ret := _m.Called(blockNumber, reason) + + if len(ret) == 0 { + panic("no return value specified for ExecuteReorgFromMismatchBlock") + } + + var r0 error + if rf, ok := ret.Get(0).(func(uint64, string) error); ok { + r0 = rf(blockNumber, reason) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExecuteReorgFromMismatchBlock' +type SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call struct { + *mock.Call +} + +// ExecuteReorgFromMismatchBlock is a helper method to define mock.On call +// - blockNumber uint64 +// - reason string +func (_e *SyncCheckReorger_Expecter) ExecuteReorgFromMismatchBlock(blockNumber interface{}, reason interface{}) *SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call { + return &SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call{Call: _e.mock.On("ExecuteReorgFromMismatchBlock", blockNumber, reason)} +} + +func (_c *SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call) Run(run func(blockNumber uint64, reason string)) *SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64), args[1].(string)) + }) + return _c +} + +func (_c *SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call) Return(_a0 error) *SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call) RunAndReturn(run func(uint64, string) error) *SyncCheckReorger_ExecuteReorgFromMismatchBlock_Call { + _c.Call.Return(run) + return _c +} + +// OnDetectedMismatchL1BlockReorg provides a mock function with given fields: +func (_m *SyncCheckReorger) OnDetectedMismatchL1BlockReorg() { + _m.Called() +} + +// SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnDetectedMismatchL1BlockReorg' +type SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call struct { + *mock.Call +} + +// OnDetectedMismatchL1BlockReorg is a helper method to define mock.On call +func (_e *SyncCheckReorger_Expecter) OnDetectedMismatchL1BlockReorg() *SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call { + return &SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call{Call: _e.mock.On("OnDetectedMismatchL1BlockReorg")} +} + +func (_c *SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call) Run(run func()) *SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call) Return() *SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call { + _c.Call.Return() + return _c +} + +func (_c *SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call) RunAndReturn(run func()) *SyncCheckReorger_OnDetectedMismatchL1BlockReorg_Call { + _c.Call.Return(run) + return _c +} + +// NewSyncCheckReorger creates a new instance of SyncCheckReorger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSyncCheckReorger(t interface { + mock.TestingT + Cleanup(func()) +}) *SyncCheckReorger { + mock := &SyncCheckReorger{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/synchronizer/l1_check_block/pre_check_l1block.go b/synchronizer/l1_check_block/pre_check_l1block.go new file mode 100644 index 0000000000..431777f705 --- /dev/null +++ b/synchronizer/l1_check_block/pre_check_l1block.go @@ -0,0 +1,139 @@ +package l1_check_block + +// This make a pre-check of blocks but don't mark them as checked +// It checks blocks between a segment: example: +// real check point SAFE: +// pre check: (SAFE+1) -> (LATEST-32) +// It gets all pending blocks +// - Start cheking + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/0xPolygonHermez/zkevm-node/log" + "github.com/0xPolygonHermez/zkevm-node/state" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" + "github.com/jackc/pgx/v4" +) + +var ( + // ErrDeSync is an error that indicates that from the starting of verification to end something have been changed on state + ErrDeSync = errors.New("DeSync: a block hash is different from the state block hash") +) + +// StatePreCheckInterfacer is an interface for the state +type StatePreCheckInterfacer interface { + GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*state.Block, error) +} + +// PreCheckL1BlockHash is a struct that implements a checker of L1Block hash +type PreCheckL1BlockHash struct { + L1Client L1Requester + State StatePreCheckInterfacer + InitialSegmentBlockNumber SafeL1BlockNumberFetcher + EndSegmentBlockNumber SafeL1BlockNumberFetcher +} + +// NewPreCheckL1BlockHash creates a new CheckL1BlockHash +func NewPreCheckL1BlockHash(l1Client L1Requester, state StatePreCheckInterfacer, + initial, end SafeL1BlockNumberFetcher) *PreCheckL1BlockHash { + return &PreCheckL1BlockHash{ + L1Client: l1Client, + State: state, + InitialSegmentBlockNumber: initial, + EndSegmentBlockNumber: end, + } +} + +// Name is a method that returns the name of the checker +func (p *PreCheckL1BlockHash) Name() string { + return logPrefix + ":memory_check: " +} + +// Step is a method that checks the L1 block hash, run until all blocks are checked and returns +func (p *PreCheckL1BlockHash) Step(ctx context.Context) error { + from, err := p.InitialSegmentBlockNumber.GetSafeBlockNumber(ctx, p.L1Client) + if err != nil { + return err + } + to, err := p.EndSegmentBlockNumber.GetSafeBlockNumber(ctx, p.L1Client) + if err != nil { + return err + } + if from > to { + log.Warnf("%s: fromBlockNumber(%s) %d is greater than toBlockNumber(%s) %d, Check configuration", p.Name(), p.InitialSegmentBlockNumber.Description(), from, p.EndSegmentBlockNumber.Description(), to) + return nil + } + + blocksToCheck, err := p.State.GetUncheckedBlocks(ctx, from, to, nil) + if err != nil { + log.Warnf("%s can't get unchecked blocks, so it discard the reorg error", p.Name()) + return err + } + msg := fmt.Sprintf("%s: Checking blocks from (%s) %d to (%s) %d -> len(blocks)=%d", p.Name(), p.InitialSegmentBlockNumber.Description(), from, p.EndSegmentBlockNumber.Description(), to, len(blocksToCheck)) + if len(blocksToCheck) == 0 { + log.Debugf(msg) + return nil + } + log.Infof(msg) + startTime := time.Now() + for _, block := range blocksToCheck { + // check block + err = CheckBlockHash(ctx, block, p.L1Client, p.Name()) + if common.IsReorgError(err) { + // Double-check the state block that still is the same + log.Debugf("%s: Reorg detected at blockNumber: %d, checking that the block on State doesn't have change", p.Name(), block.BlockNumber) + isTheSame, errBlockIsTheSame := p.checkThatStateBlockIsTheSame(ctx, block) + if errBlockIsTheSame != nil { + log.Warnf("%s can't double-check that blockNumber %d haven't changed, so it discard the reorg error", p.Name(), block.BlockNumber) + return err + } + if !isTheSame { + log.Infof("%s: DeSync detected, blockNumber: %d is different now that when we started the check", p.Name(), block.BlockNumber) + return ErrDeSync + } + log.Infof("%s: Reorg detected and verified the state block, blockNumber: %d", p.Name(), block.BlockNumber) + return err + } + if err != nil { + return err + } + } + elapsed := time.Since(startTime) + log.Infof("%s: Checked blocks from (%s) %d to (%s) %d -> len(blocks):%d elapsed: %s", p.Name(), p.InitialSegmentBlockNumber.Description(), from, p.EndSegmentBlockNumber.Description(), to, len(blocksToCheck), elapsed.String()) + + return nil +} + +// CheckBlockHash is a method that checks the L1 block hash +// returns true if is the same +func (p *PreCheckL1BlockHash) checkThatStateBlockIsTheSame(ctx context.Context, block *state.Block) (bool, error) { + blocks, err := p.State.GetUncheckedBlocks(ctx, block.BlockNumber, block.BlockNumber, nil) + if err != nil { + log.Warnf("%s: Fails to get blockNumber %d in state .Err:%s", p.Name(), block.BlockNumber, err.Error()) + return false, err + } + if len(blocks) == 0 { + // The block is checked or deleted, so it is not the same + log.Debugf("%s: The blockNumber %d is no longer in the state (or checked or deleted)", p.Name(), block.BlockNumber) + return false, nil + } + stateBlock := blocks[0] + if stateBlock.BlockNumber != block.BlockNumber { + msg := fmt.Sprintf("%s: The blockNumber returned by state %d is different from the state blockNumber %d", + p.Name(), block.BlockNumber, stateBlock.BlockNumber) + log.Warn(msg) + return false, fmt.Errorf(msg) + } + if stateBlock.BlockHash != block.BlockHash { + msg := fmt.Sprintf("%s: The blockNumber %d differs the hash checked %s from current in state %s", + p.Name(), block.BlockNumber, block.BlockHash.String(), stateBlock.BlockHash.String()) + log.Warn(msg) + return false, nil + } + // The block is the same + return true, nil +} diff --git a/synchronizer/l1_check_block/pre_check_l1block_test.go b/synchronizer/l1_check_block/pre_check_l1block_test.go new file mode 100644 index 0000000000..39c359a513 --- /dev/null +++ b/synchronizer/l1_check_block/pre_check_l1block_test.go @@ -0,0 +1,144 @@ +package l1_check_block_test + +import ( + "context" + "math/big" + "testing" + + "github.com/0xPolygonHermez/zkevm-node/state" + commonsync "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block" + mock_l1_check_block "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block/mocks" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" +) + +type testPreCheckData struct { + sut *l1_check_block.PreCheckL1BlockHash + mockL1Client *mock_l1_check_block.L1Requester + mockState *mock_l1_check_block.StatePreCheckInterfacer + mockInitialFetch *mock_l1_check_block.SafeL1BlockNumberFetcher + mockEndFetch *mock_l1_check_block.SafeL1BlockNumberFetcher + ctx context.Context + stateBlocks []*state.Block +} + +func newPreCheckData(t *testing.T) *testPreCheckData { + mockL1Client := mock_l1_check_block.NewL1Requester(t) + mockState := mock_l1_check_block.NewStatePreCheckInterfacer(t) + mockInitialFetch := mock_l1_check_block.NewSafeL1BlockNumberFetcher(t) + mockEndFetch := mock_l1_check_block.NewSafeL1BlockNumberFetcher(t) + sut := l1_check_block.NewPreCheckL1BlockHash(mockL1Client, mockState, mockInitialFetch, mockEndFetch) + return &testPreCheckData{ + sut: sut, + mockL1Client: mockL1Client, + mockState: mockState, + mockInitialFetch: mockInitialFetch, + mockEndFetch: mockEndFetch, + ctx: context.Background(), + stateBlocks: []*state.Block{ + { + BlockNumber: 1234, + BlockHash: common.HexToHash("0xd77dd3a9ee6f9202ca5a75024b7d9cbd3d7436b2910d450f88c261c0089c0cd9"), + }, + { + BlockNumber: 1237, + BlockHash: common.HexToHash("0x8faffac37f561c18917c33ff3540262ecfbe11a367b4e1c48181326cd8ba347f"), + }, + }, + } +} + +// If from > to, it ignore because there are no blocks to check +func TestPreCheckL1BlockFromGreaterThanTo(t *testing.T) { + data := newPreCheckData(t) + data.mockInitialFetch.EXPECT().Description().Return("initial") + data.mockEndFetch.EXPECT().Description().Return("end") + data.mockInitialFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1234), nil) + data.mockEndFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1230), nil) + + res := data.sut.Step(data.ctx) + require.NoError(t, res) +} + +// No blocks on state -> nothing to do +func TestPreCheckL1BlockNoBlocksOnState(t *testing.T) { + data := newPreCheckData(t) + data.mockInitialFetch.EXPECT().Description().Return("initial") + data.mockEndFetch.EXPECT().Description().Return("end") + data.mockInitialFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1234), nil) + data.mockEndFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1250), nil) + data.mockState.EXPECT().GetUncheckedBlocks(data.ctx, uint64(1234), uint64(1250), nil).Return(nil, nil) + + res := data.sut.Step(data.ctx) + require.NoError(t, res) +} + +func TestPreCheckL1BlockBlocksMatch(t *testing.T) { + data := newPreCheckData(t) + data.mockInitialFetch.EXPECT().Description().Return("initial") + data.mockEndFetch.EXPECT().Description().Return("end") + data.mockInitialFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1234), nil) + data.mockEndFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1250), nil) + data.mockState.EXPECT().GetUncheckedBlocks(data.ctx, uint64(1234), uint64(1250), nil).Return(data.stateBlocks, nil) + l1Block1 := &types.Header{ + Number: big.NewInt(int64(data.stateBlocks[0].BlockNumber)), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlocks[0].BlockNumber))).Return(l1Block1, nil) + l1Block2 := &types.Header{ + Number: big.NewInt(int64(data.stateBlocks[1].BlockNumber)), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlocks[1].BlockNumber))).Return(l1Block2, nil) + //data.mockState.EXPECT().GetUncheckedBlocks(data.ctx, uint64(1237), uint64(1237), nil).Return(data.stateBlocks[0:1], nil) + + res := data.sut.Step(data.ctx) + require.NoError(t, res) +} + +func TestPreCheckL1BlockBlocksMismatch(t *testing.T) { + data := newPreCheckData(t) + data.mockInitialFetch.EXPECT().Description().Return("initial") + data.mockEndFetch.EXPECT().Description().Return("end") + data.mockInitialFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1234), nil) + data.mockEndFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1250), nil) + data.stateBlocks[1].BlockHash = common.HexToHash("0x12345678901234567890123456789012345678901234567890") + data.mockState.EXPECT().GetUncheckedBlocks(data.ctx, uint64(1234), uint64(1250), nil).Return(data.stateBlocks, nil) + l1Block1 := &types.Header{ + Number: big.NewInt(int64(data.stateBlocks[0].BlockNumber)), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlocks[0].BlockNumber))).Return(l1Block1, nil) + l1Block2 := &types.Header{ + Number: big.NewInt(int64(data.stateBlocks[1].BlockNumber)), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlocks[1].BlockNumber))).Return(l1Block2, nil) + data.mockState.EXPECT().GetUncheckedBlocks(data.ctx, uint64(1237), uint64(1237), nil).Return(data.stateBlocks[1:2], nil) + + res := data.sut.Step(data.ctx) + require.Error(t, res) + resErr, ok := res.(*commonsync.ReorgError) + require.True(t, ok, "The error must be ReorgError") + require.Equal(t, uint64(1237), resErr.BlockNumber) +} + +func TestPreCheckL1BlockBlocksMismatchButIsNoLongerInState(t *testing.T) { + data := newPreCheckData(t) + data.mockInitialFetch.EXPECT().Description().Return("initial") + data.mockEndFetch.EXPECT().Description().Return("end") + data.mockInitialFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1234), nil) + data.mockEndFetch.EXPECT().GetSafeBlockNumber(data.ctx, data.mockL1Client).Return(uint64(1250), nil) + data.stateBlocks[1].BlockHash = common.HexToHash("0x12345678901234567890123456789012345678901234567890") + data.mockState.EXPECT().GetUncheckedBlocks(data.ctx, uint64(1234), uint64(1250), nil).Return(data.stateBlocks, nil) + l1Block1 := &types.Header{ + Number: big.NewInt(int64(data.stateBlocks[0].BlockNumber)), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlocks[0].BlockNumber))).Return(l1Block1, nil) + l1Block2 := &types.Header{ + Number: big.NewInt(int64(data.stateBlocks[1].BlockNumber)), + } + data.mockL1Client.EXPECT().HeaderByNumber(data.ctx, big.NewInt(int64(data.stateBlocks[1].BlockNumber))).Return(l1Block2, nil) + data.mockState.EXPECT().GetUncheckedBlocks(data.ctx, uint64(1237), uint64(1237), nil).Return(nil, nil) + + res := data.sut.Step(data.ctx) + require.ErrorIs(t, res, l1_check_block.ErrDeSync) +} diff --git a/synchronizer/l1_check_block/safe_l1_block.go b/synchronizer/l1_check_block/safe_l1_block.go new file mode 100644 index 0000000000..7b767b4900 --- /dev/null +++ b/synchronizer/l1_check_block/safe_l1_block.go @@ -0,0 +1,120 @@ +package l1_check_block + +import ( + "context" + "fmt" + "math/big" + + "github.com/0xPolygonHermez/zkevm-node/log" + "github.com/ethereum/go-ethereum/rpc" +) + +// L1BlockPoint is an enum that represents the point of the L1 block +type L1BlockPoint int + +const ( + // FinalizedBlockNumber is the finalized block number + FinalizedBlockNumber L1BlockPoint = 3 + // SafeBlockNumber is the safe block number + SafeBlockNumber L1BlockPoint = 2 + // PendingBlockNumber is the pending block number + PendingBlockNumber L1BlockPoint = 1 + // LastBlockNumber is the last block number + LastBlockNumber L1BlockPoint = 0 +) + +// ToString converts a L1BlockPoint to a string +func (v L1BlockPoint) ToString() string { + switch v { + case FinalizedBlockNumber: + return "finalized" + case SafeBlockNumber: + return "safe" + case PendingBlockNumber: + return "pending" + case LastBlockNumber: + return "latest" + } + return "Unknown" +} + +// StringToL1BlockPoint converts a string to a L1BlockPoint +func StringToL1BlockPoint(s string) L1BlockPoint { + switch s { + case "finalized": + return FinalizedBlockNumber + case "safe": + return SafeBlockNumber + case "pending": + return PendingBlockNumber + case "latest": + return LastBlockNumber + default: + return FinalizedBlockNumber + } +} + +// ToGethRequest converts a L1BlockPoint to a big.Int used for request to GETH +func (v L1BlockPoint) ToGethRequest() *big.Int { + switch v { + case FinalizedBlockNumber: + return big.NewInt(int64(rpc.FinalizedBlockNumber)) + case PendingBlockNumber: + return big.NewInt(int64(rpc.PendingBlockNumber)) + case SafeBlockNumber: + return big.NewInt(int64(rpc.SafeBlockNumber)) + case LastBlockNumber: + return nil + } + return big.NewInt(int64(v)) +} + +// SafeL1BlockNumberFetch is a struct that implements a safe L1 block number fetch +type SafeL1BlockNumberFetch struct { + // SafeBlockPoint is the block number that is reference to l1 Block + SafeBlockPoint L1BlockPoint + // Offset is a vaule add to the L1 block + Offset int +} + +// NewSafeL1BlockNumberFetch creates a new SafeL1BlockNumberFetch +func NewSafeL1BlockNumberFetch(safeBlockPoint L1BlockPoint, offset int) *SafeL1BlockNumberFetch { + return &SafeL1BlockNumberFetch{ + SafeBlockPoint: safeBlockPoint, + Offset: offset, + } +} + +// Description returns a string representation of SafeL1BlockNumberFetch +func (p *SafeL1BlockNumberFetch) Description() string { + return fmt.Sprintf("%s/%d", p.SafeBlockPoint.ToString(), p.Offset) +} + +// GetSafeBlockNumber gets the safe block number from L1 +func (p *SafeL1BlockNumberFetch) GetSafeBlockNumber(ctx context.Context, requester L1Requester) (uint64, error) { + l1SafePointBlock, err := requester.HeaderByNumber(ctx, p.SafeBlockPoint.ToGethRequest()) + if err != nil { + log.Errorf("%s: Error getting L1 block %d. err: %s", logPrefix, p.String(), err.Error()) + return uint64(0), err + } + result := l1SafePointBlock.Number.Uint64() + if p.Offset < 0 { + if result < uint64(-p.Offset) { + result = 0 + } else { + result += uint64(p.Offset) + } + } else { + result = l1SafePointBlock.Number.Uint64() + uint64(p.Offset) + } + if p.SafeBlockPoint == LastBlockNumber { + result = min(result, l1SafePointBlock.Number.Uint64()) + } + + return result, nil +} + +// String returns a string representation of SafeL1BlockNumberFetch +func (p *SafeL1BlockNumberFetch) String() string { + return fmt.Sprintf("SafeBlockPoint: %s, Offset: %d", p.SafeBlockPoint.ToString(), p.Offset) +} diff --git a/synchronizer/l1_check_block/safe_l1_block_test.go b/synchronizer/l1_check_block/safe_l1_block_test.go new file mode 100644 index 0000000000..4d3167adcd --- /dev/null +++ b/synchronizer/l1_check_block/safe_l1_block_test.go @@ -0,0 +1,113 @@ +package l1_check_block_test + +import ( + "context" + "math/big" + "testing" + + "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block" + mock_l1_check_block "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block/mocks" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetSafeBlockNumber(t *testing.T) { + ctx := context.Background() + mockRequester := mock_l1_check_block.NewL1Requester(t) + //safeBlockPoint := big.NewInt(50) + offset := 10 + safeL1Block := l1_check_block.NewSafeL1BlockNumberFetch(l1_check_block.StringToL1BlockPoint("safe"), offset) + + mockRequester.EXPECT().HeaderByNumber(ctx, mock.Anything).Return(&types.Header{ + Number: big.NewInt(100), + }, nil) + blockNumber, err := safeL1Block.GetSafeBlockNumber(ctx, mockRequester) + assert.NoError(t, err) + expectedBlockNumber := uint64(100 + offset) + assert.Equal(t, expectedBlockNumber, blockNumber) +} + +func TestGetSafeBlockNumberMutliplesCases(t *testing.T) { + tests := []struct { + name string + blockPoint string + offset int + l1ReturnBlockNumber uint64 + expectedCallToGeth *big.Int + expectedBlockNumber uint64 + }{ + { + name: "SafeBlockNumber+10", + blockPoint: "safe", + offset: 10, + l1ReturnBlockNumber: 100, + expectedCallToGeth: big.NewInt(int64(rpc.SafeBlockNumber)), + expectedBlockNumber: 110, + }, + { + name: "FinalizedBlockNumber+10", + blockPoint: "finalized", + offset: 10, + l1ReturnBlockNumber: 100, + expectedCallToGeth: big.NewInt(int64(rpc.FinalizedBlockNumber)), + expectedBlockNumber: 110, + }, + { + name: "PendingBlockNumber+10", + blockPoint: "pending", + offset: 10, + l1ReturnBlockNumber: 100, + expectedCallToGeth: big.NewInt(int64(rpc.PendingBlockNumber)), + expectedBlockNumber: 110, + }, + { + name: "LastBlockNumber+10, can't add 10 to latest block number. So must return latest block number and ignore positive offset", + blockPoint: "latest", + offset: 10, + l1ReturnBlockNumber: 100, + expectedCallToGeth: nil, + expectedBlockNumber: 100, + }, + { + name: "FinalizedBlockNumber-1000. negative blockNumbers are not welcome. So must return 0", + blockPoint: "finalized", + offset: -1000, + l1ReturnBlockNumber: 100, + expectedCallToGeth: big.NewInt(int64(rpc.FinalizedBlockNumber)), + expectedBlockNumber: 0, + }, + { + name: "FinalizedBlockNumber(1000)-1000. is 0 ", + blockPoint: "finalized", + offset: -1000, + l1ReturnBlockNumber: 1000, + expectedCallToGeth: big.NewInt(int64(rpc.FinalizedBlockNumber)), + expectedBlockNumber: 0, + }, + { + name: "FinalizedBlockNumber(1001)-1000. is 1 ", + blockPoint: "finalized", + offset: -1000, + l1ReturnBlockNumber: 1001, + expectedCallToGeth: big.NewInt(int64(rpc.FinalizedBlockNumber)), + expectedBlockNumber: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + mockRequester := mock_l1_check_block.NewL1Requester(t) + safeL1Block := l1_check_block.NewSafeL1BlockNumberFetch(l1_check_block.StringToL1BlockPoint(tt.blockPoint), tt.offset) + + mockRequester.EXPECT().HeaderByNumber(ctx, tt.expectedCallToGeth).Return(&types.Header{ + Number: big.NewInt(int64(tt.l1ReturnBlockNumber)), + }, nil) + blockNumber, err := safeL1Block.GetSafeBlockNumber(ctx, mockRequester) + assert.NoError(t, err) + assert.Equal(t, tt.expectedBlockNumber, blockNumber) + }) + } +} diff --git a/synchronizer/l1_parallel_sync/l1_rollup_info_consumer.go b/synchronizer/l1_parallel_sync/l1_rollup_info_consumer.go index 5a457acbf0..4dd78632fd 100644 --- a/synchronizer/l1_parallel_sync/l1_rollup_info_consumer.go +++ b/synchronizer/l1_parallel_sync/l1_rollup_info_consumer.go @@ -3,12 +3,14 @@ package l1_parallel_sync import ( "context" "errors" + "fmt" "sync" "time" "github.com/0xPolygonHermez/zkevm-node/etherman" "github.com/0xPolygonHermez/zkevm-node/log" "github.com/0xPolygonHermez/zkevm-node/state" + syncCommon "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" "github.com/ethereum/go-ethereum/common" types "github.com/ethereum/go-ethereum/core/types" ) @@ -22,7 +24,6 @@ var ( errContextCanceled = errors.New("consumer:context canceled") errConsumerStopped = errors.New("consumer:stopped by request") errConsumerStoppedBecauseIsSynchronized = errors.New("consumer:stopped because is synchronized") - errL1Reorg = errors.New("consumer: L1 reorg detected") errConsumerAndProducerDesynchronized = errors.New("consumer: consumer and producer are desynchronized") ) @@ -155,13 +156,12 @@ func checkPreviousBlocks(rollupInfo rollupInfoByBlockRangeResult, cachedBlock *s } if cachedBlock.BlockNumber == rollupInfo.previousBlockOfRange.NumberU64() { if cachedBlock.BlockHash != rollupInfo.previousBlockOfRange.Hash() { - log.Errorf("consumer: Previous block %d hash is not the same", cachedBlock.BlockNumber) - return errL1Reorg - } - if cachedBlock.ParentHash != rollupInfo.previousBlockOfRange.ParentHash() { - log.Errorf("consumer: Previous block %d parentHash is not the same", cachedBlock.BlockNumber) - return errL1Reorg + err := fmt.Errorf("consumer: Previous block %d hash is not the same. state.Hash:%s != l1.Hash:%s", + cachedBlock.BlockNumber, cachedBlock.BlockHash, rollupInfo.previousBlockOfRange.Hash()) + log.Errorf(err.Error()) + return syncCommon.NewReorgError(cachedBlock.BlockNumber, err) } + log.Infof("consumer: Verified previous block %d not the same: OK", cachedBlock.BlockNumber) } return nil diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 33cf49a7ee..73ad10eddb 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -16,6 +16,7 @@ import ( "github.com/0xPolygonHermez/zkevm-node/synchronizer/actions/processor_manager" syncCommon "github.com/0xPolygonHermez/zkevm-node/synchronizer/common" "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces" + "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_check_block" "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1_parallel_sync" "github.com/0xPolygonHermez/zkevm-node/synchronizer/l1event_orders" "github.com/0xPolygonHermez/zkevm-node/synchronizer/l2_sync/l2_shared" @@ -77,6 +78,7 @@ type ClientSynchronizer struct { l1EventProcessors *processor_manager.L1EventProcessors syncTrustedStateExecutor syncinterfaces.SyncTrustedStateExecutor halter syncinterfaces.CriticalErrorHandler + asyncL1BlockChecker syncinterfaces.L1BlockCheckerIntegrator } // NewSynchronizer creates and initializes an instance of Synchronizer @@ -123,6 +125,31 @@ func NewSynchronizer( syncBlockProtection: syncBlockProtection, halter: syncCommon.NewCriticalErrorHalt(eventLog, 5*time.Second), //nolint:gomnd } + if cfg.L1BlockCheck.Enable { + log.Infof("L1BlockChecker enabled: %s", cfg.L1BlockCheck.String()) + l1BlockChecker := l1_check_block.NewCheckL1BlockHash(ethMan, res.state, + l1_check_block.NewSafeL1BlockNumberFetch(l1_check_block.StringToL1BlockPoint(cfg.L1BlockCheck.L1SafeBlockPoint), cfg.L1BlockCheck.L1SafeBlockOffset)) + + var preCheckAsync syncinterfaces.AsyncL1BlockChecker + if cfg.L1BlockCheck.PreCheckEnable { + log.Infof("L1BlockChecker enabled precheck from: %s/%d to: %s/%d", + cfg.L1BlockCheck.L1SafeBlockPoint, cfg.L1BlockCheck.L1SafeBlockOffset, + cfg.L1BlockCheck.L1PreSafeBlockPoint, cfg.L1BlockCheck.L1PreSafeBlockOffset) + l1BlockPreChecker := l1_check_block.NewPreCheckL1BlockHash(ethMan, res.state, + l1_check_block.NewSafeL1BlockNumberFetch(l1_check_block.StringToL1BlockPoint(cfg.L1BlockCheck.L1SafeBlockPoint), cfg.L1BlockCheck.L1SafeBlockOffset), + l1_check_block.NewSafeL1BlockNumberFetch(l1_check_block.StringToL1BlockPoint(cfg.L1BlockCheck.L1PreSafeBlockPoint), cfg.L1BlockCheck.L1PreSafeBlockOffset), + ) + preCheckAsync = l1_check_block.NewAsyncCheck(l1BlockPreChecker) + } + + res.asyncL1BlockChecker = l1_check_block.NewL1BlockCheckerIntegration( + l1_check_block.NewAsyncCheck(l1BlockChecker), + preCheckAsync, + res.state, + res, + cfg.L1BlockCheck.ForceCheckBeforeStart, + time.Second) + } if !isTrustedSequencer { log.Info("Permissionless: creating and Initializing L2 synchronization components") @@ -165,7 +192,7 @@ func NewSynchronizer( res.l1EventProcessors = defaultsL1EventProcessors(res, l1checkerL2Blocks) switch cfg.L1SynchronizationMode { case ParallelMode: - log.Fatal("L1SynchronizationMode is parallel. Not yet suported, please use sequential mode to sync") + log.Info("L1SynchronizationMode is parallel") res.l1SyncOrchestration = newL1SyncParallel(ctx, cfg, etherManForL1, res, runInDevelopmentMode) case SequentialMode: log.Info("L1SynchronizationMode is sequential") @@ -251,6 +278,10 @@ func (s *ClientSynchronizer) Sync() error { // If there is no lastEthereumBlock means that sync from the beginning is necessary. If not, it continues from the retrieved ethereum block // Get the latest synced block. If there is no block on db, use genesis block log.Info("Sync started") + if s.asyncL1BlockChecker != nil { + _ = s.asyncL1BlockChecker.OnStart(s.ctx) + } + dbTx, err := s.state.BeginStateTransaction(s.ctx) if err != nil { log.Errorf("error creating db transaction to get latest block. Error: %v", err) @@ -372,6 +403,7 @@ func (s *ClientSynchronizer) Sync() error { continue } log.Infof("latestSequencedBatchNumber: %d, latestSyncedBatch: %d, lastVerifiedBatchNumber: %d", latestSequencedBatchNumber, latestSyncedBatch, lastVerifiedBatchNumber) + resetDone := false // Sync trusted state // latestSyncedBatch -> Last batch on DB // latestSequencedBatchNumber -> last batch on SMC @@ -379,6 +411,13 @@ func (s *ClientSynchronizer) Sync() error { startTrusted := time.Now() if s.syncTrustedStateExecutor != nil && !s.isTrustedSequencer { log.Info("Syncing trusted state (permissionless)") + //Sync Trusted State + log.Debug("Doing reorg check before L2 sync") + resetDone, lastEthBlockSynced, err = s.checkReorgAndExecuteReset(lastEthBlockSynced) + if resetDone || err != nil { + log.Infof("Reset done before L2 sync") + continue + } err = s.syncTrustedState(latestSyncedBatch) metrics.FullTrustedSyncTime(time.Since(startTrusted)) if err != nil { @@ -387,10 +426,14 @@ func (s *ClientSynchronizer) Sync() error { if errors.Is(err, syncinterfaces.ErrFatalDesyncFromL1) { l1BlockNumber := err.(*l2_shared.DeSyncPermissionlessAndTrustedNodeError).L1BlockNumber log.Error("Trusted and permissionless desync! reseting to last common point: L1Block (%d-1)", l1BlockNumber) - err = s.resetState(l1BlockNumber - 1) - if err != nil { - log.Errorf("error resetting the state to a discrepancy block. Retrying... Err: %v", err) - continue + for { + resetDone, lastEthBlockSynced, err = s.detectedReorgBadBlockExecuteReset(lastEthBlockSynced, syncCommon.GetReorgErrorBlockNumber(err)) + if resetDone { + break + } else { + log.Error("reorg isn't done, retrying...") + time.Sleep(time.Second) + } } } else if errors.Is(err, syncinterfaces.ErrMissingSyncFromL1) { log.Info("Syncing from trusted node need data from L1") @@ -407,6 +450,11 @@ func (s *ClientSynchronizer) Sync() error { waitDuration = s.cfg.SyncInterval.Duration } //Sync L1Blocks + resetDone, lastEthBlockSynced, err = s.checkReorgAndExecuteReset(lastEthBlockSynced) + if resetDone || err != nil { + continue + } + startL1 := time.Now() if s.l1SyncOrchestration != nil && (latestSyncedBatch < latestSequencedBatchNumber || !s.cfg.L1ParallelSynchronization.FallbackToSequentialModeOnSynchronized) { log.Infof("Syncing L1 blocks in parallel lastEthBlockSynced=%d", lastEthBlockSynced.BlockNumber) @@ -421,6 +469,19 @@ func (s *ClientSynchronizer) Sync() error { lastEthBlockSynced, err = s.syncBlocksSequential(lastEthBlockSynced) } metrics.FullL1SyncTime(time.Since(startL1)) + if syncCommon.IsReorgError(err) { + log.Warnf("error syncing blocks: %s", err.Error()) + for { + resetDone, lastEthBlockSynced, err = s.detectedReorgBadBlockExecuteReset(lastEthBlockSynced, syncCommon.GetReorgErrorBlockNumber(err)) + if resetDone { + break + } else { + log.Error("reorg isn't done, retrying...") + time.Sleep(time.Second) + } + } + continue + } if err != nil { log.Warn("error syncing blocks: ", err) s.CleanTrustedState() @@ -491,22 +552,6 @@ func sanityCheckForGenesisBlockRollupInfo(blocks []etherman.Block, order map[com // This function syncs the node from a specific block to the latest // lastEthBlockSynced -> last block synced in the db func (s *ClientSynchronizer) syncBlocksParallel(lastEthBlockSynced *state.Block) (*state.Block, error) { - // This function will read events fromBlockNum to latestEthBlock. Check reorg to be sure that everything is ok. - block, err := s.newCheckReorg(lastEthBlockSynced, nil) - if err != nil { - log.Errorf("error checking reorgs. Retrying... Err: %v", err) - return lastEthBlockSynced, fmt.Errorf("error checking reorgs") - } - if block != nil { - log.Infof("reorg detected. Resetting the state from block %v to block %v", lastEthBlockSynced.BlockNumber, block.BlockNumber) - err = s.resetState(block.BlockNumber) - if err != nil { - log.Errorf("error resetting the state to a previous block. Retrying... Err: %v", err) - s.l1SyncOrchestration.Reset(lastEthBlockSynced.BlockNumber) - return lastEthBlockSynced, fmt.Errorf("error resetting the state to a previous block") - } - return block, nil - } log.Infof("Starting L1 sync orchestrator in parallel block: %d", lastEthBlockSynced.BlockNumber) return s.l1SyncOrchestration.Start(lastEthBlockSynced) } @@ -521,21 +566,6 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc } lastKnownBlock := header.Number - // This function will read events fromBlockNum to latestEthBlock. Check reorg to be sure that everything is ok. - block, err := s.newCheckReorg(lastEthBlockSynced, nil) - if err != nil { - log.Errorf("error checking reorgs. Retrying... Err: %v", err) - return lastEthBlockSynced, fmt.Errorf("error checking reorgs") - } - if block != nil { - err = s.resetState(block.BlockNumber) - if err != nil { - log.Errorf("error resetting the state to a previous block. Retrying... Err: %v", err) - return lastEthBlockSynced, fmt.Errorf("error resetting the state to a previous block") - } - return block, nil - } - var fromBlock uint64 if lastEthBlockSynced.BlockNumber > 0 { fromBlock = lastEthBlockSynced.BlockNumber @@ -576,7 +606,7 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc log.Error("error getting previousBlock from db. Error: ", err) return lastEthBlockSynced, err } - blockReorged, err := s.newCheckReorg(prevBlock, nil) + blockReorged, err := s.checkReorg(prevBlock, nil) if err != nil { log.Error("error checking reorgs in previous blocks. Error: ", err) return lastEthBlockSynced, err @@ -592,7 +622,7 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc return blockReorged, nil } // Check reorg again to be sure that the chain has not changed between the previous checkReorg and the call GetRollupInfoByBlockRange - block, err := s.newCheckReorg(lastEthBlockSynced, initBlockReceived) + block, err := s.checkReorg(lastEthBlockSynced, initBlockReceived) if err != nil { log.Errorf("error checking reorgs. Retrying... Err: %v", err) return lastEthBlockSynced, fmt.Errorf("error checking reorgs") @@ -773,12 +803,118 @@ func (s *ClientSynchronizer) resetState(blockNumber uint64) error { log.Error("error committing the resetted state. Error: ", err) return err } + if s.asyncL1BlockChecker != nil { + s.asyncL1BlockChecker.OnResetState(s.ctx) + } if s.l1SyncOrchestration != nil { - s.l1SyncOrchestration.Reset(blockNumber) + lastBlock, err := s.state.GetLastBlock(s.ctx, nil) + if err != nil { + log.Errorf("error getting last block synced from db. Error: %v", err) + s.l1SyncOrchestration.Reset(blockNumber) + } else { + s.l1SyncOrchestration.Reset(lastBlock.BlockNumber) + } } return nil } +// OnDetectedMismatchL1BlockReorg function will be called when a reorg is detected (asynchronous call) +func (s *ClientSynchronizer) OnDetectedMismatchL1BlockReorg() { + log.Infof("Detected Reorg in background at block (mismatch)") + if s.l1SyncOrchestration != nil && s.l1SyncOrchestration.IsProducerRunning() { + log.Errorf("Stop synchronizer: because L1 sync parallel aborting background process") + s.l1SyncOrchestration.Abort() + } +} + +// ExecuteReorgFromMismatchBlock function will reset the state to the block before the bad block +func (s *ClientSynchronizer) ExecuteReorgFromMismatchBlock(blockNumber uint64, reason string) error { + log.Info("Detected reorg at block (mismatch): ", blockNumber, " reason: ", reason, " resetting the state to block:", blockNumber-1) + s.CleanTrustedState() + return s.resetState(blockNumber - 1) +} +func (s *ClientSynchronizer) detectedReorgBadBlockExecuteReset(lastEthBlockSynced *state.Block, badBlockNumber uint64) (bool, *state.Block, error) { + firstBlockOK, err := s.checkReorg(lastEthBlockSynced, nil) + if err != nil { + log.Warnf("error checking reorgs. using badBlock detected: %d Err: %v", badBlockNumber, err) + firstBlockOK = nil + } + if firstBlockOK != nil && firstBlockOK.BlockNumber >= badBlockNumber { + log.Warnf("Reorg detected firstBlockOk: %d. But oldest bad block detected: %d", firstBlockOK.BlockNumber, badBlockNumber) + firstBlockOK = nil + } + // We already known a bad block, reset from there + if firstBlockOK == nil { + firstBlockOK, err = s.state.GetPreviousBlockToBlockNumber(s.ctx, badBlockNumber, nil) + if err != nil { + log.Errorf("error getting previous block %d from db. Can't execute REORG. Error: %v", badBlockNumber, err) + return false, lastEthBlockSynced, err + } + } + newFirstBlock, err := s.executeReorgFromFirstValidBlock(lastEthBlockSynced, firstBlockOK) + if err != nil { + log.Errorf("error executing reorg. Retrying... Err: %v", err) + return false, lastEthBlockSynced, fmt.Errorf("error executing reorg. Err: %w", err) + } + return true, newFirstBlock, nil +} + +// checkReorgAndExecuteReset function will check if there is a reorg and execute the reset +// returns true is reset have been done +func (s *ClientSynchronizer) checkReorgAndExecuteReset(lastEthBlockSynced *state.Block) (bool, *state.Block, error) { + var err error + + block, err := s.checkReorg(lastEthBlockSynced, nil) + if err != nil { + log.Errorf("error checking reorgs. Retrying... Err: %v", err) + return false, lastEthBlockSynced, fmt.Errorf("error checking reorgs") + } + if block != nil { + newFirstBlock, err := s.executeReorgFromFirstValidBlock(lastEthBlockSynced, block) + if err != nil { + log.Errorf("error executing reorg. Retrying... Err: %v", err) + return false, lastEthBlockSynced, fmt.Errorf("error executing reorg. Err: %w", err) + } + return true, newFirstBlock, nil + } + + return false, lastEthBlockSynced, nil +} + +func (s *ClientSynchronizer) executeReorgFromFirstValidBlock(lastEthBlockSynced *state.Block, firstValidBlock *state.Block) (*state.Block, error) { + log.Infof("reorg detected. Resetting the state from block %v to block %v", lastEthBlockSynced.BlockNumber, firstValidBlock.BlockNumber) + s.CleanTrustedState() + err := s.resetState(firstValidBlock.BlockNumber) + if err != nil { + log.Errorf("error resetting the state to a previous block. Retrying... Err: %s", err.Error()) + return nil, fmt.Errorf("error resetting the state to a previous block. Err: %w", err) + } + newLastBlock, err := s.state.GetLastBlock(s.ctx, nil) + if err != nil { + log.Warnf("error getting last block synced from db, returning expected block %d. Error: %v", firstValidBlock.BlockNumber, err) + return firstValidBlock, nil + } + if newLastBlock.BlockNumber != firstValidBlock.BlockNumber { + log.Warnf("Doesnt match LastBlock on State and expecting one after a resetState. The block in state is %d and the expected block is %d", newLastBlock.BlockNumber, + firstValidBlock.BlockNumber) + return firstValidBlock, nil + } + return newLastBlock, nil +} + +func (s *ClientSynchronizer) checkReorg(latestBlock *state.Block, syncedBlock *etherman.Block) (*state.Block, error) { + if latestBlock == nil { + err := fmt.Errorf("lastEthBlockSynced is nil calling checkReorgAndExecuteReset") + log.Errorf("%s, it never have to happens", err.Error()) + return nil, err + } + block, errReturnedReorgFunction := s.newCheckReorg(latestBlock, syncedBlock) + if s.asyncL1BlockChecker != nil { + return s.asyncL1BlockChecker.CheckReorgWrapper(s.ctx, block, errReturnedReorgFunction) + } + return block, errReturnedReorgFunction +} + /* This function will check if there is a reorg. As input param needs the last ethereum block synced. Retrieve the block info from the blockchain @@ -787,76 +923,6 @@ If hash or hash parent don't match, reorg detected and the function will return must be reverted. Then, check the previous ethereum block synced, get block info from the blockchain and check hash and has parent. This operation has to be done until a match is found. */ -// TODO This function will be deprecated -func (s *ClientSynchronizer) oldCheckReorg(latestBlock *state.Block) (*state.Block, error) { //nolint:unused - // This function only needs to worry about reorgs if some of the reorganized blocks contained rollup info. - latestEthBlockSynced := *latestBlock - reorgedBlock := *latestBlock - var depth uint64 - for { - block, err := s.etherMan.EthBlockByNumber(s.ctx, reorgedBlock.BlockNumber) - if err != nil { - log.Errorf("error getting latest block synced from blockchain. Block: %d, error: %v", reorgedBlock.BlockNumber, err) - return nil, err - } - log.Infof("[checkReorg function] BlockNumber: %d BlockHash got from L1 provider: %s", block.Number().Uint64(), block.Hash().String()) - log.Infof("[checkReorg function] latestBlockNumber: %d latestBlockHash already synced: %s", latestBlock.BlockNumber, latestBlock.BlockHash.String()) - if block.NumberU64() != reorgedBlock.BlockNumber { - err = fmt.Errorf("wrong ethereum block retrieved from blockchain. Block numbers don't match. BlockNumber stored: %d. BlockNumber retrieved: %d", - reorgedBlock.BlockNumber, block.NumberU64()) - log.Error("error: ", err) - return nil, err - } - // Compare hashes - if (block.Hash() != reorgedBlock.BlockHash || block.ParentHash() != reorgedBlock.ParentHash) && reorgedBlock.BlockNumber > s.genesis.BlockNumber { - log.Infof("checkReorg: Bad block %d hashOk %t parentHashOk %t", reorgedBlock.BlockNumber, block.Hash() == reorgedBlock.BlockHash, block.ParentHash() == reorgedBlock.ParentHash) - log.Debug("[checkReorg function] => latestBlockNumber: ", reorgedBlock.BlockNumber) - log.Debug("[checkReorg function] => latestBlockHash: ", reorgedBlock.BlockHash) - log.Debug("[checkReorg function] => latestBlockHashParent: ", reorgedBlock.ParentHash) - log.Debug("[checkReorg function] => BlockNumber: ", reorgedBlock.BlockNumber, block.NumberU64()) - log.Debug("[checkReorg function] => BlockHash: ", block.Hash()) - log.Debug("[checkReorg function] => BlockHashParent: ", block.ParentHash()) - depth++ - log.Debug("REORG: Looking for the latest correct ethereum block. Depth: ", depth) - // Reorg detected. Getting previous block - dbTx, err := s.state.BeginStateTransaction(s.ctx) - if err != nil { - log.Errorf("error creating db transaction to get prevoius blocks") - return nil, err - } - lb, err := s.state.GetPreviousBlock(s.ctx, depth, dbTx) - errC := dbTx.Commit(s.ctx) - if errC != nil { - log.Errorf("error committing dbTx, err: %v", errC) - rollbackErr := dbTx.Rollback(s.ctx) - if rollbackErr != nil { - log.Errorf("error rolling back state. RollbackErr: %v", rollbackErr) - return nil, rollbackErr - } - log.Errorf("error committing dbTx, err: %v", errC) - return nil, errC - } - if errors.Is(err, state.ErrNotFound) { - log.Warn("error checking reorg: previous block not found in db: ", err) - return &state.Block{}, nil - } else if err != nil { - log.Error("error getting previousBlock from db. Error: ", err) - return nil, err - } - reorgedBlock = *lb - } else { - log.Debugf("checkReorg: Block %d hashOk %t parentHashOk %t", reorgedBlock.BlockNumber, block.Hash() == reorgedBlock.BlockHash, block.ParentHash() == reorgedBlock.ParentHash) - break - } - } - if latestEthBlockSynced.BlockHash != reorgedBlock.BlockHash { - latestBlock = &reorgedBlock - log.Info("Reorg detected in block: ", latestEthBlockSynced.BlockNumber, " last block OK: ", latestBlock.BlockNumber) - return latestBlock, nil - } - log.Debugf("No reorg detected in block: %d. BlockHash: %s", latestEthBlockSynced.BlockNumber, latestEthBlockSynced.BlockHash.String()) - return nil, nil -} func (s *ClientSynchronizer) newCheckReorg(latestStoredBlock *state.Block, syncedBlock *etherman.Block) (*state.Block, error) { // This function only needs to worry about reorgs if some of the reorganized blocks contained rollup info. diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index 98ab184de6..00138eb2bd 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -129,6 +129,9 @@ func TestForcedBatchEtrog(t *testing.T) { SyncChunkSize: 10, L1SynchronizationMode: SequentialMode, SyncBlockProtection: "latest", + L1BlockCheck: L1BlockCheckConfig{ + Enable: false, + }, } m := mocks{ @@ -206,7 +209,7 @@ func TestForcedBatchEtrog(t *testing.T) { m.Etherman. On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). Return(ethBlock0, nil). - Once() + Times(2) n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. @@ -925,6 +928,9 @@ func TestReorg(t *testing.T) { SyncChunkSize: 3, L1SynchronizationMode: SequentialMode, SyncBlockProtection: "latest", + L1BlockCheck: L1BlockCheckConfig{ + Enable: false, + }, } m := mocks{ @@ -1012,6 +1018,16 @@ func TestReorg(t *testing.T) { On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). Return(nil) + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1, nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. On("HeaderByNumber", mock.Anything, n). @@ -1097,6 +1113,16 @@ func TestReorg(t *testing.T) { Return(nil). Once() + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + m.Etherman. On("HeaderByNumber", mock.Anything, n). Return(ethHeader3bis, nil). @@ -1197,17 +1223,13 @@ func TestReorg(t *testing.T) { Return(nil). Once() - m.ZKEVMClient. - On("BatchNumber", ctx). - Return(uint64(1), nil) - m.DbTx. On("Commit", ctx). + Return(nil). Run(func(args mock.Arguments) { sync.Stop() ctx.Done() }). - Return(nil). Once() }). Return(m.DbTx, nil). @@ -1226,6 +1248,9 @@ func TestLatestSyncedBlockEmpty(t *testing.T) { SyncChunkSize: 3, L1SynchronizationMode: SequentialMode, SyncBlockProtection: "latest", + L1BlockCheck: L1BlockCheckConfig{ + Enable: false, + }, } m := mocks{ @@ -1307,6 +1332,16 @@ func TestLatestSyncedBlockEmpty(t *testing.T) { On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). Return(nil) + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1, nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. On("HeaderByNumber", mock.Anything, n). @@ -1369,6 +1404,11 @@ func TestLatestSyncedBlockEmpty(t *testing.T) { Return(nil). Once() + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + m.ZKEVMClient. On("BatchNumber", ctx). Return(uint64(1), nil). @@ -1400,15 +1440,10 @@ func TestLatestSyncedBlockEmpty(t *testing.T) { m.Etherman. On("GetFinalizedBlockNumber", ctx). Return(ethBlock3.NumberU64(), nil). - Once() - - m.ZKEVMClient. - On("BatchNumber", ctx). Run(func(args mock.Arguments) { sync.Stop() ctx.Done() }). - Return(uint64(1), nil). Once() }). Return(m.DbTx, nil). @@ -1427,6 +1462,9 @@ func TestRegularReorg(t *testing.T) { SyncChunkSize: 3, L1SynchronizationMode: SequentialMode, SyncBlockProtection: "latest", + L1BlockCheck: L1BlockCheckConfig{ + Enable: false, + }, } m := mocks{ @@ -1469,10 +1507,6 @@ func TestRegularReorg(t *testing.T) { lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} - m.ZKEVMClient. - On("BatchNumber", ctx). - Return(uint64(1), nil) - m.State. On("GetForkIDByBatchNumber", mock.Anything). Return(uint64(9), nil). @@ -1482,6 +1516,12 @@ func TestRegularReorg(t *testing.T) { Return(lastBlock1, nil). Once() + // After a ResetState get lastblock that must be block 0 + m.State. + On("GetLastBlock", ctx, nil). + Return(lastBlock0, nil). + Once() + m.State. On("GetLastBatchNumber", ctx, m.DbTx). Return(uint64(10), nil). @@ -1514,12 +1554,18 @@ func TestRegularReorg(t *testing.T) { On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). Return(nil) - n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. - On("HeaderByNumber", mock.Anything, n). - Return(ethHeader2bis, nil). + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1, nil). Once() + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + + n := big.NewInt(rpc.LatestBlockNumber.Int64()) + m.Etherman. On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). Return(ethBlock1bis, nil). @@ -1573,6 +1619,16 @@ func TestRegularReorg(t *testing.T) { Return(nil). Once() + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + m.Etherman. On("HeaderByNumber", mock.Anything, n). Return(ethHeader2bis, nil). @@ -1688,6 +1744,9 @@ func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) { SyncChunkSize: 3, L1SynchronizationMode: SequentialMode, SyncBlockProtection: "latest", + L1BlockCheck: L1BlockCheckConfig{ + Enable: false, + }, } m := mocks{ @@ -1772,6 +1831,16 @@ func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) { On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). Return(nil) + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock2.BlockNumber). + Return(ethBlock2, nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + n := big.NewInt(rpc.LatestBlockNumber.Int64()) m.Etherman. On("HeaderByNumber", mock.Anything, n). @@ -1860,6 +1929,11 @@ func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) { Return(nil). Once() + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + m.ZKEVMClient. On("BatchNumber", ctx). Return(uint64(1), nil). @@ -1924,15 +1998,10 @@ func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) { m.DbTx. On("Commit", ctx). Return(nil). - Once() - - m.ZKEVMClient. - On("BatchNumber", ctx). Run(func(args mock.Arguments) { sync.Stop() ctx.Done() }). - Return(uint64(1), nil). Once() }). Return(m.DbTx, nil). diff --git a/test/Makefile b/test/Makefile index a2afd00d70..831b2cad10 100644 --- a/test/Makefile +++ b/test/Makefile @@ -707,6 +707,9 @@ generate-mocks-synchronizer: ## Generates mocks for synchronizer , using mockery rm -Rf ../synchronizer/actions/elderberry/mocks export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --all --case snake --dir ../synchronizer/actions/elderberry --output ../synchronizer/actions/elderberry/mocks --outpkg mock_elderberry ${COMMON_MOCKERY_PARAMS} + rm -Rf ../synchronizer/l1_check_block/mocks + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --all --case snake --dir ../synchronizer/l1_check_block --output ../synchronizer/l1_check_block/mocks --outpkg mock_l1_check_block ${COMMON_MOCKERY_PARAMS} + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=Tx --srcpkg=github.com/jackc/pgx/v4 --output=../synchronizer/mocks --structname=DbTxMock --filename=mock_dbtx.go ${COMMON_MOCKERY_PARAMS} diff --git a/test/e2e/jsonrpc2_test.go b/test/e2e/jsonrpc2_test.go index fcd883a956..f8a0113814 100644 --- a/test/e2e/jsonrpc2_test.go +++ b/test/e2e/jsonrpc2_test.go @@ -780,7 +780,10 @@ func TestEstimateGas(t *testing.T) { msg.GasPrice = gasPrice } - _, err = ethereumClient.EstimateGas(ctx, msg) + gas, err := ethereumClient.EstimateGas(ctx, msg) + t.Log("testCase: ", testCase.name) + t.Log("err: ", err) + t.Log("gas: ", gas) if testCase.expectedError != nil { rpcErr := err.(rpc.Error) errMsg := fmt.Sprintf("[%v] expected: %v %v found: %v %v", network.Name, testCase.expectedError.ErrorCode(), testCase.expectedError.Error(), rpcErr.ErrorCode(), rpcErr.Error()) From f5437744a84ca9ed8a107f4f7ad12224570ab523 Mon Sep 17 00:00:00 2001 From: Alonso Rodriguez Date: Wed, 17 Apr 2024 12:05:18 +0200 Subject: [PATCH 06/23] Fix + remove empty blocks (#3564) * Fix + remove empty blocks * unit test * linter --- db/migrations/state/0020.sql | 28 ++++ db/migrations/state/0020_test.go | 99 +++++++++++ synchronizer/synchronizer.go | 13 +- synchronizer/synchronizer_test.go | 270 ++++++++++++++++++++++++++++++ 4 files changed, 404 insertions(+), 6 deletions(-) create mode 100644 db/migrations/state/0020.sql create mode 100644 db/migrations/state/0020_test.go diff --git a/db/migrations/state/0020.sql b/db/migrations/state/0020.sql new file mode 100644 index 0000000000..1068b6f8da --- /dev/null +++ b/db/migrations/state/0020.sql @@ -0,0 +1,28 @@ +-- +migrate Up + +-- This migration will delete all empty blocks +DELETE FROM state.block +WHERE NOT EXISTS (SELECT * + FROM state.virtual_batch + WHERE state.virtual_batch.block_num = state.block.block_num) + AND NOT EXISTS (SELECT * + FROM state.verified_batch + WHERE state.verified_batch.block_num = state.block.block_num) + AND NOT EXISTS (SELECT * + FROM state.forced_batch + WHERE state.forced_batch.block_num = state.block.block_num) + AND NOT EXISTS (SELECT * + FROM state.exit_root + WHERE state.exit_root.block_num = state.block.block_num) + AND NOT EXISTS (SELECT * + FROM state.monitored_txs + WHERE state.monitored_txs.block_num = state.block.block_num) + AND NOT EXISTS (SELECT * + FROM state.fork_id + WHERE state.fork_id.block_num = state.block.block_num); + + + +-- +migrate Down + +-- no action is needed, the data must remain deleted as it is useless \ No newline at end of file diff --git a/db/migrations/state/0020_test.go b/db/migrations/state/0020_test.go new file mode 100644 index 0000000000..e58ea23381 --- /dev/null +++ b/db/migrations/state/0020_test.go @@ -0,0 +1,99 @@ +package migrations_test + +import ( + "database/sql" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +// this migration changes length of the token name +type migrationTest0020 struct{} + +func (m migrationTest0020) InsertData(db *sql.DB) error { + addBlocks := ` + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(1, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b20', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50fe', '2024-03-11 02:52:23.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(2, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b21', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f1', '2024-03-11 02:52:24.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(3, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b22', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f2', '2024-03-11 02:52:25.000', false); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(4, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b23', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f3', '2024-03-11 02:52:26.000', false); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(5, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b24', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f4', '2024-03-11 02:52:27.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(6, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b25', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f5', '2024-03-11 02:52:28.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(7, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b26', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f6', '2024-03-11 02:52:29.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(8, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b27', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f7', '2024-03-11 02:52:30.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(9, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b28', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f8', '2024-03-11 02:52:31.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(10, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b29', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50f9', '2024-03-11 02:52:32.000', true); + INSERT INTO state.block + (block_num, block_hash, parent_hash, received_at, checked) + VALUES(11, '0x013be63487a53c874614dd1ae0434cf211e393b2e386c8fde74da203b5469b2a', '0x0328698ebeda498df8c63040e2a4771d24722ab2c1e8291226b9215c7eec50fa', '2024-03-11 02:52:33.000', true); + INSERT INTO state.batch + (batch_num, global_exit_root, local_exit_root, state_root, acc_input_hash, "timestamp", coinbase, raw_txs_data, forced_batch_num, batch_resources, closing_reason, wip, checked) + VALUES(1, '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x3f86b09b43e3e49a41fc20a07579b79eba044253367817d5c241d23c0e2bc5c9', '0xa5bd7311fe00707809dd3aa718be2ea0cb363626b9db44172098515f07acf940', '2023-03-24 16:35:27.000', '0x148Ee7dAF16574cD020aFa34CC658f8F3fbd2800', decode('','hex'), NULL, '{"Bytes": 0, "ZKCounters": {"GasUsed": 0, "UsedSteps": 0, "UsedBinaries": 0, "UsedMemAligns": 0, "UsedArithmetics": 0, "UsedKeccakHashes": 0, "UsedPoseidonHashes": 0, "UsedSha256Hashes_V2": 0, "UsedPoseidonPaddings": 0}}'::jsonb, '', false, true); + INSERT INTO state.virtual_batch + (batch_num, tx_hash, coinbase, block_num, sequencer_addr, timestamp_batch_etrog, l1_info_root) + VALUES(1, '0x4314ed5d8ad4812e88895942b2b4642af176d80a97c5489a16a7a5aeb08b51a6', '0x148Ee7dAF16574cD020aFa34CC658f8F3fbd2800', 2, '0x148Ee7dAF16574cD020aFa34CC658f8F3fbd2800', '2024-04-09 16:26:45.000', '0xcdb4258d7ccd8fd41c4a26fd8d9d1fadbc9c506e64d489170525a65e2ad3580b'); + INSERT INTO state.verified_batch + (batch_num, tx_hash, aggregator, state_root, block_num, is_trusted) + VALUES(1, '0x28e82f15ab7bac043598623c65a838c315d00ecb5d6e013c406d6bb889680592', '0x6329Fe417621925C81c16F9F9a18c203C21Af7ab', '0x80bd488b1e150b9b42611d038c7fdfa43a3e95b3a02e5c2d57074e73b583f8fd', 3, true); + INSERT INTO state.fork_id + (fork_id, from_batch_num, to_batch_num, "version", block_num) + VALUES(5, 813267, 1228916, 'v2.0.0-RC1-fork.5', 5); + INSERT INTO state.monitored_txs + ("owner", id, from_addr, to_addr, nonce, value, "data", gas, gas_price, status, history, block_num, created_at, updated_at, gas_offset) + VALUES('sequencer', 'sequence-from-2006249-to-2006252', '0x148Ee7dAF16574cD020aFa34CC658f8F3fbd2800', '0x519E42c24163192Dca44CD3fBDCEBF6be9130987', 58056, NULL, 'def57e540000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000006614ec3100000000000000000000000000000000000000000000000000000000001e9ce8000000000000000000000000148ee7da0000000300000000ee8306089a84ae0baa0082520894417a7ba2d8d0060ae6c54fd098590db854b9c1d58609184e72a0008082044d80802787e068e6fe23cda64eb868cefb7231a17449d508a77919f6c5408814aaab5f259d43a62eb50df0b2d5740552d3f95176a1f0e31cade590facf70b01c1129151bab0b00000003000000000b00000003000000000b00000003000000000b00000003000000000b0000000300000000000000000000000000000000000000', 1474265, 25212431373, 'done', '{0x44423d538d6fc2f2e882fcd0d1952a735d81c824827b83936e6a5e52268a7d8e}', 7, '2024-04-09 09:26:36.235', '2024-04-09 09:38:24.377', 150000); + INSERT INTO state.exit_root + (id, block_num, "timestamp", mainnet_exit_root, rollup_exit_root, global_exit_root, prev_block_hash, l1_info_root, l1_info_tree_index) + VALUES(379599, 8, '2024-04-09 09:43:59.000', decode('C90DCBC69719971625800AD619E5EEEFD0378317E26F0DDE9B30B3C7C84DBD78','hex'), decode('514D72BBF7C2AD8E4D15EC1186EBF077E98208479651B1C30C5AC7DA11BAB209','hex'), decode('B20FACBED4A2774CE33A0F68D9B6F9B4D9AD553DACD73705503910B141D2102E','hex'), decode('845E01F723E5C77DBE5A4889F299860FBECD8353BFD423D366851F3A90496334','hex'), decode('EDB0EF9C80E947C411FD9B8B23318708132F8A3BD15CD366499866EF91748FC8','hex'), 8032); + INSERT INTO state.forced_batch + (block_num, forced_batch_num, global_exit_root, timestamp, raw_txs_data, coinbase) + VALUES(10, 1, '0x3f86b09b43e3e49a41fc20a07579b79eba044253367817d5c241d23c0e2bc5ca', '2024-04-09 09:26:36.235', '0x3f86b09b', '0x3f86b09b43e3e49a41fc20a07579b79eba044253367817d5c241d23c0e2bc5c9'); + ` + if _, err := db.Exec(addBlocks); err != nil { + return err + } + blockCount := `SELECT count(*) FROM state.block` + var count int + err := db.QueryRow(blockCount).Scan(&count) + if err != nil { + return err + } + if count != 11 { + return fmt.Errorf("error: initial wrong number of blocks") + } + return nil +} + +func (m migrationTest0020) RunAssertsAfterMigrationUp(t *testing.T, db *sql.DB) { + blockCount := `SELECT count(*) FROM state.block` + var count int + err := db.QueryRow(blockCount).Scan(&count) + assert.NoError(t, err) + assert.Equal(t, 6, count) +} + +func (m migrationTest0020) RunAssertsAfterMigrationDown(t *testing.T, db *sql.DB) { +} + +func TestMigration0020(t *testing.T) { + runMigrationTest(t, 20, migrationTest0020{}) +} diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 73ad10eddb..d2b2c7e7a9 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -943,17 +943,18 @@ func (s *ClientSynchronizer) newCheckReorg(latestStoredBlock *state.Block, synce BlockHash: b.Hash(), ParentHash: b.ParentHash(), } + if block.BlockNumber != reorgedBlock.BlockNumber { + err := fmt.Errorf("wrong ethereum block retrieved from blockchain. Block numbers don't match. BlockNumber stored: %d. BlockNumber retrieved: %d", + reorgedBlock.BlockNumber, block.BlockNumber) + log.Error("error: ", err) + return nil, err + } } else { log.Infof("[checkReorg function] Using block %d from GetRollupInfoByBlockRange", block.BlockNumber) } log.Infof("[checkReorg function] BlockNumber: %d BlockHash got from L1 provider: %s", block.BlockNumber, block.BlockHash.String()) log.Infof("[checkReorg function] reorgedBlockNumber: %d reorgedBlockHash already synced: %s", reorgedBlock.BlockNumber, reorgedBlock.BlockHash.String()) - if block.BlockNumber != reorgedBlock.BlockNumber { - err := fmt.Errorf("wrong ethereum block retrieved from blockchain. Block numbers don't match. BlockNumber stored: %d. BlockNumber retrieved: %d", - reorgedBlock.BlockNumber, block.BlockNumber) - log.Error("error: ", err) - return nil, err - } + // Compare hashes if (block.BlockHash != reorgedBlock.BlockHash || block.ParentHash != reorgedBlock.ParentHash) && reorgedBlock.BlockNumber > s.genesis.BlockNumber { log.Infof("checkReorg: Bad block %d hashOk %t parentHashOk %t", reorgedBlock.BlockNumber, block.BlockHash == reorgedBlock.BlockHash, block.ParentHash == reorgedBlock.ParentHash) diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index 00138eb2bd..d136d6fef0 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -2010,3 +2010,273 @@ func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) { err = sync.Sync() require.NoError(t, err) } + +func TestCallFromEmptyBlockAndReorg(t *testing.T) { + genesis := state.Genesis{ + BlockNumber: uint64(0), + } + cfg := Config{ + SyncInterval: cfgTypes.Duration{Duration: 1 * time.Second}, + SyncChunkSize: 3, + L1SynchronizationMode: SequentialMode, + SyncBlockProtection: "latest", + L1BlockCheck: L1BlockCheckConfig{ + Enable: false, + }, + } + + m := mocks{ + Etherman: mock_syncinterfaces.NewEthermanFullInterface(t), + State: mock_syncinterfaces.NewStateFullInterface(t), + Pool: mock_syncinterfaces.NewPoolInterface(t), + DbTx: syncMocks.NewDbTxMock(t), + ZKEVMClient: mock_syncinterfaces.NewZKEVMClientInterface(t), + EthTxManager: mock_syncinterfaces.NewEthTxManager(t), + } + ethermanForL1 := []syncinterfaces.EthermanFullInterface{m.Etherman} + sync, err := NewSynchronizer(false, m.Etherman, ethermanForL1, m.State, m.Pool, m.EthTxManager, m.ZKEVMClient, m.zkEVMClientEthereumCompatible, nil, genesis, cfg, false) + require.NoError(t, err) + + // state preparation + ctxMatchBy := mock.MatchedBy(func(ctx context.Context) bool { return ctx != nil }) + forkIdInterval := state.ForkIDInterval{ + ForkId: 9, + FromBatchNumber: 0, + ToBatchNumber: math.MaxUint64, + } + m.State.EXPECT().GetForkIDInMemory(uint64(9)).Return(&forkIdInterval) + + m.State. + On("BeginStateTransaction", ctxMatchBy). + Run(func(args mock.Arguments) { + ctx := args[0].(context.Context) + parentHash := common.HexToHash("0x111") + ethHeader0 := ðTypes.Header{Number: big.NewInt(0), ParentHash: parentHash} + ethBlock0 := ethTypes.NewBlockWithHeader(ethHeader0) + ethHeader1bis := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash(), Time: 10, GasUsed: 20, Root: common.HexToHash("0x234")} + ethBlock1bis := ethTypes.NewBlockWithHeader(ethHeader1bis) + ethHeader2bis := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1bis.Hash()} + ethBlock2bis := ethTypes.NewBlockWithHeader(ethHeader2bis) + ethHeader1 := ðTypes.Header{Number: big.NewInt(1), ParentHash: ethBlock0.Hash()} + ethBlock1 := ethTypes.NewBlockWithHeader(ethHeader1) + ethHeader2 := ðTypes.Header{Number: big.NewInt(2), ParentHash: ethBlock1.Hash()} + ethBlock2 := ethTypes.NewBlockWithHeader(ethHeader2) + + lastBlock0 := &state.Block{BlockHash: ethBlock0.Hash(), BlockNumber: ethBlock0.Number().Uint64(), ParentHash: ethBlock0.ParentHash()} + lastBlock1 := &state.Block{BlockHash: ethBlock1.Hash(), BlockNumber: ethBlock1.Number().Uint64(), ParentHash: ethBlock1.ParentHash()} + + m.State. + On("GetForkIDByBatchNumber", mock.Anything). + Return(uint64(9), nil). + Maybe() + m.State. + On("GetLastBlock", ctx, m.DbTx). + Return(lastBlock1, nil). + Once() + + m.State. + On("GetLastBatchNumber", ctx, m.DbTx). + Return(uint64(10), nil). + Once() + + m.State. + On("SetInitSyncBatch", ctx, uint64(10), m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("GetLatestBatchNumber"). + Return(uint64(10), nil) + + var nilDbTx pgx.Tx + m.State. + On("GetLastBatchNumber", ctx, nilDbTx). + Return(uint64(10), nil) + + m.Etherman. + On("GetLatestVerifiedBatchNum"). + Return(uint64(10), nil) + + m.State. + On("SetLastBatchInfoSeenOnEthereum", ctx, uint64(10), uint64(10), nilDbTx). + Return(nil) + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1, nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + + n := big.NewInt(rpc.LatestBlockNumber.Int64()) + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + Return(ethBlock1, nil). + Once() + + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader2bis, nil). + Once() + + // m.Etherman. + // On("EthBlockByNumber", ctx, lastBlock1.BlockNumber). + // Return(ethBlock1, nil). + // Once() + + ti := time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC) + + ethermanBlock0 := etherman.Block{ + BlockNumber: 0, + ReceivedAt: ti, + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + } + ethermanBlock2bis := etherman.Block{ + BlockNumber: 2, + ReceivedAt: ti, + BlockHash: ethBlock2bis.Hash(), + ParentHash: ethBlock2bis.ParentHash(), + } + blocks := []etherman.Block{ethermanBlock2bis} + order := map[common.Hash][]etherman.Order{} + + fromBlock := ethBlock1.NumberU64() + toBlock := fromBlock + cfg.SyncChunkSize + if toBlock > ethBlock2.NumberU64() { + toBlock = ethBlock2.NumberU64() + } + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + var depth uint64 = 1 + stateBlock0 := &state.Block{ + BlockNumber: ethBlock0.NumberU64(), + BlockHash: ethBlock0.Hash(), + ParentHash: ethBlock0.ParentHash(), + ReceivedAt: ti, + } + m.State. + On("GetPreviousBlock", ctx, depth, m.DbTx). + Return(stateBlock0, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + m.State. + On("Reset", ctx, ethBlock0.NumberU64(), m.DbTx). + Return(nil). + Once() + + m.EthTxManager. + On("Reorg", ctx, ethBlock0.NumberU64()+1, m.DbTx). + Return(nil). + Once() + + m.DbTx. + On("Commit", ctx). + Return(nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.ZKEVMClient. + On("BatchNumber", ctx). + Return(uint64(1), nil). + Once() + + m.Etherman. + On("EthBlockByNumber", ctx, lastBlock0.BlockNumber). + Return(ethBlock0, nil). + Once() + + m.Etherman. + On("HeaderByNumber", mock.Anything, n). + Return(ethHeader2bis, nil). + Once() + + blocks = []etherman.Block{ethermanBlock0, ethermanBlock2bis} + fromBlock = ethBlock0.NumberU64() + toBlock = fromBlock + cfg.SyncChunkSize + if toBlock > ethBlock2.NumberU64() { + toBlock = ethBlock2.NumberU64() + } + m.Etherman. + On("GetRollupInfoByBlockRange", mock.Anything, fromBlock, &toBlock). + Return(blocks, order, nil). + Once() + + m.Etherman. + On("GetFinalizedBlockNumber", ctx). + Return(ethBlock2bis.NumberU64(), nil). + Once() + + m.State. + On("BeginStateTransaction", ctx). + Return(m.DbTx, nil). + Once() + + stateBlock2bis := &state.Block{ + BlockNumber: ethermanBlock2bis.BlockNumber, + BlockHash: ethermanBlock2bis.BlockHash, + ParentHash: ethermanBlock2bis.ParentHash, + ReceivedAt: ethermanBlock2bis.ReceivedAt, + Checked: true, + } + m.State. + On("AddBlock", ctx, stateBlock2bis, m.DbTx). + Return(nil). + Once() + + m.State. + On("GetStoredFlushID", ctx). + Return(uint64(1), cProverIDExecution, nil). + Once() + + m.DbTx. + On("Commit", ctx). + Run(func(args mock.Arguments) { + sync.Stop() + ctx.Done() + }). + Return(nil). + Once() + }). + Return(m.DbTx, nil). + Once() + + err = sync.Sync() + require.NoError(t, err) +} From 5da5dbd1fb4f1f06ec70891c9cbabc42539909da Mon Sep 17 00:00:00 2001 From: Alonso Rodriguez Date: Wed, 17 Apr 2024 15:22:38 +0200 Subject: [PATCH 07/23] Fix/#3565 reorg (#3566) * fix + logs * fix loop * Revert "fix + logs" This reverts commit 39ced69339f46f145aabdf03a93279b737d02bf0. --- synchronizer/synchronizer.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index d2b2c7e7a9..a9df6330c2 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -570,9 +570,9 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc if lastEthBlockSynced.BlockNumber > 0 { fromBlock = lastEthBlockSynced.BlockNumber } + toBlock := fromBlock + s.cfg.SyncChunkSize for { - toBlock := fromBlock + s.cfg.SyncChunkSize if toBlock > lastKnownBlock.Uint64() { toBlock = lastKnownBlock.Uint64() } @@ -659,7 +659,8 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc break } - fromBlock = toBlock + fromBlock = lastEthBlockSynced.BlockNumber + toBlock = toBlock + s.cfg.SyncChunkSize } return lastEthBlockSynced, nil From 76793bb075919280e78a48034932a1590eec9261 Mon Sep 17 00:00:00 2001 From: Alonso Rodriguez Date: Mon, 22 Apr 2024 13:31:09 +0200 Subject: [PATCH 08/23] fix L1InfoRoot when an error happens during the process of the L1 information (#3576) * fix * Comments + mock * avoid error from some L1providers when fromBlock is higher than toBlock * Revert some changes * comments * add L2BlockModulus to L1check * doc * fix dbTx = nil * fix unit tests --- config/default.go | 2 +- docs/config-file/node-config-doc.html | 2 +- docs/config-file/node-config-doc.md | 6 ++--- docs/config-file/node-config-schema.json | 2 +- state/l1infotree.go | 12 ++++++++++ state/reset.go | 7 +++++- state/state.go | 26 +++++++++++++++++++++- synchronizer/actions/check_l2block.go | 12 +++++++--- synchronizer/actions/check_l2block_test.go | 20 +++++++++++------ synchronizer/synchronizer.go | 14 +++++++++++- 10 files changed, 84 insertions(+), 19 deletions(-) diff --git a/config/default.go b/config/default.go index 3f8a12407c..061a04982f 100644 --- a/config/default.go +++ b/config/default.go @@ -105,7 +105,7 @@ TrustedSequencerURL = "" # If it is empty or not specified, then the value is re SyncBlockProtection = "safe" # latest, finalized, safe L1SynchronizationMode = "sequential" L1SyncCheckL2BlockHash = true -L1SyncCheckL2BlockNumberhModulus = 30 +L1SyncCheckL2BlockNumberhModulus = 600 [Synchronizer.L1BlockCheck] Enable = true L1SafeBlockPoint = "finalized" diff --git a/docs/config-file/node-config-doc.html b/docs/config-file/node-config-doc.html index 99a31fd86e..16cfba8d7d 100644 --- a/docs/config-file/node-config-doc.html +++ b/docs/config-file/node-config-doc.html @@ -16,7 +16,7 @@
"300ms"
 

Default: 500Type: number

MaxRequestsPerIPAndSecond defines how much requests a single IP can
send within a single second


Default: ""Type: string

SequencerNodeURI is used allow Non-Sequencer nodes
to relay transactions to the Sequencer node


Default: 0Type: integer

MaxCumulativeGasUsed is the max gas allowed per batch


WebSockets configuration
Default: trueType: boolean

Enabled defines if the WebSocket requests are enabled or disabled


Default: "0.0.0.0"Type: string

Host defines the network adapter that will be used to serve the WS requests


Default: 8546Type: integer

Port defines the port to serve the endpoints via WS


Default: 104857600Type: integer

ReadLimit defines the maximum size of a message read from the client (in bytes)


Default: trueType: boolean

EnableL2SuggestedGasPricePolling enables polling of the L2 gas price to block tx in the RPC with lower gas price.


Default: falseType: boolean

BatchRequestsEnabled defines if the Batch requests are enabled or disabled


Default: 20Type: integer

BatchRequestsLimit defines the limit of requests that can be incorporated into each batch request


Type: array of integer

L2Coinbase defines which address is going to receive the fees

Must contain a minimum of 20 items

Must contain a maximum of 20 items

Each item of this array must be:


Default: 10000Type: integer

MaxLogsCount is a configuration to set the max number of logs that can be returned
in a single call to the state, if zero it means no limit


Default: 10000Type: integer

MaxLogsBlockRange is a configuration to set the max range for block number when querying TXs
logs in a single call to the state, if zero it means no limit


Default: 60000Type: integer

MaxNativeBlockHashBlockRange is a configuration to set the max range for block number when querying
native block hashes in a single call to the state, if zero it means no limit


Default: trueType: boolean

EnableHttpLog allows the user to enable or disable the logs related to the HTTP
requests to be captured by the server.


ZKCountersLimits defines the ZK Counter limits
Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Default: 0Type: integer

Configuration of service `Syncrhonizer`. For this service is also really important the value of `IsTrustedSequencer` because depending of this values is going to ask to a trusted node for trusted transactions or not
Default: "1s"Type: string

SyncInterval is the delay interval between reading new rollup information


Examples:

"1m"
 
"300ms"
-

Default: 100Type: integer

SyncChunkSize is the number of blocks to sync on each chunk


Default: ""Type: string

TrustedSequencerURL is the rpc url to connect and sync the trusted state


Default: "safe"Type: string

SyncBlockProtection specify the state to sync (lastest, finalized or safe)


Default: trueType: boolean

L1SyncCheckL2BlockHash if is true when a batch is closed is force to check L2Block hash against trustedNode (only apply for permissionless)


Default: 30Type: integer

L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check
a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...)


Default: trueType: boolean

Enable if is true then the check l1 Block Hash is active


Default: "finalized"Type: enum (of string)

L1SafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest

Must be one of:

  • "finalized"
  • "safe"
  • "latest"

Default: 0Type: integer

L1SafeBlockOffset is the offset to add to L1SafeBlockPoint as a safe point
it can be positive or negative
Example: L1SafeBlockPoint= finalized, L1SafeBlockOffset= -10, then the safe block ten blocks before the finalized block


Default: trueType: boolean

ForceCheckBeforeStart if is true then the first time the system is started it will force to check all pending blocks


Default: trueType: boolean

PreCheckEnable if is true then the pre-check is active, will check blocks between L1SafeBlock and L1PreSafeBlock


Default: "safe"Type: enum (of string)

L1PreSafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest

Must be one of:

  • "finalized"
  • "safe"
  • "latest"

Default: 0Type: integer

L1PreSafeBlockOffset is the offset to add to L1PreSafeBlockPoint as a safe point
it can be positive or negative
Example: L1PreSafeBlockPoint= finalized, L1PreSafeBlockOffset= -10, then the safe block ten blocks before the finalized block


Default: "sequential"Type: enum (of string)

L1SynchronizationMode define how to synchronize with L1:
- parallel: Request data to L1 in parallel, and process sequentially. The advantage is that executor is not blocked waiting for L1 data
- sequential: Request data to L1 and execute

Must be one of:

  • "sequential"
  • "parallel"

L1ParallelSynchronization Configuration for parallel mode (if L1SynchronizationMode equal to 'parallel')
Default: 10Type: integer

MaxClients Number of clients used to synchronize with L1


Default: 25Type: integer

MaxPendingNoProcessedBlocks Size of the buffer used to store rollup information from L1, must be >= to NumberOfEthereumClientsToSync
sugested twice of NumberOfParallelOfEthereumClients


Default: "5s"Type: string

RequestLastBlockPeriod is the time to wait to request the
last block to L1 to known if we need to retrieve more data.
This value only apply when the system is synchronized


Examples:

"1m"
+

Default: 100Type: integer

SyncChunkSize is the number of blocks to sync on each chunk


Default: ""Type: string

TrustedSequencerURL is the rpc url to connect and sync the trusted state


Default: "safe"Type: string

SyncBlockProtection specify the state to sync (lastest, finalized or safe)


Default: trueType: boolean

L1SyncCheckL2BlockHash if is true when a batch is closed is force to check L2Block hash against trustedNode (only apply for permissionless)


Default: 600Type: integer

L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check
a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...)


Default: trueType: boolean

Enable if is true then the check l1 Block Hash is active


Default: "finalized"Type: enum (of string)

L1SafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest

Must be one of:

  • "finalized"
  • "safe"
  • "latest"

Default: 0Type: integer

L1SafeBlockOffset is the offset to add to L1SafeBlockPoint as a safe point
it can be positive or negative
Example: L1SafeBlockPoint= finalized, L1SafeBlockOffset= -10, then the safe block ten blocks before the finalized block


Default: trueType: boolean

ForceCheckBeforeStart if is true then the first time the system is started it will force to check all pending blocks


Default: trueType: boolean

PreCheckEnable if is true then the pre-check is active, will check blocks between L1SafeBlock and L1PreSafeBlock


Default: "safe"Type: enum (of string)

L1PreSafeBlockPoint is the point that a block is considered safe enough to be checked
it can be: finalized, safe,pending or latest

Must be one of:

  • "finalized"
  • "safe"
  • "latest"

Default: 0Type: integer

L1PreSafeBlockOffset is the offset to add to L1PreSafeBlockPoint as a safe point
it can be positive or negative
Example: L1PreSafeBlockPoint= finalized, L1PreSafeBlockOffset= -10, then the safe block ten blocks before the finalized block


Default: "sequential"Type: enum (of string)

L1SynchronizationMode define how to synchronize with L1:
- parallel: Request data to L1 in parallel, and process sequentially. The advantage is that executor is not blocked waiting for L1 data
- sequential: Request data to L1 and execute

Must be one of:

  • "sequential"
  • "parallel"

L1ParallelSynchronization Configuration for parallel mode (if L1SynchronizationMode equal to 'parallel')
Default: 10Type: integer

MaxClients Number of clients used to synchronize with L1


Default: 25Type: integer

MaxPendingNoProcessedBlocks Size of the buffer used to store rollup information from L1, must be >= to NumberOfEthereumClientsToSync
sugested twice of NumberOfParallelOfEthereumClients


Default: "5s"Type: string

RequestLastBlockPeriod is the time to wait to request the
last block to L1 to known if we need to retrieve more data.
This value only apply when the system is synchronized


Examples:

"1m"
 
"300ms"
 

Consumer Configuration for the consumer of rollup information from L1
Default: "5s"Type: string

AceptableInacctivityTime is the expected maximum time that the consumer
could wait until new data is produced. If the time is greater it emmit a log to warn about
that. The idea is keep working the consumer as much as possible, so if the producer is not
fast enought then you could increse the number of parallel clients to sync with L1


Examples:

"1m"
 
"300ms"
diff --git a/docs/config-file/node-config-doc.md b/docs/config-file/node-config-doc.md
index 9a94f41ced..144dfb3324 100644
--- a/docs/config-file/node-config-doc.md
+++ b/docs/config-file/node-config-doc.md
@@ -1433,15 +1433,15 @@ L1SyncCheckL2BlockHash=true
 
 **Type:** : `integer`
 
-**Default:** `30`
+**Default:** `600`
 
 **Description:** L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check
 a modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...)
 
-**Example setting the default value** (30):
+**Example setting the default value** (600):
 ```
 [Synchronizer]
-L1SyncCheckL2BlockNumberhModulus=30
+L1SyncCheckL2BlockNumberhModulus=600
 ```
 
 ### 9.7. `[Synchronizer.L1BlockCheck]`
diff --git a/docs/config-file/node-config-schema.json b/docs/config-file/node-config-schema.json
index 504c330f35..021f2859bb 100644
--- a/docs/config-file/node-config-schema.json
+++ b/docs/config-file/node-config-schema.json
@@ -530,7 +530,7 @@
 				"L1SyncCheckL2BlockNumberhModulus": {
 					"type": "integer",
 					"description": "L1SyncCheckL2BlockNumberhModulus is the modulus used to choose the l2block to check\na modules 5, for instance, means check all l2block multiples of 5 (10,15,20,...)",
-					"default": 30
+					"default": 600
 				},
 				"L1BlockCheck": {
 					"properties": {
diff --git a/state/l1infotree.go b/state/l1infotree.go
index 8cac9ea5d7..8c081f880c 100644
--- a/state/l1infotree.go
+++ b/state/l1infotree.go
@@ -3,6 +3,7 @@ package state
 import (
 	"context"
 	"errors"
+	"fmt"
 
 	"github.com/0xPolygonHermez/zkevm-node/l1infotree"
 	"github.com/0xPolygonHermez/zkevm-node/log"
@@ -54,6 +55,14 @@ func (s *State) buildL1InfoTreeCacheIfNeed(ctx context.Context, dbTx pgx.Tx) err
 
 // AddL1InfoTreeLeaf adds a new leaf to the L1InfoTree and returns the entry and error
 func (s *State) AddL1InfoTreeLeaf(ctx context.Context, l1InfoTreeLeaf *L1InfoTreeLeaf, dbTx pgx.Tx) (*L1InfoTreeExitRootStorageEntry, error) {
+	var stateTx *StateTx
+	if dbTx != nil {
+		var ok bool
+		stateTx, ok = dbTx.(*StateTx)
+		if !ok {
+			return nil, fmt.Errorf("error casting dbTx to stateTx")
+		}
+	}
 	var newIndex uint32
 	gerIndex, err := s.GetLatestIndex(ctx, dbTx)
 	if err != nil && !errors.Is(err, ErrNotFound) {
@@ -73,6 +82,9 @@ func (s *State) AddL1InfoTreeLeaf(ctx context.Context, l1InfoTreeLeaf *L1InfoTre
 		log.Error("error add new leaf to the L1InfoTree. Error: ", err)
 		return nil, err
 	}
+	if stateTx != nil {
+		stateTx.SetL1InfoTreeModified()
+	}
 	entry := L1InfoTreeExitRootStorageEntry{
 		L1InfoTreeLeaf:  *l1InfoTreeLeaf,
 		L1InfoTreeRoot:  root,
diff --git a/state/reset.go b/state/reset.go
index 655f5f3dd1..e1c5a72675 100644
--- a/state/reset.go
+++ b/state/reset.go
@@ -18,10 +18,15 @@ func (s *State) Reset(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) erro
 		log.Error("error resetting L1BlockNumber. Error: ", err)
 		return err
 	}
+	s.ResetL1InfoTree()
+	return nil
+}
+
+// ResetL1InfoTree resets the L1InfoTree
+func (s *State) ResetL1InfoTree() {
 	// Discard L1InfoTree cache
 	// We can't rebuild cache, because we are inside a transaction, so we dont known
 	// is going to be a commit or a rollback. So is going to be rebuild on the next
 	// request that needs it.
 	s.l1InfoTree = nil
-	return nil
 }
diff --git a/state/state.go b/state/state.go
index a1a754242f..4c662035f8 100644
--- a/state/state.go
+++ b/state/state.go
@@ -62,13 +62,37 @@ func NewState(cfg Config, storage storage, executorClient executor.ExecutorServi
 	return state
 }
 
+// StateTx is the state transaction that extends the database tx
+type StateTx struct {
+	pgx.Tx
+	stateInstance      *State
+	L1InfoTreeModified bool
+}
+
 // BeginStateTransaction starts a state transaction
 func (s *State) BeginStateTransaction(ctx context.Context) (pgx.Tx, error) {
 	tx, err := s.Begin(ctx)
 	if err != nil {
 		return nil, err
 	}
-	return tx, nil
+	res := &StateTx{
+		Tx:            tx,
+		stateInstance: s,
+	}
+	return res, nil
+}
+
+// Rollback do the dbTx rollback + modifications in cache mechanism
+func (tx *StateTx) Rollback(ctx context.Context) error {
+	if tx.L1InfoTreeModified {
+		tx.stateInstance.ResetL1InfoTree()
+	}
+	return tx.Tx.Rollback(ctx)
+}
+
+// SetL1InfoTreeModified sets the flag to true to save that the L1InfoTree has been modified
+func (tx *StateTx) SetL1InfoTreeModified() {
+	tx.L1InfoTreeModified = true
 }
 
 // GetBalance from a given address
diff --git a/synchronizer/actions/check_l2block.go b/synchronizer/actions/check_l2block.go
index 14c9e5cb19..4a864e3a2f 100644
--- a/synchronizer/actions/check_l2block.go
+++ b/synchronizer/actions/check_l2block.go
@@ -36,13 +36,16 @@ type CheckL2BlockHash struct {
 func NewCheckL2BlockHash(state stateGetL2Block,
 	trustedClient trustedRPCGetL2Block,
 	initialL2BlockNumber uint64,
-	modulusBlockNumber uint64) *CheckL2BlockHash {
+	modulusBlockNumber uint64) (*CheckL2BlockHash, error) {
+	if modulusBlockNumber == 0 {
+		return nil, fmt.Errorf("error: modulusBlockNumber is zero")
+	}
 	return &CheckL2BlockHash{
 		state:                 state,
 		trustedClient:         trustedClient,
 		lastL2BlockChecked:    initialL2BlockNumber,
 		modulusL2BlockToCheck: modulusBlockNumber,
-	}
+	}, nil
 }
 
 // CheckL2Block checks the  L2Block hash between the local and the trusted
@@ -74,6 +77,9 @@ func (p *CheckL2BlockHash) GetNextL2BlockToCheck(lastLocalL2BlockNumber, minL2Bl
 		log.Infof("checkL2block: skip check L2block (next to check: %d) currently LastL2BlockNumber: %d", minL2BlockNumberToCheck, lastLocalL2BlockNumber)
 		return false, 0
 	}
+	if l2BlockNumber%p.modulusL2BlockToCheck != 0 {
+		return false, 0
+	}
 	return true, l2BlockNumber
 }
 
@@ -95,7 +101,7 @@ func (p *CheckL2BlockHash) GetL2Blocks(ctx context.Context, blockNumber uint64,
 	trustedL2Block, err := p.trustedClient.BlockByNumber(ctx, big.NewInt(int64(blockNumber)))
 	if err != nil {
 		log.Errorf("checkL2block: Error getting L2Block %d from the Trusted RPC. err:%s", blockNumber, err.Error())
-		return nil, nil, err
+		return nil, nil, nil
 	}
 	return localL2Block, trustedL2Block, nil
 }
diff --git a/synchronizer/actions/check_l2block_test.go b/synchronizer/actions/check_l2block_test.go
index 28a8a503b7..cdbf61a981 100644
--- a/synchronizer/actions/check_l2block_test.go
+++ b/synchronizer/actions/check_l2block_test.go
@@ -32,12 +32,15 @@ func TestCheckL2BlockHash_GetMinimumL2BlockToCheck(t *testing.T) {
 		{1, 10, 10},
 		{9, 10, 10},
 		{10, 10, 20},
-		{0, 0, 1},
-		{1, 0, 2},
+		{0, 1, 1},
+		{1, 1, 2},
 	}
+	_, err := actions.NewCheckL2BlockHash(nil, nil, 1, 0)
+	require.Error(t, err)
 	for _, data := range values {
 		// Call the GetNextL2BlockToCheck method
-		checkL2Block := actions.NewCheckL2BlockHash(nil, nil, data.initial, data.modulus)
+		checkL2Block, err := actions.NewCheckL2BlockHash(nil, nil, data.initial, data.modulus)
+		require.NoError(t, err)
 		nextL2Block := checkL2Block.GetMinimumL2BlockToCheck()
 
 		// Assert the expected result
@@ -58,7 +61,9 @@ func newCheckL2BlocksTestData(t *testing.T, initialL2Block, modulus uint64) Chec
 		mockState:   mock_syncinterfaces.NewStateFullInterface(t),
 		zKEVMClient: mock_syncinterfaces.NewZKEVMClientEthereumCompatibleInterface(t),
 	}
-	res.sut = actions.NewCheckL2BlockHash(res.mockState, res.zKEVMClient, initialL2Block, modulus)
+	var err error
+	res.sut, err = actions.NewCheckL2BlockHash(res.mockState, res.zKEVMClient, initialL2Block, modulus)
+	require.NoError(t, err)
 	return res
 }
 func TestCheckL2BlockHash_GetNextL2BlockToCheck(t *testing.T) {
@@ -77,7 +82,8 @@ func TestCheckL2BlockHash_GetNextL2BlockToCheck(t *testing.T) {
 	}
 
 	for _, data := range values {
-		checkL2Block := actions.NewCheckL2BlockHash(nil, nil, 0, 0)
+		checkL2Block, err := actions.NewCheckL2BlockHash(nil, nil, 0, 1)
+		require.NoError(t, err)
 		shouldCheck, nextL2Block := checkL2Block.GetNextL2BlockToCheck(data.lastLocalL2BlockNumber, data.minL2BlockNumberToCheck)
 
 		assert.Equal(t, data.expectedShouldCheck, shouldCheck, data)
@@ -86,7 +92,7 @@ func TestCheckL2BlockHash_GetNextL2BlockToCheck(t *testing.T) {
 }
 
 func TestCheckL2BlockHashMatch(t *testing.T) {
-	data := newCheckL2BlocksTestData(t, 1, 10)
+	data := newCheckL2BlocksTestData(t, 1, 14)
 	lastL2Block := uint64(14)
 	lastL2BlockBigInt := big.NewInt(int64(lastL2Block))
 	gethHeader := types.Header{
@@ -113,7 +119,7 @@ func TestCheckL2BlockHashMatch(t *testing.T) {
 }
 
 func TestCheckL2BlockHashMismatch(t *testing.T) {
-	data := newCheckL2BlocksTestData(t, 1, 10)
+	data := newCheckL2BlocksTestData(t, 1, 14)
 	lastL2Block := uint64(14)
 	lastL2BlockBigInt := big.NewInt(int64(lastL2Block))
 	gethHeader := types.Header{
diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go
index a9df6330c2..ef9bbf08a3 100644
--- a/synchronizer/synchronizer.go
+++ b/synchronizer/synchronizer.go
@@ -183,7 +183,11 @@ func NewSynchronizer(
 				log.Errorf("error getting last L2Block number from state. Error: %v", err)
 				return nil, err
 			}
-			l1checkerL2Blocks = actions.NewCheckL2BlockHash(res.state, res.zkEVMClientEthereumCompatible, initialL2Block, cfg.L1SyncCheckL2BlockNumberhModulus)
+			l1checkerL2Blocks, err = actions.NewCheckL2BlockHash(res.state, res.zkEVMClientEthereumCompatible, initialL2Block, cfg.L1SyncCheckL2BlockNumberhModulus)
+			if err != nil {
+				log.Error("error creating new instance of checkL2BlockHash. Error: ", err)
+				return nil, err
+			}
 		} else {
 			log.Infof("Trusted Node can't check L2Block hash, ignoring parameter")
 		}
@@ -574,8 +578,13 @@ func (s *ClientSynchronizer) syncBlocksSequential(lastEthBlockSynced *state.Bloc
 
 	for {
 		if toBlock > lastKnownBlock.Uint64() {
+			log.Debug("Setting toBlock to the lastKnownBlock")
 			toBlock = lastKnownBlock.Uint64()
 		}
+		if fromBlock > toBlock {
+			log.Debug("FromBlock is higher than toBlock. Skipping...")
+			return lastEthBlockSynced, nil
+		}
 		log.Infof("Syncing block %d of %d", fromBlock, lastKnownBlock.Uint64())
 		log.Infof("Getting rollup info from block %d to block %d", fromBlock, toBlock)
 		// This function returns the rollup information contained in the ethereum blocks and an extra param called order.
@@ -700,6 +709,7 @@ func (s *ClientSynchronizer) ProcessBlockRange(blocks []etherman.Block, order ma
 		// Add block information
 		err = s.state.AddBlock(s.ctx, &b, dbTx)
 		if err != nil {
+			// If any goes wrong we ensure that the state is rollbacked
 			log.Errorf("error storing block. BlockNumber: %d, error: %v", blocks[i].BlockNumber, err)
 			rollbackErr := dbTx.Rollback(s.ctx)
 			if rollbackErr != nil {
@@ -736,6 +746,7 @@ func (s *ClientSynchronizer) ProcessBlockRange(blocks []etherman.Block, order ma
 		log.Debug("Checking FlushID to commit L1 data to db")
 		err = s.checkFlushID(dbTx)
 		if err != nil {
+			// If any goes wrong we ensure that the state is rollbacked
 			log.Errorf("error checking flushID. Error: %v", err)
 			rollbackErr := dbTx.Rollback(s.ctx)
 			if rollbackErr != nil {
@@ -746,6 +757,7 @@ func (s *ClientSynchronizer) ProcessBlockRange(blocks []etherman.Block, order ma
 		}
 		err = dbTx.Commit(s.ctx)
 		if err != nil {
+			// If any goes wrong we ensure that the state is rollbacked
 			log.Errorf("error committing state to store block. BlockNumber: %d, err: %v", blocks[i].BlockNumber, err)
 			rollbackErr := dbTx.Rollback(s.ctx)
 			if rollbackErr != nil {

From e10b4a977d1c70b64bd3d9ea3bb8f2e9603c37aa Mon Sep 17 00:00:00 2001
From: agnusmor 
Date: Mon, 22 Apr 2024 10:11:26 +0200
Subject: [PATCH 09/23] added logs to analyze blocking issue when storing L2
 block

---
 sequencer/l2block.go | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/sequencer/l2block.go b/sequencer/l2block.go
index a148d5b5ea..a7fd011b09 100644
--- a/sequencer/l2block.go
+++ b/sequencer/l2block.go
@@ -411,6 +411,8 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 		return err
 	}
 
+	log.Infof("l2 block %d [%d] stored in statedb", blockResponse.BlockNumber, l2Block.trackingNum)
+
 	// Update txs status in the pool
 	for _, txResponse := range blockResponse.TransactionResponses {
 		// Change Tx status to selected
@@ -420,6 +422,8 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 		}
 	}
 
+	log.Infof("l2 block %d [%d] transactions updated as selected in the pooldb", blockResponse.BlockNumber, l2Block.trackingNum)
+
 	// Send L2 block to data streamer
 	err = f.DSSendL2Block(f.wipBatch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex())
 	if err != nil {
@@ -427,6 +431,8 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 		log.Errorf("error sending L2 block %d [%d] to data streamer, error: %v", blockResponse.BlockNumber, l2Block.trackingNum, err)
 	}
 
+	log.Infof("l2 block %d [%d] sent to datastream", blockResponse.BlockNumber, l2Block.trackingNum)
+
 	for _, tx := range l2Block.transactions {
 		// Delete the tx from the pending list in the worker (addrQueue)
 		f.workerIntf.DeletePendingTxToStore(tx.Hash, tx.From)

From 2b972bcc5ec58b0f559419bdf6d5cbaa4903012d Mon Sep 17 00:00:00 2001
From: agnusmor 
Date: Mon, 22 Apr 2024 16:33:29 +0200
Subject: [PATCH 10/23] add debug logs for datastreamer

---
 sequencer/datastreamer.go |  2 ++
 sequencer/l2block.go      |  3 +++
 sequencer/sequencer.go    | 17 +++++++++++++++++
 3 files changed, 22 insertions(+)

diff --git a/sequencer/datastreamer.go b/sequencer/datastreamer.go
index 700b8b3e02..bbbfe14496 100644
--- a/sequencer/datastreamer.go
+++ b/sequencer/datastreamer.go
@@ -1,6 +1,7 @@
 package sequencer
 
 import (
+	"github.com/0xPolygonHermez/zkevm-node/log"
 	"github.com/0xPolygonHermez/zkevm-node/state"
 )
 
@@ -42,6 +43,7 @@ func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.Proce
 			l2Transactions = append(l2Transactions, l2Transaction)
 		}
 
+		log.Infof("sending l2block %d to datastream channel", blockResponse.BlockNumber)
 		f.dataToStream <- state.DSL2FullBlock{
 			DSL2Block: l2Block,
 			Txs:       l2Transactions,
diff --git a/sequencer/l2block.go b/sequencer/l2block.go
index a7fd011b09..ed7ae314f6 100644
--- a/sequencer/l2block.go
+++ b/sequencer/l2block.go
@@ -411,6 +411,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 		return err
 	}
 
+	//TODO: remove this log
 	log.Infof("l2 block %d [%d] stored in statedb", blockResponse.BlockNumber, l2Block.trackingNum)
 
 	// Update txs status in the pool
@@ -422,6 +423,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 		}
 	}
 
+	//TODO: remove this log
 	log.Infof("l2 block %d [%d] transactions updated as selected in the pooldb", blockResponse.BlockNumber, l2Block.trackingNum)
 
 	// Send L2 block to data streamer
@@ -431,6 +433,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 		log.Errorf("error sending L2 block %d [%d] to data streamer, error: %v", blockResponse.BlockNumber, l2Block.trackingNum, err)
 	}
 
+	//TODO: remove this log
 	log.Infof("l2 block %d [%d] sent to datastream", blockResponse.BlockNumber, l2Block.trackingNum)
 
 	for _, tx := range l2Block.transactions {
diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go
index 64b5711fae..22201776ce 100644
--- a/sequencer/sequencer.go
+++ b/sequencer/sequencer.go
@@ -256,6 +256,8 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 			case state.DSL2FullBlock:
 				l2Block := data
 
+				//TODO: remove this log
+				log.Infof("start atomic op for l2block %d", l2Block.L2BlockNumber)
 				err = s.streamServer.StartAtomicOp()
 				if err != nil {
 					log.Errorf("failed to start atomic op for l2block %d, error: %v ", l2Block.L2BlockNumber, err)
@@ -267,6 +269,8 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 					Value: l2Block.L2BlockNumber,
 				}
 
+				//TODO: remove this log
+				log.Infof("add stream bookmark for l2block %d", l2Block.L2BlockNumber)
 				_, err = s.streamServer.AddStreamBookmark(bookMark.Encode())
 				if err != nil {
 					log.Errorf("failed to add stream bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err)
@@ -281,6 +285,8 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 						Value: l2Block.L2BlockNumber - 1,
 					}
 
+					//TODO: remove this log
+					log.Infof("get previous l2block %d", l2Block.L2BlockNumber-1)
 					previousL2BlockEntry, err := s.streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
 					if err != nil {
 						log.Errorf("failed to get previous l2block %d, error: %v", l2Block.L2BlockNumber-1, err)
@@ -303,12 +309,16 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 					ChainID:         uint32(chainID),
 				}
 
+				//TODO: remove this log
+				log.Infof("add l2blockStart stream entry for l2block %d", l2Block.L2BlockNumber)
 				_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockStart, blockStart.Encode())
 				if err != nil {
 					log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 					continue
 				}
 
+				//TODO: remove this log
+				log.Infof("adding l2tx stream entries for l2block %d", l2Block.L2BlockNumber)
 				for _, l2Transaction := range l2Block.Txs {
 					_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2Tx, l2Transaction.Encode())
 					if err != nil {
@@ -323,18 +333,25 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 					StateRoot:     l2Block.StateRoot,
 				}
 
+				//TODO: remove this log
+				log.Infof("add l2blockEnd stream entry for l2block %d", l2Block.L2BlockNumber)
 				_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockEnd, blockEnd.Encode())
 				if err != nil {
 					log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 					continue
 				}
 
+				//TODO: remove this log
+				log.Infof("commit atomic op for l2block %d", l2Block.L2BlockNumber)
 				err = s.streamServer.CommitAtomicOp()
 				if err != nil {
 					log.Errorf("failed to commit atomic op for l2block %d, error: %v ", l2Block.L2BlockNumber, err)
 					continue
 				}
 
+				//TODO: remove this log
+				log.Infof("l2block %d sent to datastream", l2Block.L2BlockNumber)
+
 			// Stream a bookmark
 			case state.DSBookMark:
 				bookmark := data

From 7a0b72d8e607a2b1d04ea66d4342526ce5449558 Mon Sep 17 00:00:00 2001
From: Joan Esteban <129153821+joanestebanr@users.noreply.github.com>
Date: Tue, 23 Apr 2024 10:29:01 +0200
Subject: [PATCH 11/23] fix #3581 synchronizer panic synchronizing from trusted
 node (#3582)

---
 .../l2_shared/processor_trusted_batch_sync.go     |  4 ++++
 .../l2_sync/l2_shared/trusted_batches_retrieve.go | 15 +++++++++++++++
 2 files changed, 19 insertions(+)

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 db4ddd15e0..d0f6557d1e 100644
--- a/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go
+++ b/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go
@@ -171,6 +171,10 @@ func (s *ProcessorTrustedBatchSync) AddPostChecker(checker PostClosedBatchChecke
 
 // 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) {
+	if trustedBatch == nil {
+		log.Errorf("%s trustedBatch is nil, it never should be nil", debugPrefix)
+		return nil, fmt.Errorf("%s trustedBatch is nil, it never should be nil", debugPrefix)
+	}
 	log.Debugf("%s Processing trusted batch: %v", debugPrefix, trustedBatch.Number)
 	stateCurrentBatch, statePreviousBatch := s.GetCurrentAndPreviousBatchFromCache(&status)
 	if s.l1SyncChecker != nil {
diff --git a/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go b/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go
index 70311c6966..c3e36e59ae 100644
--- a/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go
+++ b/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go
@@ -109,6 +109,16 @@ func isSyncrhonizedTrustedState(lastTrustedStateBatchNumber uint64, latestSynced
 	return lastTrustedStateBatchNumber < latestSyncedBatch
 }
 
+func sanityCheckBatchReturnedByTrusted(batch *types.Batch, expectedBatchNumber uint64) error {
+	if batch == nil {
+		return fmt.Errorf("batch %d is nil", expectedBatchNumber)
+	}
+	if uint64(batch.Number) != expectedBatchNumber {
+		return fmt.Errorf("batch %d is not the expected batch %d", batch.Number, expectedBatchNumber)
+	}
+	return nil
+}
+
 func (s *TrustedBatchesRetrieve) syncTrustedBatchesToFrom(ctx context.Context, latestSyncedBatch uint64, lastTrustedStateBatchNumber uint64) error {
 	batchNumberToSync := max(latestSyncedBatch, s.firstBatchNumberToSync)
 	for batchNumberToSync <= lastTrustedStateBatchNumber {
@@ -120,6 +130,11 @@ func (s *TrustedBatchesRetrieve) syncTrustedBatchesToFrom(ctx context.Context, l
 			log.Warnf("%s failed to get batch %d from trusted state. Error: %v", debugPrefix, batchNumberToSync, err)
 			return err
 		}
+		err = sanityCheckBatchReturnedByTrusted(batchToSync, batchNumberToSync)
+		if err != nil {
+			log.Warnf("%s sanity check over Batch returned by Trusted-RPC failed: %v", debugPrefix, err)
+			return err
+		}
 
 		dbTx, err := s.state.BeginStateTransaction(ctx)
 		if err != nil {

From ec6691a6276bba2d7465cd26c98f4f825c10bfa1 Mon Sep 17 00:00:00 2001
From: Joan Esteban <129153821+joanestebanr@users.noreply.github.com>
Date: Tue, 23 Apr 2024 15:13:59 +0200
Subject: [PATCH 12/23] synchronized: #3583  stop sync from l2 after no closed
 batch (#3584)

* stop processing trusted Node after first open batch
---
 .../l2_shared/processor_trusted_batch_sync.go |   4 +-
 .../tests/trusted_batches_retrieve_test.go    | 117 ++++++++++++++++++
 .../l2_shared/trusted_batches_retrieve.go     |   4 +
 3 files changed, 124 insertions(+), 1 deletion(-)
 create mode 100644 synchronizer/l2_sync/l2_shared/tests/trusted_batches_retrieve_test.go

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 d0f6557d1e..5463555d94 100644
--- a/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go
+++ b/synchronizer/l2_sync/l2_shared/processor_trusted_batch_sync.go
@@ -378,7 +378,9 @@ func (s *ProcessorTrustedBatchSync) GetModeForProcessBatch(trustedNodeBatch *typ
 	result.OldAccInputHash = statePreviousBatch.AccInputHash
 	result.Now = s.timeProvider.Now()
 	result.DebugPrefix = fmt.Sprintf("%s mode %s:", debugPrefix, result.Mode)
-
+	if result.BatchMustBeClosed {
+		result.DebugPrefix += " (must_be_closed)"
+	}
 	if isTrustedBatchEmptyAndClosed(trustedNodeBatch) {
 		if s.Cfg.AcceptEmptyClosedBatches {
 			log.Infof("%s Batch %v: TrustedBatch Empty and closed, accepted due configuration", result.DebugPrefix, trustedNodeBatch.Number)
diff --git a/synchronizer/l2_sync/l2_shared/tests/trusted_batches_retrieve_test.go b/synchronizer/l2_sync/l2_shared/tests/trusted_batches_retrieve_test.go
new file mode 100644
index 0000000000..f050fa565f
--- /dev/null
+++ b/synchronizer/l2_sync/l2_shared/tests/trusted_batches_retrieve_test.go
@@ -0,0 +1,117 @@
+package test_l2_shared
+
+import (
+	"context"
+	"math/big"
+	"testing"
+
+	"github.com/0xPolygonHermez/zkevm-node/jsonrpc/types"
+	"github.com/0xPolygonHermez/zkevm-node/state"
+	"github.com/0xPolygonHermez/zkevm-node/synchronizer/common"
+	mock_syncinterfaces "github.com/0xPolygonHermez/zkevm-node/synchronizer/common/syncinterfaces/mocks"
+	"github.com/0xPolygonHermez/zkevm-node/synchronizer/l2_sync/l2_shared"
+	l2sharedmocks "github.com/0xPolygonHermez/zkevm-node/synchronizer/l2_sync/l2_shared/mocks"
+	syncMocks "github.com/0xPolygonHermez/zkevm-node/synchronizer/mocks"
+	"github.com/stretchr/testify/mock"
+	"github.com/stretchr/testify/require"
+)
+
+type testDataTrustedBatchRetrieve struct {
+	mockBatchProcessor *l2sharedmocks.BatchProcessor
+	mockZkEVMClient    *mock_syncinterfaces.ZKEVMClientTrustedBatchesGetter
+	mockState          *l2sharedmocks.StateInterface
+	mockSync           *mock_syncinterfaces.SynchronizerFlushIDManager
+	mockTimer          *common.MockTimerProvider
+	mockDbTx           *syncMocks.DbTxMock
+	TrustedStateMngr   *l2_shared.TrustedStateManager
+	sut                *l2_shared.TrustedBatchesRetrieve
+	ctx                context.Context
+}
+
+func newTestDataTrustedBatchRetrieve(t *testing.T) *testDataTrustedBatchRetrieve {
+	mockBatchProcessor := l2sharedmocks.NewBatchProcessor(t)
+	mockZkEVMClient := mock_syncinterfaces.NewZKEVMClientTrustedBatchesGetter(t)
+	mockState := l2sharedmocks.NewStateInterface(t)
+	mockSync := mock_syncinterfaces.NewSynchronizerFlushIDManager(t)
+	mockTimer := &common.MockTimerProvider{}
+	mockDbTx := syncMocks.NewDbTxMock(t)
+	TrustedStateMngr := l2_shared.NewTrustedStateManager(mockTimer, 0)
+	sut := l2_shared.NewTrustedBatchesRetrieve(mockBatchProcessor, mockZkEVMClient, mockState, mockSync, *TrustedStateMngr)
+	ctx := context.TODO()
+	return &testDataTrustedBatchRetrieve{
+		mockBatchProcessor: mockBatchProcessor,
+		mockZkEVMClient:    mockZkEVMClient,
+		mockState:          mockState,
+		mockSync:           mockSync,
+		mockTimer:          mockTimer,
+		mockDbTx:           mockDbTx,
+		TrustedStateMngr:   TrustedStateMngr,
+		sut:                sut,
+		ctx:                ctx,
+	}
+}
+
+const (
+	closedBatch    = true
+	notClosedBatch = false
+)
+
+// This test must do from 100 to 104.
+// But the batch 100 is open on TrustedNode so it stop processing
+func TestSyncTrustedBatchesToFromStopAfterFirstWIPBatch(t *testing.T) {
+	data := newTestDataTrustedBatchRetrieve(t)
+	data.mockZkEVMClient.EXPECT().BatchNumber(data.ctx).Return(uint64(102), nil)
+
+	expectationsForSyncTrustedStateIteration(t, 100, notClosedBatch, data)
+
+	err := data.sut.SyncTrustedState(data.ctx, 100, 104)
+	require.NoError(t, err)
+}
+
+// This must process 100 (that is closed)
+// and stop processing at 101 because is not yet close this batch
+func TestSyncTrustedBatchesToFromStopAfterFirstWIPBatchCase2(t *testing.T) {
+	data := newTestDataTrustedBatchRetrieve(t)
+	data.mockZkEVMClient.EXPECT().BatchNumber(data.ctx).Return(uint64(102), nil)
+
+	expectationsForSyncTrustedStateIteration(t, 100, closedBatch, data)
+	expectationsForSyncTrustedStateIteration(t, 101, notClosedBatch, data)
+
+	err := data.sut.SyncTrustedState(data.ctx, 100, 104)
+	require.NoError(t, err)
+}
+
+// This test must do from 100 to 102. Is for check manually that the logs
+// That is not tested but must not emit the log:
+//   - Batch 101 is not closed. so we break synchronization from Trusted Node because can only have 1 WIP batch on state
+func TestSyncTrustedBatchesToFromStopAfterFirstWIPBatchCase3(t *testing.T) {
+	data := newTestDataTrustedBatchRetrieve(t)
+	data.mockZkEVMClient.EXPECT().BatchNumber(data.ctx).Return(uint64(102), nil)
+	expectationsForSyncTrustedStateIteration(t, 100, closedBatch, data)
+	expectationsForSyncTrustedStateIteration(t, 101, closedBatch, data)
+	expectationsForSyncTrustedStateIteration(t, 102, notClosedBatch, data)
+
+	err := data.sut.SyncTrustedState(data.ctx, 100, 102)
+	require.NoError(t, err)
+}
+
+func expectationsForSyncTrustedStateIteration(t *testing.T, batchNumber uint64, closed bool, data *testDataTrustedBatchRetrieve) {
+	batch100 := &types.Batch{
+		Number: types.ArgUint64(batchNumber),
+		Closed: closed,
+	}
+	data.mockZkEVMClient.EXPECT().BatchByNumber(data.ctx, big.NewInt(0).SetUint64(batchNumber)).Return(batch100, nil)
+	data.mockState.EXPECT().BeginStateTransaction(data.ctx).Return(data.mockDbTx, nil)
+	// Get Previous Batch 99 from State
+	stateBatch99 := &state.Batch{
+		BatchNumber: batchNumber - 1,
+	}
+	data.mockState.EXPECT().GetBatchByNumber(data.ctx, uint64(batchNumber-1), data.mockDbTx).Return(stateBatch99, nil)
+	stateBatch100 := &state.Batch{
+		BatchNumber: batchNumber,
+	}
+	data.mockState.EXPECT().GetBatchByNumber(data.ctx, uint64(batchNumber), data.mockDbTx).Return(stateBatch100, nil)
+	data.mockBatchProcessor.EXPECT().ProcessTrustedBatch(data.ctx, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
+	data.mockSync.EXPECT().CheckFlushID(mock.Anything).Return(nil)
+	data.mockDbTx.EXPECT().Commit(data.ctx).Return(nil)
+}
diff --git a/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go b/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go
index c3e36e59ae..b4031b4653 100644
--- a/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go
+++ b/synchronizer/l2_sync/l2_shared/trusted_batches_retrieve.go
@@ -176,6 +176,10 @@ func (s *TrustedBatchesRetrieve) syncTrustedBatchesToFrom(ctx context.Context, l
 			s.TrustedStateMngr.Clear()
 		}
 		batchNumberToSync++
+		if !batchToSync.Closed && batchNumberToSync <= lastTrustedStateBatchNumber {
+			log.Infof("%s Batch %d is not closed. so we break synchronization from Trusted Node because can only have 1 WIP batch on state", debugPrefix, batchToSync.Number)
+			return nil
+		}
 	}
 
 	log.Infof("syncTrustedState: Trusted state fully synchronized from %d to %d", latestSyncedBatch, lastTrustedStateBatchNumber)

From 8af746a00214c429e0e88879113a97b71e281c85 Mon Sep 17 00:00:00 2001
From: dPunisher 
Date: Wed, 24 Apr 2024 11:55:02 +0200
Subject: [PATCH 13/23] Update datastream lib to the latest version with
 additional debug info

---
 go.mod | 3 +--
 go.sum | 6 ++----
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/go.mod b/go.mod
index afb6ff9d5a..5205922dcd 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/0xPolygonHermez/zkevm-node
 go 1.21
 
 require (
-	github.com/0xPolygonHermez/zkevm-data-streamer v0.1.18
+	github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240422135400-0df0d27226b3
 	github.com/didip/tollbooth/v6 v6.1.2
 	github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
 	github.com/ethereum/go-ethereum v1.13.11
@@ -171,7 +171,6 @@ require (
 
 require (
 	github.com/fatih/color v1.16.0
-	github.com/joho/godotenv v1.5.1
 	github.com/prometheus/client_golang v1.18.0
 	golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
 )
diff --git a/go.sum b/go.sum
index 579d0d5b6b..3bb8e0138d 100644
--- a/go.sum
+++ b/go.sum
@@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/0xPolygonHermez/zkevm-data-streamer v0.1.18 h1:InqeTcHrNbfj1OUfn2aFplFay7ibd7KhYqvmMZYZfn0=
-github.com/0xPolygonHermez/zkevm-data-streamer v0.1.18/go.mod h1:0QkAXcFa92mFJrCbN3UPUJGJYes851yEgYHLONnaosE=
+github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240422135400-0df0d27226b3 h1:g5IMJalQxVRNfnXrzQG7bx2COktaFBf1mNuF4SLuQss=
+github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240422135400-0df0d27226b3/go.mod h1:0QkAXcFa92mFJrCbN3UPUJGJYes851yEgYHLONnaosE=
 github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
@@ -483,8 +483,6 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
-github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
-github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=

From b7a24841393354c720f527f0ff72dbcf0b4f0eed Mon Sep 17 00:00:00 2001
From: dPunisher 
Date: Wed, 24 Apr 2024 12:06:01 +0200
Subject: [PATCH 14/23] update dslib client interface

---
 tools/datastreamer/main.go | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/tools/datastreamer/main.go b/tools/datastreamer/main.go
index 41f3611f1f..975e4c7ecd 100644
--- a/tools/datastreamer/main.go
+++ b/tools/datastreamer/main.go
@@ -558,14 +558,13 @@ func decodeEntry(cliCtx *cli.Context) error {
 		os.Exit(1)
 	}
 
-	client.FromEntry = cliCtx.Uint64("entry")
-	err = client.ExecCommand(datastreamer.CmdEntry)
+	entry, err := client.ExecCommandGetEntry(cliCtx.Uint64("entry"))
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	printEntry(client.Entry)
+	printEntry(entry)
 	return nil
 }
 
@@ -597,35 +596,28 @@ func decodeL2Block(cliCtx *cli.Context) error {
 		Value: l2BlockNumber,
 	}
 
-	client.FromBookmark = bookMark.Encode()
-	err = client.ExecCommand(datastreamer.CmdBookmark)
+	firstEntry, err := client.ExecCommandGetBookmark(bookMark.Encode())
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
-
-	firstEntry := client.Entry
 	printEntry(firstEntry)
 
-	client.FromEntry = firstEntry.Number + 1
-	err = client.ExecCommand(datastreamer.CmdEntry)
+	secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
-
-	secondEntry := client.Entry
 	printEntry(secondEntry)
 
 	i := uint64(2) //nolint:gomnd
 	for secondEntry.Type == state.EntryTypeL2Tx {
-		client.FromEntry = firstEntry.Number + i
-		err = client.ExecCommand(datastreamer.CmdEntry)
+		entry, err := client.ExecCommandGetEntry(firstEntry.Number + i)
 		if err != nil {
 			log.Error(err)
 			os.Exit(1)
 		}
-		secondEntry = client.Entry
+		secondEntry = entry
 		printEntry(secondEntry)
 		i++
 	}

From 939da908c59784797f0a3c4cb2df1437b267d65b Mon Sep 17 00:00:00 2001
From: Alonso Rodriguez 
Date: Thu, 25 Apr 2024 16:37:23 +0200
Subject: [PATCH 15/23] fix log (#3595)

---
 synchronizer/actions/etrog/processor_l1_sequence_batches.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/synchronizer/actions/etrog/processor_l1_sequence_batches.go b/synchronizer/actions/etrog/processor_l1_sequence_batches.go
index e1528594d9..65e713137e 100644
--- a/synchronizer/actions/etrog/processor_l1_sequence_batches.go
+++ b/synchronizer/actions/etrog/processor_l1_sequence_batches.go
@@ -287,8 +287,8 @@ func (p *ProcessorL1SequenceBatchesEtrog) ProcessSequenceBatches(ctx context.Con
 
 			// Reset trusted state
 			previousBatchNumber := batch.BatchNumber - 1
-			if tBatch.StateRoot == (common.Hash{}) {
-				log.Warnf("cleaning state before inserting batch from L1. Clean until batch: %d", previousBatchNumber)
+			if tBatch.WIP {
+				log.Infof("cleaning state before inserting batch from L1. Clean until batch: %d", previousBatchNumber)
 			} else {
 				log.Warnf("missmatch in trusted state detected, discarding batches until batchNum %d", previousBatchNumber)
 			}

From 34e4854be57a88d1c713c06b2eebaeddfdde90ea Mon Sep 17 00:00:00 2001
From: Joan Esteban <129153821+joanestebanr@users.noreply.github.com>
Date: Mon, 29 Apr 2024 10:17:32 +0200
Subject: [PATCH 16/23] fix #3598 update GER when closing batch (#3599)

* fix #3598 update GER when closing batch
---
 .../executor_trusted_batch_sync.go            | 13 ++--
 .../executor_trusted_batch_sync_test.go       | 68 +++++++++++++++++++
 2 files changed, 74 insertions(+), 7 deletions(-)

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 7c89494441..ea8bbd7fa8 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
@@ -218,6 +218,12 @@ func (b *SyncTrustedBatchExecutorForEtrog) IncrementalProcess(ctx context.Contex
 		log.Errorf("%s error batchResultSanityCheck. Error: %s", data.DebugPrefix, err.Error())
 		return nil, err
 	}
+	log.Debugf("%s updateWIPBatch ", data.DebugPrefix)
+	err = b.updateWIPBatch(ctx, data, processBatchResp.NewStateRoot, dbTx)
+	if err != nil {
+		log.Errorf("%s error updateWIPBatch. Error: ", data.DebugPrefix, err)
+		return nil, err
+	}
 
 	if data.BatchMustBeClosed {
 		log.Debugf("%s Closing batch", data.DebugPrefix)
@@ -226,13 +232,6 @@ func (b *SyncTrustedBatchExecutorForEtrog) IncrementalProcess(ctx context.Contex
 			log.Errorf("%s error closing batch. Error: ", data.DebugPrefix, err)
 			return nil, err
 		}
-	} else {
-		log.Debugf("%s updateWIPBatch", data.DebugPrefix)
-		err = b.updateWIPBatch(ctx, data, processBatchResp.NewStateRoot, dbTx)
-		if err != nil {
-			log.Errorf("%s error updateWIPBatch. Error: ", data.DebugPrefix, err)
-			return nil, err
-		}
 	}
 
 	updatedBatch := *data.StateBatch
diff --git a/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go b/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go
index 97a7125b96..1fc1b46afa 100644
--- a/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go
+++ b/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go
@@ -89,6 +89,74 @@ func TestIncrementalProcessUpdateBatchL2DataOnCache(t *testing.T) {
 	require.Equal(t, false, res.ClearCache)
 }
 
+// This test check that if you process incrementally a batch that need to be close
+// the GER is update because we call UpdateWIPBatch
+// NOTE: CloseBatch() doesnt update GER
+func TestIncrementalProcessUpdateBatchL2DataAndGER(t *testing.T) {
+	// Arrange
+	stateMock := mock_l2_sync_etrog.NewStateInterface(t)
+	syncMock := mock_syncinterfaces.NewSynchronizerFlushIDManager(t)
+
+	sut := SyncTrustedBatchExecutorForEtrog{
+		state: stateMock,
+		sync:  syncMock,
+	}
+	ctx := context.Background()
+
+	stateBatchL2Data, _ := hex.DecodeString(codedL2BlockHeader + codedRLP2Txs1)
+	trustedBatchL2Data, _ := hex.DecodeString(codedL2BlockHeader + codedRLP2Txs1 + codedL2BlockHeader + codedRLP2Txs1)
+	expectedStateRoot := common.HexToHash("0x723e5c4c7ee7890e1e66c2e391d553ee792d2204ecb4fe921830f12f8dcd1a92")
+	//deltaBatchL2Data := []byte{4}
+	batchNumber := uint64(123)
+	data := l2_shared.ProcessData{
+		BatchNumber:       batchNumber,
+		OldStateRoot:      common.Hash{},
+		BatchMustBeClosed: true,
+		TrustedBatch: &types.Batch{
+			Number:      123,
+			BatchL2Data: trustedBatchL2Data,
+			StateRoot:   expectedStateRoot,
+			Closed:      true,
+		},
+		StateBatch: &state.Batch{
+			BatchNumber:    batchNumber,
+			BatchL2Data:    stateBatchL2Data,
+			GlobalExitRoot: common.HexToHash("0x9c8fa7ce2e197f9f1b3c30de9f93de3c1cb290e6c118a18446f47a9e1364c3ab"),
+		},
+	}
+	expectedUpdate := state.ProcessingReceipt{
+		BatchNumber:    123,
+		StateRoot:      expectedStateRoot,
+		LocalExitRoot:  data.TrustedBatch.LocalExitRoot,
+		GlobalExitRoot: data.TrustedBatch.GlobalExitRoot,
+		AccInputHash:   data.TrustedBatch.AccInputHash,
+		BatchL2Data:    trustedBatchL2Data,
+	}
+
+	stateMock.EXPECT().UpdateWIPBatch(ctx, expectedUpdate, mock.Anything).Return(nil).Once()
+	stateMock.EXPECT().GetL1InfoTreeDataFromBatchL2Data(ctx, mock.Anything, mock.Anything).Return(map[uint32]state.L1DataV2{}, expectedStateRoot, common.Hash{}, nil).Once()
+	stateMock.EXPECT().GetForkIDByBatchNumber(batchNumber).Return(uint64(7)).Once()
+
+	processBatchResp := &state.ProcessBatchResponse{
+		NewStateRoot: expectedStateRoot,
+	}
+	stateMock.EXPECT().ProcessBatchV2(ctx, mock.Anything, true).Return(processBatchResp, nil).Once()
+
+	syncMock.EXPECT().PendingFlushID(mock.Anything, mock.Anything).Once()
+	syncMock.EXPECT().CheckFlushID(mock.Anything).Return(nil).Maybe()
+	expectedUpdateClosed := expectedUpdate
+	expectedUpdateClosed.GlobalExitRoot = common.Hash{}
+	expectedUpdateClosed.ClosingReason = state.SyncL2TrustedBatchClosingReason
+	stateMock.EXPECT().CloseBatch(ctx, expectedUpdateClosed, mock.Anything).Return(nil).Once()
+	// Act
+	res, err := sut.IncrementalProcess(ctx, &data, nil)
+	// Assert
+	log.Info(res)
+	require.NoError(t, err)
+	require.Equal(t, trustedBatchL2Data, res.UpdateBatch.BatchL2Data)
+	require.Equal(t, false, res.ClearCache)
+}
+
 func newTestData(t *testing.T) testDataForBathExecutor {
 	stateMock := mock_l2_sync_etrog.NewStateInterface(t)
 	syncMock := mock_syncinterfaces.NewSynchronizerFlushIDManager(t)

From 5a76fb5c367b7631808dfd01bec1961e7c4cc7e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Toni=20Ram=C3=ADrez?=
 <58293609+ToniRamirezM@users.noreply.github.com>
Date: Mon, 29 Apr 2024 11:47:36 +0200
Subject: [PATCH 17/23] Change data stream format (#3597)

* protobuf datastream
---
 Makefile                                      |   1 +
 .../src/proto/datastream/v1/datastream.proto  |  64 ++
 sequencer/batch.go                            |   6 +
 sequencer/datastreamer.go                     |  27 +-
 sequencer/finalizer_test.go                   |   1 +
 sequencer/forcedbatch.go                      |   2 +-
 sequencer/l2block.go                          |   2 +-
 sequencer/sequencer.go                        | 134 ++-
 state/datastream.go                           | 482 +++++------
 state/datastream/datastream.pb.go             | 773 ++++++++++++++++++
 state/pgstatestorage/datastream.go            |  13 +-
 state/test/datastream_test.go                 |  82 --
 test/docker-compose.yml                       |   6 +
 tools/datastreamer/Makefile                   |  22 +-
 tools/datastreamer/config/tool.config.toml    |   6 +-
 tools/datastreamer/main.go                    | 733 +++++++----------
 16 files changed, 1537 insertions(+), 817 deletions(-)
 create mode 100644 proto/src/proto/datastream/v1/datastream.proto
 create mode 100644 state/datastream/datastream.pb.go
 delete mode 100644 state/test/datastream_test.go

diff --git a/Makefile b/Makefile
index 83d4fed5fe..ba55fb3429 100644
--- a/Makefile
+++ b/Makefile
@@ -164,6 +164,7 @@ generate-code-from-proto: ## Generates code from proto files
 	cd proto/src/proto/hashdb/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../merkletree/hashdb --go-grpc_out=../../../../../merkletree/hashdb --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative hashdb.proto
 	cd proto/src/proto/executor/v1 && protoc --proto_path=. --go_out=../../../../../state/runtime/executor --go-grpc_out=../../../../../state/runtime/executor --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative executor.proto
 	cd proto/src/proto/aggregator/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../aggregator/prover --go-grpc_out=../../../../../aggregator/prover --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative aggregator.proto
+	cd proto/src/proto/datastream/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../state/datastream --go-grpc_out=../../../../../state/datastream --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative datastream.proto
 
 ## Help display.
 ## Pulls comments from beside commands and prints a nicely formatted
diff --git a/proto/src/proto/datastream/v1/datastream.proto b/proto/src/proto/datastream/v1/datastream.proto
new file mode 100644
index 0000000000..6b8a89adc6
--- /dev/null
+++ b/proto/src/proto/datastream/v1/datastream.proto
@@ -0,0 +1,64 @@
+syntax = "proto3";
+
+package datastream.v1;
+
+option go_package = "github.com/0xPolygonHermez/zkevm-node/state/datastream";
+
+message Batch {
+    uint64 number = 1;
+    bytes local_exit_root = 2;
+    bytes state_root = 3;
+    uint64 fork_id = 4;
+    uint64 chain_id = 5;
+}
+
+message L2Block {
+    uint64 number = 1;
+    uint64 batch_number = 2;
+    uint64 timestamp = 3;
+    uint32 delta_timestamp = 4;
+    uint64 min_timestamp = 5;
+    bytes l1_blockhash = 6;
+    uint32 l1_infotree_index = 7;
+    bytes hash = 8;
+    bytes state_root = 9;
+    bytes global_exit_root = 10;
+    bytes coinbase = 11;
+}
+
+message Transaction {
+    uint64 l2block_number = 1;
+    bool is_valid = 2;
+    bytes encoded = 3;
+    uint32 effective_gas_price_percentage = 4;
+    bytes im_state_root = 5;
+}
+
+message UpdateGER {
+    uint64 batch_number = 1;
+    uint64 timestamp = 2;
+    bytes global_exit_root = 3;
+    bytes coinbase = 4;
+    uint64 fork_id = 5;
+    uint64 chain_id = 6;
+    bytes state_root = 7;
+}
+
+message BookMark {
+    BookmarkType type = 1;
+    uint64 value = 2;
+}
+
+enum BookmarkType {
+    BOOKMARK_TYPE_UNSPECIFIED = 0;
+    BOOKMARK_TYPE_BATCH = 1;
+    BOOKMARK_TYPE_L2_BLOCK = 2;
+}
+
+enum EntryType {
+    ENTRY_TYPE_UNSPECIFIED = 0;
+    ENTRY_TYPE_BATCH = 1;
+    ENTRY_TYPE_L2_BLOCK = 2;
+    ENTRY_TYPE_TRANSACTION = 3;
+    ENTRY_TYPE_UPDATE_GER = 4;
+}
diff --git a/sequencer/batch.go b/sequencer/batch.go
index 1d644b22c5..c189f26380 100644
--- a/sequencer/batch.go
+++ b/sequencer/batch.go
@@ -26,6 +26,7 @@ type Batch struct {
 	imRemainingResources    state.BatchResources // remaining batch resources when processing tx-by-tx
 	finalRemainingResources state.BatchResources // remaining batch resources when a L2 block is processed
 	closingReason           state.ClosingReason
+	finalLocalExitRoot      common.Hash
 }
 
 func (w *Batch) isEmpty() bool {
@@ -94,6 +95,7 @@ func (f *finalizer) setWIPBatch(ctx context.Context, wipStateBatch *state.Batch)
 		countOfTxs:              wipStateBatchCountOfTxs,
 		imRemainingResources:    remainingResources,
 		finalRemainingResources: remainingResources,
+		finalLocalExitRoot:      wipStateBatch.LocalExitRoot,
 	}
 
 	return wipBatch, nil
@@ -293,6 +295,7 @@ func (f *finalizer) openNewWIPBatch(ctx context.Context, batchNumber uint64, sta
 		imRemainingResources:    maxRemainingResources,
 		finalRemainingResources: maxRemainingResources,
 		closingReason:           state.EmptyClosingReason,
+		finalLocalExitRoot:      newStateBatch.LocalExitRoot,
 	}, err
 }
 
@@ -328,6 +331,9 @@ func (f *finalizer) closeWIPBatch(ctx context.Context) error {
 			log.Errorf("error committing close wip batch, error: %v", err)
 			return err
 		}
+
+		// Sent batch to DS
+		f.DSSendBatch(f.wipBatch.batchNumber, f.wipBatch.finalStateRoot, f.wipBatch.finalLocalExitRoot)
 	}
 
 	return nil
diff --git a/sequencer/datastreamer.go b/sequencer/datastreamer.go
index bbbfe14496..2c790c0946 100644
--- a/sequencer/datastreamer.go
+++ b/sequencer/datastreamer.go
@@ -3,9 +3,11 @@ package sequencer
 import (
 	"github.com/0xPolygonHermez/zkevm-node/log"
 	"github.com/0xPolygonHermez/zkevm-node/state"
+	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
+	"github.com/ethereum/go-ethereum/common"
 )
 
-func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.ProcessBlockResponse, l1InfoTreeIndex uint32) error {
+func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.ProcessBlockResponse, l1InfoTreeIndex uint32, minTimestamp uint64) error {
 	forkID := f.stateIntf.GetForkIDByBatchNumber(batchNumber)
 
 	// Send data to streamer
@@ -13,12 +15,13 @@ func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.Proce
 		l2Block := state.DSL2Block{
 			BatchNumber:     batchNumber,
 			L2BlockNumber:   blockResponse.BlockNumber,
-			Timestamp:       int64(blockResponse.Timestamp),
+			Timestamp:       blockResponse.Timestamp,
+			Min_timestamp:   minTimestamp,
 			L1InfoTreeIndex: l1InfoTreeIndex,
 			L1BlockHash:     blockResponse.BlockHashL1,
 			GlobalExitRoot:  blockResponse.GlobalExitRoot,
 			Coinbase:        f.sequencerAddress,
-			ForkID:          uint16(forkID),
+			ForkID:          forkID,
 			BlockHash:       blockResponse.BlockHash,
 			StateRoot:       blockResponse.BlockHash, //From etrog, the blockhash is the block root
 		}
@@ -57,9 +60,23 @@ func (f *finalizer) DSSendBatchBookmark(batchNumber uint64) {
 	// Check if stream server enabled
 	if f.streamServer != nil {
 		// Send batch bookmark to the streamer
-		f.dataToStream <- state.DSBookMark{
-			Type:  state.BookMarkTypeBatch,
+		f.dataToStream <- datastream.BookMark{
+			Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
 			Value: batchNumber,
 		}
 	}
 }
+
+func (f *finalizer) DSSendBatch(batchNumber uint64, stateRoot common.Hash, localExitRoot common.Hash) {
+	forkID := f.stateIntf.GetForkIDByBatchNumber(batchNumber)
+
+	if f.streamServer != nil {
+		// Send batch to the streamer
+		f.dataToStream <- datastream.Batch{
+			Number:        batchNumber,
+			ForkId:        forkID,
+			StateRoot:     stateRoot.Bytes(),
+			LocalExitRoot: localExitRoot.Bytes(),
+		}
+	}
+}
diff --git a/sequencer/finalizer_test.go b/sequencer/finalizer_test.go
index 8e7b5fa9d9..9b9d555b94 100644
--- a/sequencer/finalizer_test.go
+++ b/sequencer/finalizer_test.go
@@ -981,6 +981,7 @@ func TestFinalizer_closeWIPBatch(t *testing.T) {
 			// arrange
 			stateMock.Mock.On("CloseWIPBatch", ctx, receipt, mock.Anything).Return(tc.managerErr).Once()
 			stateMock.On("BeginStateTransaction", ctx).Return(dbTxMock, nilErr).Once()
+			stateMock.On("GetForkIDByBatchNumber", mock.Anything).Return(uint64(state.FORKID_BLUEBERRY))
 			if tc.managerErr == nil {
 				dbTxMock.On("Commit", ctx).Return(nilErr).Once()
 			} else {
diff --git a/sequencer/forcedbatch.go b/sequencer/forcedbatch.go
index ebe078c1b8..d6386091d6 100644
--- a/sequencer/forcedbatch.go
+++ b/sequencer/forcedbatch.go
@@ -197,7 +197,7 @@ func (f *finalizer) handleProcessForcedBatchResponse(ctx context.Context, newBat
 		}
 
 		// Send L2 block to data streamer
-		err = f.DSSendL2Block(newBatchNumber, forcedL2BlockResponse, 0)
+		err = f.DSSendL2Block(newBatchNumber, forcedL2BlockResponse, 0, forcedL2BlockResponse.Timestamp)
 		if err != nil {
 			//TODO: we need to halt/rollback the L2 block if we had an error sending to the data streamer?
 			log.Errorf("error sending L2 block %d to data streamer, error: %v", forcedL2BlockResponse.BlockNumber, err)
diff --git a/sequencer/l2block.go b/sequencer/l2block.go
index ed7ae314f6..f2472a65b5 100644
--- a/sequencer/l2block.go
+++ b/sequencer/l2block.go
@@ -427,7 +427,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 	log.Infof("l2 block %d [%d] transactions updated as selected in the pooldb", blockResponse.BlockNumber, l2Block.trackingNum)
 
 	// Send L2 block to data streamer
-	err = f.DSSendL2Block(f.wipBatch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex())
+	err = f.DSSendL2Block(f.wipBatch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex(), l2Block.timestamp)
 	if err != nil {
 		//TODO: we need to halt/rollback the L2 block if we had an error sending to the data streamer?
 		log.Errorf("error sending L2 block %d [%d] to data streamer, error: %v", blockResponse.BlockNumber, l2Block.trackingNum, err)
diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go
index 22201776ce..5608ddc12e 100644
--- a/sequencer/sequencer.go
+++ b/sequencer/sequencer.go
@@ -11,7 +11,9 @@ import (
 	"github.com/0xPolygonHermez/zkevm-node/log"
 	"github.com/0xPolygonHermez/zkevm-node/pool"
 	"github.com/0xPolygonHermez/zkevm-node/state"
+	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
 	"github.com/ethereum/go-ethereum/common"
+	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -137,7 +139,7 @@ func (s *Sequencer) checkStateInconsistency(ctx context.Context) {
 }
 
 func (s *Sequencer) updateDataStreamerFile(ctx context.Context, chainID uint64) {
-	err := state.GenerateDataStreamerFile(ctx, s.streamServer, s.stateIntf, true, nil, chainID, s.cfg.StreamServer.UpgradeEtrogBatchNumber)
+	err := state.GenerateDataStreamFile(ctx, s.streamServer, s.stateIntf, true, nil, chainID, s.cfg.StreamServer.UpgradeEtrogBatchNumber)
 	if err != nil {
 		log.Fatalf("failed to generate data streamer file, error: %v", err)
 	}
@@ -264,54 +266,77 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 					continue
 				}
 
-				bookMark := state.DSBookMark{
-					Type:  state.BookMarkTypeL2Block,
+				bookMark := &datastream.BookMark{
+					Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
 					Value: l2Block.L2BlockNumber,
 				}
 
 				//TODO: remove this log
 				log.Infof("add stream bookmark for l2block %d", l2Block.L2BlockNumber)
-				_, err = s.streamServer.AddStreamBookmark(bookMark.Encode())
+				marshalledBookMark, err := proto.Marshal(bookMark)
+				if err != nil {
+					log.Errorf("failed to marshal bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err)
+					continue
+				}
+
+				_, err = s.streamServer.AddStreamBookmark(marshalledBookMark)
 				if err != nil {
 					log.Errorf("failed to add stream bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 					continue
 				}
 
 				// Get previous block timestamp to calculate delta timestamp
-				previousL2Block := state.DSL2BlockStart{}
+				previousL2Block := datastream.L2Block{}
 				if l2Block.L2BlockNumber > 0 {
-					bookMark = state.DSBookMark{
-						Type:  state.BookMarkTypeL2Block,
+					bookMark = &datastream.BookMark{
+						Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
 						Value: l2Block.L2BlockNumber - 1,
 					}
 
 					//TODO: remove this log
 					log.Infof("get previous l2block %d", l2Block.L2BlockNumber-1)
-					previousL2BlockEntry, err := s.streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
+					marshalledBookMark, err := proto.Marshal(bookMark)
+					if err != nil {
+						log.Errorf("failed to marshal bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err)
+						continue
+					}
+
+					previousL2BlockEntry, err := s.streamServer.GetFirstEventAfterBookmark(marshalledBookMark)
 					if err != nil {
 						log.Errorf("failed to get previous l2block %d, error: %v", l2Block.L2BlockNumber-1, err)
 						continue
 					}
 
-					previousL2Block = state.DSL2BlockStart{}.Decode(previousL2BlockEntry.Data)
+					err = proto.Unmarshal(previousL2BlockEntry.Data, &previousL2Block)
+					if err != nil {
+						log.Errorf("failed to unmarshal previous l2block %d, error: %v", l2Block.L2BlockNumber-1, err)
+						continue
+					}
 				}
 
-				blockStart := state.DSL2BlockStart{
+				streamL2Block := &datastream.L2Block{
+					Number:          l2Block.L2BlockNumber,
 					BatchNumber:     l2Block.BatchNumber,
-					L2BlockNumber:   l2Block.L2BlockNumber,
 					Timestamp:       l2Block.Timestamp,
 					DeltaTimestamp:  uint32(l2Block.Timestamp - previousL2Block.Timestamp),
-					L1InfoTreeIndex: l2Block.L1InfoTreeIndex,
-					L1BlockHash:     l2Block.L1BlockHash,
-					GlobalExitRoot:  l2Block.GlobalExitRoot,
-					Coinbase:        l2Block.Coinbase,
-					ForkID:          l2Block.ForkID,
-					ChainID:         uint32(chainID),
+					MinTimestamp:    l2Block.Min_timestamp,
+					L1Blockhash:     l2Block.L1BlockHash.Bytes(),
+					L1InfotreeIndex: l2Block.L1InfoTreeIndex,
+					Hash:            l2Block.BlockHash.Bytes(),
+					StateRoot:       l2Block.StateRoot.Bytes(),
+					GlobalExitRoot:  l2Block.GlobalExitRoot.Bytes(),
+					Coinbase:        l2Block.Coinbase.Bytes(),
+				}
+
+				marshalledL2Block, err := proto.Marshal(streamL2Block)
+				if err != nil {
+					log.Errorf("failed to marshal l2block %d, error: %v", l2Block.L2BlockNumber, err)
+					continue
 				}
 
 				//TODO: remove this log
 				log.Infof("add l2blockStart stream entry for l2block %d", l2Block.L2BlockNumber)
-				_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockStart, blockStart.Encode())
+				_, err = s.streamServer.AddStreamEntry(datastreamer.EntryType(datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK), marshalledL2Block)
 				if err != nil {
 					log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 					continue
@@ -320,25 +345,25 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 				//TODO: remove this log
 				log.Infof("adding l2tx stream entries for l2block %d", l2Block.L2BlockNumber)
 				for _, l2Transaction := range l2Block.Txs {
-					_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2Tx, l2Transaction.Encode())
+					streamL2Transaction := &datastream.Transaction{
+						L2BlockNumber:               l2Transaction.L2BlockNumber,
+						IsValid:                     l2Transaction.IsValid != 0,
+						Encoded:                     l2Transaction.Encoded,
+						EffectiveGasPricePercentage: uint32(l2Transaction.EffectiveGasPricePercentage),
+						ImStateRoot:                 l2Transaction.ImStateRoot.Bytes(),
+					}
+
+					marshalledL2Transaction, err := proto.Marshal(streamL2Transaction)
 					if err != nil {
-						log.Errorf("failed to add l2tx stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
+						log.Errorf("failed to marshal l2tx for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 						continue
 					}
-				}
 
-				blockEnd := state.DSL2BlockEnd{
-					L2BlockNumber: l2Block.L2BlockNumber,
-					BlockHash:     l2Block.BlockHash,
-					StateRoot:     l2Block.StateRoot,
-				}
-
-				//TODO: remove this log
-				log.Infof("add l2blockEnd stream entry for l2block %d", l2Block.L2BlockNumber)
-				_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockEnd, blockEnd.Encode())
-				if err != nil {
-					log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
-					continue
+					_, err = s.streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION), marshalledL2Transaction)
+					if err != nil {
+						log.Errorf("failed to add l2tx stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
+						continue
+					}
 				}
 
 				//TODO: remove this log
@@ -353,24 +378,55 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 				log.Infof("l2block %d sent to datastream", l2Block.L2BlockNumber)
 
 			// Stream a bookmark
-			case state.DSBookMark:
-				bookmark := data
+			case datastream.BookMark:
+				err = s.streamServer.StartAtomicOp()
+				if err != nil {
+					log.Errorf("failed to start atomic op for bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
+					continue
+				}
 
+				marshalledBookMark, err := proto.Marshal(&data)
+				if err != nil {
+					log.Errorf("failed to marshal bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
+					continue
+				}
+
+				_, err = s.streamServer.AddStreamBookmark(marshalledBookMark)
+				if err != nil {
+					log.Errorf("failed to add stream bookmark for bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
+					continue
+				}
+
+				err = s.streamServer.CommitAtomicOp()
+				if err != nil {
+					log.Errorf("failed to commit atomic op for bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
+					continue
+				}
+			case datastream.Batch:
 				err = s.streamServer.StartAtomicOp()
 				if err != nil {
-					log.Errorf("failed to start atomic op for bookmark type %d, value %d, error: %v", bookmark.Type, bookmark.Value, err)
+					log.Errorf("failed to start atomic op for batch, error: %v", err)
 					continue
 				}
 
-				_, err = s.streamServer.AddStreamBookmark(bookmark.Encode())
+				data.ChainId = chainID
+
+				marshalledBatch, err := proto.Marshal(&data)
+				if err != nil {
+					log.Errorf("failed to marshal batch, error: %v", err)
+					continue
+				}
+
+				_, err = s.streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH), marshalledBatch)
 				if err != nil {
-					log.Errorf("failed to add stream bookmark type %d, value %d, error: %v", bookmark.Type, bookmark.Value, err)
+					log.Errorf("failed to add stream entry for batch, error: %v", err)
 					continue
 				}
 
 				err = s.streamServer.CommitAtomicOp()
 				if err != nil {
-					log.Errorf("failed to commit atomic op for bookmark type %d, value %d, error: %v", bookmark.Type, bookmark.Value, err)
+					log.Errorf("failed to commit atomic op for batch, error: %v", err)
+					continue
 				}
 
 			// Invalid stream message type
diff --git a/state/datastream.go b/state/datastream.go
index d50c7adecf..eb3670e6f9 100644
--- a/state/datastream.go
+++ b/state/datastream.go
@@ -2,14 +2,16 @@ package state
 
 import (
 	"context"
-	"encoding/binary"
 	"math/big"
+	"time"
 
 	"github.com/0xPolygonHermez/zkevm-data-streamer/datastreamer"
 	"github.com/0xPolygonHermez/zkevm-node/log"
+	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/iden3/go-iden3-crypto/keccak256"
 	"github.com/jackc/pgx/v4"
+	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -17,18 +19,6 @@ const (
 	StreamTypeSequencer datastreamer.StreamType = 1
 	// EntryTypeBookMark represents a bookmark entry
 	EntryTypeBookMark datastreamer.EntryType = datastreamer.EtBookmark
-	// EntryTypeL2BlockStart represents a L2 block start
-	EntryTypeL2BlockStart datastreamer.EntryType = 1
-	// EntryTypeL2Tx represents a L2 transaction
-	EntryTypeL2Tx datastreamer.EntryType = 2
-	// EntryTypeL2BlockEnd represents a L2 block end
-	EntryTypeL2BlockEnd datastreamer.EntryType = 3
-	// EntryTypeUpdateGER represents a GER update
-	EntryTypeUpdateGER datastreamer.EntryType = 4
-	// BookMarkTypeL2Block represents a L2 block bookmark
-	BookMarkTypeL2Block byte = 0
-	// BookMarkTypeBatch represents a batch
-	BookMarkTypeBatch byte = 1
 	// SystemSC is the system smart contract address
 	SystemSC = "0x000000000000000000000000000000005ca1ab1e"
 	// posConstant is the constant used to compute the position of the intermediate state root
@@ -38,7 +28,8 @@ const (
 // DSBatch represents a data stream batch
 type DSBatch struct {
 	Batch
-	ForkID uint16
+	ForkID         uint64
+	EtrogTimestamp *time.Time
 }
 
 // DSFullBatch represents a data stream batch ant its L2 blocks
@@ -55,64 +46,18 @@ type DSL2FullBlock struct {
 
 // DSL2Block is a full l2 block
 type DSL2Block struct {
-	BatchNumber     uint64         // 8 bytes
-	L2BlockNumber   uint64         // 8 bytes
-	Timestamp       int64          // 8 bytes
-	L1InfoTreeIndex uint32         // 4 bytes
-	L1BlockHash     common.Hash    // 32 bytes
-	GlobalExitRoot  common.Hash    // 32 bytes
-	Coinbase        common.Address // 20 bytes
-	ForkID          uint16         // 2 bytes
-	ChainID         uint32         // 4 bytes
-	BlockHash       common.Hash    // 32 bytes
-	StateRoot       common.Hash    // 32 bytes
-}
-
-// DSL2BlockStart represents a data stream L2 block start
-type DSL2BlockStart struct {
-	BatchNumber     uint64         // 8 bytes
-	L2BlockNumber   uint64         // 8 bytes
-	Timestamp       int64          // 8 bytes
-	DeltaTimestamp  uint32         // 4 bytes
-	L1InfoTreeIndex uint32         // 4 bytes
-	L1BlockHash     common.Hash    // 32 bytes
-	GlobalExitRoot  common.Hash    // 32 bytes
-	Coinbase        common.Address // 20 bytes
-	ForkID          uint16         // 2 bytes
-	ChainID         uint32         // 4 bytes
-
-}
-
-// Encode returns the encoded DSL2BlockStart as a byte slice
-func (b DSL2BlockStart) Encode() []byte {
-	bytes := make([]byte, 0)
-	bytes = binary.BigEndian.AppendUint64(bytes, b.BatchNumber)
-	bytes = binary.BigEndian.AppendUint64(bytes, b.L2BlockNumber)
-	bytes = binary.BigEndian.AppendUint64(bytes, uint64(b.Timestamp))
-	bytes = binary.BigEndian.AppendUint32(bytes, b.DeltaTimestamp)
-	bytes = binary.BigEndian.AppendUint32(bytes, b.L1InfoTreeIndex)
-	bytes = append(bytes, b.L1BlockHash.Bytes()...)
-	bytes = append(bytes, b.GlobalExitRoot.Bytes()...)
-	bytes = append(bytes, b.Coinbase.Bytes()...)
-	bytes = binary.BigEndian.AppendUint16(bytes, b.ForkID)
-	bytes = binary.BigEndian.AppendUint32(bytes, b.ChainID)
-	return bytes
-}
-
-// Decode decodes the DSL2BlockStart from a byte slice
-func (b DSL2BlockStart) Decode(data []byte) DSL2BlockStart {
-	b.BatchNumber = binary.BigEndian.Uint64(data[0:8])
-	b.L2BlockNumber = binary.BigEndian.Uint64(data[8:16])
-	b.Timestamp = int64(binary.BigEndian.Uint64(data[16:24]))
-	b.DeltaTimestamp = binary.BigEndian.Uint32(data[24:28])
-	b.L1InfoTreeIndex = binary.BigEndian.Uint32(data[28:32])
-	b.L1BlockHash = common.BytesToHash(data[32:64])
-	b.GlobalExitRoot = common.BytesToHash(data[64:96])
-	b.Coinbase = common.BytesToAddress(data[96:116])
-	b.ForkID = binary.BigEndian.Uint16(data[116:118])
-	b.ChainID = binary.BigEndian.Uint32(data[118:122])
-
-	return b
+	BatchNumber     uint64
+	L2BlockNumber   uint64
+	Timestamp       uint64
+	Min_timestamp   uint64
+	L1InfoTreeIndex uint32
+	L1BlockHash     common.Hash
+	GlobalExitRoot  common.Hash
+	Coinbase        common.Address
+	ForkID          uint64
+	ChainID         uint64
+	BlockHash       common.Hash
+	StateRoot       common.Hash
 }
 
 // DSL2Transaction represents a data stream L2 transaction
@@ -126,108 +71,6 @@ type DSL2Transaction struct {
 	Encoded                     []byte
 }
 
-// Encode returns the encoded DSL2Transaction as a byte slice
-func (l DSL2Transaction) Encode() []byte {
-	bytes := make([]byte, 0)
-	bytes = append(bytes, l.EffectiveGasPricePercentage)
-	bytes = append(bytes, l.IsValid)
-	bytes = append(bytes, l.StateRoot[:]...)
-	bytes = binary.BigEndian.AppendUint32(bytes, l.EncodedLength)
-	bytes = append(bytes, l.Encoded...)
-	return bytes
-}
-
-// Decode decodes the DSL2Transaction from a byte slice
-func (l DSL2Transaction) Decode(data []byte) DSL2Transaction {
-	l.EffectiveGasPricePercentage = data[0]
-	l.IsValid = data[1]
-	l.StateRoot = common.BytesToHash(data[2:34])
-	l.EncodedLength = binary.BigEndian.Uint32(data[34:38])
-	l.Encoded = data[38:]
-	return l
-}
-
-// DSL2BlockEnd represents a L2 block end
-type DSL2BlockEnd struct {
-	L2BlockNumber uint64      // 8 bytes
-	BlockHash     common.Hash // 32 bytes
-	StateRoot     common.Hash // 32 bytes
-}
-
-// Encode returns the encoded DSL2BlockEnd as a byte slice
-func (b DSL2BlockEnd) Encode() []byte {
-	bytes := make([]byte, 0)
-	bytes = binary.BigEndian.AppendUint64(bytes, b.L2BlockNumber)
-	bytes = append(bytes, b.BlockHash[:]...)
-	bytes = append(bytes, b.StateRoot[:]...)
-	return bytes
-}
-
-// Decode decodes the DSL2BlockEnd from a byte slice
-func (b DSL2BlockEnd) Decode(data []byte) DSL2BlockEnd {
-	b.L2BlockNumber = binary.BigEndian.Uint64(data[0:8])
-	b.BlockHash = common.BytesToHash(data[8:40])
-	b.StateRoot = common.BytesToHash(data[40:72])
-	return b
-}
-
-// DSBookMark represents a data stream bookmark
-type DSBookMark struct {
-	Type  byte   // 1 byte
-	Value uint64 // 8 bytes
-}
-
-// Encode returns the encoded DSBookMark as a byte slice
-func (b DSBookMark) Encode() []byte {
-	bytes := make([]byte, 0)
-	bytes = append(bytes, b.Type)
-	bytes = binary.BigEndian.AppendUint64(bytes, b.Value)
-	return bytes
-}
-
-// Decode decodes the DSBookMark from a byte slice
-func (b DSBookMark) Decode(data []byte) DSBookMark {
-	b.Type = data[0]
-	b.Value = binary.BigEndian.Uint64(data[1:9])
-	return b
-}
-
-// DSUpdateGER represents a data stream GER update
-type DSUpdateGER struct {
-	BatchNumber    uint64         // 8 bytes
-	Timestamp      int64          // 8 bytes
-	GlobalExitRoot common.Hash    // 32 bytes
-	Coinbase       common.Address // 20 bytes
-	ForkID         uint16         // 2 bytes
-	ChainID        uint32         // 4 bytes
-	StateRoot      common.Hash    // 32 bytes
-}
-
-// Encode returns the encoded DSUpdateGER as a byte slice
-func (g DSUpdateGER) Encode() []byte {
-	bytes := make([]byte, 0)
-	bytes = binary.BigEndian.AppendUint64(bytes, g.BatchNumber)
-	bytes = binary.BigEndian.AppendUint64(bytes, uint64(g.Timestamp))
-	bytes = append(bytes, g.GlobalExitRoot[:]...)
-	bytes = append(bytes, g.Coinbase[:]...)
-	bytes = binary.BigEndian.AppendUint16(bytes, g.ForkID)
-	bytes = binary.BigEndian.AppendUint32(bytes, g.ChainID)
-	bytes = append(bytes, g.StateRoot[:]...)
-	return bytes
-}
-
-// Decode decodes the DSUpdateGER from a byte slice
-func (g DSUpdateGER) Decode(data []byte) DSUpdateGER {
-	g.BatchNumber = binary.BigEndian.Uint64(data[0:8])
-	g.Timestamp = int64(binary.BigEndian.Uint64(data[8:16]))
-	g.GlobalExitRoot = common.BytesToHash(data[16:48])
-	g.Coinbase = common.BytesToAddress(data[48:68])
-	g.ForkID = binary.BigEndian.Uint16(data[68:70])
-	g.ChainID = binary.BigEndian.Uint32(data[70:74])
-	g.StateRoot = common.BytesToHash(data[74:106])
-	return g
-}
-
 // DSState gathers the methods required to interact with the data stream state.
 type DSState interface {
 	GetDSGenesisBlock(ctx context.Context, dbTx pgx.Tx) (*DSL2Block, error)
@@ -240,14 +83,14 @@ type DSState interface {
 	GetL1InfoRootLeafByIndex(ctx context.Context, l1InfoTreeIndex uint32, dbTx pgx.Tx) (L1InfoTreeExitRootStorageEntry, error)
 }
 
-// GenerateDataStreamerFile generates or resumes a data stream file
-func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.StreamServer, stateDB DSState, readWIPBatch bool, imStateRoots *map[uint64][]byte, chainID uint64, upgradeEtrogBatchNumber uint64) error {
+// GenerateDataStreamFile generates or resumes a data stream file
+func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.StreamServer, stateDB DSState, readWIPBatch bool, imStateRoots *map[uint64][]byte, chainID uint64, upgradeEtrogBatchNumber uint64) error {
 	header := streamServer.GetHeader()
 
 	var currentBatchNumber uint64 = 0
 	var lastAddedL2BlockNumber uint64 = 0
 	var lastAddedBatchNumber uint64 = 0
-	var previousTimestamp int64 = 0
+	var previousTimestamp uint64 = 0
 
 	if header.TotalEntries == 0 {
 		// Get Genesis block
@@ -261,52 +104,73 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St
 			return err
 		}
 
-		bookMark := DSBookMark{
-			Type:  BookMarkTypeBatch,
+		bookMark := &datastream.BookMark{
+			Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
 			Value: genesisL2Block.BatchNumber,
 		}
 
-		_, err = streamServer.AddStreamBookmark(bookMark.Encode())
+		marshalledBookMark, err := proto.Marshal(bookMark)
 		if err != nil {
 			return err
 		}
 
-		bookMark = DSBookMark{
-			Type:  BookMarkTypeL2Block,
+		_, err = streamServer.AddStreamBookmark(marshalledBookMark)
+		if err != nil {
+			return err
+		}
+
+		bookMark = &datastream.BookMark{
+			Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
 			Value: genesisL2Block.L2BlockNumber,
 		}
 
-		_, err = streamServer.AddStreamBookmark(bookMark.Encode())
+		marshalledBookMark, err = proto.Marshal(bookMark)
+		if err != nil {
+			return err
+		}
+
+		_, err = streamServer.AddStreamBookmark(marshalledBookMark)
 		if err != nil {
 			return err
 		}
 
-		genesisBlock := DSL2BlockStart{
-			BatchNumber:     genesisL2Block.BatchNumber,
-			L2BlockNumber:   genesisL2Block.L2BlockNumber,
-			Timestamp:       genesisL2Block.Timestamp,
+		genesisBlock := &datastream.L2Block{
+			Number:          genesisL2Block.L2BlockNumber,
 			DeltaTimestamp:  0,
-			L1InfoTreeIndex: 0,
-			GlobalExitRoot:  genesisL2Block.GlobalExitRoot,
-			Coinbase:        genesisL2Block.Coinbase,
-			ForkID:          genesisL2Block.ForkID,
-			ChainID:         uint32(chainID),
+			MinTimestamp:    0,
+			L1InfotreeIndex: 0,
+			Hash:            genesisL2Block.BlockHash.Bytes(),
+			StateRoot:       genesisL2Block.StateRoot.Bytes(),
+			GlobalExitRoot:  genesisL2Block.GlobalExitRoot.Bytes(),
+			Coinbase:        genesisL2Block.Coinbase.Bytes(),
 		}
 
-		log.Infof("Genesis block: %+v", genesisBlock)
+		log.Debugf("Genesis block: %+v", genesisBlock)
+
+		marshalledGenesisBlock, err := proto.Marshal(genesisBlock)
+		if err != nil {
+			return err
+		}
 
-		_, err = streamServer.AddStreamEntry(1, genesisBlock.Encode())
+		_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK), marshalledGenesisBlock)
 		if err != nil {
 			return err
 		}
 
-		genesisBlockEnd := DSL2BlockEnd{
-			L2BlockNumber: genesisL2Block.L2BlockNumber,
-			BlockHash:     genesisL2Block.BlockHash,
-			StateRoot:     genesisL2Block.StateRoot,
+		genesisBatch := &datastream.Batch{
+			Number:        genesisL2Block.BatchNumber,
+			LocalExitRoot: common.Hash{}.Bytes(),
+			StateRoot:     genesisL2Block.StateRoot.Bytes(),
+			ForkId:        genesisL2Block.ForkID,
+			ChainId:       chainID,
+		}
+
+		marshalledGenesisBatch, err := proto.Marshal(genesisBatch)
+		if err != nil {
+			return err
 		}
 
-		_, err = streamServer.AddStreamEntry(EntryTypeL2BlockEnd, genesisBlockEnd.Encode())
+		_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH), marshalledGenesisBatch)
 		if err != nil {
 			return err
 		}
@@ -325,35 +189,88 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St
 		log.Infof("Latest entry: %+v", latestEntry)
 
 		switch latestEntry.Type {
-		case EntryTypeUpdateGER:
+		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH):
+			log.Info("Latest entry type is Batch")
+
+			batch := &datastream.Batch{}
+			if err := proto.Unmarshal(latestEntry.Data, batch); err != nil {
+				return err
+			}
+
+			currentBatchNumber = batch.Number
+			currentBatchNumber++
+		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER):
 			log.Info("Latest entry type is UpdateGER")
-			currentBatchNumber = binary.BigEndian.Uint64(latestEntry.Data[0:8])
+
+			updateGer := &datastream.UpdateGER{}
+			if err := proto.Unmarshal(latestEntry.Data, updateGer); err != nil {
+				return err
+			}
+
+			currentBatchNumber = updateGer.BatchNumber
 			currentBatchNumber++
-		case EntryTypeL2BlockEnd:
-			log.Info("Latest entry type is L2BlockEnd")
-			blockEnd := DSL2BlockEnd{}.Decode(latestEntry.Data)
-			currentL2BlockNumber := blockEnd.L2BlockNumber
-
-			bookMark := DSBookMark{
-				Type:  BookMarkTypeL2Block,
-				Value: currentL2BlockNumber,
+		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK):
+			log.Info("Latest entry type is L2Block")
+
+			l2Block := &datastream.L2Block{}
+
+			if err := proto.Unmarshal(latestEntry.Data, l2Block); err != nil {
+				return err
+			}
+
+			currentL2BlockNumber := l2Block.Number
+			currentBatchNumber = l2Block.BatchNumber
+			previousTimestamp = l2Block.Timestamp
+			lastAddedL2BlockNumber = currentL2BlockNumber
+		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION):
+			log.Info("Latest entry type is Transaction")
+
+			transaction := &datastream.Transaction{}
+			if err := proto.Unmarshal(latestEntry.Data, transaction); err != nil {
+				return err
+			}
+
+			currentL2BlockNumber := transaction.L2BlockNumber
+			currentBatchNumber = transaction.L2BlockNumber
+			lastAddedL2BlockNumber = currentL2BlockNumber
+
+			// Get Previous l2block timestamp
+			bookMark := &datastream.BookMark{
+				Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+				Value: currentL2BlockNumber - 1,
 			}
 
-			firstEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
+			marshalledBookMark, err := proto.Marshal(bookMark)
 			if err != nil {
 				return err
 			}
 
-			blockStart := DSL2BlockStart{}.Decode(firstEntry.Data)
+			prevL2BlockEntryNumber, err := streamServer.GetBookmark(marshalledBookMark)
+			if err != nil {
+				return err
+			}
+
+			prevL2BlockEntry, err := streamServer.GetEntry(prevL2BlockEntryNumber)
+			if err != nil {
+				return err
+			}
+
+			prevL2Block := &datastream.L2Block{}
+			if err := proto.Unmarshal(prevL2BlockEntry.Data, prevL2Block); err != nil {
+				return err
+			}
+
+			previousTimestamp = prevL2Block.Timestamp
 
-			currentBatchNumber = blockStart.BatchNumber
-			previousTimestamp = blockStart.Timestamp
-			lastAddedL2BlockNumber = currentL2BlockNumber
 		case EntryTypeBookMark:
 			log.Info("Latest entry type is BookMark")
-			bookMark := DSBookMark{}
-			bookMark = bookMark.Decode(latestEntry.Data)
-			if bookMark.Type == BookMarkTypeBatch {
+
+			bookMark := &datastream.BookMark{}
+			if err := proto.Unmarshal(latestEntry.Data, bookMark); err != nil {
+				return err
+			}
+
+			if bookMark.Type == datastream.BookmarkType_BOOKMARK_TYPE_BATCH {
 				currentBatchNumber = bookMark.Value
 			} else {
 				log.Fatalf("Latest entry type is an unexpected bookmark type: %v", bookMark.Type)
@@ -424,21 +341,26 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St
 				return err
 			}
 
-			bookMark := DSBookMark{
-				Type:  BookMarkTypeBatch,
+			bookMark := &datastream.BookMark{
+				Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
 				Value: batch.BatchNumber,
 			}
 
+			marshalledBookMark, err := proto.Marshal(bookMark)
+			if err != nil {
+				return err
+			}
+
 			missingBatchBookMark := true
 			if b == 0 {
-				_, err = streamServer.GetBookmark(bookMark.Encode())
+				_, err = streamServer.GetBookmark(marshalledBookMark)
 				if err == nil {
 					missingBatchBookMark = false
 				}
 			}
 
 			if missingBatchBookMark {
-				_, err = streamServer.AddStreamBookmark(bookMark.Encode())
+				_, err = streamServer.AddStreamBookmark(marshalledBookMark)
 				if err != nil {
 					return err
 				}
@@ -448,17 +370,22 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St
 				// Empty batch
 				// Check if there is a GER update
 				if batch.GlobalExitRoot != currentGER && batch.GlobalExitRoot != (common.Hash{}) {
-					updateGer := DSUpdateGER{
+					updateGER := &datastream.UpdateGER{
 						BatchNumber:    batch.BatchNumber,
-						Timestamp:      batch.Timestamp.Unix(),
-						GlobalExitRoot: batch.GlobalExitRoot,
-						Coinbase:       batch.Coinbase,
-						ForkID:         batch.ForkID,
-						ChainID:        uint32(chainID),
-						StateRoot:      batch.StateRoot,
+						Timestamp:      uint64(batch.Timestamp.Unix()),
+						GlobalExitRoot: batch.GlobalExitRoot.Bytes(),
+						Coinbase:       batch.Coinbase.Bytes(),
+						ForkId:         batch.ForkID,
+						ChainId:        chainID,
+						StateRoot:      batch.StateRoot.Bytes(),
+					}
+
+					marshalledUpdateGER, err := proto.Marshal(updateGER)
+					if err != nil {
+						return err
 					}
 
-					_, err = streamServer.AddStreamEntry(EntryTypeUpdateGER, updateGer.Encode())
+					_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER), marshalledUpdateGER)
 					if err != nil {
 						return err
 					}
@@ -517,38 +444,57 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St
 						}
 					}
 
-					blockStart := DSL2BlockStart{
+					streamL2Block := &datastream.L2Block{
+						Number:          l2Block.L2BlockNumber,
 						BatchNumber:     l2Block.BatchNumber,
-						L2BlockNumber:   l2Block.L2BlockNumber,
 						Timestamp:       l2Block.Timestamp,
 						DeltaTimestamp:  uint32(l2Block.Timestamp - previousTimestamp),
-						L1InfoTreeIndex: l1InfoTreeIndex,
-						L1BlockHash:     l1BlockHash,
-						GlobalExitRoot:  l2Block.GlobalExitRoot,
-						Coinbase:        l2Block.Coinbase,
-						ForkID:          l2Block.ForkID,
-						ChainID:         uint32(chainID),
+						MinTimestamp:    uint64(batch.Timestamp.Unix()),
+						L1Blockhash:     l1BlockHash.Bytes(),
+						L1InfotreeIndex: l1InfoTreeIndex,
+						Hash:            l2Block.BlockHash.Bytes(),
+						StateRoot:       l2Block.StateRoot.Bytes(),
+						GlobalExitRoot:  l2Block.GlobalExitRoot.Bytes(),
+						Coinbase:        l2Block.Coinbase.Bytes(),
+					}
+
+					if l2Block.ForkID >= FORKID_ETROG {
+						streamL2Block.Hash = l2Block.StateRoot.Bytes()
+					}
+
+					if l2Block.ForkID == FORKID_ETROG && batch.EtrogTimestamp != nil {
+						streamL2Block.MinTimestamp = uint64(batch.EtrogTimestamp.Unix())
 					}
 
 					previousTimestamp = l2Block.Timestamp
 
-					bookMark := DSBookMark{
-						Type:  BookMarkTypeL2Block,
-						Value: blockStart.L2BlockNumber,
+					bookMark := &datastream.BookMark{
+						Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+						Value: streamL2Block.Number,
+					}
+
+					marshalledBookMark, err := proto.Marshal(bookMark)
+					if err != nil {
+						return err
 					}
 
 					// Check if l2 block was already added
-					_, err = streamServer.GetBookmark(bookMark.Encode())
+					_, err = streamServer.GetBookmark(marshalledBookMark)
 					if err == nil {
 						continue
 					}
 
-					_, err = streamServer.AddStreamBookmark(bookMark.Encode())
+					_, err = streamServer.AddStreamBookmark(marshalledBookMark)
+					if err != nil {
+						return err
+					}
+
+					marshalledL2Block, err := proto.Marshal(streamL2Block)
 					if err != nil {
 						return err
 					}
 
-					_, err = streamServer.AddStreamEntry(EntryTypeL2BlockStart, blockStart.Encode())
+					_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK), marshalledL2Block)
 					if err != nil {
 						return err
 					}
@@ -559,7 +505,7 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St
 						// > 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 {
+							if imStateRoots == nil || (*imStateRoots)[streamL2Block.Number] == nil {
 								position := GetSystemSCPosition(l2Block.L2BlockNumber)
 								imStateRoot, err := stateDB.GetStorageAt(ctx, common.HexToAddress(SystemSC), big.NewInt(0).SetBytes(position), l2Block.StateRoot)
 								if err != nil {
@@ -567,35 +513,53 @@ func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.St
 								}
 								tx.StateRoot = common.BigToHash(imStateRoot)
 							} else {
-								tx.StateRoot = common.BytesToHash((*imStateRoots)[blockStart.L2BlockNumber])
+								tx.StateRoot = common.BytesToHash((*imStateRoots)[streamL2Block.Number])
 							}
 						} else if l2Block.ForkID > FORKID_ETROG {
 							tx.StateRoot = tx.ImStateRoot
 						}
 
-						_, err = streamServer.AddStreamEntry(EntryTypeL2Tx, tx.Encode())
+						transaction := &datastream.Transaction{
+							L2BlockNumber:               tx.L2BlockNumber,
+							IsValid:                     tx.IsValid != 0,
+							Encoded:                     tx.Encoded,
+							EffectiveGasPricePercentage: uint32(tx.EffectiveGasPricePercentage),
+							ImStateRoot:                 tx.StateRoot.Bytes(),
+						}
+
+						marshalledTransaction, err := proto.Marshal(transaction)
 						if err != nil {
 							return err
 						}
-					}
-
-					blockEnd := DSL2BlockEnd{
-						L2BlockNumber: l2Block.L2BlockNumber,
-						BlockHash:     l2Block.BlockHash,
-						StateRoot:     l2Block.StateRoot,
-					}
 
-					if l2Block.ForkID >= FORKID_ETROG {
-						blockEnd.BlockHash = l2Block.StateRoot
+						_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION), marshalledTransaction)
+						if err != nil {
+							return err
+						}
 					}
 
-					_, err = streamServer.AddStreamEntry(EntryTypeL2BlockEnd, blockEnd.Encode())
-					if err != nil {
-						return err
-					}
 					currentGER = l2Block.GlobalExitRoot
 				}
 			}
+
+			batch := &datastream.Batch{
+				Number:        batch.BatchNumber,
+				LocalExitRoot: batch.LocalExitRoot.Bytes(),
+				StateRoot:     batch.StateRoot.Bytes(),
+				ForkId:        batch.ForkID,
+				ChainId:       chainID,
+			}
+
+			marshalledBatch, err := proto.Marshal(batch)
+			if err != nil {
+				return err
+			}
+
+			_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH), marshalledBatch)
+			if err != nil {
+				return err
+			}
+
 			// Commit at the end of each batch group
 			err = streamServer.CommitAtomicOp()
 			if err != nil {
diff --git a/state/datastream/datastream.pb.go b/state/datastream/datastream.pb.go
new file mode 100644
index 0000000000..1f0ede74fc
--- /dev/null
+++ b/state/datastream/datastream.pb.go
@@ -0,0 +1,773 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.32.0
+// 	protoc        v4.25.3
+// source: datastream.proto
+
+package datastream
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type BookmarkType int32
+
+const (
+	BookmarkType_BOOKMARK_TYPE_UNSPECIFIED BookmarkType = 0
+	BookmarkType_BOOKMARK_TYPE_BATCH       BookmarkType = 1
+	BookmarkType_BOOKMARK_TYPE_L2_BLOCK    BookmarkType = 2
+)
+
+// Enum value maps for BookmarkType.
+var (
+	BookmarkType_name = map[int32]string{
+		0: "BOOKMARK_TYPE_UNSPECIFIED",
+		1: "BOOKMARK_TYPE_BATCH",
+		2: "BOOKMARK_TYPE_L2_BLOCK",
+	}
+	BookmarkType_value = map[string]int32{
+		"BOOKMARK_TYPE_UNSPECIFIED": 0,
+		"BOOKMARK_TYPE_BATCH":       1,
+		"BOOKMARK_TYPE_L2_BLOCK":    2,
+	}
+)
+
+func (x BookmarkType) Enum() *BookmarkType {
+	p := new(BookmarkType)
+	*p = x
+	return p
+}
+
+func (x BookmarkType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BookmarkType) Descriptor() protoreflect.EnumDescriptor {
+	return file_datastream_proto_enumTypes[0].Descriptor()
+}
+
+func (BookmarkType) Type() protoreflect.EnumType {
+	return &file_datastream_proto_enumTypes[0]
+}
+
+func (x BookmarkType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use BookmarkType.Descriptor instead.
+func (BookmarkType) EnumDescriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{0}
+}
+
+type EntryType int32
+
+const (
+	EntryType_ENTRY_TYPE_UNSPECIFIED EntryType = 0
+	EntryType_ENTRY_TYPE_BATCH       EntryType = 1
+	EntryType_ENTRY_TYPE_L2_BLOCK    EntryType = 2
+	EntryType_ENTRY_TYPE_TRANSACTION EntryType = 3
+	EntryType_ENTRY_TYPE_UPDATE_GER  EntryType = 4
+)
+
+// Enum value maps for EntryType.
+var (
+	EntryType_name = map[int32]string{
+		0: "ENTRY_TYPE_UNSPECIFIED",
+		1: "ENTRY_TYPE_BATCH",
+		2: "ENTRY_TYPE_L2_BLOCK",
+		3: "ENTRY_TYPE_TRANSACTION",
+		4: "ENTRY_TYPE_UPDATE_GER",
+	}
+	EntryType_value = map[string]int32{
+		"ENTRY_TYPE_UNSPECIFIED": 0,
+		"ENTRY_TYPE_BATCH":       1,
+		"ENTRY_TYPE_L2_BLOCK":    2,
+		"ENTRY_TYPE_TRANSACTION": 3,
+		"ENTRY_TYPE_UPDATE_GER":  4,
+	}
+)
+
+func (x EntryType) Enum() *EntryType {
+	p := new(EntryType)
+	*p = x
+	return p
+}
+
+func (x EntryType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (EntryType) Descriptor() protoreflect.EnumDescriptor {
+	return file_datastream_proto_enumTypes[1].Descriptor()
+}
+
+func (EntryType) Type() protoreflect.EnumType {
+	return &file_datastream_proto_enumTypes[1]
+}
+
+func (x EntryType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use EntryType.Descriptor instead.
+func (EntryType) EnumDescriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{1}
+}
+
+type Batch struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number        uint64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+	LocalExitRoot []byte `protobuf:"bytes,2,opt,name=local_exit_root,json=localExitRoot,proto3" json:"local_exit_root,omitempty"`
+	StateRoot     []byte `protobuf:"bytes,3,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
+	ForkId        uint64 `protobuf:"varint,4,opt,name=fork_id,json=forkId,proto3" json:"fork_id,omitempty"`
+	ChainId       uint64 `protobuf:"varint,5,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
+}
+
+func (x *Batch) Reset() {
+	*x = Batch{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_datastream_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Batch) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Batch) ProtoMessage() {}
+
+func (x *Batch) ProtoReflect() protoreflect.Message {
+	mi := &file_datastream_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Batch.ProtoReflect.Descriptor instead.
+func (*Batch) Descriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Batch) GetNumber() uint64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+func (x *Batch) GetLocalExitRoot() []byte {
+	if x != nil {
+		return x.LocalExitRoot
+	}
+	return nil
+}
+
+func (x *Batch) GetStateRoot() []byte {
+	if x != nil {
+		return x.StateRoot
+	}
+	return nil
+}
+
+func (x *Batch) GetForkId() uint64 {
+	if x != nil {
+		return x.ForkId
+	}
+	return 0
+}
+
+func (x *Batch) GetChainId() uint64 {
+	if x != nil {
+		return x.ChainId
+	}
+	return 0
+}
+
+type L2Block struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number          uint64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+	BatchNumber     uint64 `protobuf:"varint,2,opt,name=batch_number,json=batchNumber,proto3" json:"batch_number,omitempty"`
+	Timestamp       uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	DeltaTimestamp  uint32 `protobuf:"varint,4,opt,name=delta_timestamp,json=deltaTimestamp,proto3" json:"delta_timestamp,omitempty"`
+	MinTimestamp    uint64 `protobuf:"varint,5,opt,name=min_timestamp,json=minTimestamp,proto3" json:"min_timestamp,omitempty"`
+	L1Blockhash     []byte `protobuf:"bytes,6,opt,name=l1_blockhash,json=l1Blockhash,proto3" json:"l1_blockhash,omitempty"`
+	L1InfotreeIndex uint32 `protobuf:"varint,7,opt,name=l1_infotree_index,json=l1InfotreeIndex,proto3" json:"l1_infotree_index,omitempty"`
+	Hash            []byte `protobuf:"bytes,8,opt,name=hash,proto3" json:"hash,omitempty"`
+	StateRoot       []byte `protobuf:"bytes,9,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
+	GlobalExitRoot  []byte `protobuf:"bytes,10,opt,name=global_exit_root,json=globalExitRoot,proto3" json:"global_exit_root,omitempty"`
+	Coinbase        []byte `protobuf:"bytes,11,opt,name=coinbase,proto3" json:"coinbase,omitempty"`
+}
+
+func (x *L2Block) Reset() {
+	*x = L2Block{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_datastream_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *L2Block) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*L2Block) ProtoMessage() {}
+
+func (x *L2Block) ProtoReflect() protoreflect.Message {
+	mi := &file_datastream_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use L2Block.ProtoReflect.Descriptor instead.
+func (*L2Block) Descriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *L2Block) GetNumber() uint64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+func (x *L2Block) GetBatchNumber() uint64 {
+	if x != nil {
+		return x.BatchNumber
+	}
+	return 0
+}
+
+func (x *L2Block) GetTimestamp() uint64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *L2Block) GetDeltaTimestamp() uint32 {
+	if x != nil {
+		return x.DeltaTimestamp
+	}
+	return 0
+}
+
+func (x *L2Block) GetMinTimestamp() uint64 {
+	if x != nil {
+		return x.MinTimestamp
+	}
+	return 0
+}
+
+func (x *L2Block) GetL1Blockhash() []byte {
+	if x != nil {
+		return x.L1Blockhash
+	}
+	return nil
+}
+
+func (x *L2Block) GetL1InfotreeIndex() uint32 {
+	if x != nil {
+		return x.L1InfotreeIndex
+	}
+	return 0
+}
+
+func (x *L2Block) GetHash() []byte {
+	if x != nil {
+		return x.Hash
+	}
+	return nil
+}
+
+func (x *L2Block) GetStateRoot() []byte {
+	if x != nil {
+		return x.StateRoot
+	}
+	return nil
+}
+
+func (x *L2Block) GetGlobalExitRoot() []byte {
+	if x != nil {
+		return x.GlobalExitRoot
+	}
+	return nil
+}
+
+func (x *L2Block) GetCoinbase() []byte {
+	if x != nil {
+		return x.Coinbase
+	}
+	return nil
+}
+
+type Transaction struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	L2BlockNumber               uint64 `protobuf:"varint,1,opt,name=l2block_number,json=l2blockNumber,proto3" json:"l2block_number,omitempty"`
+	IsValid                     bool   `protobuf:"varint,2,opt,name=is_valid,json=isValid,proto3" json:"is_valid,omitempty"`
+	Encoded                     []byte `protobuf:"bytes,3,opt,name=encoded,proto3" json:"encoded,omitempty"`
+	EffectiveGasPricePercentage uint32 `protobuf:"varint,4,opt,name=effective_gas_price_percentage,json=effectiveGasPricePercentage,proto3" json:"effective_gas_price_percentage,omitempty"`
+	ImStateRoot                 []byte `protobuf:"bytes,5,opt,name=im_state_root,json=imStateRoot,proto3" json:"im_state_root,omitempty"`
+}
+
+func (x *Transaction) Reset() {
+	*x = Transaction{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_datastream_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Transaction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Transaction) ProtoMessage() {}
+
+func (x *Transaction) ProtoReflect() protoreflect.Message {
+	mi := &file_datastream_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Transaction.ProtoReflect.Descriptor instead.
+func (*Transaction) Descriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *Transaction) GetL2BlockNumber() uint64 {
+	if x != nil {
+		return x.L2BlockNumber
+	}
+	return 0
+}
+
+func (x *Transaction) GetIsValid() bool {
+	if x != nil {
+		return x.IsValid
+	}
+	return false
+}
+
+func (x *Transaction) GetEncoded() []byte {
+	if x != nil {
+		return x.Encoded
+	}
+	return nil
+}
+
+func (x *Transaction) GetEffectiveGasPricePercentage() uint32 {
+	if x != nil {
+		return x.EffectiveGasPricePercentage
+	}
+	return 0
+}
+
+func (x *Transaction) GetImStateRoot() []byte {
+	if x != nil {
+		return x.ImStateRoot
+	}
+	return nil
+}
+
+type UpdateGER struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	BatchNumber    uint64 `protobuf:"varint,1,opt,name=batch_number,json=batchNumber,proto3" json:"batch_number,omitempty"`
+	Timestamp      uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	GlobalExitRoot []byte `protobuf:"bytes,3,opt,name=global_exit_root,json=globalExitRoot,proto3" json:"global_exit_root,omitempty"`
+	Coinbase       []byte `protobuf:"bytes,4,opt,name=coinbase,proto3" json:"coinbase,omitempty"`
+	ForkId         uint64 `protobuf:"varint,5,opt,name=fork_id,json=forkId,proto3" json:"fork_id,omitempty"`
+	ChainId        uint64 `protobuf:"varint,6,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
+	StateRoot      []byte `protobuf:"bytes,7,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
+}
+
+func (x *UpdateGER) Reset() {
+	*x = UpdateGER{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_datastream_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UpdateGER) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateGER) ProtoMessage() {}
+
+func (x *UpdateGER) ProtoReflect() protoreflect.Message {
+	mi := &file_datastream_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateGER.ProtoReflect.Descriptor instead.
+func (*UpdateGER) Descriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *UpdateGER) GetBatchNumber() uint64 {
+	if x != nil {
+		return x.BatchNumber
+	}
+	return 0
+}
+
+func (x *UpdateGER) GetTimestamp() uint64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *UpdateGER) GetGlobalExitRoot() []byte {
+	if x != nil {
+		return x.GlobalExitRoot
+	}
+	return nil
+}
+
+func (x *UpdateGER) GetCoinbase() []byte {
+	if x != nil {
+		return x.Coinbase
+	}
+	return nil
+}
+
+func (x *UpdateGER) GetForkId() uint64 {
+	if x != nil {
+		return x.ForkId
+	}
+	return 0
+}
+
+func (x *UpdateGER) GetChainId() uint64 {
+	if x != nil {
+		return x.ChainId
+	}
+	return 0
+}
+
+func (x *UpdateGER) GetStateRoot() []byte {
+	if x != nil {
+		return x.StateRoot
+	}
+	return nil
+}
+
+type BookMark struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Type  BookmarkType `protobuf:"varint,1,opt,name=type,proto3,enum=datastream.v1.BookmarkType" json:"type,omitempty"`
+	Value uint64       `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *BookMark) Reset() {
+	*x = BookMark{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_datastream_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *BookMark) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BookMark) ProtoMessage() {}
+
+func (x *BookMark) ProtoReflect() protoreflect.Message {
+	mi := &file_datastream_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BookMark.ProtoReflect.Descriptor instead.
+func (*BookMark) Descriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *BookMark) GetType() BookmarkType {
+	if x != nil {
+		return x.Type
+	}
+	return BookmarkType_BOOKMARK_TYPE_UNSPECIFIED
+}
+
+func (x *BookMark) GetValue() uint64 {
+	if x != nil {
+		return x.Value
+	}
+	return 0
+}
+
+var File_datastream_proto protoreflect.FileDescriptor
+
+var file_datastream_proto_rawDesc = []byte{
+	0x0a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x12, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76,
+	0x31, 0x22, 0x9a, 0x01, 0x0a, 0x05, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6e,
+	0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d,
+	0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69,
+	0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, 0x6f,
+	0x63, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
+	0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6f,
+	0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x66, 0x6f, 0x72,
+	0x6b, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18,
+	0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0xf8,
+	0x02, 0x0a, 0x07, 0x4c, 0x32, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75,
+	0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62,
+	0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x75, 0x6d, 0x62,
+	0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4e,
+	0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+	0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
+	0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x74, 0x69, 0x6d,
+	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x64, 0x65,
+	0x6c, 0x74, 0x61, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x0d,
+	0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+	0x70, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x31, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x68, 0x61, 0x73,
+	0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6c, 0x31, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
+	0x68, 0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x31, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x74,
+	0x72, 0x65, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x0f, 0x6c, 0x31, 0x49, 0x6e, 0x66, 0x6f, 0x74, 0x72, 0x65, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78,
+	0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
+	0x68, 0x61, 0x73, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f,
+	0x6f, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52,
+	0x6f, 0x6f, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78,
+	0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67,
+	0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a,
+	0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0xd2, 0x01, 0x0a, 0x0b, 0x54, 0x72,
+	0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x32, 0x62,
+	0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x0d, 0x6c, 0x32, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
+	0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65,
+	0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e,
+	0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69,
+	0x76, 0x65, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72,
+	0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1b, 0x65,
+	0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65,
+	0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6d,
+	0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x0b, 0x69, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0xe5,
+	0x01, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x45, 0x52, 0x12, 0x21, 0x0a, 0x0c,
+	0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12,
+	0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a,
+	0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f,
+	0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x45,
+	0x78, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62,
+	0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62,
+	0x61, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x05,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08,
+	0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07,
+	0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65,
+	0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61,
+	0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x51, 0x0a, 0x08, 0x42, 0x6f, 0x6f, 0x6b, 0x4d, 0x61,
+	0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x1b, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31,
+	0x2e, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
+	0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x62, 0x0a, 0x0c, 0x42, 0x6f, 0x6f,
+	0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x4f, 0x4f,
+	0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
+	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x42, 0x4f, 0x4f, 0x4b,
+	0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x10,
+	0x01, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59,
+	0x50, 0x45, 0x5f, 0x4c, 0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x2a, 0x8d, 0x01,
+	0x0a, 0x09, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x45,
+	0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
+	0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x4e, 0x54, 0x52, 0x59,
+	0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x10, 0x01, 0x12, 0x17, 0x0a,
+	0x13, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x32, 0x5f, 0x42,
+	0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f,
+	0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e,
+	0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45,
+	0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x47, 0x45, 0x52, 0x10, 0x04, 0x42, 0x38, 0x5a,
+	0x36, 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, 0x64, 0x61, 0x74,
+	0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_datastream_proto_rawDescOnce sync.Once
+	file_datastream_proto_rawDescData = file_datastream_proto_rawDesc
+)
+
+func file_datastream_proto_rawDescGZIP() []byte {
+	file_datastream_proto_rawDescOnce.Do(func() {
+		file_datastream_proto_rawDescData = protoimpl.X.CompressGZIP(file_datastream_proto_rawDescData)
+	})
+	return file_datastream_proto_rawDescData
+}
+
+var file_datastream_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_datastream_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_datastream_proto_goTypes = []interface{}{
+	(BookmarkType)(0),   // 0: datastream.v1.BookmarkType
+	(EntryType)(0),      // 1: datastream.v1.EntryType
+	(*Batch)(nil),       // 2: datastream.v1.Batch
+	(*L2Block)(nil),     // 3: datastream.v1.L2Block
+	(*Transaction)(nil), // 4: datastream.v1.Transaction
+	(*UpdateGER)(nil),   // 5: datastream.v1.UpdateGER
+	(*BookMark)(nil),    // 6: datastream.v1.BookMark
+}
+var file_datastream_proto_depIdxs = []int32{
+	0, // 0: datastream.v1.BookMark.type:type_name -> datastream.v1.BookmarkType
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_datastream_proto_init() }
+func file_datastream_proto_init() {
+	if File_datastream_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_datastream_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Batch); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_datastream_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*L2Block); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_datastream_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Transaction); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_datastream_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpdateGER); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_datastream_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*BookMark); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_datastream_proto_rawDesc,
+			NumEnums:      2,
+			NumMessages:   5,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_datastream_proto_goTypes,
+		DependencyIndexes: file_datastream_proto_depIdxs,
+		EnumInfos:         file_datastream_proto_enumTypes,
+		MessageInfos:      file_datastream_proto_msgTypes,
+	}.Build()
+	File_datastream_proto = out.File
+	file_datastream_proto_rawDesc = nil
+	file_datastream_proto_goTypes = nil
+	file_datastream_proto_depIdxs = nil
+}
diff --git a/state/pgstatestorage/datastream.go b/state/pgstatestorage/datastream.go
index 4b15000aeb..31c9814c0a 100644
--- a/state/pgstatestorage/datastream.go
+++ b/state/pgstatestorage/datastream.go
@@ -78,7 +78,7 @@ func scanL2Block(row pgx.Row) (*state.DSL2Block, error) {
 	}
 	l2Block.GlobalExitRoot = common.HexToHash(gerStr)
 	l2Block.Coinbase = common.HexToAddress(coinbaseStr)
-	l2Block.Timestamp = timestamp.Unix()
+	l2Block.Timestamp = uint64(timestamp.Unix())
 	l2Block.BlockHash = common.HexToHash(blockHashStr)
 	l2Block.StateRoot = common.HexToHash(stateRootStr)
 
@@ -151,9 +151,13 @@ func scanDSL2Transaction(row pgx.Row) (*state.DSL2Transaction, error) {
 // GetDSBatches returns the DS batches
 func (p *PostgresStorage) GetDSBatches(ctx context.Context, firstBatchNumber, lastBatchNumber uint64, readWIPBatch bool, dbTx pgx.Tx) ([]*state.DSBatch, error) {
 	var getBatchByNumberSQL = `
-		SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data, b.forced_batch_num, b.wip, f.fork_id
-		  FROM state.batch b, state.fork_id f
-		 WHERE b.batch_num >= $1 AND b.batch_num <= $2 AND batch_num between f.from_batch_num AND f.to_batch_num`
+		SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data, b.forced_batch_num, b.wip, f.fork_id, vb.timestamp_batch_etrog
+		 FROM state.batch b
+		 LEFT JOIN 
+    		state.fork_id f ON b.batch_num BETWEEN f.from_batch_num AND f.to_batch_num
+		 LEFT JOIN 
+    		state.virtual_batch vb ON b.batch_num = vb.batch_num
+		 WHERE b.batch_num >= $1 AND b.batch_num <= $2`
 
 	if !readWIPBatch {
 		getBatchByNumberSQL += " AND b.wip is false"
@@ -205,6 +209,7 @@ func scanDSBatch(row pgx.Row) (state.DSBatch, error) {
 		&batch.ForcedBatchNum,
 		&batch.WIP,
 		&batch.ForkID,
+		&batch.EtrogTimestamp,
 	)
 	if err != nil {
 		return batch, err
diff --git a/state/test/datastream_test.go b/state/test/datastream_test.go
deleted file mode 100644
index 8860cf9740..0000000000
--- a/state/test/datastream_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package test
-
-import (
-	"fmt"
-	"testing"
-	"time"
-
-	"github.com/0xPolygonHermez/zkevm-node/state"
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestL2BlockStartEncode(t *testing.T) {
-	l2BlockStart := state.DSL2BlockStart{
-		BatchNumber:     1,
-		L2BlockNumber:   2,
-		Timestamp:       3,
-		DeltaTimestamp:  4,
-		L1InfoTreeIndex: 5,
-		L1BlockHash:     common.HexToHash("0x06"),
-		GlobalExitRoot:  common.HexToHash("0x07"),
-		Coinbase:        common.HexToAddress("0x08"),
-		ForkID:          9,
-		ChainID:         10,
-	}
-
-	encoded := l2BlockStart.Encode()
-	expected := []byte{
-		0, 0, 0, 0, 0, 0, 0, 1,
-		0, 0, 0, 0, 0, 0, 0, 2,
-		0, 0, 0, 0, 0, 0, 0, 3,
-		0, 0, 0, 4,
-		0, 0, 0, 5,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,
-		0, 9,
-		0, 0, 0, 10}
-
-	assert.Equal(t, expected, encoded)
-}
-
-func TestL2TransactionEncode(t *testing.T) {
-	l2Transaction := state.DSL2Transaction{
-		EffectiveGasPricePercentage: 128,                          // 1 byte
-		IsValid:                     1,                            // 1 byte
-		StateRoot:                   common.HexToHash("0x010203"), // 32 bytes
-		EncodedLength:               5,                            // 4 bytes
-		Encoded:                     []byte{1, 2, 3, 4, 5},        // 5 bytes
-	}
-
-	encoded := l2Transaction.Encode()
-	expected := []byte{128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 5, 1, 2, 3, 4, 5}
-	assert.Equal(t, expected, encoded)
-}
-
-func TestL2BlockEndEncode(t *testing.T) {
-	l2BlockEnd := state.DSL2BlockEnd{
-		L2BlockNumber: 1,                        // 8 bytes
-		BlockHash:     common.HexToHash("0x02"), // 32 bytes
-		StateRoot:     common.HexToHash("0x03"), // 32 bytes
-	}
-
-	encoded := l2BlockEnd.Encode()
-	expected := []byte{0, 0, 0, 0, 0, 0, 0, 1,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
-		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}
-
-	assert.Equal(t, expected, encoded)
-}
-
-func TestCalculateSCPosition(t *testing.T) {
-	a := time.Now()
-	blockNumber := uint64(2934867)
-	expected := common.HexToHash("0xaa93c484856be45716623765b429a967296594ca362e61e91d671fb422e0f744")
-	position := state.GetSystemSCPosition(blockNumber)
-	assert.Equal(t, expected, common.BytesToHash(position))
-	b := time.Now()
-
-	c := b.Sub(a)
-	fmt.Println(c)
-}
diff --git a/test/docker-compose.yml b/test/docker-compose.yml
index 08dbc93431..d24d4c9d1f 100644
--- a/test/docker-compose.yml
+++ b/test/docker-compose.yml
@@ -514,9 +514,12 @@ services:
   zkevm-prover:
     container_name: zkevm-prover
     image: hermeznetwork/zkevm-prover:v6.0.0
+    platform: linux/amd64
     ports:
       - 50061:50061 # MT
       - 50071:50071 # Executor
+    environment:
+      - EXPERIMENTAL_DOCKER_DESKTOP_FORCE_QEMU=1
     volumes:
       - ./config/test.prover.config.json:/usr/src/app/config.json
     command: >
@@ -602,7 +605,10 @@ services:
 
   zkevm-permissionless-prover:
     container_name: zkevm-permissionless-prover
+    platform: linux/amd64
     image: hermeznetwork/zkevm-prover:v6.0.0
+    environment:
+      - EXPERIMENTAL_DOCKER_DESKTOP_FORCE_QEMU=1
     ports:
       # - 50058:50058 # Prover
       - 50059:50052 # Mock prover
diff --git a/tools/datastreamer/Makefile b/tools/datastreamer/Makefile
index 5698417c34..e79b0cb1a8 100644
--- a/tools/datastreamer/Makefile
+++ b/tools/datastreamer/Makefile
@@ -6,12 +6,14 @@ check-go:
 
 # Targets that require the checks
 generate-file: check-go
-reprocess: check-go
 decode-entry-offline: check-go
 decode-l2block-offline: check-go
 decode-entry: check-go
 decode-l2block: check-go
+decode-batch: check-go
+decode-batch-offline: check-go
 truncate: check-go
+dump-batch: check-go
 
 arguments := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
 
@@ -27,6 +29,10 @@ decode-entry: ## Runs the tool to decode a given entry number
 decode-l2block: ## Runs the tool to decode a given L2 block
 	go run main.go decode-l2block -cfg config/tool.config.toml -l2block $(arguments)
 
+.PHONY: decode-batch
+decode-batch: ## Runs the tool to decode a given batch
+	go run main.go decode-batch -cfg config/tool.config.toml -batch $(arguments)
+
 .PHONY: decode-entry-offline
 decode-entry-offline: ## Runs the offline tool to decode a given entry number
 	go run main.go decode-entry-offline -cfg config/tool.config.toml -entry $(arguments)
@@ -35,13 +41,21 @@ decode-entry-offline: ## Runs the offline tool to decode a given entry number
 decode-l2block-offline: ## Runs the offline tool to decode a given L2 block
 	go run main.go decode-l2block-offline -cfg config/tool.config.toml -l2block $(arguments)
 
+.PHONY: decode-batch-offline
+decode-batch-offline: ## Runs the offline tool to decode a given batch
+	go run main.go decode-batch-offline -cfg config/tool.config.toml -batch $(arguments)
+
 .PHONY: truncate
 truncate: ## Runs the offline tool to truncate the stream file
 	go run main.go truncate -cfg config/tool.config.toml -entry $(arguments)
 
-# .PHONY: reprocess
-reprocess: ## Runs the tool to reprocess the information in the stream since a given l2 block
-	go run main.go reprocess -cfg config/tool.config.toml -genesis ../test/config/test.genesis.config.json -l2block $(arguments)
+.PHONY: dump-batch
+dump-batch: ## Runs the tool to dump a given batch to file
+	go run main.go dump-batch -cfg config/tool.config.toml -d -batch $(arguments)
+
+.PHONY: dump-batch-offline
+dump-batch-offline: ## Runs the tool to dump a given batch to file offline
+	go run main.go dump-batch-offline -cfg config/tool.config.toml -d -batch $(arguments)
 
 ## Help display.
 ## Pulls comments from beside commands and prints a nicely formatted
diff --git a/tools/datastreamer/config/tool.config.toml b/tools/datastreamer/config/tool.config.toml
index c497f3362f..0671438dcb 100644
--- a/tools/datastreamer/config/tool.config.toml
+++ b/tools/datastreamer/config/tool.config.toml
@@ -5,7 +5,7 @@ StreamType = 1
 [Offline]
 Port = 6901
 Filename = "datastream.bin"
-Version = 1
+Version = 3
 ChainID = 1440
 UpgradeEtrogBatchNumber = 0
 
@@ -18,10 +18,6 @@ Port = "5432"
 EnableLog = false
 MaxConns = 200
 
-[Executor]
-URI = "zkevm-prover:50071"
-MaxGRPCMessageSize = 100000000
-
 [MerkleTree]
 URI = "zkevm-prover:50061"
 MaxThreads = 20
diff --git a/tools/datastreamer/main.go b/tools/datastreamer/main.go
index 975e4c7ecd..bb84aeebf3 100644
--- a/tools/datastreamer/main.go
+++ b/tools/datastreamer/main.go
@@ -2,7 +2,6 @@ package main
 
 import (
 	"context"
-	"encoding/binary"
 	"encoding/json"
 	"fmt"
 	"math/big"
@@ -12,19 +11,16 @@ import (
 
 	"github.com/0xPolygonHermez/zkevm-data-streamer/datastreamer"
 	"github.com/0xPolygonHermez/zkevm-data-streamer/log"
-	nodeConfig "github.com/0xPolygonHermez/zkevm-node/config"
 	"github.com/0xPolygonHermez/zkevm-node/db"
-	"github.com/0xPolygonHermez/zkevm-node/encoding"
-	"github.com/0xPolygonHermez/zkevm-node/hex"
 	"github.com/0xPolygonHermez/zkevm-node/merkletree"
 	"github.com/0xPolygonHermez/zkevm-node/state"
+	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
 	"github.com/0xPolygonHermez/zkevm-node/state/pgstatestorage"
-	"github.com/0xPolygonHermez/zkevm-node/state/runtime/executor"
 	"github.com/0xPolygonHermez/zkevm-node/tools/datastreamer/config"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/fatih/color"
-	"github.com/google/uuid"
 	"github.com/urfave/cli/v2"
+	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -41,14 +37,6 @@ var (
 		Required:    true,
 	}
 
-	genesisFileFlag = cli.StringFlag{
-		Name:        config.FlagGenesis,
-		Aliases:     []string{"g"},
-		Usage:       "Genesis `FILE`",
-		DefaultText: "./config/genesis.json",
-		Required:    true,
-	}
-
 	entryFlag = cli.Uint64Flag{
 		Name:     "entry",
 		Aliases:  []string{"e"},
@@ -63,10 +51,17 @@ var (
 		Required: true,
 	}
 
-	updateFileFlag = cli.BoolFlag{
-		Name:     "update",
-		Aliases:  []string{"u"},
-		Usage:    "Update `FILE`",
+	batchFlag = cli.Uint64Flag{
+		Name:     "batch",
+		Aliases:  []string{"bn"},
+		Usage:    "Batch `NUMBER`",
+		Required: true,
+	}
+
+	dumpFlag = cli.BoolFlag{
+		Name:     "dump",
+		Aliases:  []string{"d"},
+		Usage:    "Dump batch to file",
 		Required: false,
 	}
 )
@@ -86,18 +81,6 @@ func main() {
 				&configFileFlag,
 			},
 		},
-		{
-			Name:    "reprocess",
-			Aliases: []string{},
-			Usage:   "Reprocess l2block since a given l2block number",
-			Action:  reprocess,
-			Flags: []cli.Flag{
-				&configFileFlag,
-				&genesisFileFlag,
-				&l2blockFlag,
-				&updateFileFlag,
-			},
-		},
 		{
 			Name:    "decode-entry-offline",
 			Aliases: []string{},
@@ -118,6 +101,16 @@ func main() {
 				&l2blockFlag,
 			},
 		},
+		{
+			Name:    "decode-batch-offline",
+			Aliases: []string{},
+			Usage:   "Decodes a batch offline",
+			Action:  decodeBatchOffline,
+			Flags: []cli.Flag{
+				&configFileFlag,
+				&batchFlag,
+			},
+		},
 		{
 			Name:    "decode-entry",
 			Aliases: []string{},
@@ -138,6 +131,16 @@ func main() {
 				&l2blockFlag,
 			},
 		},
+		{
+			Name:    "decode-batch",
+			Aliases: []string{},
+			Usage:   "Decodes a batch",
+			Action:  decodeBatch,
+			Flags: []cli.Flag{
+				&configFileFlag,
+				&batchFlag,
+			},
+		},
 		{
 			Name:    "truncate",
 			Aliases: []string{},
@@ -148,6 +151,28 @@ func main() {
 				&entryFlag,
 			},
 		},
+		{
+			Name:    "dump-batch",
+			Aliases: []string{},
+			Usage:   "Dumps a batch to file",
+			Action:  decodeBatch,
+			Flags: []cli.Flag{
+				&configFileFlag,
+				&batchFlag,
+				&dumpFlag,
+			},
+		},
+		{
+			Name:    "dump-batch-offline",
+			Aliases: []string{},
+			Usage:   "Dumps a batch to file offline",
+			Action:  decodeBatchOffline,
+			Flags: []cli.Flag{
+				&configFileFlag,
+				&batchFlag,
+				&dumpFlag,
+			},
+		},
 	}
 
 	err := app.Run(os.Args)
@@ -272,7 +297,7 @@ func generate(cliCtx *cli.Context) error {
 		}
 	}
 
-	err = state.GenerateDataStreamerFile(cliCtx.Context, streamServer, stateDB, false, &imStateRoots, c.Offline.ChainID, c.Offline.UpgradeEtrogBatchNumber) // nolint:gomnd
+	err = state.GenerateDataStreamFile(cliCtx.Context, streamServer, stateDB, false, &imStateRoots, c.Offline.ChainID, c.Offline.UpgradeEtrogBatchNumber)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
@@ -299,13 +324,18 @@ func getImStateRoots(ctx context.Context, start, end uint64, isStateRoots *map[u
 			log.Errorf("Error: %v\n", err)
 			os.Exit(1)
 		}
+
+		if common.BytesToHash(imStateRoot.Bytes()) == state.ZeroHash && x != 0 {
+			break
+		}
+
 		imStateRootMux.Lock()
 		(*isStateRoots)[x] = imStateRoot.Bytes()
 		imStateRootMux.Unlock()
 	}
 }
 
-func reprocess(cliCtx *cli.Context) error {
+func decodeEntry(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -314,230 +344,90 @@ func reprocess(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	ctx := cliCtx.Context
-
-	genesisFileAsStr, err := nodeConfig.LoadGenesisFileAsString(cliCtx.String(config.FlagGenesis))
+	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
 	if err != nil {
-		fmt.Printf("failed to load genesis file. Error: %v", err)
+		log.Error(err)
 		os.Exit(1)
 	}
 
-	networkConfig, err := nodeConfig.LoadGenesisFromJSONString(genesisFileAsStr)
+	err = client.Start()
 	if err != nil {
-		fmt.Printf("failed to load genesis configuration from file. Error: %v", err)
+		log.Error(err)
 		os.Exit(1)
 	}
 
-	currentL2BlockNumber := cliCtx.Uint64("l2block")
-	var stateRoot []byte
-
-	streamServer, err := initializeStreamServer(c)
+	entry, err := client.ExecCommandGetEntry(cliCtx.Uint64("entry"))
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	if currentL2BlockNumber == 0 {
-		printColored(color.FgHiYellow, "\n\nSetting Genesis block\n\n")
-
-		mtDBServerConfig := merkletree.Config{URI: c.MerkleTree.URI}
-		var mtDBCancel context.CancelFunc
-		mtDBServiceClient, mtDBClientConn, mtDBCancel := merkletree.NewMTDBServiceClient(ctx, mtDBServerConfig)
-		defer func() {
-			mtDBCancel()
-			mtDBClientConn.Close()
-		}()
-
-		stateTree := merkletree.NewStateTree(mtDBServiceClient)
-
-		stateRoot, err = setGenesis(ctx, stateTree, networkConfig.Genesis)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
-		// Get Genesis block from the file and validate the state root
-		bookMark := state.DSBookMark{
-			Type:  state.BookMarkTypeL2Block,
-			Value: 0,
-		}
-
-		firstEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-		printEntry(firstEntry)
-
-		secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-		printEntry(secondEntry)
+	printEntry(entry)
+	return nil
+}
 
-		if common.Bytes2Hex(stateRoot) != common.Bytes2Hex(secondEntry.Data[40:72]) {
-			printColored(color.FgRed, "\nError: Genesis state root does not match\n\n")
-			os.Exit(1)
-		} else {
-			printColored(color.FgGreen, "\nGenesis state root matches\n\n")
-		}
-		currentL2BlockNumber++
+func decodeL2Block(cliCtx *cli.Context) error {
+	c, err := config.Load(cliCtx)
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
 	}
 
-	// Connect to the executor
-	executorClient, executorClientConn, executorCancel := executor.NewExecutorClient(ctx, c.Executor)
-	defer func() {
-		executorCancel()
-		executorClientConn.Close()
-	}()
+	log.Init(c.Log)
 
-	bookMark := state.DSBookMark{
-		Type:  state.BookMarkTypeL2Block,
-		Value: currentL2BlockNumber,
+	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
 	}
 
-	startEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
+	err = client.Start()
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	var previousStateRoot = stateRoot
-	var maxEntry = streamServer.GetHeader().TotalEntries
-
-	for x := startEntry.Number; x < maxEntry; x++ {
-		printColored(color.FgHiYellow, fmt.Sprintf("\nProcessing entity: %d\n", x))
-
-		currentEntry, err := streamServer.GetEntry(x)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
-		var processBatchRequest *executor.ProcessBatchRequest
-		var expectedNewRoot []byte
-		var entryToUpdate *datastreamer.FileEntry
-
-		switch currentEntry.Type {
-		case state.EntryTypeBookMark:
-			printEntry(currentEntry)
-			entryToUpdate = nil
-			continue
-		case state.EntryTypeUpdateGER:
-			printEntry(currentEntry)
-			processBatchRequest = &executor.ProcessBatchRequest{
-				OldBatchNum:      binary.BigEndian.Uint64(currentEntry.Data[0:8]) - 1,
-				Coinbase:         common.Bytes2Hex(currentEntry.Data[48:68]),
-				BatchL2Data:      nil,
-				OldStateRoot:     previousStateRoot,
-				GlobalExitRoot:   currentEntry.Data[16:48],
-				OldAccInputHash:  []byte{},
-				EthTimestamp:     binary.BigEndian.Uint64(currentEntry.Data[8:16]),
-				UpdateMerkleTree: uint32(1),
-				ChainId:          c.Offline.ChainID,
-				ForkId:           uint64(binary.BigEndian.Uint16(currentEntry.Data[68:70])),
-			}
-
-			expectedNewRoot = currentEntry.Data[70:102]
-			entryToUpdate = nil
-		case state.EntryTypeL2BlockStart:
-			startEntry = currentEntry
-			printEntry(startEntry)
-
-			txEntry, err := streamServer.GetEntry(startEntry.Number + 1)
-			if err != nil {
-				log.Error(err)
-				os.Exit(1)
-			}
-			printEntry(txEntry)
-
-			endEntry, err := streamServer.GetEntry(startEntry.Number + 2) //nolint:gomnd
-			if err != nil {
-				log.Error(err)
-				os.Exit(1)
-			}
-			printEntry(endEntry)
-
-			forkID := uint64(binary.BigEndian.Uint16(startEntry.Data[76:78]))
-
-			tx, err := state.DecodeTx(common.Bytes2Hex((txEntry.Data[6:])))
-			if err != nil {
-				log.Error(err)
-				os.Exit(1)
-			}
+	l2BlockNumber := cliCtx.Uint64("l2block")
 
-			// Get the old state root
-			oldStateRoot := getOldStateRoot(startEntry.Number, streamServer)
+	bookMark := &datastream.BookMark{
+		Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+		Value: l2BlockNumber,
+	}
 
-			// RLP encode the transaction using the proper fork id
-			batchL2Data, err := state.EncodeTransaction(*tx, txEntry.Data[0], forkID) //nolint:gomnd
-			if err != nil {
-				log.Error(err)
-				os.Exit(1)
-			}
+	marshalledBookMark, err := proto.Marshal(bookMark)
+	if err != nil {
+		return err
+	}
 
-			processBatchRequest = &executor.ProcessBatchRequest{
-				OldBatchNum:      binary.BigEndian.Uint64(startEntry.Data[0:8]) - 1,
-				Coinbase:         common.Bytes2Hex(startEntry.Data[56:76]),
-				BatchL2Data:      batchL2Data,
-				OldStateRoot:     oldStateRoot,
-				GlobalExitRoot:   startEntry.Data[24:56],
-				OldAccInputHash:  []byte{},
-				EthTimestamp:     binary.BigEndian.Uint64(startEntry.Data[16:24]),
-				UpdateMerkleTree: uint32(1),
-				ChainId:          c.Offline.ChainID,
-				ForkId:           uint64(binary.BigEndian.Uint16(startEntry.Data[76:78])),
-			}
+	firstEntry, err := client.ExecCommandGetBookmark(marshalledBookMark)
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
+	}
+	printEntry(firstEntry)
 
-			expectedNewRoot = endEntry.Data[40:72]
-			entryToUpdate = &endEntry
-			x += 2 //nolint:gomnd
-		}
+	secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1)
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
+	}
 
-		// Process batch
-		processBatchResponse, err := executorClient.ProcessBatch(ctx, processBatchRequest)
+	i := uint64(2) //nolint:gomnd
+	for secondEntry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION) {
+		printEntry(secondEntry)
+		entry, err := client.ExecCommandGetEntry(firstEntry.Number + i)
 		if err != nil {
 			log.Error(err)
 			os.Exit(1)
 		}
-
-		if processBatchResponse.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR {
-			fmt.Printf("Error: %v\n", processBatchResponse.Error)
-			os.Exit(1)
-		}
-
-		if common.Bytes2Hex(processBatchResponse.NewStateRoot) != common.Bytes2Hex(expectedNewRoot) {
-			printColored(color.FgRed, "\nNew state root does not match\n\n")
-			printColored(color.FgRed, fmt.Sprintf("Old State Root.........: %s\n", "0x"+common.Bytes2Hex(processBatchRequest.GetOldStateRoot())))
-			printColored(color.FgRed, fmt.Sprintf("New State Root.........: %s\n", "0x"+common.Bytes2Hex(processBatchResponse.NewStateRoot)))
-			printColored(color.FgRed, fmt.Sprintf("Expected New State Root: %s\n", "0x"+common.Bytes2Hex(expectedNewRoot)))
-			// Check if we must update the file with the new state root
-			if cliCtx.Bool("update") {
-				if entryToUpdate.Type != state.EntryTypeL2BlockEnd {
-					printColored(color.FgRed, "Error: Entry to update is not a L2BlockEnd\n")
-					os.Exit(1)
-				}
-				blockEnd := state.DSL2BlockEnd{}.Decode(entryToUpdate.Data)
-				blockEnd.StateRoot = common.BytesToHash(processBatchResponse.NewStateRoot)
-				err = streamServer.UpdateEntryData(entryToUpdate.Number, state.EntryTypeL2BlockEnd, blockEnd.Encode())
-				if err != nil {
-					printColored(color.FgRed, fmt.Sprintf("Error: %v\n", err))
-					os.Exit(1)
-				}
-			} else {
-				break
-			}
-		} else {
-			printColored(color.FgGreen, "New state root matches\n")
-			previousStateRoot = processBatchResponse.NewStateRoot
-		}
+		secondEntry = entry
+		i++
 	}
 
 	return nil
 }
 
-func decodeEntry(cliCtx *cli.Context) error {
+func decodeEntryOffline(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -546,29 +436,24 @@ func decodeEntry(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
-	}
-
-	err = client.Start()
+	streamServer, err := initializeStreamServer(c)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	entry, err := client.ExecCommandGetEntry(cliCtx.Uint64("entry"))
+	entry, err := streamServer.GetEntry(cliCtx.Uint64("entry"))
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
 	printEntry(entry)
+
 	return nil
 }
 
-func decodeL2Block(cliCtx *cli.Context) error {
+func decodeL2BlockOffline(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -577,13 +462,7 @@ func decodeL2Block(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
-	}
-
-	err = client.Start()
+	streamServer, err := initializeStreamServer(c)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
@@ -591,41 +470,45 @@ func decodeL2Block(cliCtx *cli.Context) error {
 
 	l2BlockNumber := cliCtx.Uint64("l2block")
 
-	bookMark := state.DSBookMark{
-		Type:  state.BookMarkTypeL2Block,
+	bookMark := &datastream.BookMark{
+		Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
 		Value: l2BlockNumber,
 	}
 
-	firstEntry, err := client.ExecCommandGetBookmark(bookMark.Encode())
+	marshalledBookMark, err := proto.Marshal(bookMark)
+	if err != nil {
+		return err
+	}
+
+	firstEntry, err := streamServer.GetFirstEventAfterBookmark(marshalledBookMark)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 	printEntry(firstEntry)
 
-	secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1)
+	secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
-	printEntry(secondEntry)
 
 	i := uint64(2) //nolint:gomnd
-	for secondEntry.Type == state.EntryTypeL2Tx {
-		entry, err := client.ExecCommandGetEntry(firstEntry.Number + i)
+
+	for secondEntry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION) {
+		printEntry(secondEntry)
+		secondEntry, err = streamServer.GetEntry(firstEntry.Number + i)
 		if err != nil {
 			log.Error(err)
 			os.Exit(1)
 		}
-		secondEntry = entry
-		printEntry(secondEntry)
 		i++
 	}
 
 	return nil
 }
 
-func decodeEntryOffline(cliCtx *cli.Context) error {
+func truncate(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -640,18 +523,19 @@ func decodeEntryOffline(cliCtx *cli.Context) error {
 		os.Exit(1)
 	}
 
-	entry, err := streamServer.GetEntry(cliCtx.Uint64("entry"))
+	err = streamServer.TruncateFile(cliCtx.Uint64("entry"))
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	printEntry(entry)
+	printColored(color.FgGreen, "File truncated\n")
 
 	return nil
 }
 
-func decodeL2BlockOffline(cliCtx *cli.Context) error {
+func decodeBatch(cliCtx *cli.Context) error {
+	var batchData = []byte{}
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -660,48 +544,85 @@ func decodeL2BlockOffline(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	streamServer, err := initializeStreamServer(c)
+	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	l2BlockNumber := cliCtx.Uint64("l2block")
+	err = client.Start()
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
+	}
 
-	bookMark := state.DSBookMark{
-		Type:  state.BookMarkTypeL2Block,
-		Value: l2BlockNumber,
+	batchNumber := cliCtx.Uint64("batch")
+
+	bookMark := &datastream.BookMark{
+		Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
+		Value: batchNumber,
 	}
 
-	firstEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
+	marshalledBookMark, err := proto.Marshal(bookMark)
+	if err != nil {
+		return err
+	}
+
+	firstEntry, err := client.ExecCommandGetBookmark(marshalledBookMark)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 	printEntry(firstEntry)
 
-	secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
+	batchData = append(batchData, firstEntry.Encode()...)
+
+	secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
+	printEntry(secondEntry)
+
+	batchData = append(batchData, secondEntry.Encode()...)
 
 	i := uint64(2) //nolint:gomnd
-	printEntry(secondEntry)
-	for secondEntry.Type == state.EntryTypeL2Tx {
-		secondEntry, err = streamServer.GetEntry(firstEntry.Number + i)
+	for {
+		entry, err := client.ExecCommandGetEntry(firstEntry.Number + i)
 		if err != nil {
 			log.Error(err)
 			os.Exit(1)
 		}
+
+		if entry.Type == state.EntryTypeBookMark {
+			if err := proto.Unmarshal(entry.Data, bookMark); err != nil {
+				return err
+			}
+			if bookMark.Type == datastream.BookmarkType_BOOKMARK_TYPE_BATCH {
+				break
+			}
+		}
+
+		secondEntry = entry
 		printEntry(secondEntry)
+		batchData = append(batchData, secondEntry.Encode()...)
 		i++
 	}
 
+	// Dump batchdata to a file
+	if cliCtx.Bool("dump") {
+		err = os.WriteFile(fmt.Sprintf("batch_%d.bin", batchNumber), batchData, 0644) // nolint:gosec, gomnd
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+	}
+
 	return nil
 }
 
-func truncate(cliCtx *cli.Context) error {
+func decodeBatchOffline(cliCtx *cli.Context) error {
+	var batchData = []byte{}
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -716,26 +637,84 @@ func truncate(cliCtx *cli.Context) error {
 		os.Exit(1)
 	}
 
-	err = streamServer.TruncateFile(cliCtx.Uint64("entry"))
+	batchNumber := cliCtx.Uint64("batch")
+
+	bookMark := &datastream.BookMark{
+		Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
+		Value: batchNumber,
+	}
+
+	marshalledBookMark, err := proto.Marshal(bookMark)
+	if err != nil {
+		return err
+	}
+
+	firstEntry, err := streamServer.GetFirstEventAfterBookmark(marshalledBookMark)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
+	printEntry(firstEntry)
+	batchData = append(batchData, firstEntry.Encode()...)
 
-	printColored(color.FgGreen, "File truncated\n")
+	secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
+	}
+
+	i := uint64(2) //nolint:gomnd
+	printEntry(secondEntry)
+	batchData = append(batchData, secondEntry.Encode()...)
+	for {
+		secondEntry, err = streamServer.GetEntry(firstEntry.Number + i)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
+		if secondEntry.Type == state.EntryTypeBookMark {
+			if err := proto.Unmarshal(secondEntry.Data, bookMark); err != nil {
+				return err
+			}
+			if bookMark.Type == datastream.BookmarkType_BOOKMARK_TYPE_BATCH {
+				break
+			}
+		}
+
+		printEntry(secondEntry)
+		batchData = append(batchData, secondEntry.Encode()...)
+		i++
+	}
+
+	// Dump batchdata to a file
+	if cliCtx.Bool("dump") {
+		err = os.WriteFile(fmt.Sprintf("offline_batch_%d.bin", batchNumber), batchData, 0644) // nolint:gosec, gomnd
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+	}
 
 	return nil
 }
 
 func printEntry(entry datastreamer.FileEntry) {
-	var bookmarkTypeDesc = map[byte]string{
-		state.BookMarkTypeL2Block: "L2 Block Number",
-		state.BookMarkTypeBatch:   "Batch Number",
+	var bookmarkTypeDesc = map[datastream.BookmarkType]string{
+		datastream.BookmarkType_BOOKMARK_TYPE_UNSPECIFIED: "Unspecified",
+		datastream.BookmarkType_BOOKMARK_TYPE_BATCH:       "Batch Number",
+		datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK:    "L2 Block Number",
 	}
 
 	switch entry.Type {
 	case state.EntryTypeBookMark:
-		bookmark := state.DSBookMark{}.Decode(entry.Data)
+		bookmark := &datastream.BookMark{}
+		err := proto.Unmarshal(entry.Data, bookmark)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
 		printColored(color.FgGreen, "Entry Type......: ")
 		printColored(color.FgHiYellow, "BookMark\n")
 		printColored(color.FgGreen, "Entry Number....: ")
@@ -744,48 +723,83 @@ func printEntry(entry datastreamer.FileEntry) {
 		printColored(color.FgHiWhite, fmt.Sprintf("%d (%s)\n", bookmark.Type, bookmarkTypeDesc[bookmark.Type]))
 		printColored(color.FgGreen, "Value...........: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", bookmark.Value))
-	case state.EntryTypeL2BlockStart:
-		blockStart := state.DSL2BlockStart{}.Decode(entry.Data)
+	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK):
+		l2Block := &datastream.L2Block{}
+		err := proto.Unmarshal(entry.Data, l2Block)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
 		printColored(color.FgGreen, "Entry Type......: ")
-		printColored(color.FgHiYellow, "L2 Block Start\n")
+		printColored(color.FgHiYellow, "L2 Block\n")
 		printColored(color.FgGreen, "Entry Number....: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
-		printColored(color.FgGreen, "Batch Number....: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.BatchNumber))
 		printColored(color.FgGreen, "L2 Block Number.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.L2BlockNumber))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.Number))
+		printColored(color.FgGreen, "Batch Number....: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.BatchNumber))
 		printColored(color.FgGreen, "Timestamp.......: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%v (%d)\n", time.Unix(blockStart.Timestamp, 0), blockStart.Timestamp))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d (%v)\n", l2Block.Timestamp, time.Unix(int64(l2Block.Timestamp), 0)))
 		printColored(color.FgGreen, "Delta Timestamp.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.DeltaTimestamp))
-		printColored(color.FgGreen, "L1 InfoTree Idx.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.L1InfoTreeIndex))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.DeltaTimestamp))
+		printColored(color.FgGreen, "Min. Timestamp..: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.MinTimestamp))
 		printColored(color.FgGreen, "L1 Block Hash...: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", blockStart.L1BlockHash))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.L1Blockhash)))
+		printColored(color.FgGreen, "L1 InfoTree Idx.: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.L1InfotreeIndex))
+		printColored(color.FgGreen, "Block Hash......: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.Hash)))
+		printColored(color.FgGreen, "State Root......: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.StateRoot)))
 		printColored(color.FgGreen, "Global Exit Root: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", blockStart.GlobalExitRoot))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.GlobalExitRoot)))
 		printColored(color.FgGreen, "Coinbase........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", blockStart.Coinbase))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToAddress(l2Block.Coinbase)))
+	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH):
+		batch := &datastream.Batch{}
+		err := proto.Unmarshal(entry.Data, batch)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+		printColored(color.FgGreen, "Entry Type......: ")
+		printColored(color.FgHiYellow, "Batch\n")
+		printColored(color.FgGreen, "Entry Number....: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
+		printColored(color.FgGreen, "Batch Number....: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.Number))
+		printColored(color.FgGreen, "State Root......: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(batch.StateRoot)))
+		printColored(color.FgGreen, "Local Exit Root.: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(batch.LocalExitRoot)))
 		printColored(color.FgGreen, "Fork ID.........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.ForkID))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.ForkId))
 		printColored(color.FgGreen, "Chain ID........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.ChainID))
-	case state.EntryTypeL2Tx:
-		dsTx := state.DSL2Transaction{}.Decode(entry.Data)
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.ChainId))
+	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION):
+		dsTx := &datastream.Transaction{}
+		err := proto.Unmarshal(entry.Data, dsTx)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
 		printColored(color.FgGreen, "Entry Type......: ")
 		printColored(color.FgHiYellow, "L2 Transaction\n")
 		printColored(color.FgGreen, "Entry Number....: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
+		printColored(color.FgGreen, "L2 Block Number.: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.L2BlockNumber))
+		printColored(color.FgGreen, "Is Valid........: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%t\n", dsTx.IsValid))
+		printColored(color.FgGreen, "Data............: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(dsTx.Encoded)))
 		printColored(color.FgGreen, "Effec. Gas Price: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.EffectiveGasPricePercentage))
-		printColored(color.FgGreen, "Is Valid........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%t\n", dsTx.IsValid == 1))
 		printColored(color.FgGreen, "IM State Root...: ")
-		printColored(color.FgHiWhite, fmt.Sprint(dsTx.StateRoot.Hex()+"\n"))
-		printColored(color.FgGreen, "Encoded Length..: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.EncodedLength))
-		printColored(color.FgGreen, "Encoded.........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(dsTx.Encoded)))
+		printColored(color.FgHiWhite, fmt.Sprint("0x"+common.Bytes2Hex(dsTx.ImStateRoot)+"\n"))
 
 		tx, err := state.DecodeTx(common.Bytes2Hex(dsTx.Encoded))
 		if err != nil {
@@ -804,20 +818,14 @@ func printEntry(entry datastreamer.FileEntry) {
 		nonce := tx.Nonce()
 		printColored(color.FgGreen, "Nonce...........: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", nonce))
-	case state.EntryTypeL2BlockEnd:
-		blockEnd := state.DSL2BlockEnd{}.Decode(entry.Data)
-		printColored(color.FgGreen, "Entry Type......: ")
-		printColored(color.FgHiYellow, "L2 Block End\n")
-		printColored(color.FgGreen, "Entry Number....: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
-		printColored(color.FgGreen, "L2 Block Number.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockEnd.L2BlockNumber))
-		printColored(color.FgGreen, "L2 Block Hash...: ")
-		printColored(color.FgHiWhite, fmt.Sprint(blockEnd.BlockHash.Hex()+"\n"))
-		printColored(color.FgGreen, "State Root......: ")
-		printColored(color.FgHiWhite, fmt.Sprint(blockEnd.StateRoot.Hex()+"\n"))
-	case state.EntryTypeUpdateGER:
-		updateGer := state.DSUpdateGER{}.Decode(entry.Data)
+	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER):
+		updateGer := &datastream.UpdateGER{}
+		err := proto.Unmarshal(entry.Data, updateGer)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
 		printColored(color.FgGreen, "Entry Type......: ")
 		printColored(color.FgHiYellow, "Update GER\n")
 		printColored(color.FgGreen, "Entry Number....: ")
@@ -825,17 +833,17 @@ func printEntry(entry datastreamer.FileEntry) {
 		printColored(color.FgGreen, "Batch Number....: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.BatchNumber))
 		printColored(color.FgGreen, "Timestamp.......: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%v (%d)\n", time.Unix(updateGer.Timestamp, 0), updateGer.Timestamp))
+		printColored(color.FgHiWhite, fmt.Sprintf("%v (%d)\n", time.Unix(int64(updateGer.Timestamp), 0), updateGer.Timestamp))
 		printColored(color.FgGreen, "Global Exit Root: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", updateGer.GlobalExitRoot))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.Bytes2Hex(updateGer.GlobalExitRoot)))
 		printColored(color.FgGreen, "Coinbase........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", updateGer.Coinbase))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToAddress(updateGer.Coinbase)))
 		printColored(color.FgGreen, "Fork ID.........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ForkID))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ForkId))
 		printColored(color.FgGreen, "Chain ID........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ChainID))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ChainId))
 		printColored(color.FgGreen, "State Root......: ")
-		printColored(color.FgHiWhite, fmt.Sprint(updateGer.StateRoot.Hex()+"\n"))
+		printColored(color.FgHiWhite, fmt.Sprint(common.Bytes2Hex(updateGer.StateRoot)+"\n"))
 	}
 }
 
@@ -843,112 +851,3 @@ func printColored(color color.Attribute, text string) {
 	colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", color, text)
 	fmt.Print(colored)
 }
-
-// setGenesis populates state with genesis information
-func setGenesis(ctx context.Context, tree *merkletree.StateTree, genesis state.Genesis) ([]byte, error) {
-	var (
-		root    common.Hash
-		newRoot []byte
-		err     error
-	)
-
-	if tree == nil {
-		return newRoot, fmt.Errorf("state tree is nil")
-	}
-
-	uuid := uuid.New().String()
-
-	for _, action := range genesis.Actions {
-		address := common.HexToAddress(action.Address)
-		switch action.Type {
-		case int(merkletree.LeafTypeBalance):
-			balance, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
-			if err != nil {
-				return newRoot, err
-			}
-			newRoot, _, err = tree.SetBalance(ctx, address, balance, newRoot, uuid)
-			if err != nil {
-				return newRoot, err
-			}
-		case int(merkletree.LeafTypeNonce):
-			nonce, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
-			if err != nil {
-				return newRoot, err
-			}
-			newRoot, _, err = tree.SetNonce(ctx, address, nonce, newRoot, uuid)
-			if err != nil {
-				return newRoot, err
-			}
-		case int(merkletree.LeafTypeCode):
-			code, err := hex.DecodeHex(action.Bytecode)
-			if err != nil {
-				return newRoot, fmt.Errorf("could not decode SC bytecode for address %q: %v", address, err)
-			}
-			newRoot, _, err = tree.SetCode(ctx, address, code, newRoot, uuid)
-			if err != nil {
-				return newRoot, err
-			}
-		case int(merkletree.LeafTypeStorage):
-			// Parse position and value
-			positionBI, err := encoding.DecodeBigIntHexOrDecimal(action.StoragePosition)
-			if err != nil {
-				return newRoot, err
-			}
-			valueBI, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
-			if err != nil {
-				return newRoot, err
-			}
-			// Store
-			newRoot, _, err = tree.SetStorageAt(ctx, address, positionBI, valueBI, newRoot, uuid)
-			if err != nil {
-				return newRoot, err
-			}
-		default:
-			return newRoot, fmt.Errorf("unknown genesis action type %q", action.Type)
-		}
-	}
-
-	root.SetBytes(newRoot)
-
-	// flush state db
-	err = tree.Flush(ctx, root, uuid)
-	if err != nil {
-		fmt.Printf("error flushing state tree after genesis: %v", err)
-		return newRoot, err
-	}
-
-	return newRoot, nil
-}
-
-func getOldStateRoot(entityNumber uint64, streamServer *datastreamer.StreamServer) []byte {
-	var found = false
-	var entry datastreamer.FileEntry
-	var err error
-
-	for !found && entityNumber > 1 {
-		entityNumber--
-		entry, err = streamServer.GetEntry(entityNumber)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
-		if entry.Type == state.EntryTypeL2BlockEnd || entry.Type == state.EntryTypeUpdateGER {
-			found = true
-		}
-	}
-
-	if !found {
-		fmt.Printf("Error: Could not find old state root")
-		os.Exit(1)
-	}
-
-	printColored(color.FgHiYellow, "Getting Old State Root from\n")
-	printEntry(entry)
-
-	if entry.Type == state.EntryTypeUpdateGER {
-		return entry.Data[70:102]
-	}
-
-	return entry.Data[40:72]
-}

From e261069756d9589dcf33f080c18939418d1f8374 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Toni=20Ram=C3=ADrez?=
 <58293609+ToniRamirezM@users.noreply.github.com>
Date: Mon, 29 Apr 2024 12:56:29 +0200
Subject: [PATCH 18/23] Revert "Change data stream format (#3597)" (#3603)

This reverts commit 5a76fb5c367b7631808dfd01bec1961e7c4cc7e7.
---
 Makefile                                      |   1 -
 .../src/proto/datastream/v1/datastream.proto  |  64 --
 sequencer/batch.go                            |   6 -
 sequencer/datastreamer.go                     |  27 +-
 sequencer/finalizer_test.go                   |   1 -
 sequencer/forcedbatch.go                      |   2 +-
 sequencer/l2block.go                          |   2 +-
 sequencer/sequencer.go                        | 134 +--
 state/datastream.go                           | 482 ++++++-----
 state/datastream/datastream.pb.go             | 773 ------------------
 state/pgstatestorage/datastream.go            |  13 +-
 state/test/datastream_test.go                 |  82 ++
 test/docker-compose.yml                       |   6 -
 tools/datastreamer/Makefile                   |  22 +-
 tools/datastreamer/config/tool.config.toml    |   6 +-
 tools/datastreamer/main.go                    | 733 ++++++++++-------
 16 files changed, 817 insertions(+), 1537 deletions(-)
 delete mode 100644 proto/src/proto/datastream/v1/datastream.proto
 delete mode 100644 state/datastream/datastream.pb.go
 create mode 100644 state/test/datastream_test.go

diff --git a/Makefile b/Makefile
index ba55fb3429..83d4fed5fe 100644
--- a/Makefile
+++ b/Makefile
@@ -164,7 +164,6 @@ generate-code-from-proto: ## Generates code from proto files
 	cd proto/src/proto/hashdb/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../merkletree/hashdb --go-grpc_out=../../../../../merkletree/hashdb --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative hashdb.proto
 	cd proto/src/proto/executor/v1 && protoc --proto_path=. --go_out=../../../../../state/runtime/executor --go-grpc_out=../../../../../state/runtime/executor --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative executor.proto
 	cd proto/src/proto/aggregator/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../aggregator/prover --go-grpc_out=../../../../../aggregator/prover --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative aggregator.proto
-	cd proto/src/proto/datastream/v1 && protoc --proto_path=. --proto_path=../../../../include --go_out=../../../../../state/datastream --go-grpc_out=../../../../../state/datastream --go-grpc_opt=paths=source_relative --go_opt=paths=source_relative datastream.proto
 
 ## Help display.
 ## Pulls comments from beside commands and prints a nicely formatted
diff --git a/proto/src/proto/datastream/v1/datastream.proto b/proto/src/proto/datastream/v1/datastream.proto
deleted file mode 100644
index 6b8a89adc6..0000000000
--- a/proto/src/proto/datastream/v1/datastream.proto
+++ /dev/null
@@ -1,64 +0,0 @@
-syntax = "proto3";
-
-package datastream.v1;
-
-option go_package = "github.com/0xPolygonHermez/zkevm-node/state/datastream";
-
-message Batch {
-    uint64 number = 1;
-    bytes local_exit_root = 2;
-    bytes state_root = 3;
-    uint64 fork_id = 4;
-    uint64 chain_id = 5;
-}
-
-message L2Block {
-    uint64 number = 1;
-    uint64 batch_number = 2;
-    uint64 timestamp = 3;
-    uint32 delta_timestamp = 4;
-    uint64 min_timestamp = 5;
-    bytes l1_blockhash = 6;
-    uint32 l1_infotree_index = 7;
-    bytes hash = 8;
-    bytes state_root = 9;
-    bytes global_exit_root = 10;
-    bytes coinbase = 11;
-}
-
-message Transaction {
-    uint64 l2block_number = 1;
-    bool is_valid = 2;
-    bytes encoded = 3;
-    uint32 effective_gas_price_percentage = 4;
-    bytes im_state_root = 5;
-}
-
-message UpdateGER {
-    uint64 batch_number = 1;
-    uint64 timestamp = 2;
-    bytes global_exit_root = 3;
-    bytes coinbase = 4;
-    uint64 fork_id = 5;
-    uint64 chain_id = 6;
-    bytes state_root = 7;
-}
-
-message BookMark {
-    BookmarkType type = 1;
-    uint64 value = 2;
-}
-
-enum BookmarkType {
-    BOOKMARK_TYPE_UNSPECIFIED = 0;
-    BOOKMARK_TYPE_BATCH = 1;
-    BOOKMARK_TYPE_L2_BLOCK = 2;
-}
-
-enum EntryType {
-    ENTRY_TYPE_UNSPECIFIED = 0;
-    ENTRY_TYPE_BATCH = 1;
-    ENTRY_TYPE_L2_BLOCK = 2;
-    ENTRY_TYPE_TRANSACTION = 3;
-    ENTRY_TYPE_UPDATE_GER = 4;
-}
diff --git a/sequencer/batch.go b/sequencer/batch.go
index c189f26380..1d644b22c5 100644
--- a/sequencer/batch.go
+++ b/sequencer/batch.go
@@ -26,7 +26,6 @@ type Batch struct {
 	imRemainingResources    state.BatchResources // remaining batch resources when processing tx-by-tx
 	finalRemainingResources state.BatchResources // remaining batch resources when a L2 block is processed
 	closingReason           state.ClosingReason
-	finalLocalExitRoot      common.Hash
 }
 
 func (w *Batch) isEmpty() bool {
@@ -95,7 +94,6 @@ func (f *finalizer) setWIPBatch(ctx context.Context, wipStateBatch *state.Batch)
 		countOfTxs:              wipStateBatchCountOfTxs,
 		imRemainingResources:    remainingResources,
 		finalRemainingResources: remainingResources,
-		finalLocalExitRoot:      wipStateBatch.LocalExitRoot,
 	}
 
 	return wipBatch, nil
@@ -295,7 +293,6 @@ func (f *finalizer) openNewWIPBatch(ctx context.Context, batchNumber uint64, sta
 		imRemainingResources:    maxRemainingResources,
 		finalRemainingResources: maxRemainingResources,
 		closingReason:           state.EmptyClosingReason,
-		finalLocalExitRoot:      newStateBatch.LocalExitRoot,
 	}, err
 }
 
@@ -331,9 +328,6 @@ func (f *finalizer) closeWIPBatch(ctx context.Context) error {
 			log.Errorf("error committing close wip batch, error: %v", err)
 			return err
 		}
-
-		// Sent batch to DS
-		f.DSSendBatch(f.wipBatch.batchNumber, f.wipBatch.finalStateRoot, f.wipBatch.finalLocalExitRoot)
 	}
 
 	return nil
diff --git a/sequencer/datastreamer.go b/sequencer/datastreamer.go
index 2c790c0946..bbbfe14496 100644
--- a/sequencer/datastreamer.go
+++ b/sequencer/datastreamer.go
@@ -3,11 +3,9 @@ package sequencer
 import (
 	"github.com/0xPolygonHermez/zkevm-node/log"
 	"github.com/0xPolygonHermez/zkevm-node/state"
-	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
-	"github.com/ethereum/go-ethereum/common"
 )
 
-func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.ProcessBlockResponse, l1InfoTreeIndex uint32, minTimestamp uint64) error {
+func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.ProcessBlockResponse, l1InfoTreeIndex uint32) error {
 	forkID := f.stateIntf.GetForkIDByBatchNumber(batchNumber)
 
 	// Send data to streamer
@@ -15,13 +13,12 @@ func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.Proce
 		l2Block := state.DSL2Block{
 			BatchNumber:     batchNumber,
 			L2BlockNumber:   blockResponse.BlockNumber,
-			Timestamp:       blockResponse.Timestamp,
-			Min_timestamp:   minTimestamp,
+			Timestamp:       int64(blockResponse.Timestamp),
 			L1InfoTreeIndex: l1InfoTreeIndex,
 			L1BlockHash:     blockResponse.BlockHashL1,
 			GlobalExitRoot:  blockResponse.GlobalExitRoot,
 			Coinbase:        f.sequencerAddress,
-			ForkID:          forkID,
+			ForkID:          uint16(forkID),
 			BlockHash:       blockResponse.BlockHash,
 			StateRoot:       blockResponse.BlockHash, //From etrog, the blockhash is the block root
 		}
@@ -60,23 +57,9 @@ func (f *finalizer) DSSendBatchBookmark(batchNumber uint64) {
 	// Check if stream server enabled
 	if f.streamServer != nil {
 		// Send batch bookmark to the streamer
-		f.dataToStream <- datastream.BookMark{
-			Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
+		f.dataToStream <- state.DSBookMark{
+			Type:  state.BookMarkTypeBatch,
 			Value: batchNumber,
 		}
 	}
 }
-
-func (f *finalizer) DSSendBatch(batchNumber uint64, stateRoot common.Hash, localExitRoot common.Hash) {
-	forkID := f.stateIntf.GetForkIDByBatchNumber(batchNumber)
-
-	if f.streamServer != nil {
-		// Send batch to the streamer
-		f.dataToStream <- datastream.Batch{
-			Number:        batchNumber,
-			ForkId:        forkID,
-			StateRoot:     stateRoot.Bytes(),
-			LocalExitRoot: localExitRoot.Bytes(),
-		}
-	}
-}
diff --git a/sequencer/finalizer_test.go b/sequencer/finalizer_test.go
index 9b9d555b94..8e7b5fa9d9 100644
--- a/sequencer/finalizer_test.go
+++ b/sequencer/finalizer_test.go
@@ -981,7 +981,6 @@ func TestFinalizer_closeWIPBatch(t *testing.T) {
 			// arrange
 			stateMock.Mock.On("CloseWIPBatch", ctx, receipt, mock.Anything).Return(tc.managerErr).Once()
 			stateMock.On("BeginStateTransaction", ctx).Return(dbTxMock, nilErr).Once()
-			stateMock.On("GetForkIDByBatchNumber", mock.Anything).Return(uint64(state.FORKID_BLUEBERRY))
 			if tc.managerErr == nil {
 				dbTxMock.On("Commit", ctx).Return(nilErr).Once()
 			} else {
diff --git a/sequencer/forcedbatch.go b/sequencer/forcedbatch.go
index d6386091d6..ebe078c1b8 100644
--- a/sequencer/forcedbatch.go
+++ b/sequencer/forcedbatch.go
@@ -197,7 +197,7 @@ func (f *finalizer) handleProcessForcedBatchResponse(ctx context.Context, newBat
 		}
 
 		// Send L2 block to data streamer
-		err = f.DSSendL2Block(newBatchNumber, forcedL2BlockResponse, 0, forcedL2BlockResponse.Timestamp)
+		err = f.DSSendL2Block(newBatchNumber, forcedL2BlockResponse, 0)
 		if err != nil {
 			//TODO: we need to halt/rollback the L2 block if we had an error sending to the data streamer?
 			log.Errorf("error sending L2 block %d to data streamer, error: %v", forcedL2BlockResponse.BlockNumber, err)
diff --git a/sequencer/l2block.go b/sequencer/l2block.go
index f2472a65b5..ed7ae314f6 100644
--- a/sequencer/l2block.go
+++ b/sequencer/l2block.go
@@ -427,7 +427,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error {
 	log.Infof("l2 block %d [%d] transactions updated as selected in the pooldb", blockResponse.BlockNumber, l2Block.trackingNum)
 
 	// Send L2 block to data streamer
-	err = f.DSSendL2Block(f.wipBatch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex(), l2Block.timestamp)
+	err = f.DSSendL2Block(f.wipBatch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex())
 	if err != nil {
 		//TODO: we need to halt/rollback the L2 block if we had an error sending to the data streamer?
 		log.Errorf("error sending L2 block %d [%d] to data streamer, error: %v", blockResponse.BlockNumber, l2Block.trackingNum, err)
diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go
index 5608ddc12e..22201776ce 100644
--- a/sequencer/sequencer.go
+++ b/sequencer/sequencer.go
@@ -11,9 +11,7 @@ import (
 	"github.com/0xPolygonHermez/zkevm-node/log"
 	"github.com/0xPolygonHermez/zkevm-node/pool"
 	"github.com/0xPolygonHermez/zkevm-node/state"
-	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
 	"github.com/ethereum/go-ethereum/common"
-	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -139,7 +137,7 @@ func (s *Sequencer) checkStateInconsistency(ctx context.Context) {
 }
 
 func (s *Sequencer) updateDataStreamerFile(ctx context.Context, chainID uint64) {
-	err := state.GenerateDataStreamFile(ctx, s.streamServer, s.stateIntf, true, nil, chainID, s.cfg.StreamServer.UpgradeEtrogBatchNumber)
+	err := state.GenerateDataStreamerFile(ctx, s.streamServer, s.stateIntf, true, nil, chainID, s.cfg.StreamServer.UpgradeEtrogBatchNumber)
 	if err != nil {
 		log.Fatalf("failed to generate data streamer file, error: %v", err)
 	}
@@ -266,77 +264,54 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 					continue
 				}
 
-				bookMark := &datastream.BookMark{
-					Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+				bookMark := state.DSBookMark{
+					Type:  state.BookMarkTypeL2Block,
 					Value: l2Block.L2BlockNumber,
 				}
 
 				//TODO: remove this log
 				log.Infof("add stream bookmark for l2block %d", l2Block.L2BlockNumber)
-				marshalledBookMark, err := proto.Marshal(bookMark)
-				if err != nil {
-					log.Errorf("failed to marshal bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err)
-					continue
-				}
-
-				_, err = s.streamServer.AddStreamBookmark(marshalledBookMark)
+				_, err = s.streamServer.AddStreamBookmark(bookMark.Encode())
 				if err != nil {
 					log.Errorf("failed to add stream bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 					continue
 				}
 
 				// Get previous block timestamp to calculate delta timestamp
-				previousL2Block := datastream.L2Block{}
+				previousL2Block := state.DSL2BlockStart{}
 				if l2Block.L2BlockNumber > 0 {
-					bookMark = &datastream.BookMark{
-						Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+					bookMark = state.DSBookMark{
+						Type:  state.BookMarkTypeL2Block,
 						Value: l2Block.L2BlockNumber - 1,
 					}
 
 					//TODO: remove this log
 					log.Infof("get previous l2block %d", l2Block.L2BlockNumber-1)
-					marshalledBookMark, err := proto.Marshal(bookMark)
-					if err != nil {
-						log.Errorf("failed to marshal bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err)
-						continue
-					}
-
-					previousL2BlockEntry, err := s.streamServer.GetFirstEventAfterBookmark(marshalledBookMark)
+					previousL2BlockEntry, err := s.streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
 					if err != nil {
 						log.Errorf("failed to get previous l2block %d, error: %v", l2Block.L2BlockNumber-1, err)
 						continue
 					}
 
-					err = proto.Unmarshal(previousL2BlockEntry.Data, &previousL2Block)
-					if err != nil {
-						log.Errorf("failed to unmarshal previous l2block %d, error: %v", l2Block.L2BlockNumber-1, err)
-						continue
-					}
+					previousL2Block = state.DSL2BlockStart{}.Decode(previousL2BlockEntry.Data)
 				}
 
-				streamL2Block := &datastream.L2Block{
-					Number:          l2Block.L2BlockNumber,
+				blockStart := state.DSL2BlockStart{
 					BatchNumber:     l2Block.BatchNumber,
+					L2BlockNumber:   l2Block.L2BlockNumber,
 					Timestamp:       l2Block.Timestamp,
 					DeltaTimestamp:  uint32(l2Block.Timestamp - previousL2Block.Timestamp),
-					MinTimestamp:    l2Block.Min_timestamp,
-					L1Blockhash:     l2Block.L1BlockHash.Bytes(),
-					L1InfotreeIndex: l2Block.L1InfoTreeIndex,
-					Hash:            l2Block.BlockHash.Bytes(),
-					StateRoot:       l2Block.StateRoot.Bytes(),
-					GlobalExitRoot:  l2Block.GlobalExitRoot.Bytes(),
-					Coinbase:        l2Block.Coinbase.Bytes(),
-				}
-
-				marshalledL2Block, err := proto.Marshal(streamL2Block)
-				if err != nil {
-					log.Errorf("failed to marshal l2block %d, error: %v", l2Block.L2BlockNumber, err)
-					continue
+					L1InfoTreeIndex: l2Block.L1InfoTreeIndex,
+					L1BlockHash:     l2Block.L1BlockHash,
+					GlobalExitRoot:  l2Block.GlobalExitRoot,
+					Coinbase:        l2Block.Coinbase,
+					ForkID:          l2Block.ForkID,
+					ChainID:         uint32(chainID),
 				}
 
 				//TODO: remove this log
 				log.Infof("add l2blockStart stream entry for l2block %d", l2Block.L2BlockNumber)
-				_, err = s.streamServer.AddStreamEntry(datastreamer.EntryType(datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK), marshalledL2Block)
+				_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockStart, blockStart.Encode())
 				if err != nil {
 					log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 					continue
@@ -345,27 +320,27 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 				//TODO: remove this log
 				log.Infof("adding l2tx stream entries for l2block %d", l2Block.L2BlockNumber)
 				for _, l2Transaction := range l2Block.Txs {
-					streamL2Transaction := &datastream.Transaction{
-						L2BlockNumber:               l2Transaction.L2BlockNumber,
-						IsValid:                     l2Transaction.IsValid != 0,
-						Encoded:                     l2Transaction.Encoded,
-						EffectiveGasPricePercentage: uint32(l2Transaction.EffectiveGasPricePercentage),
-						ImStateRoot:                 l2Transaction.ImStateRoot.Bytes(),
-					}
-
-					marshalledL2Transaction, err := proto.Marshal(streamL2Transaction)
-					if err != nil {
-						log.Errorf("failed to marshal l2tx for l2block %d, error: %v", l2Block.L2BlockNumber, err)
-						continue
-					}
-
-					_, err = s.streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION), marshalledL2Transaction)
+					_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2Tx, l2Transaction.Encode())
 					if err != nil {
 						log.Errorf("failed to add l2tx stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
 						continue
 					}
 				}
 
+				blockEnd := state.DSL2BlockEnd{
+					L2BlockNumber: l2Block.L2BlockNumber,
+					BlockHash:     l2Block.BlockHash,
+					StateRoot:     l2Block.StateRoot,
+				}
+
+				//TODO: remove this log
+				log.Infof("add l2blockEnd stream entry for l2block %d", l2Block.L2BlockNumber)
+				_, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockEnd, blockEnd.Encode())
+				if err != nil {
+					log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err)
+					continue
+				}
+
 				//TODO: remove this log
 				log.Infof("commit atomic op for l2block %d", l2Block.L2BlockNumber)
 				err = s.streamServer.CommitAtomicOp()
@@ -378,55 +353,24 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 				log.Infof("l2block %d sent to datastream", l2Block.L2BlockNumber)
 
 			// Stream a bookmark
-			case datastream.BookMark:
-				err = s.streamServer.StartAtomicOp()
-				if err != nil {
-					log.Errorf("failed to start atomic op for bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
-					continue
-				}
+			case state.DSBookMark:
+				bookmark := data
 
-				marshalledBookMark, err := proto.Marshal(&data)
-				if err != nil {
-					log.Errorf("failed to marshal bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
-					continue
-				}
-
-				_, err = s.streamServer.AddStreamBookmark(marshalledBookMark)
-				if err != nil {
-					log.Errorf("failed to add stream bookmark for bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
-					continue
-				}
-
-				err = s.streamServer.CommitAtomicOp()
-				if err != nil {
-					log.Errorf("failed to commit atomic op for bookmark type %d, value %d, error: %v", data.Type, data.Value, err)
-					continue
-				}
-			case datastream.Batch:
 				err = s.streamServer.StartAtomicOp()
 				if err != nil {
-					log.Errorf("failed to start atomic op for batch, error: %v", err)
+					log.Errorf("failed to start atomic op for bookmark type %d, value %d, error: %v", bookmark.Type, bookmark.Value, err)
 					continue
 				}
 
-				data.ChainId = chainID
-
-				marshalledBatch, err := proto.Marshal(&data)
-				if err != nil {
-					log.Errorf("failed to marshal batch, error: %v", err)
-					continue
-				}
-
-				_, err = s.streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH), marshalledBatch)
+				_, err = s.streamServer.AddStreamBookmark(bookmark.Encode())
 				if err != nil {
-					log.Errorf("failed to add stream entry for batch, error: %v", err)
+					log.Errorf("failed to add stream bookmark type %d, value %d, error: %v", bookmark.Type, bookmark.Value, err)
 					continue
 				}
 
 				err = s.streamServer.CommitAtomicOp()
 				if err != nil {
-					log.Errorf("failed to commit atomic op for batch, error: %v", err)
-					continue
+					log.Errorf("failed to commit atomic op for bookmark type %d, value %d, error: %v", bookmark.Type, bookmark.Value, err)
 				}
 
 			// Invalid stream message type
diff --git a/state/datastream.go b/state/datastream.go
index eb3670e6f9..d50c7adecf 100644
--- a/state/datastream.go
+++ b/state/datastream.go
@@ -2,16 +2,14 @@ package state
 
 import (
 	"context"
+	"encoding/binary"
 	"math/big"
-	"time"
 
 	"github.com/0xPolygonHermez/zkevm-data-streamer/datastreamer"
 	"github.com/0xPolygonHermez/zkevm-node/log"
-	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/iden3/go-iden3-crypto/keccak256"
 	"github.com/jackc/pgx/v4"
-	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -19,6 +17,18 @@ const (
 	StreamTypeSequencer datastreamer.StreamType = 1
 	// EntryTypeBookMark represents a bookmark entry
 	EntryTypeBookMark datastreamer.EntryType = datastreamer.EtBookmark
+	// EntryTypeL2BlockStart represents a L2 block start
+	EntryTypeL2BlockStart datastreamer.EntryType = 1
+	// EntryTypeL2Tx represents a L2 transaction
+	EntryTypeL2Tx datastreamer.EntryType = 2
+	// EntryTypeL2BlockEnd represents a L2 block end
+	EntryTypeL2BlockEnd datastreamer.EntryType = 3
+	// EntryTypeUpdateGER represents a GER update
+	EntryTypeUpdateGER datastreamer.EntryType = 4
+	// BookMarkTypeL2Block represents a L2 block bookmark
+	BookMarkTypeL2Block byte = 0
+	// BookMarkTypeBatch represents a batch
+	BookMarkTypeBatch byte = 1
 	// SystemSC is the system smart contract address
 	SystemSC = "0x000000000000000000000000000000005ca1ab1e"
 	// posConstant is the constant used to compute the position of the intermediate state root
@@ -28,8 +38,7 @@ const (
 // DSBatch represents a data stream batch
 type DSBatch struct {
 	Batch
-	ForkID         uint64
-	EtrogTimestamp *time.Time
+	ForkID uint16
 }
 
 // DSFullBatch represents a data stream batch ant its L2 blocks
@@ -46,18 +55,64 @@ type DSL2FullBlock struct {
 
 // DSL2Block is a full l2 block
 type DSL2Block struct {
-	BatchNumber     uint64
-	L2BlockNumber   uint64
-	Timestamp       uint64
-	Min_timestamp   uint64
-	L1InfoTreeIndex uint32
-	L1BlockHash     common.Hash
-	GlobalExitRoot  common.Hash
-	Coinbase        common.Address
-	ForkID          uint64
-	ChainID         uint64
-	BlockHash       common.Hash
-	StateRoot       common.Hash
+	BatchNumber     uint64         // 8 bytes
+	L2BlockNumber   uint64         // 8 bytes
+	Timestamp       int64          // 8 bytes
+	L1InfoTreeIndex uint32         // 4 bytes
+	L1BlockHash     common.Hash    // 32 bytes
+	GlobalExitRoot  common.Hash    // 32 bytes
+	Coinbase        common.Address // 20 bytes
+	ForkID          uint16         // 2 bytes
+	ChainID         uint32         // 4 bytes
+	BlockHash       common.Hash    // 32 bytes
+	StateRoot       common.Hash    // 32 bytes
+}
+
+// DSL2BlockStart represents a data stream L2 block start
+type DSL2BlockStart struct {
+	BatchNumber     uint64         // 8 bytes
+	L2BlockNumber   uint64         // 8 bytes
+	Timestamp       int64          // 8 bytes
+	DeltaTimestamp  uint32         // 4 bytes
+	L1InfoTreeIndex uint32         // 4 bytes
+	L1BlockHash     common.Hash    // 32 bytes
+	GlobalExitRoot  common.Hash    // 32 bytes
+	Coinbase        common.Address // 20 bytes
+	ForkID          uint16         // 2 bytes
+	ChainID         uint32         // 4 bytes
+
+}
+
+// Encode returns the encoded DSL2BlockStart as a byte slice
+func (b DSL2BlockStart) Encode() []byte {
+	bytes := make([]byte, 0)
+	bytes = binary.BigEndian.AppendUint64(bytes, b.BatchNumber)
+	bytes = binary.BigEndian.AppendUint64(bytes, b.L2BlockNumber)
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(b.Timestamp))
+	bytes = binary.BigEndian.AppendUint32(bytes, b.DeltaTimestamp)
+	bytes = binary.BigEndian.AppendUint32(bytes, b.L1InfoTreeIndex)
+	bytes = append(bytes, b.L1BlockHash.Bytes()...)
+	bytes = append(bytes, b.GlobalExitRoot.Bytes()...)
+	bytes = append(bytes, b.Coinbase.Bytes()...)
+	bytes = binary.BigEndian.AppendUint16(bytes, b.ForkID)
+	bytes = binary.BigEndian.AppendUint32(bytes, b.ChainID)
+	return bytes
+}
+
+// Decode decodes the DSL2BlockStart from a byte slice
+func (b DSL2BlockStart) Decode(data []byte) DSL2BlockStart {
+	b.BatchNumber = binary.BigEndian.Uint64(data[0:8])
+	b.L2BlockNumber = binary.BigEndian.Uint64(data[8:16])
+	b.Timestamp = int64(binary.BigEndian.Uint64(data[16:24]))
+	b.DeltaTimestamp = binary.BigEndian.Uint32(data[24:28])
+	b.L1InfoTreeIndex = binary.BigEndian.Uint32(data[28:32])
+	b.L1BlockHash = common.BytesToHash(data[32:64])
+	b.GlobalExitRoot = common.BytesToHash(data[64:96])
+	b.Coinbase = common.BytesToAddress(data[96:116])
+	b.ForkID = binary.BigEndian.Uint16(data[116:118])
+	b.ChainID = binary.BigEndian.Uint32(data[118:122])
+
+	return b
 }
 
 // DSL2Transaction represents a data stream L2 transaction
@@ -71,6 +126,108 @@ type DSL2Transaction struct {
 	Encoded                     []byte
 }
 
+// Encode returns the encoded DSL2Transaction as a byte slice
+func (l DSL2Transaction) Encode() []byte {
+	bytes := make([]byte, 0)
+	bytes = append(bytes, l.EffectiveGasPricePercentage)
+	bytes = append(bytes, l.IsValid)
+	bytes = append(bytes, l.StateRoot[:]...)
+	bytes = binary.BigEndian.AppendUint32(bytes, l.EncodedLength)
+	bytes = append(bytes, l.Encoded...)
+	return bytes
+}
+
+// Decode decodes the DSL2Transaction from a byte slice
+func (l DSL2Transaction) Decode(data []byte) DSL2Transaction {
+	l.EffectiveGasPricePercentage = data[0]
+	l.IsValid = data[1]
+	l.StateRoot = common.BytesToHash(data[2:34])
+	l.EncodedLength = binary.BigEndian.Uint32(data[34:38])
+	l.Encoded = data[38:]
+	return l
+}
+
+// DSL2BlockEnd represents a L2 block end
+type DSL2BlockEnd struct {
+	L2BlockNumber uint64      // 8 bytes
+	BlockHash     common.Hash // 32 bytes
+	StateRoot     common.Hash // 32 bytes
+}
+
+// Encode returns the encoded DSL2BlockEnd as a byte slice
+func (b DSL2BlockEnd) Encode() []byte {
+	bytes := make([]byte, 0)
+	bytes = binary.BigEndian.AppendUint64(bytes, b.L2BlockNumber)
+	bytes = append(bytes, b.BlockHash[:]...)
+	bytes = append(bytes, b.StateRoot[:]...)
+	return bytes
+}
+
+// Decode decodes the DSL2BlockEnd from a byte slice
+func (b DSL2BlockEnd) Decode(data []byte) DSL2BlockEnd {
+	b.L2BlockNumber = binary.BigEndian.Uint64(data[0:8])
+	b.BlockHash = common.BytesToHash(data[8:40])
+	b.StateRoot = common.BytesToHash(data[40:72])
+	return b
+}
+
+// DSBookMark represents a data stream bookmark
+type DSBookMark struct {
+	Type  byte   // 1 byte
+	Value uint64 // 8 bytes
+}
+
+// Encode returns the encoded DSBookMark as a byte slice
+func (b DSBookMark) Encode() []byte {
+	bytes := make([]byte, 0)
+	bytes = append(bytes, b.Type)
+	bytes = binary.BigEndian.AppendUint64(bytes, b.Value)
+	return bytes
+}
+
+// Decode decodes the DSBookMark from a byte slice
+func (b DSBookMark) Decode(data []byte) DSBookMark {
+	b.Type = data[0]
+	b.Value = binary.BigEndian.Uint64(data[1:9])
+	return b
+}
+
+// DSUpdateGER represents a data stream GER update
+type DSUpdateGER struct {
+	BatchNumber    uint64         // 8 bytes
+	Timestamp      int64          // 8 bytes
+	GlobalExitRoot common.Hash    // 32 bytes
+	Coinbase       common.Address // 20 bytes
+	ForkID         uint16         // 2 bytes
+	ChainID        uint32         // 4 bytes
+	StateRoot      common.Hash    // 32 bytes
+}
+
+// Encode returns the encoded DSUpdateGER as a byte slice
+func (g DSUpdateGER) Encode() []byte {
+	bytes := make([]byte, 0)
+	bytes = binary.BigEndian.AppendUint64(bytes, g.BatchNumber)
+	bytes = binary.BigEndian.AppendUint64(bytes, uint64(g.Timestamp))
+	bytes = append(bytes, g.GlobalExitRoot[:]...)
+	bytes = append(bytes, g.Coinbase[:]...)
+	bytes = binary.BigEndian.AppendUint16(bytes, g.ForkID)
+	bytes = binary.BigEndian.AppendUint32(bytes, g.ChainID)
+	bytes = append(bytes, g.StateRoot[:]...)
+	return bytes
+}
+
+// Decode decodes the DSUpdateGER from a byte slice
+func (g DSUpdateGER) Decode(data []byte) DSUpdateGER {
+	g.BatchNumber = binary.BigEndian.Uint64(data[0:8])
+	g.Timestamp = int64(binary.BigEndian.Uint64(data[8:16]))
+	g.GlobalExitRoot = common.BytesToHash(data[16:48])
+	g.Coinbase = common.BytesToAddress(data[48:68])
+	g.ForkID = binary.BigEndian.Uint16(data[68:70])
+	g.ChainID = binary.BigEndian.Uint32(data[70:74])
+	g.StateRoot = common.BytesToHash(data[74:106])
+	return g
+}
+
 // DSState gathers the methods required to interact with the data stream state.
 type DSState interface {
 	GetDSGenesisBlock(ctx context.Context, dbTx pgx.Tx) (*DSL2Block, error)
@@ -83,14 +240,14 @@ type DSState interface {
 	GetL1InfoRootLeafByIndex(ctx context.Context, l1InfoTreeIndex uint32, dbTx pgx.Tx) (L1InfoTreeExitRootStorageEntry, error)
 }
 
-// GenerateDataStreamFile generates or resumes a data stream file
-func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.StreamServer, stateDB DSState, readWIPBatch bool, imStateRoots *map[uint64][]byte, chainID uint64, upgradeEtrogBatchNumber uint64) error {
+// GenerateDataStreamerFile generates or resumes a data stream file
+func GenerateDataStreamerFile(ctx context.Context, streamServer *datastreamer.StreamServer, stateDB DSState, readWIPBatch bool, imStateRoots *map[uint64][]byte, chainID uint64, upgradeEtrogBatchNumber uint64) error {
 	header := streamServer.GetHeader()
 
 	var currentBatchNumber uint64 = 0
 	var lastAddedL2BlockNumber uint64 = 0
 	var lastAddedBatchNumber uint64 = 0
-	var previousTimestamp uint64 = 0
+	var previousTimestamp int64 = 0
 
 	if header.TotalEntries == 0 {
 		// Get Genesis block
@@ -104,73 +261,52 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 			return err
 		}
 
-		bookMark := &datastream.BookMark{
-			Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
+		bookMark := DSBookMark{
+			Type:  BookMarkTypeBatch,
 			Value: genesisL2Block.BatchNumber,
 		}
 
-		marshalledBookMark, err := proto.Marshal(bookMark)
+		_, err = streamServer.AddStreamBookmark(bookMark.Encode())
 		if err != nil {
 			return err
 		}
 
-		_, err = streamServer.AddStreamBookmark(marshalledBookMark)
-		if err != nil {
-			return err
-		}
-
-		bookMark = &datastream.BookMark{
-			Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+		bookMark = DSBookMark{
+			Type:  BookMarkTypeL2Block,
 			Value: genesisL2Block.L2BlockNumber,
 		}
 
-		marshalledBookMark, err = proto.Marshal(bookMark)
-		if err != nil {
-			return err
-		}
-
-		_, err = streamServer.AddStreamBookmark(marshalledBookMark)
+		_, err = streamServer.AddStreamBookmark(bookMark.Encode())
 		if err != nil {
 			return err
 		}
 
-		genesisBlock := &datastream.L2Block{
-			Number:          genesisL2Block.L2BlockNumber,
+		genesisBlock := DSL2BlockStart{
+			BatchNumber:     genesisL2Block.BatchNumber,
+			L2BlockNumber:   genesisL2Block.L2BlockNumber,
+			Timestamp:       genesisL2Block.Timestamp,
 			DeltaTimestamp:  0,
-			MinTimestamp:    0,
-			L1InfotreeIndex: 0,
-			Hash:            genesisL2Block.BlockHash.Bytes(),
-			StateRoot:       genesisL2Block.StateRoot.Bytes(),
-			GlobalExitRoot:  genesisL2Block.GlobalExitRoot.Bytes(),
-			Coinbase:        genesisL2Block.Coinbase.Bytes(),
+			L1InfoTreeIndex: 0,
+			GlobalExitRoot:  genesisL2Block.GlobalExitRoot,
+			Coinbase:        genesisL2Block.Coinbase,
+			ForkID:          genesisL2Block.ForkID,
+			ChainID:         uint32(chainID),
 		}
 
-		log.Debugf("Genesis block: %+v", genesisBlock)
-
-		marshalledGenesisBlock, err := proto.Marshal(genesisBlock)
-		if err != nil {
-			return err
-		}
+		log.Infof("Genesis block: %+v", genesisBlock)
 
-		_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK), marshalledGenesisBlock)
+		_, err = streamServer.AddStreamEntry(1, genesisBlock.Encode())
 		if err != nil {
 			return err
 		}
 
-		genesisBatch := &datastream.Batch{
-			Number:        genesisL2Block.BatchNumber,
-			LocalExitRoot: common.Hash{}.Bytes(),
-			StateRoot:     genesisL2Block.StateRoot.Bytes(),
-			ForkId:        genesisL2Block.ForkID,
-			ChainId:       chainID,
-		}
-
-		marshalledGenesisBatch, err := proto.Marshal(genesisBatch)
-		if err != nil {
-			return err
+		genesisBlockEnd := DSL2BlockEnd{
+			L2BlockNumber: genesisL2Block.L2BlockNumber,
+			BlockHash:     genesisL2Block.BlockHash,
+			StateRoot:     genesisL2Block.StateRoot,
 		}
 
-		_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH), marshalledGenesisBatch)
+		_, err = streamServer.AddStreamEntry(EntryTypeL2BlockEnd, genesisBlockEnd.Encode())
 		if err != nil {
 			return err
 		}
@@ -189,88 +325,35 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 		log.Infof("Latest entry: %+v", latestEntry)
 
 		switch latestEntry.Type {
-		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH):
-			log.Info("Latest entry type is Batch")
-
-			batch := &datastream.Batch{}
-			if err := proto.Unmarshal(latestEntry.Data, batch); err != nil {
-				return err
-			}
-
-			currentBatchNumber = batch.Number
-			currentBatchNumber++
-		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER):
+		case EntryTypeUpdateGER:
 			log.Info("Latest entry type is UpdateGER")
-
-			updateGer := &datastream.UpdateGER{}
-			if err := proto.Unmarshal(latestEntry.Data, updateGer); err != nil {
-				return err
-			}
-
-			currentBatchNumber = updateGer.BatchNumber
+			currentBatchNumber = binary.BigEndian.Uint64(latestEntry.Data[0:8])
 			currentBatchNumber++
-		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK):
-			log.Info("Latest entry type is L2Block")
-
-			l2Block := &datastream.L2Block{}
-
-			if err := proto.Unmarshal(latestEntry.Data, l2Block); err != nil {
-				return err
-			}
-
-			currentL2BlockNumber := l2Block.Number
-			currentBatchNumber = l2Block.BatchNumber
-			previousTimestamp = l2Block.Timestamp
-			lastAddedL2BlockNumber = currentL2BlockNumber
-		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION):
-			log.Info("Latest entry type is Transaction")
-
-			transaction := &datastream.Transaction{}
-			if err := proto.Unmarshal(latestEntry.Data, transaction); err != nil {
-				return err
-			}
-
-			currentL2BlockNumber := transaction.L2BlockNumber
-			currentBatchNumber = transaction.L2BlockNumber
-			lastAddedL2BlockNumber = currentL2BlockNumber
-
-			// Get Previous l2block timestamp
-			bookMark := &datastream.BookMark{
-				Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
-				Value: currentL2BlockNumber - 1,
-			}
-
-			marshalledBookMark, err := proto.Marshal(bookMark)
-			if err != nil {
-				return err
-			}
-
-			prevL2BlockEntryNumber, err := streamServer.GetBookmark(marshalledBookMark)
-			if err != nil {
-				return err
+		case EntryTypeL2BlockEnd:
+			log.Info("Latest entry type is L2BlockEnd")
+			blockEnd := DSL2BlockEnd{}.Decode(latestEntry.Data)
+			currentL2BlockNumber := blockEnd.L2BlockNumber
+
+			bookMark := DSBookMark{
+				Type:  BookMarkTypeL2Block,
+				Value: currentL2BlockNumber,
 			}
 
-			prevL2BlockEntry, err := streamServer.GetEntry(prevL2BlockEntryNumber)
+			firstEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
 			if err != nil {
 				return err
 			}
 
-			prevL2Block := &datastream.L2Block{}
-			if err := proto.Unmarshal(prevL2BlockEntry.Data, prevL2Block); err != nil {
-				return err
-			}
-
-			previousTimestamp = prevL2Block.Timestamp
+			blockStart := DSL2BlockStart{}.Decode(firstEntry.Data)
 
+			currentBatchNumber = blockStart.BatchNumber
+			previousTimestamp = blockStart.Timestamp
+			lastAddedL2BlockNumber = currentL2BlockNumber
 		case EntryTypeBookMark:
 			log.Info("Latest entry type is BookMark")
-
-			bookMark := &datastream.BookMark{}
-			if err := proto.Unmarshal(latestEntry.Data, bookMark); err != nil {
-				return err
-			}
-
-			if bookMark.Type == datastream.BookmarkType_BOOKMARK_TYPE_BATCH {
+			bookMark := DSBookMark{}
+			bookMark = bookMark.Decode(latestEntry.Data)
+			if bookMark.Type == BookMarkTypeBatch {
 				currentBatchNumber = bookMark.Value
 			} else {
 				log.Fatalf("Latest entry type is an unexpected bookmark type: %v", bookMark.Type)
@@ -341,26 +424,21 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 				return err
 			}
 
-			bookMark := &datastream.BookMark{
-				Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
+			bookMark := DSBookMark{
+				Type:  BookMarkTypeBatch,
 				Value: batch.BatchNumber,
 			}
 
-			marshalledBookMark, err := proto.Marshal(bookMark)
-			if err != nil {
-				return err
-			}
-
 			missingBatchBookMark := true
 			if b == 0 {
-				_, err = streamServer.GetBookmark(marshalledBookMark)
+				_, err = streamServer.GetBookmark(bookMark.Encode())
 				if err == nil {
 					missingBatchBookMark = false
 				}
 			}
 
 			if missingBatchBookMark {
-				_, err = streamServer.AddStreamBookmark(marshalledBookMark)
+				_, err = streamServer.AddStreamBookmark(bookMark.Encode())
 				if err != nil {
 					return err
 				}
@@ -370,22 +448,17 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 				// Empty batch
 				// Check if there is a GER update
 				if batch.GlobalExitRoot != currentGER && batch.GlobalExitRoot != (common.Hash{}) {
-					updateGER := &datastream.UpdateGER{
+					updateGer := DSUpdateGER{
 						BatchNumber:    batch.BatchNumber,
-						Timestamp:      uint64(batch.Timestamp.Unix()),
-						GlobalExitRoot: batch.GlobalExitRoot.Bytes(),
-						Coinbase:       batch.Coinbase.Bytes(),
-						ForkId:         batch.ForkID,
-						ChainId:        chainID,
-						StateRoot:      batch.StateRoot.Bytes(),
-					}
-
-					marshalledUpdateGER, err := proto.Marshal(updateGER)
-					if err != nil {
-						return err
+						Timestamp:      batch.Timestamp.Unix(),
+						GlobalExitRoot: batch.GlobalExitRoot,
+						Coinbase:       batch.Coinbase,
+						ForkID:         batch.ForkID,
+						ChainID:        uint32(chainID),
+						StateRoot:      batch.StateRoot,
 					}
 
-					_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER), marshalledUpdateGER)
+					_, err = streamServer.AddStreamEntry(EntryTypeUpdateGER, updateGer.Encode())
 					if err != nil {
 						return err
 					}
@@ -444,57 +517,38 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 						}
 					}
 
-					streamL2Block := &datastream.L2Block{
-						Number:          l2Block.L2BlockNumber,
+					blockStart := DSL2BlockStart{
 						BatchNumber:     l2Block.BatchNumber,
+						L2BlockNumber:   l2Block.L2BlockNumber,
 						Timestamp:       l2Block.Timestamp,
 						DeltaTimestamp:  uint32(l2Block.Timestamp - previousTimestamp),
-						MinTimestamp:    uint64(batch.Timestamp.Unix()),
-						L1Blockhash:     l1BlockHash.Bytes(),
-						L1InfotreeIndex: l1InfoTreeIndex,
-						Hash:            l2Block.BlockHash.Bytes(),
-						StateRoot:       l2Block.StateRoot.Bytes(),
-						GlobalExitRoot:  l2Block.GlobalExitRoot.Bytes(),
-						Coinbase:        l2Block.Coinbase.Bytes(),
-					}
-
-					if l2Block.ForkID >= FORKID_ETROG {
-						streamL2Block.Hash = l2Block.StateRoot.Bytes()
-					}
-
-					if l2Block.ForkID == FORKID_ETROG && batch.EtrogTimestamp != nil {
-						streamL2Block.MinTimestamp = uint64(batch.EtrogTimestamp.Unix())
+						L1InfoTreeIndex: l1InfoTreeIndex,
+						L1BlockHash:     l1BlockHash,
+						GlobalExitRoot:  l2Block.GlobalExitRoot,
+						Coinbase:        l2Block.Coinbase,
+						ForkID:          l2Block.ForkID,
+						ChainID:         uint32(chainID),
 					}
 
 					previousTimestamp = l2Block.Timestamp
 
-					bookMark := &datastream.BookMark{
-						Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
-						Value: streamL2Block.Number,
-					}
-
-					marshalledBookMark, err := proto.Marshal(bookMark)
-					if err != nil {
-						return err
+					bookMark := DSBookMark{
+						Type:  BookMarkTypeL2Block,
+						Value: blockStart.L2BlockNumber,
 					}
 
 					// Check if l2 block was already added
-					_, err = streamServer.GetBookmark(marshalledBookMark)
+					_, err = streamServer.GetBookmark(bookMark.Encode())
 					if err == nil {
 						continue
 					}
 
-					_, err = streamServer.AddStreamBookmark(marshalledBookMark)
-					if err != nil {
-						return err
-					}
-
-					marshalledL2Block, err := proto.Marshal(streamL2Block)
+					_, err = streamServer.AddStreamBookmark(bookMark.Encode())
 					if err != nil {
 						return err
 					}
 
-					_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK), marshalledL2Block)
+					_, err = streamServer.AddStreamEntry(EntryTypeL2BlockStart, blockStart.Encode())
 					if err != nil {
 						return err
 					}
@@ -505,7 +559,7 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 						// > 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)[streamL2Block.Number] == nil {
+							if imStateRoots == nil || (*imStateRoots)[blockStart.L2BlockNumber] == nil {
 								position := GetSystemSCPosition(l2Block.L2BlockNumber)
 								imStateRoot, err := stateDB.GetStorageAt(ctx, common.HexToAddress(SystemSC), big.NewInt(0).SetBytes(position), l2Block.StateRoot)
 								if err != nil {
@@ -513,53 +567,35 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 								}
 								tx.StateRoot = common.BigToHash(imStateRoot)
 							} else {
-								tx.StateRoot = common.BytesToHash((*imStateRoots)[streamL2Block.Number])
+								tx.StateRoot = common.BytesToHash((*imStateRoots)[blockStart.L2BlockNumber])
 							}
 						} else if l2Block.ForkID > FORKID_ETROG {
 							tx.StateRoot = tx.ImStateRoot
 						}
 
-						transaction := &datastream.Transaction{
-							L2BlockNumber:               tx.L2BlockNumber,
-							IsValid:                     tx.IsValid != 0,
-							Encoded:                     tx.Encoded,
-							EffectiveGasPricePercentage: uint32(tx.EffectiveGasPricePercentage),
-							ImStateRoot:                 tx.StateRoot.Bytes(),
-						}
-
-						marshalledTransaction, err := proto.Marshal(transaction)
+						_, err = streamServer.AddStreamEntry(EntryTypeL2Tx, tx.Encode())
 						if err != nil {
 							return err
 						}
+					}
 
-						_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION), marshalledTransaction)
-						if err != nil {
-							return err
-						}
+					blockEnd := DSL2BlockEnd{
+						L2BlockNumber: l2Block.L2BlockNumber,
+						BlockHash:     l2Block.BlockHash,
+						StateRoot:     l2Block.StateRoot,
 					}
 
+					if l2Block.ForkID >= FORKID_ETROG {
+						blockEnd.BlockHash = l2Block.StateRoot
+					}
+
+					_, err = streamServer.AddStreamEntry(EntryTypeL2BlockEnd, blockEnd.Encode())
+					if err != nil {
+						return err
+					}
 					currentGER = l2Block.GlobalExitRoot
 				}
 			}
-
-			batch := &datastream.Batch{
-				Number:        batch.BatchNumber,
-				LocalExitRoot: batch.LocalExitRoot.Bytes(),
-				StateRoot:     batch.StateRoot.Bytes(),
-				ForkId:        batch.ForkID,
-				ChainId:       chainID,
-			}
-
-			marshalledBatch, err := proto.Marshal(batch)
-			if err != nil {
-				return err
-			}
-
-			_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH), marshalledBatch)
-			if err != nil {
-				return err
-			}
-
 			// Commit at the end of each batch group
 			err = streamServer.CommitAtomicOp()
 			if err != nil {
diff --git a/state/datastream/datastream.pb.go b/state/datastream/datastream.pb.go
deleted file mode 100644
index 1f0ede74fc..0000000000
--- a/state/datastream/datastream.pb.go
+++ /dev/null
@@ -1,773 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// 	protoc-gen-go v1.32.0
-// 	protoc        v4.25.3
-// source: datastream.proto
-
-package datastream
-
-import (
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	reflect "reflect"
-	sync "sync"
-)
-
-const (
-	// Verify that this generated code is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
-	// Verify that runtime/protoimpl is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type BookmarkType int32
-
-const (
-	BookmarkType_BOOKMARK_TYPE_UNSPECIFIED BookmarkType = 0
-	BookmarkType_BOOKMARK_TYPE_BATCH       BookmarkType = 1
-	BookmarkType_BOOKMARK_TYPE_L2_BLOCK    BookmarkType = 2
-)
-
-// Enum value maps for BookmarkType.
-var (
-	BookmarkType_name = map[int32]string{
-		0: "BOOKMARK_TYPE_UNSPECIFIED",
-		1: "BOOKMARK_TYPE_BATCH",
-		2: "BOOKMARK_TYPE_L2_BLOCK",
-	}
-	BookmarkType_value = map[string]int32{
-		"BOOKMARK_TYPE_UNSPECIFIED": 0,
-		"BOOKMARK_TYPE_BATCH":       1,
-		"BOOKMARK_TYPE_L2_BLOCK":    2,
-	}
-)
-
-func (x BookmarkType) Enum() *BookmarkType {
-	p := new(BookmarkType)
-	*p = x
-	return p
-}
-
-func (x BookmarkType) String() string {
-	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (BookmarkType) Descriptor() protoreflect.EnumDescriptor {
-	return file_datastream_proto_enumTypes[0].Descriptor()
-}
-
-func (BookmarkType) Type() protoreflect.EnumType {
-	return &file_datastream_proto_enumTypes[0]
-}
-
-func (x BookmarkType) Number() protoreflect.EnumNumber {
-	return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use BookmarkType.Descriptor instead.
-func (BookmarkType) EnumDescriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{0}
-}
-
-type EntryType int32
-
-const (
-	EntryType_ENTRY_TYPE_UNSPECIFIED EntryType = 0
-	EntryType_ENTRY_TYPE_BATCH       EntryType = 1
-	EntryType_ENTRY_TYPE_L2_BLOCK    EntryType = 2
-	EntryType_ENTRY_TYPE_TRANSACTION EntryType = 3
-	EntryType_ENTRY_TYPE_UPDATE_GER  EntryType = 4
-)
-
-// Enum value maps for EntryType.
-var (
-	EntryType_name = map[int32]string{
-		0: "ENTRY_TYPE_UNSPECIFIED",
-		1: "ENTRY_TYPE_BATCH",
-		2: "ENTRY_TYPE_L2_BLOCK",
-		3: "ENTRY_TYPE_TRANSACTION",
-		4: "ENTRY_TYPE_UPDATE_GER",
-	}
-	EntryType_value = map[string]int32{
-		"ENTRY_TYPE_UNSPECIFIED": 0,
-		"ENTRY_TYPE_BATCH":       1,
-		"ENTRY_TYPE_L2_BLOCK":    2,
-		"ENTRY_TYPE_TRANSACTION": 3,
-		"ENTRY_TYPE_UPDATE_GER":  4,
-	}
-)
-
-func (x EntryType) Enum() *EntryType {
-	p := new(EntryType)
-	*p = x
-	return p
-}
-
-func (x EntryType) String() string {
-	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (EntryType) Descriptor() protoreflect.EnumDescriptor {
-	return file_datastream_proto_enumTypes[1].Descriptor()
-}
-
-func (EntryType) Type() protoreflect.EnumType {
-	return &file_datastream_proto_enumTypes[1]
-}
-
-func (x EntryType) Number() protoreflect.EnumNumber {
-	return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Use EntryType.Descriptor instead.
-func (EntryType) EnumDescriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{1}
-}
-
-type Batch struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Number        uint64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
-	LocalExitRoot []byte `protobuf:"bytes,2,opt,name=local_exit_root,json=localExitRoot,proto3" json:"local_exit_root,omitempty"`
-	StateRoot     []byte `protobuf:"bytes,3,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
-	ForkId        uint64 `protobuf:"varint,4,opt,name=fork_id,json=forkId,proto3" json:"fork_id,omitempty"`
-	ChainId       uint64 `protobuf:"varint,5,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
-}
-
-func (x *Batch) Reset() {
-	*x = Batch{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[0]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *Batch) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Batch) ProtoMessage() {}
-
-func (x *Batch) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[0]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use Batch.ProtoReflect.Descriptor instead.
-func (*Batch) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Batch) GetNumber() uint64 {
-	if x != nil {
-		return x.Number
-	}
-	return 0
-}
-
-func (x *Batch) GetLocalExitRoot() []byte {
-	if x != nil {
-		return x.LocalExitRoot
-	}
-	return nil
-}
-
-func (x *Batch) GetStateRoot() []byte {
-	if x != nil {
-		return x.StateRoot
-	}
-	return nil
-}
-
-func (x *Batch) GetForkId() uint64 {
-	if x != nil {
-		return x.ForkId
-	}
-	return 0
-}
-
-func (x *Batch) GetChainId() uint64 {
-	if x != nil {
-		return x.ChainId
-	}
-	return 0
-}
-
-type L2Block struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Number          uint64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
-	BatchNumber     uint64 `protobuf:"varint,2,opt,name=batch_number,json=batchNumber,proto3" json:"batch_number,omitempty"`
-	Timestamp       uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
-	DeltaTimestamp  uint32 `protobuf:"varint,4,opt,name=delta_timestamp,json=deltaTimestamp,proto3" json:"delta_timestamp,omitempty"`
-	MinTimestamp    uint64 `protobuf:"varint,5,opt,name=min_timestamp,json=minTimestamp,proto3" json:"min_timestamp,omitempty"`
-	L1Blockhash     []byte `protobuf:"bytes,6,opt,name=l1_blockhash,json=l1Blockhash,proto3" json:"l1_blockhash,omitempty"`
-	L1InfotreeIndex uint32 `protobuf:"varint,7,opt,name=l1_infotree_index,json=l1InfotreeIndex,proto3" json:"l1_infotree_index,omitempty"`
-	Hash            []byte `protobuf:"bytes,8,opt,name=hash,proto3" json:"hash,omitempty"`
-	StateRoot       []byte `protobuf:"bytes,9,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
-	GlobalExitRoot  []byte `protobuf:"bytes,10,opt,name=global_exit_root,json=globalExitRoot,proto3" json:"global_exit_root,omitempty"`
-	Coinbase        []byte `protobuf:"bytes,11,opt,name=coinbase,proto3" json:"coinbase,omitempty"`
-}
-
-func (x *L2Block) Reset() {
-	*x = L2Block{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[1]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *L2Block) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*L2Block) ProtoMessage() {}
-
-func (x *L2Block) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[1]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use L2Block.ProtoReflect.Descriptor instead.
-func (*L2Block) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *L2Block) GetNumber() uint64 {
-	if x != nil {
-		return x.Number
-	}
-	return 0
-}
-
-func (x *L2Block) GetBatchNumber() uint64 {
-	if x != nil {
-		return x.BatchNumber
-	}
-	return 0
-}
-
-func (x *L2Block) GetTimestamp() uint64 {
-	if x != nil {
-		return x.Timestamp
-	}
-	return 0
-}
-
-func (x *L2Block) GetDeltaTimestamp() uint32 {
-	if x != nil {
-		return x.DeltaTimestamp
-	}
-	return 0
-}
-
-func (x *L2Block) GetMinTimestamp() uint64 {
-	if x != nil {
-		return x.MinTimestamp
-	}
-	return 0
-}
-
-func (x *L2Block) GetL1Blockhash() []byte {
-	if x != nil {
-		return x.L1Blockhash
-	}
-	return nil
-}
-
-func (x *L2Block) GetL1InfotreeIndex() uint32 {
-	if x != nil {
-		return x.L1InfotreeIndex
-	}
-	return 0
-}
-
-func (x *L2Block) GetHash() []byte {
-	if x != nil {
-		return x.Hash
-	}
-	return nil
-}
-
-func (x *L2Block) GetStateRoot() []byte {
-	if x != nil {
-		return x.StateRoot
-	}
-	return nil
-}
-
-func (x *L2Block) GetGlobalExitRoot() []byte {
-	if x != nil {
-		return x.GlobalExitRoot
-	}
-	return nil
-}
-
-func (x *L2Block) GetCoinbase() []byte {
-	if x != nil {
-		return x.Coinbase
-	}
-	return nil
-}
-
-type Transaction struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	L2BlockNumber               uint64 `protobuf:"varint,1,opt,name=l2block_number,json=l2blockNumber,proto3" json:"l2block_number,omitempty"`
-	IsValid                     bool   `protobuf:"varint,2,opt,name=is_valid,json=isValid,proto3" json:"is_valid,omitempty"`
-	Encoded                     []byte `protobuf:"bytes,3,opt,name=encoded,proto3" json:"encoded,omitempty"`
-	EffectiveGasPricePercentage uint32 `protobuf:"varint,4,opt,name=effective_gas_price_percentage,json=effectiveGasPricePercentage,proto3" json:"effective_gas_price_percentage,omitempty"`
-	ImStateRoot                 []byte `protobuf:"bytes,5,opt,name=im_state_root,json=imStateRoot,proto3" json:"im_state_root,omitempty"`
-}
-
-func (x *Transaction) Reset() {
-	*x = Transaction{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[2]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *Transaction) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Transaction) ProtoMessage() {}
-
-func (x *Transaction) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[2]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use Transaction.ProtoReflect.Descriptor instead.
-func (*Transaction) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *Transaction) GetL2BlockNumber() uint64 {
-	if x != nil {
-		return x.L2BlockNumber
-	}
-	return 0
-}
-
-func (x *Transaction) GetIsValid() bool {
-	if x != nil {
-		return x.IsValid
-	}
-	return false
-}
-
-func (x *Transaction) GetEncoded() []byte {
-	if x != nil {
-		return x.Encoded
-	}
-	return nil
-}
-
-func (x *Transaction) GetEffectiveGasPricePercentage() uint32 {
-	if x != nil {
-		return x.EffectiveGasPricePercentage
-	}
-	return 0
-}
-
-func (x *Transaction) GetImStateRoot() []byte {
-	if x != nil {
-		return x.ImStateRoot
-	}
-	return nil
-}
-
-type UpdateGER struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	BatchNumber    uint64 `protobuf:"varint,1,opt,name=batch_number,json=batchNumber,proto3" json:"batch_number,omitempty"`
-	Timestamp      uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
-	GlobalExitRoot []byte `protobuf:"bytes,3,opt,name=global_exit_root,json=globalExitRoot,proto3" json:"global_exit_root,omitempty"`
-	Coinbase       []byte `protobuf:"bytes,4,opt,name=coinbase,proto3" json:"coinbase,omitempty"`
-	ForkId         uint64 `protobuf:"varint,5,opt,name=fork_id,json=forkId,proto3" json:"fork_id,omitempty"`
-	ChainId        uint64 `protobuf:"varint,6,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
-	StateRoot      []byte `protobuf:"bytes,7,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"`
-}
-
-func (x *UpdateGER) Reset() {
-	*x = UpdateGER{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[3]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *UpdateGER) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*UpdateGER) ProtoMessage() {}
-
-func (x *UpdateGER) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[3]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use UpdateGER.ProtoReflect.Descriptor instead.
-func (*UpdateGER) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *UpdateGER) GetBatchNumber() uint64 {
-	if x != nil {
-		return x.BatchNumber
-	}
-	return 0
-}
-
-func (x *UpdateGER) GetTimestamp() uint64 {
-	if x != nil {
-		return x.Timestamp
-	}
-	return 0
-}
-
-func (x *UpdateGER) GetGlobalExitRoot() []byte {
-	if x != nil {
-		return x.GlobalExitRoot
-	}
-	return nil
-}
-
-func (x *UpdateGER) GetCoinbase() []byte {
-	if x != nil {
-		return x.Coinbase
-	}
-	return nil
-}
-
-func (x *UpdateGER) GetForkId() uint64 {
-	if x != nil {
-		return x.ForkId
-	}
-	return 0
-}
-
-func (x *UpdateGER) GetChainId() uint64 {
-	if x != nil {
-		return x.ChainId
-	}
-	return 0
-}
-
-func (x *UpdateGER) GetStateRoot() []byte {
-	if x != nil {
-		return x.StateRoot
-	}
-	return nil
-}
-
-type BookMark struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Type  BookmarkType `protobuf:"varint,1,opt,name=type,proto3,enum=datastream.v1.BookmarkType" json:"type,omitempty"`
-	Value uint64       `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
-}
-
-func (x *BookMark) Reset() {
-	*x = BookMark{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[4]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *BookMark) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*BookMark) ProtoMessage() {}
-
-func (x *BookMark) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[4]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use BookMark.ProtoReflect.Descriptor instead.
-func (*BookMark) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{4}
-}
-
-func (x *BookMark) GetType() BookmarkType {
-	if x != nil {
-		return x.Type
-	}
-	return BookmarkType_BOOKMARK_TYPE_UNSPECIFIED
-}
-
-func (x *BookMark) GetValue() uint64 {
-	if x != nil {
-		return x.Value
-	}
-	return 0
-}
-
-var File_datastream_proto protoreflect.FileDescriptor
-
-var file_datastream_proto_rawDesc = []byte{
-	0x0a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x12, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76,
-	0x31, 0x22, 0x9a, 0x01, 0x0a, 0x05, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6e,
-	0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d,
-	0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69,
-	0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, 0x6f,
-	0x63, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
-	0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
-	0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6f,
-	0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x66, 0x6f, 0x72,
-	0x6b, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18,
-	0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0xf8,
-	0x02, 0x0a, 0x07, 0x4c, 0x32, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75,
-	0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62,
-	0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x75, 0x6d, 0x62,
-	0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4e,
-	0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
-	0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
-	0x61, 0x6d, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x74, 0x69, 0x6d,
-	0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x64, 0x65,
-	0x6c, 0x74, 0x61, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x23, 0x0a, 0x0d,
-	0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20,
-	0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
-	0x70, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x31, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x68, 0x61, 0x73,
-	0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6c, 0x31, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
-	0x68, 0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x31, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x74,
-	0x72, 0x65, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52,
-	0x0f, 0x6c, 0x31, 0x49, 0x6e, 0x66, 0x6f, 0x74, 0x72, 0x65, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78,
-	0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
-	0x68, 0x61, 0x73, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f,
-	0x6f, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52,
-	0x6f, 0x6f, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78,
-	0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67,
-	0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a,
-	0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52,
-	0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0xd2, 0x01, 0x0a, 0x0b, 0x54, 0x72,
-	0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x32, 0x62,
-	0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x0d, 0x6c, 0x32, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
-	0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65,
-	0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e,
-	0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69,
-	0x76, 0x65, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72,
-	0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1b, 0x65,
-	0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65,
-	0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6d,
-	0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x0c, 0x52, 0x0b, 0x69, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0xe5,
-	0x01, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x45, 0x52, 0x12, 0x21, 0x0a, 0x0c,
-	0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12,
-	0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a,
-	0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f,
-	0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x45,
-	0x78, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62,
-	0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62,
-	0x61, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x05,
-	0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08,
-	0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07,
-	0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65,
-	0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61,
-	0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x51, 0x0a, 0x08, 0x42, 0x6f, 0x6f, 0x6b, 0x4d, 0x61,
-	0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x1b, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31,
-	0x2e, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
-	0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x62, 0x0a, 0x0c, 0x42, 0x6f, 0x6f,
-	0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x4f, 0x4f,
-	0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
-	0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x42, 0x4f, 0x4f, 0x4b,
-	0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x10,
-	0x01, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59,
-	0x50, 0x45, 0x5f, 0x4c, 0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x2a, 0x8d, 0x01,
-	0x0a, 0x09, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x45,
-	0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
-	0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x4e, 0x54, 0x52, 0x59,
-	0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x10, 0x01, 0x12, 0x17, 0x0a,
-	0x13, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x32, 0x5f, 0x42,
-	0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f,
-	0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e,
-	0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45,
-	0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x47, 0x45, 0x52, 0x10, 0x04, 0x42, 0x38, 0x5a,
-	0x36, 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, 0x64, 0x61, 0x74,
-	0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
-	file_datastream_proto_rawDescOnce sync.Once
-	file_datastream_proto_rawDescData = file_datastream_proto_rawDesc
-)
-
-func file_datastream_proto_rawDescGZIP() []byte {
-	file_datastream_proto_rawDescOnce.Do(func() {
-		file_datastream_proto_rawDescData = protoimpl.X.CompressGZIP(file_datastream_proto_rawDescData)
-	})
-	return file_datastream_proto_rawDescData
-}
-
-var file_datastream_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
-var file_datastream_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
-var file_datastream_proto_goTypes = []interface{}{
-	(BookmarkType)(0),   // 0: datastream.v1.BookmarkType
-	(EntryType)(0),      // 1: datastream.v1.EntryType
-	(*Batch)(nil),       // 2: datastream.v1.Batch
-	(*L2Block)(nil),     // 3: datastream.v1.L2Block
-	(*Transaction)(nil), // 4: datastream.v1.Transaction
-	(*UpdateGER)(nil),   // 5: datastream.v1.UpdateGER
-	(*BookMark)(nil),    // 6: datastream.v1.BookMark
-}
-var file_datastream_proto_depIdxs = []int32{
-	0, // 0: datastream.v1.BookMark.type:type_name -> datastream.v1.BookmarkType
-	1, // [1:1] is the sub-list for method output_type
-	1, // [1:1] is the sub-list for method input_type
-	1, // [1:1] is the sub-list for extension type_name
-	1, // [1:1] is the sub-list for extension extendee
-	0, // [0:1] is the sub-list for field type_name
-}
-
-func init() { file_datastream_proto_init() }
-func file_datastream_proto_init() {
-	if File_datastream_proto != nil {
-		return
-	}
-	if !protoimpl.UnsafeEnabled {
-		file_datastream_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Batch); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-		file_datastream_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*L2Block); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-		file_datastream_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Transaction); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-		file_datastream_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*UpdateGER); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-		file_datastream_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*BookMark); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-	}
-	type x struct{}
-	out := protoimpl.TypeBuilder{
-		File: protoimpl.DescBuilder{
-			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_datastream_proto_rawDesc,
-			NumEnums:      2,
-			NumMessages:   5,
-			NumExtensions: 0,
-			NumServices:   0,
-		},
-		GoTypes:           file_datastream_proto_goTypes,
-		DependencyIndexes: file_datastream_proto_depIdxs,
-		EnumInfos:         file_datastream_proto_enumTypes,
-		MessageInfos:      file_datastream_proto_msgTypes,
-	}.Build()
-	File_datastream_proto = out.File
-	file_datastream_proto_rawDesc = nil
-	file_datastream_proto_goTypes = nil
-	file_datastream_proto_depIdxs = nil
-}
diff --git a/state/pgstatestorage/datastream.go b/state/pgstatestorage/datastream.go
index 31c9814c0a..4b15000aeb 100644
--- a/state/pgstatestorage/datastream.go
+++ b/state/pgstatestorage/datastream.go
@@ -78,7 +78,7 @@ func scanL2Block(row pgx.Row) (*state.DSL2Block, error) {
 	}
 	l2Block.GlobalExitRoot = common.HexToHash(gerStr)
 	l2Block.Coinbase = common.HexToAddress(coinbaseStr)
-	l2Block.Timestamp = uint64(timestamp.Unix())
+	l2Block.Timestamp = timestamp.Unix()
 	l2Block.BlockHash = common.HexToHash(blockHashStr)
 	l2Block.StateRoot = common.HexToHash(stateRootStr)
 
@@ -151,13 +151,9 @@ func scanDSL2Transaction(row pgx.Row) (*state.DSL2Transaction, error) {
 // GetDSBatches returns the DS batches
 func (p *PostgresStorage) GetDSBatches(ctx context.Context, firstBatchNumber, lastBatchNumber uint64, readWIPBatch bool, dbTx pgx.Tx) ([]*state.DSBatch, error) {
 	var getBatchByNumberSQL = `
-		SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data, b.forced_batch_num, b.wip, f.fork_id, vb.timestamp_batch_etrog
-		 FROM state.batch b
-		 LEFT JOIN 
-    		state.fork_id f ON b.batch_num BETWEEN f.from_batch_num AND f.to_batch_num
-		 LEFT JOIN 
-    		state.virtual_batch vb ON b.batch_num = vb.batch_num
-		 WHERE b.batch_num >= $1 AND b.batch_num <= $2`
+		SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data, b.forced_batch_num, b.wip, f.fork_id
+		  FROM state.batch b, state.fork_id f
+		 WHERE b.batch_num >= $1 AND b.batch_num <= $2 AND batch_num between f.from_batch_num AND f.to_batch_num`
 
 	if !readWIPBatch {
 		getBatchByNumberSQL += " AND b.wip is false"
@@ -209,7 +205,6 @@ func scanDSBatch(row pgx.Row) (state.DSBatch, error) {
 		&batch.ForcedBatchNum,
 		&batch.WIP,
 		&batch.ForkID,
-		&batch.EtrogTimestamp,
 	)
 	if err != nil {
 		return batch, err
diff --git a/state/test/datastream_test.go b/state/test/datastream_test.go
new file mode 100644
index 0000000000..8860cf9740
--- /dev/null
+++ b/state/test/datastream_test.go
@@ -0,0 +1,82 @@
+package test
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/0xPolygonHermez/zkevm-node/state"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestL2BlockStartEncode(t *testing.T) {
+	l2BlockStart := state.DSL2BlockStart{
+		BatchNumber:     1,
+		L2BlockNumber:   2,
+		Timestamp:       3,
+		DeltaTimestamp:  4,
+		L1InfoTreeIndex: 5,
+		L1BlockHash:     common.HexToHash("0x06"),
+		GlobalExitRoot:  common.HexToHash("0x07"),
+		Coinbase:        common.HexToAddress("0x08"),
+		ForkID:          9,
+		ChainID:         10,
+	}
+
+	encoded := l2BlockStart.Encode()
+	expected := []byte{
+		0, 0, 0, 0, 0, 0, 0, 1,
+		0, 0, 0, 0, 0, 0, 0, 2,
+		0, 0, 0, 0, 0, 0, 0, 3,
+		0, 0, 0, 4,
+		0, 0, 0, 5,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,
+		0, 9,
+		0, 0, 0, 10}
+
+	assert.Equal(t, expected, encoded)
+}
+
+func TestL2TransactionEncode(t *testing.T) {
+	l2Transaction := state.DSL2Transaction{
+		EffectiveGasPricePercentage: 128,                          // 1 byte
+		IsValid:                     1,                            // 1 byte
+		StateRoot:                   common.HexToHash("0x010203"), // 32 bytes
+		EncodedLength:               5,                            // 4 bytes
+		Encoded:                     []byte{1, 2, 3, 4, 5},        // 5 bytes
+	}
+
+	encoded := l2Transaction.Encode()
+	expected := []byte{128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 5, 1, 2, 3, 4, 5}
+	assert.Equal(t, expected, encoded)
+}
+
+func TestL2BlockEndEncode(t *testing.T) {
+	l2BlockEnd := state.DSL2BlockEnd{
+		L2BlockNumber: 1,                        // 8 bytes
+		BlockHash:     common.HexToHash("0x02"), // 32 bytes
+		StateRoot:     common.HexToHash("0x03"), // 32 bytes
+	}
+
+	encoded := l2BlockEnd.Encode()
+	expected := []byte{0, 0, 0, 0, 0, 0, 0, 1,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}
+
+	assert.Equal(t, expected, encoded)
+}
+
+func TestCalculateSCPosition(t *testing.T) {
+	a := time.Now()
+	blockNumber := uint64(2934867)
+	expected := common.HexToHash("0xaa93c484856be45716623765b429a967296594ca362e61e91d671fb422e0f744")
+	position := state.GetSystemSCPosition(blockNumber)
+	assert.Equal(t, expected, common.BytesToHash(position))
+	b := time.Now()
+
+	c := b.Sub(a)
+	fmt.Println(c)
+}
diff --git a/test/docker-compose.yml b/test/docker-compose.yml
index d24d4c9d1f..08dbc93431 100644
--- a/test/docker-compose.yml
+++ b/test/docker-compose.yml
@@ -514,12 +514,9 @@ services:
   zkevm-prover:
     container_name: zkevm-prover
     image: hermeznetwork/zkevm-prover:v6.0.0
-    platform: linux/amd64
     ports:
       - 50061:50061 # MT
       - 50071:50071 # Executor
-    environment:
-      - EXPERIMENTAL_DOCKER_DESKTOP_FORCE_QEMU=1
     volumes:
       - ./config/test.prover.config.json:/usr/src/app/config.json
     command: >
@@ -605,10 +602,7 @@ services:
 
   zkevm-permissionless-prover:
     container_name: zkevm-permissionless-prover
-    platform: linux/amd64
     image: hermeznetwork/zkevm-prover:v6.0.0
-    environment:
-      - EXPERIMENTAL_DOCKER_DESKTOP_FORCE_QEMU=1
     ports:
       # - 50058:50058 # Prover
       - 50059:50052 # Mock prover
diff --git a/tools/datastreamer/Makefile b/tools/datastreamer/Makefile
index e79b0cb1a8..5698417c34 100644
--- a/tools/datastreamer/Makefile
+++ b/tools/datastreamer/Makefile
@@ -6,14 +6,12 @@ check-go:
 
 # Targets that require the checks
 generate-file: check-go
+reprocess: check-go
 decode-entry-offline: check-go
 decode-l2block-offline: check-go
 decode-entry: check-go
 decode-l2block: check-go
-decode-batch: check-go
-decode-batch-offline: check-go
 truncate: check-go
-dump-batch: check-go
 
 arguments := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
 
@@ -29,10 +27,6 @@ decode-entry: ## Runs the tool to decode a given entry number
 decode-l2block: ## Runs the tool to decode a given L2 block
 	go run main.go decode-l2block -cfg config/tool.config.toml -l2block $(arguments)
 
-.PHONY: decode-batch
-decode-batch: ## Runs the tool to decode a given batch
-	go run main.go decode-batch -cfg config/tool.config.toml -batch $(arguments)
-
 .PHONY: decode-entry-offline
 decode-entry-offline: ## Runs the offline tool to decode a given entry number
 	go run main.go decode-entry-offline -cfg config/tool.config.toml -entry $(arguments)
@@ -41,21 +35,13 @@ decode-entry-offline: ## Runs the offline tool to decode a given entry number
 decode-l2block-offline: ## Runs the offline tool to decode a given L2 block
 	go run main.go decode-l2block-offline -cfg config/tool.config.toml -l2block $(arguments)
 
-.PHONY: decode-batch-offline
-decode-batch-offline: ## Runs the offline tool to decode a given batch
-	go run main.go decode-batch-offline -cfg config/tool.config.toml -batch $(arguments)
-
 .PHONY: truncate
 truncate: ## Runs the offline tool to truncate the stream file
 	go run main.go truncate -cfg config/tool.config.toml -entry $(arguments)
 
-.PHONY: dump-batch
-dump-batch: ## Runs the tool to dump a given batch to file
-	go run main.go dump-batch -cfg config/tool.config.toml -d -batch $(arguments)
-
-.PHONY: dump-batch-offline
-dump-batch-offline: ## Runs the tool to dump a given batch to file offline
-	go run main.go dump-batch-offline -cfg config/tool.config.toml -d -batch $(arguments)
+# .PHONY: reprocess
+reprocess: ## Runs the tool to reprocess the information in the stream since a given l2 block
+	go run main.go reprocess -cfg config/tool.config.toml -genesis ../test/config/test.genesis.config.json -l2block $(arguments)
 
 ## Help display.
 ## Pulls comments from beside commands and prints a nicely formatted
diff --git a/tools/datastreamer/config/tool.config.toml b/tools/datastreamer/config/tool.config.toml
index 0671438dcb..c497f3362f 100644
--- a/tools/datastreamer/config/tool.config.toml
+++ b/tools/datastreamer/config/tool.config.toml
@@ -5,7 +5,7 @@ StreamType = 1
 [Offline]
 Port = 6901
 Filename = "datastream.bin"
-Version = 3
+Version = 1
 ChainID = 1440
 UpgradeEtrogBatchNumber = 0
 
@@ -18,6 +18,10 @@ Port = "5432"
 EnableLog = false
 MaxConns = 200
 
+[Executor]
+URI = "zkevm-prover:50071"
+MaxGRPCMessageSize = 100000000
+
 [MerkleTree]
 URI = "zkevm-prover:50061"
 MaxThreads = 20
diff --git a/tools/datastreamer/main.go b/tools/datastreamer/main.go
index bb84aeebf3..975e4c7ecd 100644
--- a/tools/datastreamer/main.go
+++ b/tools/datastreamer/main.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"context"
+	"encoding/binary"
 	"encoding/json"
 	"fmt"
 	"math/big"
@@ -11,16 +12,19 @@ import (
 
 	"github.com/0xPolygonHermez/zkevm-data-streamer/datastreamer"
 	"github.com/0xPolygonHermez/zkevm-data-streamer/log"
+	nodeConfig "github.com/0xPolygonHermez/zkevm-node/config"
 	"github.com/0xPolygonHermez/zkevm-node/db"
+	"github.com/0xPolygonHermez/zkevm-node/encoding"
+	"github.com/0xPolygonHermez/zkevm-node/hex"
 	"github.com/0xPolygonHermez/zkevm-node/merkletree"
 	"github.com/0xPolygonHermez/zkevm-node/state"
-	"github.com/0xPolygonHermez/zkevm-node/state/datastream"
 	"github.com/0xPolygonHermez/zkevm-node/state/pgstatestorage"
+	"github.com/0xPolygonHermez/zkevm-node/state/runtime/executor"
 	"github.com/0xPolygonHermez/zkevm-node/tools/datastreamer/config"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/fatih/color"
+	"github.com/google/uuid"
 	"github.com/urfave/cli/v2"
-	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -37,6 +41,14 @@ var (
 		Required:    true,
 	}
 
+	genesisFileFlag = cli.StringFlag{
+		Name:        config.FlagGenesis,
+		Aliases:     []string{"g"},
+		Usage:       "Genesis `FILE`",
+		DefaultText: "./config/genesis.json",
+		Required:    true,
+	}
+
 	entryFlag = cli.Uint64Flag{
 		Name:     "entry",
 		Aliases:  []string{"e"},
@@ -51,17 +63,10 @@ var (
 		Required: true,
 	}
 
-	batchFlag = cli.Uint64Flag{
-		Name:     "batch",
-		Aliases:  []string{"bn"},
-		Usage:    "Batch `NUMBER`",
-		Required: true,
-	}
-
-	dumpFlag = cli.BoolFlag{
-		Name:     "dump",
-		Aliases:  []string{"d"},
-		Usage:    "Dump batch to file",
+	updateFileFlag = cli.BoolFlag{
+		Name:     "update",
+		Aliases:  []string{"u"},
+		Usage:    "Update `FILE`",
 		Required: false,
 	}
 )
@@ -81,6 +86,18 @@ func main() {
 				&configFileFlag,
 			},
 		},
+		{
+			Name:    "reprocess",
+			Aliases: []string{},
+			Usage:   "Reprocess l2block since a given l2block number",
+			Action:  reprocess,
+			Flags: []cli.Flag{
+				&configFileFlag,
+				&genesisFileFlag,
+				&l2blockFlag,
+				&updateFileFlag,
+			},
+		},
 		{
 			Name:    "decode-entry-offline",
 			Aliases: []string{},
@@ -101,16 +118,6 @@ func main() {
 				&l2blockFlag,
 			},
 		},
-		{
-			Name:    "decode-batch-offline",
-			Aliases: []string{},
-			Usage:   "Decodes a batch offline",
-			Action:  decodeBatchOffline,
-			Flags: []cli.Flag{
-				&configFileFlag,
-				&batchFlag,
-			},
-		},
 		{
 			Name:    "decode-entry",
 			Aliases: []string{},
@@ -131,16 +138,6 @@ func main() {
 				&l2blockFlag,
 			},
 		},
-		{
-			Name:    "decode-batch",
-			Aliases: []string{},
-			Usage:   "Decodes a batch",
-			Action:  decodeBatch,
-			Flags: []cli.Flag{
-				&configFileFlag,
-				&batchFlag,
-			},
-		},
 		{
 			Name:    "truncate",
 			Aliases: []string{},
@@ -151,28 +148,6 @@ func main() {
 				&entryFlag,
 			},
 		},
-		{
-			Name:    "dump-batch",
-			Aliases: []string{},
-			Usage:   "Dumps a batch to file",
-			Action:  decodeBatch,
-			Flags: []cli.Flag{
-				&configFileFlag,
-				&batchFlag,
-				&dumpFlag,
-			},
-		},
-		{
-			Name:    "dump-batch-offline",
-			Aliases: []string{},
-			Usage:   "Dumps a batch to file offline",
-			Action:  decodeBatchOffline,
-			Flags: []cli.Flag{
-				&configFileFlag,
-				&batchFlag,
-				&dumpFlag,
-			},
-		},
 	}
 
 	err := app.Run(os.Args)
@@ -297,7 +272,7 @@ func generate(cliCtx *cli.Context) error {
 		}
 	}
 
-	err = state.GenerateDataStreamFile(cliCtx.Context, streamServer, stateDB, false, &imStateRoots, c.Offline.ChainID, c.Offline.UpgradeEtrogBatchNumber)
+	err = state.GenerateDataStreamerFile(cliCtx.Context, streamServer, stateDB, false, &imStateRoots, c.Offline.ChainID, c.Offline.UpgradeEtrogBatchNumber) // nolint:gomnd
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
@@ -324,18 +299,13 @@ func getImStateRoots(ctx context.Context, start, end uint64, isStateRoots *map[u
 			log.Errorf("Error: %v\n", err)
 			os.Exit(1)
 		}
-
-		if common.BytesToHash(imStateRoot.Bytes()) == state.ZeroHash && x != 0 {
-			break
-		}
-
 		imStateRootMux.Lock()
 		(*isStateRoots)[x] = imStateRoot.Bytes()
 		imStateRootMux.Unlock()
 	}
 }
 
-func decodeEntry(cliCtx *cli.Context) error {
+func reprocess(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -344,90 +314,230 @@ func decodeEntry(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
-	}
+	ctx := cliCtx.Context
 
-	err = client.Start()
+	genesisFileAsStr, err := nodeConfig.LoadGenesisFileAsString(cliCtx.String(config.FlagGenesis))
 	if err != nil {
-		log.Error(err)
+		fmt.Printf("failed to load genesis file. Error: %v", err)
 		os.Exit(1)
 	}
 
-	entry, err := client.ExecCommandGetEntry(cliCtx.Uint64("entry"))
+	networkConfig, err := nodeConfig.LoadGenesisFromJSONString(genesisFileAsStr)
 	if err != nil {
-		log.Error(err)
+		fmt.Printf("failed to load genesis configuration from file. Error: %v", err)
 		os.Exit(1)
 	}
 
-	printEntry(entry)
-	return nil
-}
+	currentL2BlockNumber := cliCtx.Uint64("l2block")
+	var stateRoot []byte
 
-func decodeL2Block(cliCtx *cli.Context) error {
-	c, err := config.Load(cliCtx)
+	streamServer, err := initializeStreamServer(c)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	log.Init(c.Log)
+	if currentL2BlockNumber == 0 {
+		printColored(color.FgHiYellow, "\n\nSetting Genesis block\n\n")
 
-	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
-	}
+		mtDBServerConfig := merkletree.Config{URI: c.MerkleTree.URI}
+		var mtDBCancel context.CancelFunc
+		mtDBServiceClient, mtDBClientConn, mtDBCancel := merkletree.NewMTDBServiceClient(ctx, mtDBServerConfig)
+		defer func() {
+			mtDBCancel()
+			mtDBClientConn.Close()
+		}()
 
-	err = client.Start()
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
-	}
+		stateTree := merkletree.NewStateTree(mtDBServiceClient)
 
-	l2BlockNumber := cliCtx.Uint64("l2block")
+		stateRoot, err = setGenesis(ctx, stateTree, networkConfig.Genesis)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
 
-	bookMark := &datastream.BookMark{
-		Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
-		Value: l2BlockNumber,
-	}
+		// Get Genesis block from the file and validate the state root
+		bookMark := state.DSBookMark{
+			Type:  state.BookMarkTypeL2Block,
+			Value: 0,
+		}
 
-	marshalledBookMark, err := proto.Marshal(bookMark)
-	if err != nil {
-		return err
+		firstEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+		printEntry(firstEntry)
+
+		secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+		printEntry(secondEntry)
+
+		if common.Bytes2Hex(stateRoot) != common.Bytes2Hex(secondEntry.Data[40:72]) {
+			printColored(color.FgRed, "\nError: Genesis state root does not match\n\n")
+			os.Exit(1)
+		} else {
+			printColored(color.FgGreen, "\nGenesis state root matches\n\n")
+		}
+		currentL2BlockNumber++
 	}
 
-	firstEntry, err := client.ExecCommandGetBookmark(marshalledBookMark)
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
+	// Connect to the executor
+	executorClient, executorClientConn, executorCancel := executor.NewExecutorClient(ctx, c.Executor)
+	defer func() {
+		executorCancel()
+		executorClientConn.Close()
+	}()
+
+	bookMark := state.DSBookMark{
+		Type:  state.BookMarkTypeL2Block,
+		Value: currentL2BlockNumber,
 	}
-	printEntry(firstEntry)
 
-	secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1)
+	startEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	i := uint64(2) //nolint:gomnd
-	for secondEntry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION) {
-		printEntry(secondEntry)
-		entry, err := client.ExecCommandGetEntry(firstEntry.Number + i)
+	var previousStateRoot = stateRoot
+	var maxEntry = streamServer.GetHeader().TotalEntries
+
+	for x := startEntry.Number; x < maxEntry; x++ {
+		printColored(color.FgHiYellow, fmt.Sprintf("\nProcessing entity: %d\n", x))
+
+		currentEntry, err := streamServer.GetEntry(x)
 		if err != nil {
 			log.Error(err)
 			os.Exit(1)
 		}
-		secondEntry = entry
-		i++
+
+		var processBatchRequest *executor.ProcessBatchRequest
+		var expectedNewRoot []byte
+		var entryToUpdate *datastreamer.FileEntry
+
+		switch currentEntry.Type {
+		case state.EntryTypeBookMark:
+			printEntry(currentEntry)
+			entryToUpdate = nil
+			continue
+		case state.EntryTypeUpdateGER:
+			printEntry(currentEntry)
+			processBatchRequest = &executor.ProcessBatchRequest{
+				OldBatchNum:      binary.BigEndian.Uint64(currentEntry.Data[0:8]) - 1,
+				Coinbase:         common.Bytes2Hex(currentEntry.Data[48:68]),
+				BatchL2Data:      nil,
+				OldStateRoot:     previousStateRoot,
+				GlobalExitRoot:   currentEntry.Data[16:48],
+				OldAccInputHash:  []byte{},
+				EthTimestamp:     binary.BigEndian.Uint64(currentEntry.Data[8:16]),
+				UpdateMerkleTree: uint32(1),
+				ChainId:          c.Offline.ChainID,
+				ForkId:           uint64(binary.BigEndian.Uint16(currentEntry.Data[68:70])),
+			}
+
+			expectedNewRoot = currentEntry.Data[70:102]
+			entryToUpdate = nil
+		case state.EntryTypeL2BlockStart:
+			startEntry = currentEntry
+			printEntry(startEntry)
+
+			txEntry, err := streamServer.GetEntry(startEntry.Number + 1)
+			if err != nil {
+				log.Error(err)
+				os.Exit(1)
+			}
+			printEntry(txEntry)
+
+			endEntry, err := streamServer.GetEntry(startEntry.Number + 2) //nolint:gomnd
+			if err != nil {
+				log.Error(err)
+				os.Exit(1)
+			}
+			printEntry(endEntry)
+
+			forkID := uint64(binary.BigEndian.Uint16(startEntry.Data[76:78]))
+
+			tx, err := state.DecodeTx(common.Bytes2Hex((txEntry.Data[6:])))
+			if err != nil {
+				log.Error(err)
+				os.Exit(1)
+			}
+
+			// Get the old state root
+			oldStateRoot := getOldStateRoot(startEntry.Number, streamServer)
+
+			// RLP encode the transaction using the proper fork id
+			batchL2Data, err := state.EncodeTransaction(*tx, txEntry.Data[0], forkID) //nolint:gomnd
+			if err != nil {
+				log.Error(err)
+				os.Exit(1)
+			}
+
+			processBatchRequest = &executor.ProcessBatchRequest{
+				OldBatchNum:      binary.BigEndian.Uint64(startEntry.Data[0:8]) - 1,
+				Coinbase:         common.Bytes2Hex(startEntry.Data[56:76]),
+				BatchL2Data:      batchL2Data,
+				OldStateRoot:     oldStateRoot,
+				GlobalExitRoot:   startEntry.Data[24:56],
+				OldAccInputHash:  []byte{},
+				EthTimestamp:     binary.BigEndian.Uint64(startEntry.Data[16:24]),
+				UpdateMerkleTree: uint32(1),
+				ChainId:          c.Offline.ChainID,
+				ForkId:           uint64(binary.BigEndian.Uint16(startEntry.Data[76:78])),
+			}
+
+			expectedNewRoot = endEntry.Data[40:72]
+			entryToUpdate = &endEntry
+			x += 2 //nolint:gomnd
+		}
+
+		// Process batch
+		processBatchResponse, err := executorClient.ProcessBatch(ctx, processBatchRequest)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
+		if processBatchResponse.Error != executor.ExecutorError_EXECUTOR_ERROR_NO_ERROR {
+			fmt.Printf("Error: %v\n", processBatchResponse.Error)
+			os.Exit(1)
+		}
+
+		if common.Bytes2Hex(processBatchResponse.NewStateRoot) != common.Bytes2Hex(expectedNewRoot) {
+			printColored(color.FgRed, "\nNew state root does not match\n\n")
+			printColored(color.FgRed, fmt.Sprintf("Old State Root.........: %s\n", "0x"+common.Bytes2Hex(processBatchRequest.GetOldStateRoot())))
+			printColored(color.FgRed, fmt.Sprintf("New State Root.........: %s\n", "0x"+common.Bytes2Hex(processBatchResponse.NewStateRoot)))
+			printColored(color.FgRed, fmt.Sprintf("Expected New State Root: %s\n", "0x"+common.Bytes2Hex(expectedNewRoot)))
+			// Check if we must update the file with the new state root
+			if cliCtx.Bool("update") {
+				if entryToUpdate.Type != state.EntryTypeL2BlockEnd {
+					printColored(color.FgRed, "Error: Entry to update is not a L2BlockEnd\n")
+					os.Exit(1)
+				}
+				blockEnd := state.DSL2BlockEnd{}.Decode(entryToUpdate.Data)
+				blockEnd.StateRoot = common.BytesToHash(processBatchResponse.NewStateRoot)
+				err = streamServer.UpdateEntryData(entryToUpdate.Number, state.EntryTypeL2BlockEnd, blockEnd.Encode())
+				if err != nil {
+					printColored(color.FgRed, fmt.Sprintf("Error: %v\n", err))
+					os.Exit(1)
+				}
+			} else {
+				break
+			}
+		} else {
+			printColored(color.FgGreen, "New state root matches\n")
+			previousStateRoot = processBatchResponse.NewStateRoot
+		}
 	}
 
 	return nil
 }
 
-func decodeEntryOffline(cliCtx *cli.Context) error {
+func decodeEntry(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -436,24 +546,29 @@ func decodeEntryOffline(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	streamServer, err := initializeStreamServer(c)
+	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	entry, err := streamServer.GetEntry(cliCtx.Uint64("entry"))
+	err = client.Start()
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	printEntry(entry)
+	entry, err := client.ExecCommandGetEntry(cliCtx.Uint64("entry"))
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
+	}
 
+	printEntry(entry)
 	return nil
 }
 
-func decodeL2BlockOffline(cliCtx *cli.Context) error {
+func decodeL2Block(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -462,7 +577,13 @@ func decodeL2BlockOffline(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	streamServer, err := initializeStreamServer(c)
+	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
+	}
+
+	err = client.Start()
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
@@ -470,45 +591,41 @@ func decodeL2BlockOffline(cliCtx *cli.Context) error {
 
 	l2BlockNumber := cliCtx.Uint64("l2block")
 
-	bookMark := &datastream.BookMark{
-		Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+	bookMark := state.DSBookMark{
+		Type:  state.BookMarkTypeL2Block,
 		Value: l2BlockNumber,
 	}
 
-	marshalledBookMark, err := proto.Marshal(bookMark)
-	if err != nil {
-		return err
-	}
-
-	firstEntry, err := streamServer.GetFirstEventAfterBookmark(marshalledBookMark)
+	firstEntry, err := client.ExecCommandGetBookmark(bookMark.Encode())
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 	printEntry(firstEntry)
 
-	secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
+	secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
+	printEntry(secondEntry)
 
 	i := uint64(2) //nolint:gomnd
-
-	for secondEntry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION) {
-		printEntry(secondEntry)
-		secondEntry, err = streamServer.GetEntry(firstEntry.Number + i)
+	for secondEntry.Type == state.EntryTypeL2Tx {
+		entry, err := client.ExecCommandGetEntry(firstEntry.Number + i)
 		if err != nil {
 			log.Error(err)
 			os.Exit(1)
 		}
+		secondEntry = entry
+		printEntry(secondEntry)
 		i++
 	}
 
 	return nil
 }
 
-func truncate(cliCtx *cli.Context) error {
+func decodeEntryOffline(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -523,19 +640,18 @@ func truncate(cliCtx *cli.Context) error {
 		os.Exit(1)
 	}
 
-	err = streamServer.TruncateFile(cliCtx.Uint64("entry"))
+	entry, err := streamServer.GetEntry(cliCtx.Uint64("entry"))
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	printColored(color.FgGreen, "File truncated\n")
+	printEntry(entry)
 
 	return nil
 }
 
-func decodeBatch(cliCtx *cli.Context) error {
-	var batchData = []byte{}
+func decodeL2BlockOffline(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -544,85 +660,48 @@ func decodeBatch(cliCtx *cli.Context) error {
 
 	log.Init(c.Log)
 
-	client, err := datastreamer.NewClient(c.Online.URI, c.Online.StreamType)
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
-	}
-
-	err = client.Start()
+	streamServer, err := initializeStreamServer(c)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	batchNumber := cliCtx.Uint64("batch")
-
-	bookMark := &datastream.BookMark{
-		Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
-		Value: batchNumber,
-	}
+	l2BlockNumber := cliCtx.Uint64("l2block")
 
-	marshalledBookMark, err := proto.Marshal(bookMark)
-	if err != nil {
-		return err
+	bookMark := state.DSBookMark{
+		Type:  state.BookMarkTypeL2Block,
+		Value: l2BlockNumber,
 	}
 
-	firstEntry, err := client.ExecCommandGetBookmark(marshalledBookMark)
+	firstEntry, err := streamServer.GetFirstEventAfterBookmark(bookMark.Encode())
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 	printEntry(firstEntry)
 
-	batchData = append(batchData, firstEntry.Encode()...)
-
-	secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1)
+	secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
-	printEntry(secondEntry)
-
-	batchData = append(batchData, secondEntry.Encode()...)
 
 	i := uint64(2) //nolint:gomnd
-	for {
-		entry, err := client.ExecCommandGetEntry(firstEntry.Number + i)
+	printEntry(secondEntry)
+	for secondEntry.Type == state.EntryTypeL2Tx {
+		secondEntry, err = streamServer.GetEntry(firstEntry.Number + i)
 		if err != nil {
 			log.Error(err)
 			os.Exit(1)
 		}
-
-		if entry.Type == state.EntryTypeBookMark {
-			if err := proto.Unmarshal(entry.Data, bookMark); err != nil {
-				return err
-			}
-			if bookMark.Type == datastream.BookmarkType_BOOKMARK_TYPE_BATCH {
-				break
-			}
-		}
-
-		secondEntry = entry
 		printEntry(secondEntry)
-		batchData = append(batchData, secondEntry.Encode()...)
 		i++
 	}
 
-	// Dump batchdata to a file
-	if cliCtx.Bool("dump") {
-		err = os.WriteFile(fmt.Sprintf("batch_%d.bin", batchNumber), batchData, 0644) // nolint:gosec, gomnd
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-	}
-
 	return nil
 }
 
-func decodeBatchOffline(cliCtx *cli.Context) error {
-	var batchData = []byte{}
+func truncate(cliCtx *cli.Context) error {
 	c, err := config.Load(cliCtx)
 	if err != nil {
 		log.Error(err)
@@ -637,84 +716,26 @@ func decodeBatchOffline(cliCtx *cli.Context) error {
 		os.Exit(1)
 	}
 
-	batchNumber := cliCtx.Uint64("batch")
-
-	bookMark := &datastream.BookMark{
-		Type:  datastream.BookmarkType_BOOKMARK_TYPE_BATCH,
-		Value: batchNumber,
-	}
-
-	marshalledBookMark, err := proto.Marshal(bookMark)
-	if err != nil {
-		return err
-	}
-
-	firstEntry, err := streamServer.GetFirstEventAfterBookmark(marshalledBookMark)
-	if err != nil {
-		log.Error(err)
-		os.Exit(1)
-	}
-	printEntry(firstEntry)
-	batchData = append(batchData, firstEntry.Encode()...)
-
-	secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1)
+	err = streamServer.TruncateFile(cliCtx.Uint64("entry"))
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
 	}
 
-	i := uint64(2) //nolint:gomnd
-	printEntry(secondEntry)
-	batchData = append(batchData, secondEntry.Encode()...)
-	for {
-		secondEntry, err = streamServer.GetEntry(firstEntry.Number + i)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
-		if secondEntry.Type == state.EntryTypeBookMark {
-			if err := proto.Unmarshal(secondEntry.Data, bookMark); err != nil {
-				return err
-			}
-			if bookMark.Type == datastream.BookmarkType_BOOKMARK_TYPE_BATCH {
-				break
-			}
-		}
-
-		printEntry(secondEntry)
-		batchData = append(batchData, secondEntry.Encode()...)
-		i++
-	}
-
-	// Dump batchdata to a file
-	if cliCtx.Bool("dump") {
-		err = os.WriteFile(fmt.Sprintf("offline_batch_%d.bin", batchNumber), batchData, 0644) // nolint:gosec, gomnd
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-	}
+	printColored(color.FgGreen, "File truncated\n")
 
 	return nil
 }
 
 func printEntry(entry datastreamer.FileEntry) {
-	var bookmarkTypeDesc = map[datastream.BookmarkType]string{
-		datastream.BookmarkType_BOOKMARK_TYPE_UNSPECIFIED: "Unspecified",
-		datastream.BookmarkType_BOOKMARK_TYPE_BATCH:       "Batch Number",
-		datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK:    "L2 Block Number",
+	var bookmarkTypeDesc = map[byte]string{
+		state.BookMarkTypeL2Block: "L2 Block Number",
+		state.BookMarkTypeBatch:   "Batch Number",
 	}
 
 	switch entry.Type {
 	case state.EntryTypeBookMark:
-		bookmark := &datastream.BookMark{}
-		err := proto.Unmarshal(entry.Data, bookmark)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
+		bookmark := state.DSBookMark{}.Decode(entry.Data)
 		printColored(color.FgGreen, "Entry Type......: ")
 		printColored(color.FgHiYellow, "BookMark\n")
 		printColored(color.FgGreen, "Entry Number....: ")
@@ -723,83 +744,48 @@ func printEntry(entry datastreamer.FileEntry) {
 		printColored(color.FgHiWhite, fmt.Sprintf("%d (%s)\n", bookmark.Type, bookmarkTypeDesc[bookmark.Type]))
 		printColored(color.FgGreen, "Value...........: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", bookmark.Value))
-	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK):
-		l2Block := &datastream.L2Block{}
-		err := proto.Unmarshal(entry.Data, l2Block)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
+	case state.EntryTypeL2BlockStart:
+		blockStart := state.DSL2BlockStart{}.Decode(entry.Data)
 		printColored(color.FgGreen, "Entry Type......: ")
-		printColored(color.FgHiYellow, "L2 Block\n")
+		printColored(color.FgHiYellow, "L2 Block Start\n")
 		printColored(color.FgGreen, "Entry Number....: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
-		printColored(color.FgGreen, "L2 Block Number.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.Number))
 		printColored(color.FgGreen, "Batch Number....: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.BatchNumber))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.BatchNumber))
+		printColored(color.FgGreen, "L2 Block Number.: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.L2BlockNumber))
 		printColored(color.FgGreen, "Timestamp.......: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d (%v)\n", l2Block.Timestamp, time.Unix(int64(l2Block.Timestamp), 0)))
+		printColored(color.FgHiWhite, fmt.Sprintf("%v (%d)\n", time.Unix(blockStart.Timestamp, 0), blockStart.Timestamp))
 		printColored(color.FgGreen, "Delta Timestamp.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.DeltaTimestamp))
-		printColored(color.FgGreen, "Min. Timestamp..: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.MinTimestamp))
-		printColored(color.FgGreen, "L1 Block Hash...: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.L1Blockhash)))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.DeltaTimestamp))
 		printColored(color.FgGreen, "L1 InfoTree Idx.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.L1InfotreeIndex))
-		printColored(color.FgGreen, "Block Hash......: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.Hash)))
-		printColored(color.FgGreen, "State Root......: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.StateRoot)))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.L1InfoTreeIndex))
+		printColored(color.FgGreen, "L1 Block Hash...: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", blockStart.L1BlockHash))
 		printColored(color.FgGreen, "Global Exit Root: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.GlobalExitRoot)))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", blockStart.GlobalExitRoot))
 		printColored(color.FgGreen, "Coinbase........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToAddress(l2Block.Coinbase)))
-	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH):
-		batch := &datastream.Batch{}
-		err := proto.Unmarshal(entry.Data, batch)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-		printColored(color.FgGreen, "Entry Type......: ")
-		printColored(color.FgHiYellow, "Batch\n")
-		printColored(color.FgGreen, "Entry Number....: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
-		printColored(color.FgGreen, "Batch Number....: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.Number))
-		printColored(color.FgGreen, "State Root......: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(batch.StateRoot)))
-		printColored(color.FgGreen, "Local Exit Root.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(batch.LocalExitRoot)))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", blockStart.Coinbase))
 		printColored(color.FgGreen, "Fork ID.........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.ForkId))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.ForkID))
 		printColored(color.FgGreen, "Chain ID........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.ChainId))
-	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION):
-		dsTx := &datastream.Transaction{}
-		err := proto.Unmarshal(entry.Data, dsTx)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockStart.ChainID))
+	case state.EntryTypeL2Tx:
+		dsTx := state.DSL2Transaction{}.Decode(entry.Data)
 		printColored(color.FgGreen, "Entry Type......: ")
 		printColored(color.FgHiYellow, "L2 Transaction\n")
 		printColored(color.FgGreen, "Entry Number....: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
-		printColored(color.FgGreen, "L2 Block Number.: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.L2BlockNumber))
-		printColored(color.FgGreen, "Is Valid........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%t\n", dsTx.IsValid))
-		printColored(color.FgGreen, "Data............: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(dsTx.Encoded)))
 		printColored(color.FgGreen, "Effec. Gas Price: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.EffectiveGasPricePercentage))
+		printColored(color.FgGreen, "Is Valid........: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%t\n", dsTx.IsValid == 1))
 		printColored(color.FgGreen, "IM State Root...: ")
-		printColored(color.FgHiWhite, fmt.Sprint("0x"+common.Bytes2Hex(dsTx.ImStateRoot)+"\n"))
+		printColored(color.FgHiWhite, fmt.Sprint(dsTx.StateRoot.Hex()+"\n"))
+		printColored(color.FgGreen, "Encoded Length..: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.EncodedLength))
+		printColored(color.FgGreen, "Encoded.........: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(dsTx.Encoded)))
 
 		tx, err := state.DecodeTx(common.Bytes2Hex(dsTx.Encoded))
 		if err != nil {
@@ -818,14 +804,20 @@ func printEntry(entry datastreamer.FileEntry) {
 		nonce := tx.Nonce()
 		printColored(color.FgGreen, "Nonce...........: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", nonce))
-	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER):
-		updateGer := &datastream.UpdateGER{}
-		err := proto.Unmarshal(entry.Data, updateGer)
-		if err != nil {
-			log.Error(err)
-			os.Exit(1)
-		}
-
+	case state.EntryTypeL2BlockEnd:
+		blockEnd := state.DSL2BlockEnd{}.Decode(entry.Data)
+		printColored(color.FgGreen, "Entry Type......: ")
+		printColored(color.FgHiYellow, "L2 Block End\n")
+		printColored(color.FgGreen, "Entry Number....: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
+		printColored(color.FgGreen, "L2 Block Number.: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", blockEnd.L2BlockNumber))
+		printColored(color.FgGreen, "L2 Block Hash...: ")
+		printColored(color.FgHiWhite, fmt.Sprint(blockEnd.BlockHash.Hex()+"\n"))
+		printColored(color.FgGreen, "State Root......: ")
+		printColored(color.FgHiWhite, fmt.Sprint(blockEnd.StateRoot.Hex()+"\n"))
+	case state.EntryTypeUpdateGER:
+		updateGer := state.DSUpdateGER{}.Decode(entry.Data)
 		printColored(color.FgGreen, "Entry Type......: ")
 		printColored(color.FgHiYellow, "Update GER\n")
 		printColored(color.FgGreen, "Entry Number....: ")
@@ -833,17 +825,17 @@ func printEntry(entry datastreamer.FileEntry) {
 		printColored(color.FgGreen, "Batch Number....: ")
 		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.BatchNumber))
 		printColored(color.FgGreen, "Timestamp.......: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%v (%d)\n", time.Unix(int64(updateGer.Timestamp), 0), updateGer.Timestamp))
+		printColored(color.FgHiWhite, fmt.Sprintf("%v (%d)\n", time.Unix(updateGer.Timestamp, 0), updateGer.Timestamp))
 		printColored(color.FgGreen, "Global Exit Root: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.Bytes2Hex(updateGer.GlobalExitRoot)))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", updateGer.GlobalExitRoot))
 		printColored(color.FgGreen, "Coinbase........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToAddress(updateGer.Coinbase)))
+		printColored(color.FgHiWhite, fmt.Sprintf("%s\n", updateGer.Coinbase))
 		printColored(color.FgGreen, "Fork ID.........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ForkId))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ForkID))
 		printColored(color.FgGreen, "Chain ID........: ")
-		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ChainId))
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ChainID))
 		printColored(color.FgGreen, "State Root......: ")
-		printColored(color.FgHiWhite, fmt.Sprint(common.Bytes2Hex(updateGer.StateRoot)+"\n"))
+		printColored(color.FgHiWhite, fmt.Sprint(updateGer.StateRoot.Hex()+"\n"))
 	}
 }
 
@@ -851,3 +843,112 @@ func printColored(color color.Attribute, text string) {
 	colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", color, text)
 	fmt.Print(colored)
 }
+
+// setGenesis populates state with genesis information
+func setGenesis(ctx context.Context, tree *merkletree.StateTree, genesis state.Genesis) ([]byte, error) {
+	var (
+		root    common.Hash
+		newRoot []byte
+		err     error
+	)
+
+	if tree == nil {
+		return newRoot, fmt.Errorf("state tree is nil")
+	}
+
+	uuid := uuid.New().String()
+
+	for _, action := range genesis.Actions {
+		address := common.HexToAddress(action.Address)
+		switch action.Type {
+		case int(merkletree.LeafTypeBalance):
+			balance, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
+			if err != nil {
+				return newRoot, err
+			}
+			newRoot, _, err = tree.SetBalance(ctx, address, balance, newRoot, uuid)
+			if err != nil {
+				return newRoot, err
+			}
+		case int(merkletree.LeafTypeNonce):
+			nonce, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
+			if err != nil {
+				return newRoot, err
+			}
+			newRoot, _, err = tree.SetNonce(ctx, address, nonce, newRoot, uuid)
+			if err != nil {
+				return newRoot, err
+			}
+		case int(merkletree.LeafTypeCode):
+			code, err := hex.DecodeHex(action.Bytecode)
+			if err != nil {
+				return newRoot, fmt.Errorf("could not decode SC bytecode for address %q: %v", address, err)
+			}
+			newRoot, _, err = tree.SetCode(ctx, address, code, newRoot, uuid)
+			if err != nil {
+				return newRoot, err
+			}
+		case int(merkletree.LeafTypeStorage):
+			// Parse position and value
+			positionBI, err := encoding.DecodeBigIntHexOrDecimal(action.StoragePosition)
+			if err != nil {
+				return newRoot, err
+			}
+			valueBI, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
+			if err != nil {
+				return newRoot, err
+			}
+			// Store
+			newRoot, _, err = tree.SetStorageAt(ctx, address, positionBI, valueBI, newRoot, uuid)
+			if err != nil {
+				return newRoot, err
+			}
+		default:
+			return newRoot, fmt.Errorf("unknown genesis action type %q", action.Type)
+		}
+	}
+
+	root.SetBytes(newRoot)
+
+	// flush state db
+	err = tree.Flush(ctx, root, uuid)
+	if err != nil {
+		fmt.Printf("error flushing state tree after genesis: %v", err)
+		return newRoot, err
+	}
+
+	return newRoot, nil
+}
+
+func getOldStateRoot(entityNumber uint64, streamServer *datastreamer.StreamServer) []byte {
+	var found = false
+	var entry datastreamer.FileEntry
+	var err error
+
+	for !found && entityNumber > 1 {
+		entityNumber--
+		entry, err = streamServer.GetEntry(entityNumber)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
+		if entry.Type == state.EntryTypeL2BlockEnd || entry.Type == state.EntryTypeUpdateGER {
+			found = true
+		}
+	}
+
+	if !found {
+		fmt.Printf("Error: Could not find old state root")
+		os.Exit(1)
+	}
+
+	printColored(color.FgHiYellow, "Getting Old State Root from\n")
+	printEntry(entry)
+
+	if entry.Type == state.EntryTypeUpdateGER {
+		return entry.Data[70:102]
+	}
+
+	return entry.Data[40:72]
+}

From 8d5cf96d589413f4639dbb834d23f12a85745f0c Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Tue, 30 Apr 2024 12:49:43 +0200
Subject: [PATCH 19/23] Sequencer L2 block parallel processing improvements
 (#3604)

* wip

* first implementation of parallel sequencer optmizations and L2 block reorg management

* Close sipBatch (if needed) when processing reorg. Halt when 2 consecuties reorgs (same L2 block)

* Return error when reserved counters overflow on l2 block process. Log used/reserved counters when closing wip batch

* added logs to analyze blocking issue when storing L2 block

* Fix unlock mutex in addTxTracker. Set wipTx to nil in RestoreTxsPendingToStore

* add high reserved resorces in wipBatch

* store high reserved counter on statedb.batch table

* Return contextId in ProcessBatchV2

* fix synchornizer test

* Set SequentialProcessL2Block to false by default. Update node config documentation

* fix non-e2e tests

* fix finalizer tests

* remove unused code

* test

* Fix sequencer loadFromPool gofunc. Fix docker compose variables
---
 config/config_test.go                         |   6 +-
 config/default.go                             |   5 +-
 .../environments/local/local.node.config.toml |   3 +-
 db/migrations/state/0021.sql                  |   7 +
 db/migrations/state/0021_test.go              |  64 +++
 docs/config-file/node-config-doc.html         |   8 +-
 docs/config-file/node-config-doc.md           |  54 ++-
 docs/config-file/node-config-schema.json      |  16 +-
 event/event.go                                |   2 +
 go.mod                                        |   2 +-
 go.sum                                        |   4 +-
 sequencer/addrqueue.go                        |  27 +-
 sequencer/addrqueue_test.go                   |   4 +-
 sequencer/batch.go                            | 383 ++++++++++++------
 sequencer/config.go                           |   6 +-
 sequencer/datastreamer.go                     |   2 +-
 sequencer/finalizer.go                        | 101 +++--
 sequencer/finalizer_test.go                   |  57 +--
 sequencer/forcedbatch.go                      |  21 +-
 sequencer/interfaces.go                       |   9 +-
 sequencer/l2block.go                          | 309 +++++++++-----
 sequencer/metrics.go                          |  61 ++-
 sequencer/mock_state.go                       |  19 +-
 sequencer/mock_worker.go                      |  70 +++-
 sequencer/sequencer.go                        |  36 +-
 sequencer/waitgroupcount.go                   |  29 ++
 sequencer/worker.go                           | 205 ++++++++--
 sequencer/worker_test.go                      |   2 +-
 state/batch.go                                |  20 +-
 state/batchV2.go                              |   8 +-
 state/pgstatestorage/batch.go                 |  50 ++-
 state/test/forkid_etrog/etrog_test.go         |   2 +-
 .../mocks/state_full_interface.go             |  25 +-
 synchronizer/common/syncinterfaces/state.go   |   2 +-
 .../executor_trusted_batch_sync.go            |   4 +-
 .../executor_trusted_batch_sync_test.go       |   6 +-
 .../l2_sync_etrog/mocks/state_interface.go    |  25 +-
 synchronizer/synchronizer_test.go             |   2 +-
 test/config/debug.node.config.toml            |   3 +-
 test/config/test.node.config.toml             |   7 +-
 test/docker-compose.yml                       |  39 +-
 41 files changed, 1208 insertions(+), 497 deletions(-)
 create mode 100644 db/migrations/state/0021.sql
 create mode 100644 db/migrations/state/0021_test.go
 create mode 100644 sequencer/waitgroupcount.go

diff --git a/config/config_test.go b/config/config_test.go
index cf918c4afe..f93735eeb9 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -101,6 +101,10 @@ func Test_Defaults(t *testing.T) {
 			path:          "Sequencer.Finalizer.ResourceExhaustedMarginPct",
 			expectedValue: uint32(10),
 		},
+		{
+			path:          "Sequencer.Finalizer.StateRootSyncInterval",
+			expectedValue: types.NewDuration(3600 * time.Second),
+		},
 		{
 			path:          "Sequencer.Finalizer.ForcedBatchesL1BlockConfirmations",
 			expectedValue: uint64(64),
@@ -127,7 +131,7 @@ func Test_Defaults(t *testing.T) {
 		},
 		{
 			path:          "Sequencer.Finalizer.BatchMaxDeltaTimestamp",
-			expectedValue: types.NewDuration(10 * time.Second),
+			expectedValue: types.NewDuration(1800 * time.Second),
 		},
 		{
 			path:          "Sequencer.Finalizer.Metrics.Interval",
diff --git a/config/default.go b/config/default.go
index 061a04982f..f55feed513 100644
--- a/config/default.go
+++ b/config/default.go
@@ -146,12 +146,13 @@ StateConsistencyCheckInterval = "5s"
 		ForcedBatchesCheckInterval = "10s"
 		L1InfoTreeL1BlockConfirmations = 64
 		L1InfoTreeCheckInterval = "10s"
-		BatchMaxDeltaTimestamp = "10s"
+		BatchMaxDeltaTimestamp = "1800s"
 		L2BlockMaxDeltaTimestamp = "3s"
 		ResourceExhaustedMarginPct = 10
+		StateRootSyncInterval = "3600s"
 		HaltOnBatchNumber = 0
 		SequentialBatchSanityCheck = false
-		SequentialProcessL2Block = true
+		SequentialProcessL2Block = false
 	[Sequencer.Finalizer.Metrics]
 		Interval = "60m"
 		EnableLog = true
diff --git a/config/environments/local/local.node.config.toml b/config/environments/local/local.node.config.toml
index 7fdad2a456..436a0d84fa 100644
--- a/config/environments/local/local.node.config.toml
+++ b/config/environments/local/local.node.config.toml
@@ -101,9 +101,10 @@ StateConsistencyCheckInterval = "5s"
 		BatchMaxDeltaTimestamp = "120s"
 		L2BlockMaxDeltaTimestamp = "3s"
 		ResourceExhaustedMarginPct = 10
+		StateRootSyncInterval = "360s"
 		HaltOnBatchNumber = 0
 		SequentialBatchSanityCheck = false
-		SequentialProcessL2Block = true
+		SequentialProcessL2Block = false
 	[Sequencer.Finalizer.Metrics]
 		Interval = "60m"
 		EnableLog = true		
diff --git a/db/migrations/state/0021.sql b/db/migrations/state/0021.sql
new file mode 100644
index 0000000000..846cda1fab
--- /dev/null
+++ b/db/migrations/state/0021.sql
@@ -0,0 +1,7 @@
+-- +migrate Up
+ALTER TABLE state.batch
+    ADD COLUMN high_reserved_counters JSONB;
+
+-- +migrate Down
+ALTER TABLE state.batch
+    DROP COLUMN high_reserved_counters;
diff --git a/db/migrations/state/0021_test.go b/db/migrations/state/0021_test.go
new file mode 100644
index 0000000000..512ba55191
--- /dev/null
+++ b/db/migrations/state/0021_test.go
@@ -0,0 +1,64 @@
+package migrations_test
+
+import (
+	"database/sql"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+type migrationTest0021 struct{}
+
+func (m migrationTest0021) InsertData(db *sql.DB) error {
+	const insertBatch0 = `
+		INSERT INTO state.batch (batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, wip) 
+		VALUES (0,'0x0000', '0x0000', '0x0000', '0x0000', now(), '0x0000', null, null, true)`
+
+	// insert batch
+	_, err := db.Exec(insertBatch0)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (m migrationTest0021) RunAssertsAfterMigrationUp(t *testing.T, db *sql.DB) {
+	var result int
+
+	// Check column high_reserved_counters exists in state.batch table
+	const getColumn = `SELECT count(*) FROM information_schema.columns WHERE table_name='batch' and column_name='high_reserved_counters'`
+	row := db.QueryRow(getColumn)
+	assert.NoError(t, row.Scan(&result))
+	assert.Equal(t, 1, result)
+
+	const insertBatch0 = `
+		INSERT INTO state.batch (batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, wip, high_reserved_counters) 
+		VALUES (1,'0x0001', '0x0001', '0x0001', '0x0001', now(), '0x0001', null, null, true, '{"Steps": 1890125}')`
+
+	// insert batch 1
+	_, err := db.Exec(insertBatch0)
+	assert.NoError(t, err)
+
+	const insertBatch1 = `
+		INSERT INTO state.batch (batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, wip, high_reserved_counters) 
+		VALUES (2,'0x0002', '0x0002', '0x0002', '0x0002', now(), '0x0002', null, null, false, '{"Steps": 1890125}')`
+
+	// insert batch 2
+	_, err = db.Exec(insertBatch1)
+	assert.NoError(t, err)
+}
+
+func (m migrationTest0021) RunAssertsAfterMigrationDown(t *testing.T, db *sql.DB) {
+	var result int
+
+	// Check column high_reserved_counters doesn't exists in state.batch table
+	const getCheckedColumn = `SELECT count(*) FROM information_schema.columns WHERE table_name='batch' and column_name='high_reserved_counters'`
+	row := db.QueryRow(getCheckedColumn)
+	assert.NoError(t, row.Scan(&result))
+	assert.Equal(t, 0, result)
+}
+
+func TestMigration0021(t *testing.T) {
+	runMigrationTest(t, 21, migrationTest0021{})
+}
diff --git a/docs/config-file/node-config-doc.html b/docs/config-file/node-config-doc.html
index 16cfba8d7d..9a82ded83c 100644
--- a/docs/config-file/node-config-doc.html
+++ b/docs/config-file/node-config-doc.html
@@ -44,13 +44,15 @@
 
"300ms"
 

Default: 10Type: integer

ResourceExhaustedMarginPct is the percentage window of the resource left out for the batch to be closed


Default: 64Type: integer

ForcedBatchesL1BlockConfirmations is number of blocks to consider GER final


Default: 64Type: integer

L1InfoTreeL1BlockConfirmations is number of blocks to consider L1InfoRoot final


Default: "10s"Type: string

ForcedBatchesCheckInterval is used by the closing signals manager to wait for its operation


Examples:

"1m"
 
"300ms"
-

Default: "10s"Type: string

L1InfoTreeCheckInterval is the wait time to check if the L1InfoRoot has been updated


Examples:

"1m"
+

Default: "10s"Type: string

L1InfoTreeCheckInterval is the time interval to check if the L1InfoRoot has been updated


Examples:

"1m"
 
"300ms"
-

Default: "10s"Type: string

BatchMaxDeltaTimestamp is the resolution of the timestamp used to close a batch


Examples:

"1m"
+

Default: "30m0s"Type: string

BatchMaxDeltaTimestamp is the resolution of the timestamp used to close a batch


Examples:

"1m"
 
"300ms"
 

Default: "3s"Type: string

L2BlockMaxDeltaTimestamp is the resolution of the timestamp used to close a L2 block


Examples:

"1m"
 
"300ms"
-

Default: 0Type: integer

HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches.
The Sequencer will halt after it closes the batch equal to this number


Default: falseType: boolean

SequentialBatchSanityCheck indicates if the reprocess of a closed batch (sanity check) must be done in a
sequential way (instead than in parallel)


Default: trueType: boolean

SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead
in the processPendingL2Blocks go func


Metrics is the config for the sequencer metrics
Default: "1h0m0s"Type: string

Interval is the interval of time to calculate sequencer metrics


Examples:

"1m"
+

Default: "1h0m0s"Type: string

StateRootSyncInterval indicates how often the stateroot generated by the L2 block process will be synchronized with
the stateroot used in the tx-by-tx execution


Examples:

"1m"
+
"300ms"
+

Default: 0Type: integer

HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches.
The Sequencer will halt after it closes the batch equal to this number


Default: falseType: boolean

SequentialBatchSanityCheck indicates if the reprocess of a closed batch (sanity check) must be done in a
sequential way (instead than in parallel)


Default: falseType: boolean

SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead
in the processPendingL2Blocks go func


Metrics is the config for the sequencer metrics
Default: "1h0m0s"Type: string

Interval is the interval of time to calculate sequencer metrics


Examples:

"1m"
 
"300ms"
 

Default: trueType: boolean

EnableLog is a flag to enable/disable metrics logs


StreamServerCfg is the config for the stream server
Default: 0Type: integer

Port to listen on


Default: ""Type: string

Filename of the binary data file


Default: 0Type: integer

Version of the binary data file


Default: 0Type: integer

ChainID is the chain ID


Default: falseType: boolean

Enabled is a flag to enable/disable the data streamer


Log is the log configuration
Default: ""Type: enum (of string)

Must be one of:

  • "production"
  • "development"

Default: ""Type: enum (of string)

Must be one of:

  • "debug"
  • "info"
  • "warn"
  • "error"
  • "dpanic"
  • "panic"
  • "fatal"

Type: array of string

Each item of this array must be:


Default: 0Type: integer

UpgradeEtrogBatchNumber is the batch number of the upgrade etrog


Configuration of the sequence sender service
Default: "5s"Type: string

WaitPeriodSendSequence is the time the sequencer waits until
trying to send a sequence to L1


Examples:

"1m"
 
"300ms"
diff --git a/docs/config-file/node-config-doc.md b/docs/config-file/node-config-doc.md
index 144dfb3324..ea312a6929 100644
--- a/docs/config-file/node-config-doc.md
+++ b/docs/config-file/node-config-doc.md
@@ -2083,6 +2083,7 @@ StateConsistencyCheckInterval="5s"
 | - [L1InfoTreeCheckInterval](#Sequencer_Finalizer_L1InfoTreeCheckInterval )                     | No      | string  | No         | -          | Duration                                                                                                                                                                                                      |
 | - [BatchMaxDeltaTimestamp](#Sequencer_Finalizer_BatchMaxDeltaTimestamp )                       | No      | string  | No         | -          | Duration                                                                                                                                                                                                      |
 | - [L2BlockMaxDeltaTimestamp](#Sequencer_Finalizer_L2BlockMaxDeltaTimestamp )                   | No      | string  | No         | -          | Duration                                                                                                                                                                                                      |
+| - [StateRootSyncInterval](#Sequencer_Finalizer_StateRootSyncInterval )                         | No      | string  | No         | -          | Duration                                                                                                                                                                                                      |
 | - [HaltOnBatchNumber](#Sequencer_Finalizer_HaltOnBatchNumber )                                 | No      | integer | No         | -          | HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches.
The Sequencer will halt after it closes the batch equal to this number | | - [SequentialBatchSanityCheck](#Sequencer_Finalizer_SequentialBatchSanityCheck ) | No | boolean | No | - | SequentialBatchSanityCheck indicates if the reprocess of a closed batch (sanity check) must be done in a
sequential way (instead than in parallel) | | - [SequentialProcessL2Block](#Sequencer_Finalizer_SequentialProcessL2Block ) | No | boolean | No | - | SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead
in the processPendingL2Blocks go func | @@ -2216,7 +2217,7 @@ ForcedBatchesCheckInterval="10s" **Default:** `"10s"` -**Description:** L1InfoTreeCheckInterval is the wait time to check if the L1InfoRoot has been updated +**Description:** L1InfoTreeCheckInterval is the time interval to check if the L1InfoRoot has been updated **Examples:** @@ -2240,7 +2241,7 @@ L1InfoTreeCheckInterval="10s" **Type:** : `string` -**Default:** `"10s"` +**Default:** `"30m0s"` **Description:** BatchMaxDeltaTimestamp is the resolution of the timestamp used to close a batch @@ -2254,10 +2255,10 @@ L1InfoTreeCheckInterval="10s" "300ms" ``` -**Example setting the default value** ("10s"): +**Example setting the default value** ("30m0s"): ``` [Sequencer.Finalizer] -BatchMaxDeltaTimestamp="10s" +BatchMaxDeltaTimestamp="30m0s" ``` #### 10.7.9. `Sequencer.Finalizer.L2BlockMaxDeltaTimestamp` @@ -2286,7 +2287,34 @@ BatchMaxDeltaTimestamp="10s" L2BlockMaxDeltaTimestamp="3s" ``` -#### 10.7.10. `Sequencer.Finalizer.HaltOnBatchNumber` +#### 10.7.10. `Sequencer.Finalizer.StateRootSyncInterval` + +**Title:** Duration + +**Type:** : `string` + +**Default:** `"1h0m0s"` + +**Description:** StateRootSyncInterval indicates how often the stateroot generated by the L2 block process will be synchronized with +the stateroot used in the tx-by-tx execution + +**Examples:** + +```json +"1m" +``` + +```json +"300ms" +``` + +**Example setting the default value** ("1h0m0s"): +``` +[Sequencer.Finalizer] +StateRootSyncInterval="1h0m0s" +``` + +#### 10.7.11. `Sequencer.Finalizer.HaltOnBatchNumber` **Type:** : `integer` @@ -2301,7 +2329,7 @@ The Sequencer will halt after it closes the batch equal to this number HaltOnBatchNumber=0 ``` -#### 10.7.11. `Sequencer.Finalizer.SequentialBatchSanityCheck` +#### 10.7.12. `Sequencer.Finalizer.SequentialBatchSanityCheck` **Type:** : `boolean` @@ -2316,22 +2344,22 @@ sequential way (instead than in parallel) SequentialBatchSanityCheck=false ``` -#### 10.7.12. `Sequencer.Finalizer.SequentialProcessL2Block` +#### 10.7.13. `Sequencer.Finalizer.SequentialProcessL2Block` **Type:** : `boolean` -**Default:** `true` +**Default:** `false` **Description:** SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead in the processPendingL2Blocks go func -**Example setting the default value** (true): +**Example setting the default value** (false): ``` [Sequencer.Finalizer] -SequentialProcessL2Block=true +SequentialProcessL2Block=false ``` -#### 10.7.13. `[Sequencer.Finalizer.Metrics]` +#### 10.7.14. `[Sequencer.Finalizer.Metrics]` **Type:** : `object` **Description:** Metrics is the config for the sequencer metrics @@ -2341,7 +2369,7 @@ SequentialProcessL2Block=true | - [Interval](#Sequencer_Finalizer_Metrics_Interval ) | No | string | No | - | Duration | | - [EnableLog](#Sequencer_Finalizer_Metrics_EnableLog ) | No | boolean | No | - | EnableLog is a flag to enable/disable metrics logs | -##### 10.7.13.1. `Sequencer.Finalizer.Metrics.Interval` +##### 10.7.14.1. `Sequencer.Finalizer.Metrics.Interval` **Title:** Duration @@ -2367,7 +2395,7 @@ SequentialProcessL2Block=true Interval="1h0m0s" ``` -##### 10.7.13.2. `Sequencer.Finalizer.Metrics.EnableLog` +##### 10.7.14.2. `Sequencer.Finalizer.Metrics.EnableLog` **Type:** : `boolean` diff --git a/docs/config-file/node-config-schema.json b/docs/config-file/node-config-schema.json index 021f2859bb..dffb74f672 100644 --- a/docs/config-file/node-config-schema.json +++ b/docs/config-file/node-config-schema.json @@ -825,7 +825,7 @@ "L1InfoTreeCheckInterval": { "type": "string", "title": "Duration", - "description": "L1InfoTreeCheckInterval is the wait time to check if the L1InfoRoot has been updated", + "description": "L1InfoTreeCheckInterval is the time interval to check if the L1InfoRoot has been updated", "default": "10s", "examples": [ "1m", @@ -836,7 +836,7 @@ "type": "string", "title": "Duration", "description": "BatchMaxDeltaTimestamp is the resolution of the timestamp used to close a batch", - "default": "10s", + "default": "30m0s", "examples": [ "1m", "300ms" @@ -852,6 +852,16 @@ "300ms" ] }, + "StateRootSyncInterval": { + "type": "string", + "title": "Duration", + "description": "StateRootSyncInterval indicates how often the stateroot generated by the L2 block process will be synchronized with\nthe stateroot used in the tx-by-tx execution", + "default": "1h0m0s", + "examples": [ + "1m", + "300ms" + ] + }, "HaltOnBatchNumber": { "type": "integer", "description": "HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches.\nThe Sequencer will halt after it closes the batch equal to this number", @@ -865,7 +875,7 @@ "SequentialProcessL2Block": { "type": "boolean", "description": "SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead\nin the processPendingL2Blocks go func", - "default": true + "default": false }, "Metrics": { "properties": { diff --git a/event/event.go b/event/event.go index e6a72799ce..6e486e21ad 100644 --- a/event/event.go +++ b/event/event.go @@ -50,6 +50,8 @@ const ( EventID_ReservedZKCountersOverflow EventID = "RESERVED ZKCOUNTERS OVERFLOW" // EventID_InvalidInfoRoot is triggered when an invalid l1InfoRoot was synced EventID_InvalidInfoRoot EventID = "INVALID INFOROOT" + // EventID_L2BlockReorg is triggered when a L2 block reorg has happened in the sequencer + EventID_L2BlockReorg EventID = "L2 BLOCK REORG" // Source_Node is the source of the event Source_Node Source = "node" diff --git a/go.mod b/go.mod index 5205922dcd..db2f719558 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/0xPolygonHermez/zkevm-node go 1.21 require ( - github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240422135400-0df0d27226b3 + github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240426122934-6f47d2485fc1 github.com/didip/tollbooth/v6 v6.1.2 github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 github.com/ethereum/go-ethereum v1.13.11 diff --git a/go.sum b/go.sum index 3bb8e0138d..a9de27ba91 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240422135400-0df0d27226b3 h1:g5IMJalQxVRNfnXrzQG7bx2COktaFBf1mNuF4SLuQss= -github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240422135400-0df0d27226b3/go.mod h1:0QkAXcFa92mFJrCbN3UPUJGJYes851yEgYHLONnaosE= +github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240426122934-6f47d2485fc1 h1:4wbCJOGcZ8BTuOfNFrcZ1cAVfTWaX1W9EYHaDx3imLc= +github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-0.20240426122934-6f47d2485fc1/go.mod h1:0QkAXcFa92mFJrCbN3UPUJGJYes851yEgYHLONnaosE= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= diff --git a/sequencer/addrqueue.go b/sequencer/addrqueue.go index 9c0d8d996e..3b2d4847c9 100644 --- a/sequencer/addrqueue.go +++ b/sequencer/addrqueue.go @@ -121,22 +121,25 @@ func (a *addrQueue) IsEmpty() bool { } // deleteTx deletes the tx from the addrQueue -func (a *addrQueue) deleteTx(txHash common.Hash) (deletedReadyTx *TxTracker) { +func (a *addrQueue) deleteTx(txHash common.Hash) (deletedTx *TxTracker, isReady bool) { txHashStr := txHash.String() if (a.readyTx != nil) && (a.readyTx.HashStr == txHashStr) { log.Infof("deleting readyTx %s from addrQueue %s", txHashStr, a.fromStr) prevReadyTx := a.readyTx a.readyTx = nil - return prevReadyTx + return prevReadyTx, true } else { + var deletedTx *TxTracker for _, txTracker := range a.notReadyTxs { if txTracker.HashStr == txHashStr { + deletedTx = txTracker log.Infof("deleting notReadyTx %s from addrQueue %s", txHashStr, a.fromStr) delete(a.notReadyTxs, txTracker.Nonce) + break } } - return nil + return deletedTx, false } } @@ -158,6 +161,22 @@ func (a *addrQueue) deletePendingTxToStore(txHash common.Hash) { } } +func (a *addrQueue) getTransactions() []*TxTracker { + // TODO: Add test for this function + + txsList := []*TxTracker{} + + if a.readyTx != nil { + txsList = append(txsList, a.readyTx) + } + + for _, tx := range a.notReadyTxs { + txsList = append(txsList, tx) + } + + return txsList +} + // updateCurrentNonceBalance updates the nonce and balance of the addrQueue and updates the ready and notReady txs func (a *addrQueue) updateCurrentNonceBalance(nonce *uint64, balance *big.Int) (newReadyTx, prevReadyTx *TxTracker, toDelete []*TxTracker) { var oldReadyTx *TxTracker = nil @@ -179,7 +198,7 @@ func (a *addrQueue) updateCurrentNonceBalance(nonce *uint64, balance *big.Int) ( } } for _, txTracker := range txsToDelete { - log.Infof("deleting notReadyTx with nonce %d from addrQueue %s", txTracker.Nonce, a.fromStr) + log.Infof("deleting notReadyTx with nonce %d from addrQueue %s, reason: %s", txTracker.Nonce, a.fromStr, *txTracker.FailedReason) delete(a.notReadyTxs, txTracker.Nonce) } } diff --git a/sequencer/addrqueue_test.go b/sequencer/addrqueue_test.go index d39ce5a356..a04e0ee793 100644 --- a/sequencer/addrqueue_test.go +++ b/sequencer/addrqueue_test.go @@ -164,11 +164,11 @@ func TestAddrQueue(t *testing.T) { t.Run("Delete readyTx 0x01", func(t *testing.T) { tc := addTxTestCases[2] tx := newTestTxTracker(tc.hash, tc.nonce, tc.gasPrice, tc.cost) - deltx := addr.deleteTx(tx.Hash) + deltx, isReady := addr.deleteTx(tx.Hash) if !(addr.readyTx == nil) { t.Fatalf("Error readyTx not nil. Expected=%s, Actual=%s", "", addr.readyTx.HashStr) } - if !(deltx.HashStr == tx.HashStr) { + if !isReady || !(deltx.HashStr == tx.HashStr) { t.Fatalf("Error returning deletedReadyTx. Expected=%s, Actual=%s", tx.HashStr, deltx.HashStr) } }) diff --git a/sequencer/batch.go b/sequencer/batch.go index 1d644b22c5..ecaa93aca7 100644 --- a/sequencer/batch.go +++ b/sequencer/batch.go @@ -11,25 +11,28 @@ import ( "github.com/0xPolygonHermez/zkevm-node/state" stateMetrics "github.com/0xPolygonHermez/zkevm-node/state/metrics" "github.com/ethereum/go-ethereum/common" + "github.com/jackc/pgx/v4" ) // Batch represents a wip or processed batch. type Batch struct { - batchNumber uint64 - coinbase common.Address - timestamp time.Time - initialStateRoot common.Hash // initial stateRoot of the batch - imStateRoot common.Hash // intermediate stateRoot when processing tx-by-tx - finalStateRoot common.Hash // final stateroot of the batch when a L2 block is processed - countOfTxs int - countOfL2Blocks int - imRemainingResources state.BatchResources // remaining batch resources when processing tx-by-tx - finalRemainingResources state.BatchResources // remaining batch resources when a L2 block is processed - closingReason state.ClosingReason + batchNumber uint64 + coinbase common.Address + timestamp time.Time + initialStateRoot common.Hash // initial stateRoot of the batch + imStateRoot common.Hash // intermediate stateRoot when processing tx-by-tx + finalStateRoot common.Hash // final stateroot of the batch when a L2 block is processed + countOfTxs int + countOfL2Blocks int + imRemainingResources state.BatchResources // remaining batch resources when processing tx-by-tx + imHighReservedZKCounters state.ZKCounters + finalRemainingResources state.BatchResources // remaining batch resources when a L2 block is processed + finalHighReservedZKCounters state.ZKCounters + closingReason state.ClosingReason } -func (w *Batch) isEmpty() bool { - return w.countOfL2Blocks == 0 +func (b *Batch) isEmpty() bool { + return b.countOfL2Blocks == 0 } // processBatchesPendingtoCheck performs a sanity check for batches closed but pending to be checked @@ -77,23 +80,25 @@ func (f *finalizer) setWIPBatch(ctx context.Context, wipStateBatch *state.Batch) wipStateBatchCountOfTxs = wipStateBatchCountOfTxs + len(rawBlock.Transactions) } - remainingResources := getMaxRemainingResources(f.batchConstraints) + remainingResources := getMaxBatchResources(f.batchConstraints) overflow, overflowResource := remainingResources.Sub(wipStateBatch.Resources) if overflow { - return nil, fmt.Errorf("failed to subtract used resources when setting the WIP batch to the state batch %d, overflow resource: %s", wipStateBatch.BatchNumber, overflowResource) + return nil, fmt.Errorf("failed to subtract used resources when setting the wip batch to the state batch %d, overflow resource: %s", wipStateBatch.BatchNumber, overflowResource) } wipBatch := &Batch{ - batchNumber: wipStateBatch.BatchNumber, - coinbase: wipStateBatch.Coinbase, - imStateRoot: wipStateBatch.StateRoot, - initialStateRoot: prevStateBatch.StateRoot, - finalStateRoot: wipStateBatch.StateRoot, - timestamp: wipStateBatch.Timestamp, - countOfL2Blocks: len(wipStateBatchBlocks.Blocks), - countOfTxs: wipStateBatchCountOfTxs, - imRemainingResources: remainingResources, - finalRemainingResources: remainingResources, + batchNumber: wipStateBatch.BatchNumber, + coinbase: wipStateBatch.Coinbase, + imStateRoot: wipStateBatch.StateRoot, + initialStateRoot: prevStateBatch.StateRoot, + finalStateRoot: wipStateBatch.StateRoot, + timestamp: wipStateBatch.Timestamp, + countOfL2Blocks: len(wipStateBatchBlocks.Blocks), + countOfTxs: wipStateBatchCountOfTxs, + imRemainingResources: remainingResources, + finalRemainingResources: remainingResources, + imHighReservedZKCounters: wipStateBatch.HighReservedZKCounters, + finalHighReservedZKCounters: wipStateBatch.HighReservedZKCounters, } return wipBatch, nil @@ -125,22 +130,52 @@ func (f *finalizer) initWIPBatch(ctx context.Context) { if lastStateBatch.BatchNumber+1 == f.cfg.HaltOnBatchNumber { f.Halt(ctx, fmt.Errorf("finalizer reached stop sequencer on batch number: %d", f.cfg.HaltOnBatchNumber), false) } - - f.wipBatch, err = f.openNewWIPBatch(ctx, lastStateBatch.BatchNumber+1, lastStateBatch.StateRoot) - if err != nil { - log.Fatalf("failed to open new wip batch, error: %v", err) - } - } else { /// if it's not closed, it is the wip state batch, set it as wip batch in the finalizer + f.wipBatch = f.openNewWIPBatch(lastStateBatch.BatchNumber+1, lastStateBatch.StateRoot) + f.pipBatch = nil + f.sipBatch = nil + } else { /// if it's not closed, it is the wip/pip/sip batch f.wipBatch, err = f.setWIPBatch(ctx, lastStateBatch) if err != nil { log.Fatalf("failed to set wip batch, error: %v", err) } + f.pipBatch = f.wipBatch + f.sipBatch = f.wipBatch } log.Infof("initial batch: %d, initialStateRoot: %s, stateRoot: %s, coinbase: %s", f.wipBatch.batchNumber, f.wipBatch.initialStateRoot, f.wipBatch.finalStateRoot, f.wipBatch.coinbase) } +func (f *finalizer) processL2BlockReorg(ctx context.Context) error { + f.waitPendingL2Blocks() + + if f.sipBatch != nil && f.sipBatch.batchNumber != f.wipBatch.batchNumber { + // If the sip batch is the previous to the current wip batch and it's still open these means that the L2 block that caused + // the reorg is the first L2 block of the wip batch, therefore we need to close sip batch before to continue. + // If we don't close the sip batch the initWIPBatch function will load the sip batch as the initial one and when trying to reprocess + // the first tx reorged we can have a batch resource overflow (if we have closed the sip batch for this reason) and we will return + // the reorged tx to the worker (calling UpdateTxZKCounters) missing the order in which we need to reprocess the reorged txs + + err := f.finalizeSIPBatch(ctx) + if err != nil { + return fmt.Errorf("error finalizing sip batch, error: %v", err) + } + } + + f.workerIntf.RestoreTxsPendingToStore(ctx) + + f.initWIPBatch(ctx) + + f.initWIPL2Block(ctx) + + // Since when processing the L2 block reorg we sync the state root we can reset next state root syncing + f.scheduleNextStateRootSync() + + f.l2BlockReorg.Store(false) + + return nil +} + // finalizeWIPBatch closes the current batch and opens a new one, potentially processing forced batches between the batch is closed and the resulting new empty batch func (f *finalizer) finalizeWIPBatch(ctx context.Context, closeReason state.ClosingReason) { prevTimestamp := f.wipL2Block.timestamp @@ -153,7 +188,7 @@ func (f *finalizer) finalizeWIPBatch(ctx context.Context, closeReason state.Clos err := f.closeAndOpenNewWIPBatch(ctx, closeReason) if err != nil { - f.Halt(ctx, fmt.Errorf("failed to create new WIP batch, error: %v", err), true) + f.Halt(ctx, fmt.Errorf("failed to create new wip batch, error: %v", err), true) } // If we have closed the wipL2Block then we open a new one @@ -162,88 +197,126 @@ func (f *finalizer) finalizeWIPBatch(ctx context.Context, closeReason state.Clos } } +// finalizeSIPBatch closes the current store-in-progress batch +func (f *finalizer) finalizeSIPBatch(ctx context.Context) error { + dbTx, err := f.stateIntf.BeginStateTransaction(ctx) + if err != nil { + return fmt.Errorf("error creating db transaction to close sip batch %d, error: %v", f.sipBatch.batchNumber, err) + } + + // Close sip batch (close in statedb) + err = f.closeSIPBatch(ctx, dbTx) + if err != nil { + return fmt.Errorf("failed to close sip batch %d, error: %v", f.sipBatch.batchNumber, err) + } + + if err != nil { + rollbackErr := dbTx.Rollback(ctx) + if rollbackErr != nil { + return fmt.Errorf("error when rollback db transaction to close sip batch %d, error: %v", f.sipBatch.batchNumber, rollbackErr) + } + return err + } + + err = dbTx.Commit(ctx) + if err != nil { + return fmt.Errorf("error when commit db transaction to close sip batch %d, error: %v", f.sipBatch.batchNumber, err) + } + + return nil +} + // closeAndOpenNewWIPBatch closes the current batch and opens a new one, potentially processing forced batches between the batch is closed and the resulting new wip batch func (f *finalizer) closeAndOpenNewWIPBatch(ctx context.Context, closeReason state.ClosingReason) error { f.nextForcedBatchesMux.Lock() processForcedBatches := len(f.nextForcedBatches) > 0 f.nextForcedBatchesMux.Unlock() - // If we will process forced batches after we close the wip batch then we must close the current wip L2 block, - // since the processForcedBatches function needs to create new L2 blocks (cannot "reuse" the current wip L2 block if it's empty) + f.wipBatch.closingReason = closeReason + + var lastStateRoot common.Hash + + //TODO: review forced batches implementation since is not good "idea" to check here for forced batches, maybe is better to do it on finalizeBatches loop if processForcedBatches { + // If we have reach the time to sync stateroot or we will process forced batches we must close the current wip L2 block and wip batch f.closeWIPL2Block(ctx) - } + // We need to wait that all pending L2 blocks are processed and stored + f.waitPendingL2Blocks() - // Wait until all L2 blocks are processed by the executor - startWait := time.Now() - f.pendingL2BlocksToProcessWG.Wait() - elapsed := time.Since(startWait) - log.Debugf("waiting for pending L2 blocks to be processed took: %v", elapsed) + lastStateRoot = f.sipBatch.finalStateRoot - // Wait until all L2 blocks are store - startWait = time.Now() - f.pendingL2BlocksToStoreWG.Wait() - log.Debugf("waiting for pending L2 blocks to be stored took: %v", time.Since(startWait)) + err := f.finalizeSIPBatch(ctx) + if err != nil { + return fmt.Errorf("error finalizing sip batch %d when processing forced batches, error: %v", f.sipBatch.batchNumber, err) + } + } else { + lastStateRoot = f.wipBatch.imStateRoot + } - f.wipBatch.closingReason = closeReason + // Close the wip batch. After will close them f.wipBatch will be nil, therefore we store in local variables the info we need from the f.wipBatch + lastBatchNumber := f.wipBatch.batchNumber - // Close the wip batch - var err error - err = f.closeWIPBatch(ctx) - if err != nil { - return fmt.Errorf("failed to close batch, error: %v", err) - } + f.closeWIPBatch(ctx) - log.Infof("batch %d closed, closing reason: %s", f.wipBatch.batchNumber, closeReason) + if lastBatchNumber+1 == f.cfg.HaltOnBatchNumber { + f.waitPendingL2Blocks() - // Reprocess full batch as sanity check - if f.cfg.SequentialBatchSanityCheck { - // Do the full batch reprocess now - _, _ = f.batchSanityCheck(ctx, f.wipBatch.batchNumber, f.wipBatch.initialStateRoot, f.wipBatch.finalStateRoot) - } else { - // Do the full batch reprocess in parallel - go func() { - _, _ = f.batchSanityCheck(ctx, f.wipBatch.batchNumber, f.wipBatch.initialStateRoot, f.wipBatch.finalStateRoot) - }() - } + // We finalize the current sip batch + err := f.finalizeSIPBatch(ctx) + if err != nil { + return fmt.Errorf("error finalizing sip batch %d when halting on batch %d", f.sipBatch.batchNumber, f.cfg.HaltOnBatchNumber) + } - if f.wipBatch.batchNumber+1 == f.cfg.HaltOnBatchNumber { f.Halt(ctx, fmt.Errorf("finalizer reached stop sequencer on batch number: %d", f.cfg.HaltOnBatchNumber), false) } - // Metadata for the next batch - stateRoot := f.wipBatch.finalStateRoot - lastBatchNumber := f.wipBatch.batchNumber - // Process forced batches if processForcedBatches { - lastBatchNumber, stateRoot = f.processForcedBatches(ctx, lastBatchNumber, stateRoot) - // We must init/reset the wip L2 block from the state since processForcedBatches can created new L2 blocks - f.initWIPL2Block(ctx) + lastBatchNumber, lastStateRoot = f.processForcedBatches(ctx, lastBatchNumber, lastStateRoot) } - f.wipBatch, err = f.openNewWIPBatch(ctx, lastBatchNumber+1, stateRoot) - if err != nil { - return fmt.Errorf("failed to open new wip batch, error: %v", err) - } + f.wipBatch = f.openNewWIPBatch(lastBatchNumber+1, lastStateRoot) - if f.wipL2Block != nil { + if processForcedBatches { + // We need to init/reset the wip L2 block in case we have processed forced batches + f.initWIPL2Block(ctx) + } else if f.wipL2Block != nil { + // If we are "reusing" the wip L2 block because it's empty we assign it to the new wip batch f.wipBatch.imStateRoot = f.wipL2Block.imStateRoot - // Subtract the WIP L2 block used resources to batch - overflow, overflowResource := f.wipBatch.imRemainingResources.Sub(state.BatchResources{ZKCounters: f.wipL2Block.usedZKCounters, Bytes: f.wipL2Block.bytes}) + f.wipL2Block.batch = f.wipBatch + + // We subtract the wip L2 block used resources to the new wip batch + overflow, overflowResource := f.wipBatch.imRemainingResources.Sub(state.BatchResources{ZKCounters: f.wipL2Block.usedZKCountersOnNew, Bytes: f.wipL2Block.bytes}) if overflow { return fmt.Errorf("failed to subtract L2 block [%d] used resources to new wip batch %d, overflow resource: %s", f.wipL2Block.trackingNum, f.wipBatch.batchNumber, overflowResource) } } - log.Infof("new WIP batch %d", f.wipBatch.batchNumber) + log.Infof("new wip batch %d", f.wipBatch.batchNumber) return nil } // openNewWIPBatch opens a new batch in the state and returns it as WipBatch -func (f *finalizer) openNewWIPBatch(ctx context.Context, batchNumber uint64, stateRoot common.Hash) (*Batch, error) { +func (f *finalizer) openNewWIPBatch(batchNumber uint64, stateRoot common.Hash) *Batch { + maxRemainingResources := getMaxBatchResources(f.batchConstraints) + + return &Batch{ + batchNumber: batchNumber, + coinbase: f.sequencerAddress, + initialStateRoot: stateRoot, + imStateRoot: stateRoot, + finalStateRoot: stateRoot, + timestamp: now(), + imRemainingResources: maxRemainingResources, + finalRemainingResources: maxRemainingResources, + closingReason: state.EmptyClosingReason, + } +} + +// insertSIPBatch inserts a new state-in-progress batch in the state db +func (f *finalizer) insertSIPBatch(ctx context.Context, batchNumber uint64, stateRoot common.Hash, dbTx pgx.Tx) error { // open next batch newStateBatch := state.Batch{ BatchNumber: batchNumber, @@ -254,82 +327,83 @@ func (f *finalizer) openNewWIPBatch(ctx context.Context, batchNumber uint64, sta LocalExitRoot: state.ZeroHash, } - dbTx, err := f.stateIntf.BeginStateTransaction(ctx) - if err != nil { - return nil, fmt.Errorf("failed to begin state transaction to open batch, error: %v", err) - } - // OpenBatch opens a new wip batch in the state - err = f.stateIntf.OpenWIPBatch(ctx, newStateBatch, dbTx) + //TODO: rename OpenWipBatch to InsertBatch + err := f.stateIntf.OpenWIPBatch(ctx, newStateBatch, dbTx) if err != nil { - if rollbackErr := dbTx.Rollback(ctx); rollbackErr != nil { - return nil, fmt.Errorf("failed to rollback due to error when open a new wip batch, rollback error: %v, error: %v", rollbackErr, err) - } - return nil, fmt.Errorf("failed to open new wip batch, error: %v", err) - } - - if err := dbTx.Commit(ctx); err != nil { - return nil, fmt.Errorf("failed to commit database transaction for opening a wip batch, error: %v", err) + return fmt.Errorf("failed to insert new batch in state db, error: %v", err) } // Send batch bookmark to the datastream f.DSSendBatchBookmark(batchNumber) // Check if synchronizer is up-to-date + //TODO: review if this is needed for !f.isSynced(ctx) { log.Info("wait for synchronizer to sync last batch") time.Sleep(time.Second) } - maxRemainingResources := getMaxRemainingResources(f.batchConstraints) - - return &Batch{ - batchNumber: newStateBatch.BatchNumber, - coinbase: newStateBatch.Coinbase, - initialStateRoot: newStateBatch.StateRoot, - imStateRoot: newStateBatch.StateRoot, - finalStateRoot: newStateBatch.StateRoot, - timestamp: newStateBatch.Timestamp, - imRemainingResources: maxRemainingResources, - finalRemainingResources: maxRemainingResources, - closingReason: state.EmptyClosingReason, - }, err + return nil } -// closeWIPBatch closes the current batch in the state -func (f *finalizer) closeWIPBatch(ctx context.Context) error { +// closeWIPBatch closes the current wip batch +func (f *finalizer) closeWIPBatch(ctx context.Context) { // 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) + f.Halt(ctx, fmt.Errorf("closing wip batch %d without L2 blocks and should have at least 1", f.wipBatch.batchNumber), false) + } + + log.Infof("wip batch %d closed, closing reason: %s", f.wipBatch.batchNumber, f.wipBatch.closingReason) + + f.wipBatch = nil +} + +// closeSIPBatch closes the current sip batch in the state +func (f *finalizer) closeSIPBatch(ctx context.Context, dbTx pgx.Tx) error { + // Sanity check: this can't happen + if f.sipBatch == nil { + f.Halt(ctx, fmt.Errorf("closing sip batch that is nil"), false) } - usedResources := getUsedBatchResources(f.batchConstraints, f.wipBatch.imRemainingResources) + // Sanity check: batch must not be empty (should have L2 blocks) + if f.sipBatch.isEmpty() { + f.Halt(ctx, fmt.Errorf("closing sip batch %d without L2 blocks and should have at least 1", f.sipBatch.batchNumber), false) + } + + usedResources := getUsedBatchResources(f.batchConstraints, f.sipBatch.imRemainingResources) receipt := state.ProcessingReceipt{ - BatchNumber: f.wipBatch.batchNumber, + BatchNumber: f.sipBatch.batchNumber, BatchResources: usedResources, - ClosingReason: f.wipBatch.closingReason, + ClosingReason: f.sipBatch.closingReason, } - dbTx, err := f.stateIntf.BeginStateTransaction(ctx) + err := f.stateIntf.CloseWIPBatch(ctx, receipt, dbTx) + if err != nil { return err } - err = f.stateIntf.CloseWIPBatch(ctx, receipt, dbTx) - if err != nil { - rollbackErr := dbTx.Rollback(ctx) - if rollbackErr != nil { - log.Errorf("error rolling back due to error when closing wip batch, rollback error: %v, error: %v", rollbackErr, err) - } - return err + // We store values needed for the batch sanity check in local variables, as we can execute the sanity check in a go func (parallel) and in this case f.sipBatch will be nil during some time + batchNumber := f.sipBatch.batchNumber + initialStateRoot := f.sipBatch.initialStateRoot + finalStateRoot := f.sipBatch.finalStateRoot + + // Reprocess full batch as sanity check + if f.cfg.SequentialBatchSanityCheck { + // Do the full batch reprocess now + _, _ = f.batchSanityCheck(ctx, batchNumber, initialStateRoot, finalStateRoot) } else { - err := dbTx.Commit(ctx) - if err != nil { - log.Errorf("error committing close wip batch, error: %v", err) - return err - } + // Do the full batch reprocess in parallel + go func() { + _, _ = f.batchSanityCheck(ctx, batchNumber, initialStateRoot, finalStateRoot) + }() } + log.Infof("sip batch %d closed in statedb, closing reason: %s", f.sipBatch.batchNumber, f.sipBatch.closingReason) + + f.sipBatch = nil + return nil } @@ -353,7 +427,7 @@ func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initi batchLog += fmt.Sprintf(" tx[%d]: %s, egpPct: %d\n", txIdx, rawTx.Tx.Hash(), rawTx.EfficiencyPercentage) } } - log.Infof("DUMP batch %d, blocks: %d, txs: %d\n%s", batch.BatchNumber, len(rawL2Blocks.Blocks), totalTxs, batchLog) + log.Infof("dump batch %d, blocks: %d, txs: %d\n%s", batch.BatchNumber, len(rawL2Blocks.Blocks), totalTxs, batchLog) f.Halt(ctx, fmt.Errorf("batch sanity check error. Check previous errors in logs to know which was the cause"), false) } @@ -384,10 +458,8 @@ func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initi return nil, ErrGetBatchByNumber } - var batchResponse *state.ProcessBatchResponse - startProcessing := time.Now() - batchResponse, err = f.stateIntf.ProcessBatchV2(ctx, batchRequest, false) + batchResponse, contextid, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, false) endProcessing := time.Now() if err != nil { @@ -429,9 +501,9 @@ func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initi return nil, ErrUpdateBatchAsChecked } - log.Infof("successful sanity check for batch %d, initialStateRoot: %s, stateRoot: %s, l2Blocks: %d, time: %v, used counters: %s", + log.Infof("successful sanity check for batch %d, initialStateRoot: %s, stateRoot: %s, l2Blocks: %d, time: %v, used counters: %s, contextId: %s", batch.BatchNumber, initialStateRoot, batchResponse.NewStateRoot.String(), len(batchResponse.BlockResponses), - endProcessing.Sub(startProcessing), f.logZKCounters(batchResponse.UsedZkCounters)) + endProcessing.Sub(startProcessing), f.logZKCounters(batchResponse.UsedZkCounters), contextid) return batchResponse, nil } @@ -509,8 +581,8 @@ func getUsedBatchResources(constraints state.BatchConstraintsCfg, remainingResou } } -// getMaxRemainingResources returns the max resources that can be used in a batch -func getMaxRemainingResources(constraints state.BatchConstraintsCfg) state.BatchResources { +// getMaxBatchResources returns the max resources that can be used in a batch +func getMaxBatchResources(constraints state.BatchConstraintsCfg) state.BatchResources { return state.BatchResources{ ZKCounters: state.ZKCounters{ GasUsed: constraints.MaxCumulativeGasUsed, @@ -527,6 +599,51 @@ func getMaxRemainingResources(constraints state.BatchConstraintsCfg) state.Batch } } +// getNeededZKCounters returns the needed counters to fit a tx in the wip batch. The needed counters are the counters used by the tx plus the high reserved counters. +// It will take into account the current high reserved counter got with previous txs but also checking reserved counters diff needed by this tx, since could be greater. +func getNeededZKCounters(highReservedCounters state.ZKCounters, usedCounters state.ZKCounters, reservedCounters state.ZKCounters) (state.ZKCounters, state.ZKCounters) { + neededCounter := func(counterName string, highCounter uint32, usedCounter uint32, reservedCounter uint32) (uint32, uint32) { + if reservedCounter < usedCounter { + log.Warnf("%s reserved counter %d is less than used counter %d, this shouldn't be possible", counterName, reservedCounter, usedCounter) + return usedCounter + highCounter, highCounter + } + diffReserved := reservedCounter - usedCounter + if diffReserved > highCounter { // reserved counter for this tx (difference) is greater that the high reserved counter got in previous txs + return usedCounter + diffReserved, diffReserved + } else { + return usedCounter + highCounter, highCounter + } + } + + needed := state.ZKCounters{} + newHigh := state.ZKCounters{} + + needed.Arithmetics, newHigh.Arithmetics = neededCounter("Arithmetics", highReservedCounters.Arithmetics, usedCounters.Arithmetics, reservedCounters.Arithmetics) + needed.Binaries, newHigh.Binaries = neededCounter("Binaries", highReservedCounters.Binaries, usedCounters.Binaries, reservedCounters.Binaries) + needed.KeccakHashes, newHigh.KeccakHashes = neededCounter("KeccakHashes", highReservedCounters.KeccakHashes, usedCounters.KeccakHashes, reservedCounters.KeccakHashes) + needed.MemAligns, newHigh.MemAligns = neededCounter("MemAligns", highReservedCounters.MemAligns, usedCounters.MemAligns, reservedCounters.MemAligns) + needed.PoseidonHashes, newHigh.PoseidonHashes = neededCounter("PoseidonHashes", highReservedCounters.PoseidonHashes, usedCounters.PoseidonHashes, reservedCounters.PoseidonHashes) + needed.PoseidonPaddings, newHigh.PoseidonPaddings = neededCounter("PoseidonPaddings", highReservedCounters.PoseidonPaddings, usedCounters.PoseidonPaddings, reservedCounters.PoseidonPaddings) + needed.Sha256Hashes_V2, newHigh.Sha256Hashes_V2 = neededCounter("Sha256Hashes_V2", highReservedCounters.Sha256Hashes_V2, usedCounters.Sha256Hashes_V2, reservedCounters.Sha256Hashes_V2) + needed.Steps, newHigh.Steps = neededCounter("Steps", highReservedCounters.Steps, usedCounters.Steps, reservedCounters.Steps) + + if reservedCounters.GasUsed < usedCounters.GasUsed { + log.Warnf("gasUsed reserved counter %d is less than used counter %d, this shouldn't be possible", reservedCounters.GasUsed, usedCounters.GasUsed) + needed.GasUsed = usedCounters.GasUsed + highReservedCounters.GasUsed + } else { + diffReserved := reservedCounters.GasUsed - usedCounters.GasUsed + if diffReserved > highReservedCounters.GasUsed { + needed.GasUsed = usedCounters.GasUsed + diffReserved + newHigh.GasUsed = diffReserved + } else { + needed.GasUsed = usedCounters.GasUsed + highReservedCounters.GasUsed + newHigh.GasUsed = highReservedCounters.GasUsed + } + } + + return needed, newHigh +} + // checkIfFinalizeBatch returns true if the batch must be closed due to a closing reason, also it returns the description of the close reason func (f *finalizer) checkIfFinalizeBatch() (bool, state.ClosingReason) { // Max txs per batch diff --git a/sequencer/config.go b/sequencer/config.go index 45210c4840..8b813c52db 100644 --- a/sequencer/config.go +++ b/sequencer/config.go @@ -70,7 +70,7 @@ type FinalizerCfg struct { // ForcedBatchesCheckInterval is used by the closing signals manager to wait for its operation ForcedBatchesCheckInterval types.Duration `mapstructure:"ForcedBatchesCheckInterval"` - // L1InfoTreeCheckInterval is the wait time to check if the L1InfoRoot has been updated + // L1InfoTreeCheckInterval is the time interval to check if the L1InfoRoot has been updated L1InfoTreeCheckInterval types.Duration `mapstructure:"L1InfoTreeCheckInterval"` // BatchMaxDeltaTimestamp is the resolution of the timestamp used to close a batch @@ -79,6 +79,10 @@ type FinalizerCfg struct { // L2BlockMaxDeltaTimestamp is the resolution of the timestamp used to close a L2 block L2BlockMaxDeltaTimestamp types.Duration `mapstructure:"L2BlockMaxDeltaTimestamp"` + // StateRootSyncInterval indicates how often the stateroot generated by the L2 block process will be synchronized with + // the stateroot used in the tx-by-tx execution + StateRootSyncInterval types.Duration `mapstructure:"StateRootSyncInterval"` + // HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches. // The Sequencer will halt after it closes the batch equal to this number HaltOnBatchNumber uint64 `mapstructure:"HaltOnBatchNumber"` diff --git a/sequencer/datastreamer.go b/sequencer/datastreamer.go index bbbfe14496..7f5e7e763a 100644 --- a/sequencer/datastreamer.go +++ b/sequencer/datastreamer.go @@ -43,7 +43,7 @@ func (f *finalizer) DSSendL2Block(batchNumber uint64, blockResponse *state.Proce l2Transactions = append(l2Transactions, l2Transaction) } - log.Infof("sending l2block %d to datastream channel", blockResponse.BlockNumber) + log.Infof("[ds-debug] sending l2block %d to datastream channel", blockResponse.BlockNumber) f.dataToStream <- state.DSL2FullBlock{ DSL2Block: l2Block, Txs: l2Transactions, diff --git a/sequencer/finalizer.go b/sequencer/finalizer.go index 64c28604ce..a06f2341fa 100644 --- a/sequencer/finalizer.go +++ b/sequencer/finalizer.go @@ -41,9 +41,13 @@ type finalizer struct { stateIntf stateInterface etherman ethermanInterface wipBatch *Batch + pipBatch *Batch // processing-in-progress batch is the batch that is being processing (L2 block process) + sipBatch *Batch // storing-in-progress batch is the batch that is being stored/updated in the state db wipL2Block *L2Block batchConstraints state.BatchConstraintsCfg haltFinalizer atomic.Bool + // stateroot sync + nextStateRootSync time.Time // forced batches nextForcedBatches []state.ForcedBatch nextForcedBatchDeadline int64 @@ -60,10 +64,12 @@ type finalizer struct { effectiveGasPrice *pool.EffectiveGasPrice // pending L2 blocks to process (executor) pendingL2BlocksToProcess chan *L2Block - pendingL2BlocksToProcessWG *sync.WaitGroup + pendingL2BlocksToProcessWG *WaitGroupCount + l2BlockReorg atomic.Bool + lastL2BlockWasReorg bool // pending L2 blocks to store in the state pendingL2BlocksToStore chan *L2Block - pendingL2BlocksToStoreWG *sync.WaitGroup + pendingL2BlocksToStoreWG *WaitGroupCount // L2 block counter for tracking purposes l2BlockCounter uint64 // executor flushid control @@ -106,6 +112,8 @@ func newFinalizer( stateIntf: stateIntf, etherman: etherman, batchConstraints: batchConstraints, + // stateroot sync + nextStateRootSync: time.Now().Add(cfg.StateRootSyncInterval.Duration), // forced batches nextForcedBatches: make([]state.ForcedBatch, 0), nextForcedBatchDeadline: 0, @@ -120,10 +128,10 @@ func newFinalizer( effectiveGasPrice: pool.NewEffectiveGasPrice(poolCfg.EffectiveGasPrice), // pending L2 blocks to process (executor) pendingL2BlocksToProcess: make(chan *L2Block, pendingL2BlocksBufferSize), - pendingL2BlocksToProcessWG: new(sync.WaitGroup), + pendingL2BlocksToProcessWG: new(WaitGroupCount), // pending L2 blocks to store in the state pendingL2BlocksToStore: make(chan *L2Block, pendingL2BlocksBufferSize), - pendingL2BlocksToStoreWG: new(sync.WaitGroup), + pendingL2BlocksToStoreWG: new(WaitGroupCount), storedFlushID: 0, // executor flushid control proverID: "", @@ -139,6 +147,7 @@ func newFinalizer( dataToStream: dataToStream, } + f.l2BlockReorg.Store(false) f.haltFinalizer.Store(false) return &f @@ -375,12 +384,19 @@ func (f *finalizer) finalizeBatches(ctx context.Context) { log.Debug("finalizer init loop") showNotFoundTxLog := true // used to log debug only the first message when there is no txs to process for { + if f.l2BlockReorg.Load() { + err := f.processL2BlockReorg(ctx) + if err != nil { + log.Errorf("error processing L2 block reorg, error: %v", err) + } + } + // We have reached the L2 block time, we need to close the current L2 block and open a new one - if f.wipL2Block.timestamp+uint64(f.cfg.L2BlockMaxDeltaTimestamp.Seconds()) <= uint64(time.Now().Unix()) { + if f.wipL2Block.createdAt.Add(f.cfg.L2BlockMaxDeltaTimestamp.Duration).Before(time.Now()) { f.finalizeWIPL2Block(ctx) } - tx, err := f.workerIntf.GetBestFittingTx(f.wipBatch.imRemainingResources) + tx, err := f.workerIntf.GetBestFittingTx(f.wipBatch.imRemainingResources, f.wipBatch.imHighReservedZKCounters) // If we have txs pending to process but none of them fits into the wip batch, we close the wip batch and open a new one if err == ErrNoFittingTransaction { @@ -394,8 +410,7 @@ func (f *finalizer) finalizeBatches(ctx context.Context) { firstTxProcess := true for { - var err error - _, err = f.processTransaction(ctx, tx, firstTxProcess) + _, err := f.processTransaction(ctx, tx, firstTxProcess) if err != nil { if err == ErrEffectiveGasPriceReprocess { firstTxProcess = false @@ -504,7 +519,7 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first loss := new(big.Int).Sub(tx.EffectiveGasPrice, txGasPrice) // If loss > 0 the warning message indicating we loss fee for thix tx if loss.Cmp(new(big.Int).SetUint64(0)) == 1 { - log.Warnf("egp-loss: gasPrice: %d, effectiveGasPrice1: %d, loss: %d, tx: %s", txGasPrice, tx.EffectiveGasPrice, loss, tx.HashStr) + log.Infof("egp-loss: gasPrice: %d, effectiveGasPrice1: %d, loss: %d, tx: %s", txGasPrice, tx.EffectiveGasPrice, loss, tx.HashStr) } tx.EffectiveGasPrice.Set(txGasPrice) @@ -542,7 +557,7 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first batchRequest.Transactions = append(batchRequest.Transactions, effectivePercentageAsDecodedHex...) executionStart := time.Now() - batchResponse, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, false) + batchResponse, contextId, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, false) executionTime := time.Since(executionStart) f.wipL2Block.metrics.transactionsTimes.executor += executionTime @@ -569,24 +584,27 @@ func (f *finalizer) processTransaction(ctx context.Context, tx *TxTracker, first oldStateRoot := f.wipBatch.imStateRoot if len(batchResponse.BlockResponses) > 0 { - errWg, err = f.handleProcessTransactionResponse(ctx, tx, batchResponse, oldStateRoot) + var neededZKCounters state.ZKCounters + errWg, err, neededZKCounters = f.handleProcessTransactionResponse(ctx, tx, batchResponse, oldStateRoot) if err != nil { return errWg, err } - } - // Update imStateRoot - f.wipBatch.imStateRoot = batchResponse.NewStateRoot + // Update imStateRoot + f.wipBatch.imStateRoot = batchResponse.NewStateRoot - log.Infof("processed tx %s, batchNumber: %d, l2Block: [%d], newStateRoot: %s, oldStateRoot: %s, time: {process: %v, executor: %v}, used counters: %s, reserved counters: %s", - tx.HashStr, batchRequest.BatchNumber, f.wipL2Block.trackingNum, batchResponse.NewStateRoot.String(), batchRequest.OldStateRoot.String(), - time.Since(start), executionTime, f.logZKCounters(batchResponse.UsedZkCounters), f.logZKCounters(batchResponse.ReservedZkCounters)) + log.Infof("processed tx %s, batchNumber: %d, l2Block: [%d], newStateRoot: %s, oldStateRoot: %s, time: {process: %v, executor: %v}, counters: {used: %s, reserved: %s, needed: %s}, contextId: %s", + tx.HashStr, batchRequest.BatchNumber, f.wipL2Block.trackingNum, batchResponse.NewStateRoot.String(), batchRequest.OldStateRoot.String(), + time.Since(start), executionTime, f.logZKCounters(batchResponse.UsedZkCounters), f.logZKCounters(batchResponse.ReservedZkCounters), f.logZKCounters(neededZKCounters), contextId) - return nil, nil + return nil, nil + } else { + return nil, fmt.Errorf("error executirn batch %d, batchResponse has returned 0 blockResponses and should return 1", f.wipBatch.batchNumber) + } } // 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, err error, neededZKCounters state.ZKCounters) { txResponse := result.BlockResponses[0].TransactionResponses[0] // Update metrics @@ -597,7 +615,7 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx 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, txResponse.RomError + return errWg, txResponse.RomError, state.ZKCounters{} } egpEnabled := f.effectiveGasPrice.IsEnabled() @@ -612,7 +630,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, err, state.ZKCounters{} } 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) @@ -637,28 +655,33 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx } if errCompare != nil && egpEnabled { - return nil, errCompare + return nil, errCompare, state.ZKCounters{} } } } - // Check if reserved resources of the tx fits in the remaining batch resources + // Check if needed resources of the tx fits in the remaining batch resources + // Needed resources are the used resources plus the max difference between used and reserved of all the txs (including this) in the batch + neededZKCounters, newHighZKCounters := getNeededZKCounters(f.wipBatch.imHighReservedZKCounters, result.UsedZkCounters, result.ReservedZkCounters) subOverflow := false - fits, overflowResource := f.wipBatch.imRemainingResources.Fits(state.BatchResources{ZKCounters: result.ReservedZkCounters, Bytes: uint64(len(tx.RawTx))}) + fits, overflowResource := f.wipBatch.imRemainingResources.Fits(state.BatchResources{ZKCounters: neededZKCounters, Bytes: uint64(len(tx.RawTx))}) if fits { // Subtract the used resources from the batch subOverflow, overflowResource = f.wipBatch.imRemainingResources.Sub(state.BatchResources{ZKCounters: result.UsedZkCounters, Bytes: uint64(len(tx.RawTx))}) - if subOverflow { // Sanity check, this cannot happen as reservedZKCounters should be >= that usedZKCounters - sLog := fmt.Sprintf("tx %s used resources exceeds the remaining batch resources, overflow resource: %s, updating metadata for tx in worker and continuing. Batch counters: %s, tx used counters: %s", - tx.HashStr, overflowResource, f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(result.UsedZkCounters)) + if subOverflow { // Sanity check, this cannot happen as neededZKCounters should be >= that usedZKCounters + sLog := fmt.Sprintf("tx %s used resources exceeds the remaining batch resources, overflow resource: %s, updating metadata for tx in worker and continuing. counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}", + tx.HashStr, overflowResource, f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(result.UsedZkCounters), f.logZKCounters(result.ReservedZkCounters), f.logZKCounters(neededZKCounters), f.logZKCounters(f.wipBatch.imHighReservedZKCounters)) log.Errorf(sLog) f.LogEvent(ctx, event.Level_Error, event.EventID_UsedZKCountersOverflow, sLog, nil) } + + // Update highReservedZKCounters + f.wipBatch.imHighReservedZKCounters = newHighZKCounters } else { - log.Infof("current tx %s reserved resources exceeds the remaining batch resources, overflow resource: %s, updating metadata for tx in worker and continuing. Batch counters: %s, tx reserved counters: %s", - tx.HashStr, overflowResource, f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(result.ReservedZkCounters)) + log.Infof("current tx %s needed resources exceeds the remaining batch resources, overflow resource: %s, updating metadata for tx in worker and continuing. counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}", + tx.HashStr, overflowResource, f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(result.UsedZkCounters), f.logZKCounters(result.ReservedZkCounters), f.logZKCounters(neededZKCounters), f.logZKCounters(f.wipBatch.imHighReservedZKCounters)) if !f.batchConstraints.IsWithinConstraints(result.ReservedZkCounters) { log.Infof("current tx %s reserved resources exceeds the max limit for batch resources (node OOC), setting tx as invalid in the pool", tx.HashStr) @@ -674,15 +697,15 @@ 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, ErrBatchResourceOverFlow + return nil, ErrBatchResourceOverFlow, state.ZKCounters{} } } - // If reserved tx resources don't fit in the remaining batch resources (or we got an overflow when trying to subtract the used resources) + // If needed tx resources don't fit in the remaining batch resources (or we got an overflow when trying to subtract the used resources) // we update the ZKCounters of the tx and returns ErrBatchResourceOverFlow error if !fits || subOverflow { f.workerIntf.UpdateTxZKCounters(txResponse.TxHash, tx.From, result.UsedZkCounters, result.ReservedZkCounters) - return nil, ErrBatchResourceOverFlow + return nil, ErrBatchResourceOverFlow, state.ZKCounters{} } // Save Enabled, GasPriceOC, BalanceOC and final effective gas price for later logging @@ -705,7 +728,7 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx // Update metrics f.wipL2Block.metrics.gas += txResponse.GasUsed - return nil, nil + return nil, nil, neededZKCounters } // compareTxEffectiveGasPrice compares newEffectiveGasPrice with tx.EffectiveGasPrice. @@ -753,14 +776,14 @@ func (f *finalizer) compareTxEffectiveGasPrice(ctx context.Context, tx *TxTracke } func (f *finalizer) updateWorkerAfterSuccessfulProcessing(ctx context.Context, txHash common.Hash, txFrom common.Address, isForced bool, result *state.ProcessBatchResponse) { - // Delete the transaction from the worker + // Delete the transaction from the worker pool if isForced { f.workerIntf.DeleteForcedTx(txHash, txFrom) - log.Debugf("forced tx %s deleted from address %s", txHash.String(), txFrom.Hex()) + log.Debugf("forced tx %s deleted from worker, address: %s", txHash.String(), txFrom.Hex()) return } else { - f.workerIntf.DeleteTx(txHash, txFrom) - log.Debugf("tx %s deleted from address %s", txHash.String(), txFrom.Hex()) + f.workerIntf.MoveTxPendingToStore(txHash, txFrom) + log.Debugf("tx %s moved to pending to store in worker, address: %s", txHash.String(), txFrom.Hex()) } txsToDelete := f.workerIntf.UpdateAfterSingleSuccessfulTxExecution(txFrom, result.ReadWriteAddresses) @@ -819,7 +842,7 @@ func (f *finalizer) handleProcessTransactionError(ctx context.Context, result *s } else { // Delete the transaction from the txSorted list f.workerIntf.DeleteTx(tx.Hash, tx.From) - log.Debugf("tx %s deleted from txSorted list", tx.HashStr) + log.Debugf("tx %s deleted from worker pool, address: %s", tx.HashStr, tx.From) wg.Add(1) go func() { @@ -859,7 +882,7 @@ func (f *finalizer) logZKCounters(counters state.ZKCounters) string { func (f *finalizer) Halt(ctx context.Context, err error, isFatal bool) { f.haltFinalizer.Store(true) - f.LogEvent(ctx, event.Level_Critical, event.EventID_FinalizerHalt, fmt.Sprintf("finalizer halted due to error, error: %s", err), nil) + f.LogEvent(ctx, event.Level_Critical, event.EventID_FinalizerHalt, fmt.Sprintf("finalizer halted due to error: %s", err), nil) if isFatal { log.Fatalf("fatal error on finalizer, error: %v", err) diff --git a/sequencer/finalizer_test.go b/sequencer/finalizer_test.go index 8e7b5fa9d9..6e54c342f8 100644 --- a/sequencer/finalizer_test.go +++ b/sequencer/finalizer_test.go @@ -941,21 +941,8 @@ func TestNewFinalizer(t *testing.T) { } }*/ -// TestFinalizer_closeBatch tests the closeBatch method. -func TestFinalizer_closeWIPBatch(t *testing.T) { - // arrange - f = setupFinalizer(true) - // set wip batch has at least one L2 block as it can not be closed empty - f.wipBatch.countOfL2Blocks++ - - usedResources := getUsedBatchResources(f.batchConstraints, f.wipBatch.imRemainingResources) - - receipt := state.ProcessingReceipt{ - BatchNumber: f.wipBatch.batchNumber, - BatchResources: usedResources, - ClosingReason: f.wipBatch.closingReason, - } - +// TestFinalizer_finalizeSIPBatch tests the finalizeSIPBatch method. +func TestFinalizer_finalizeSIPBatch(t *testing.T) { managerErr := fmt.Errorf("some err") testCases := []struct { @@ -979,22 +966,39 @@ func TestFinalizer_closeWIPBatch(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // arrange - stateMock.Mock.On("CloseWIPBatch", ctx, receipt, mock.Anything).Return(tc.managerErr).Once() + f = setupFinalizer(true) + // set wip batch has at least one L2 block as it can not be closed empty + f.sipBatch.countOfL2Blocks++ + + usedResources := getUsedBatchResources(f.batchConstraints, f.wipBatch.imRemainingResources) + + receipt := state.ProcessingReceipt{ + BatchNumber: f.wipBatch.batchNumber, + BatchResources: usedResources, + ClosingReason: f.wipBatch.closingReason, + } + + // arrange stateMock.On("BeginStateTransaction", ctx).Return(dbTxMock, nilErr).Once() + stateMock.On("CloseWIPBatch", ctx, receipt, mock.Anything).Return(tc.managerErr).Once() + if tc.managerErr == nil { + stateMock.On("GetBatchByNumber", ctx, f.sipBatch.batchNumber, nil).Return(&state.Batch{BatchNumber: f.sipBatch.batchNumber}, nilErr).Once() + stateMock.On("GetForkIDByBatchNumber", f.wipBatch.batchNumber).Return(uint64(9)).Once() + stateMock.On("GetL1InfoTreeDataFromBatchL2Data", ctx, mock.Anything, nil).Return(map[uint32]state.L1DataV2{}, state.ZeroHash, state.ZeroHash, nil) + stateMock.On("ProcessBatchV2", ctx, mock.Anything, false).Return(&state.ProcessBatchResponse{}, "", nil) + stateMock.On("UpdateBatchAsChecked", ctx, f.sipBatch.batchNumber, nil).Return(nil) dbTxMock.On("Commit", ctx).Return(nilErr).Once() } else { dbTxMock.On("Rollback", ctx).Return(nilErr).Once() } // act - err := f.closeWIPBatch(ctx) + err := f.finalizeSIPBatch(ctx) // assert if tc.expectedErr != nil { - assert.Error(t, err) - assert.EqualError(t, err, tc.expectedErr.Error()) - assert.ErrorIs(t, err, tc.managerErr) + assert.ErrorContains(t, err, tc.expectedErr.Error()) } else { assert.NoError(t, err) } @@ -1745,7 +1749,7 @@ func TestFinalizer_updateWorkerAfterSuccessfulProcessing(t *testing.T) { t.Run(tc.name, func(t *testing.T) { // arrange finalizerInstance := setupFinalizer(false) - workerMock.On("DeleteTx", tc.txTracker.Hash, tc.txTracker.From).Times(tc.expectedDeleteTxCount) + workerMock.On("MoveTxPendingToStore", tc.txTracker.Hash, tc.txTracker.From).Times(tc.expectedDeleteTxCount) txsToDelete := make([]*TxTracker, 0, len(tc.processBatchResponse.ReadWriteAddresses)) for _, infoReadWrite := range tc.processBatchResponse.ReadWriteAddresses { txsToDelete = append(txsToDelete, &TxTracker{ @@ -2037,7 +2041,7 @@ func TestFinalizer_isBatchAlmostFull(t *testing.T) { t.Run(tc.name, func(t *testing.T) { // arrange f = setupFinalizer(true) - maxRemainingResource := getMaxRemainingResources(bc) + maxRemainingResource := getMaxBatchResources(bc) f.wipBatch.imRemainingResources = tc.modifyResourceFunc(maxRemainingResource) // act @@ -2098,7 +2102,7 @@ func TestFinalizer_getConstraintThresholdUint32(t *testing.T) { func TestFinalizer_getRemainingResources(t *testing.T) { // act - remainingResources := getMaxRemainingResources(bc) + remainingResources := getMaxBatchResources(bc) // assert assert.Equal(t, remainingResources.ZKCounters.GasUsed, bc.MaxCumulativeGasUsed) @@ -2196,7 +2200,7 @@ func setupFinalizer(withWipBatch bool) *finalizer { initialStateRoot: oldHash, imStateRoot: newHash, timestamp: now(), - imRemainingResources: getMaxRemainingResources(bc), + imRemainingResources: getMaxBatchResources(bc), closingReason: state.EmptyClosingReason, } } @@ -2213,6 +2217,7 @@ func setupFinalizer(withWipBatch bool) *finalizer { poolIntf: poolMock, stateIntf: stateMock, wipBatch: wipBatch, + sipBatch: wipBatch, batchConstraints: bc, nextForcedBatches: make([]state.ForcedBatch, 0), nextForcedBatchDeadline: 0, @@ -2220,9 +2225,9 @@ func setupFinalizer(withWipBatch bool) *finalizer { effectiveGasPrice: pool.NewEffectiveGasPrice(poolCfg.EffectiveGasPrice), eventLog: eventLog, pendingL2BlocksToProcess: make(chan *L2Block, pendingL2BlocksBufferSize), - pendingL2BlocksToProcessWG: new(sync.WaitGroup), + pendingL2BlocksToProcessWG: new(WaitGroupCount), pendingL2BlocksToStore: make(chan *L2Block, pendingL2BlocksBufferSize), - pendingL2BlocksToStoreWG: new(sync.WaitGroup), + pendingL2BlocksToStoreWG: new(WaitGroupCount), storedFlushID: 0, storedFlushIDCond: sync.NewCond(new(sync.Mutex)), proverID: "", diff --git a/sequencer/forcedbatch.go b/sequencer/forcedbatch.go index ebe078c1b8..85f74abee1 100644 --- a/sequencer/forcedbatch.go +++ b/sequencer/forcedbatch.go @@ -40,15 +40,16 @@ func (f *finalizer) processForcedBatches(ctx context.Context, lastBatchNumber ui forcedBatchToProcess = *missingForcedBatch } + var contextId string log.Infof("processing forced batch %d, lastBatchNumber: %d, stateRoot: %s", forcedBatchToProcess.ForcedBatchNumber, lastBatchNumber, stateRoot.String()) - lastBatchNumber, stateRoot, err = f.processForcedBatch(ctx, forcedBatchToProcess, lastBatchNumber, stateRoot) + lastBatchNumber, stateRoot, contextId, err = f.processForcedBatch(ctx, forcedBatchToProcess, lastBatchNumber, stateRoot) if err != nil { log.Errorf("error when processing forced batch %d, error: %v", forcedBatchToProcess.ForcedBatchNumber, err) return lastBatchNumber, stateRoot } - log.Infof("processed forced batch %d, batchNumber: %d, newStateRoot: %s", forcedBatchToProcess.ForcedBatchNumber, lastBatchNumber, stateRoot.String()) + log.Infof("processed forced batch %d, batchNumber: %d, newStateRoot: %s, contextId: %s", forcedBatchToProcess.ForcedBatchNumber, lastBatchNumber, stateRoot.String(), contextId) nextForcedBatchNumber += 1 } @@ -57,26 +58,26 @@ func (f *finalizer) processForcedBatches(ctx context.Context, lastBatchNumber ui return lastBatchNumber, stateRoot } -func (f *finalizer) processForcedBatch(ctx context.Context, forcedBatch state.ForcedBatch, lastBatchNumber uint64, stateRoot common.Hash) (newLastBatchNumber uint64, newStateRoot common.Hash, retErr error) { +func (f *finalizer) processForcedBatch(ctx context.Context, forcedBatch state.ForcedBatch, lastBatchNumber uint64, stateRoot common.Hash) (newLastBatchNumber uint64, newStateRoot common.Hash, ctxId string, retErr error) { dbTx, err := f.stateIntf.BeginStateTransaction(ctx) if err != nil { log.Errorf("failed to begin state transaction for process forced batch %d, error: %v", forcedBatch.ForcedBatchNumber, err) - return lastBatchNumber, stateRoot, err + return lastBatchNumber, stateRoot, "", err } // Helper function in case we get an error when processing the forced batch - rollbackOnError := func(retError error) (newLastBatchNumber uint64, newStateRoot common.Hash, retErr error) { + rollbackOnError := func(retError error) (newLastBatchNumber uint64, newStateRoot common.Hash, ctxId string, retErr error) { err := dbTx.Rollback(ctx) if err != nil { - return lastBatchNumber, stateRoot, fmt.Errorf("rollback error due to error %v, error: %v", retError, err) + return lastBatchNumber, stateRoot, "", fmt.Errorf("rollback error due to error %v, error: %v", retError, err) } - return lastBatchNumber, stateRoot, retError + return lastBatchNumber, stateRoot, "", retError } // Get L1 block for the forced batch fbL1Block, err := f.stateIntf.GetBlockByNumber(ctx, forcedBatch.BlockNumber, dbTx) if err != nil { - return lastBatchNumber, stateRoot, fmt.Errorf("error getting L1 block number %d for forced batch %d, error: %v", forcedBatch.ForcedBatchNumber, forcedBatch.ForcedBatchNumber, err) + return lastBatchNumber, stateRoot, "", fmt.Errorf("error getting L1 block number %d for forced batch %d, error: %v", forcedBatch.ForcedBatchNumber, forcedBatch.ForcedBatchNumber, err) } newBatchNumber := lastBatchNumber + 1 @@ -107,7 +108,7 @@ func (f *finalizer) processForcedBatch(ctx context.Context, forcedBatch state.Fo Caller: stateMetrics.DiscardCallerLabel, } - batchResponse, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, true) + batchResponse, contextId, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, true) if err != nil { return rollbackOnError(fmt.Errorf("failed to process/execute forced batch %d, error: %v", forcedBatch.ForcedBatchNumber, err)) } @@ -141,7 +142,7 @@ func (f *finalizer) processForcedBatch(ctx context.Context, forcedBatch state.Fo return rollbackOnError(fmt.Errorf("error when commit dbTx when processing forced batch %d, error: %v", forcedBatch.ForcedBatchNumber, err)) } - return newBatchNumber, batchResponse.NewStateRoot, nil + return newBatchNumber, batchResponse.NewStateRoot, contextId, nil } // addForcedTxToWorker adds the txs of the forced batch to the worker diff --git a/sequencer/interfaces.go b/sequencer/interfaces.go index 10c58980ac..c92f502e10 100644 --- a/sequencer/interfaces.go +++ b/sequencer/interfaces.go @@ -50,7 +50,7 @@ type stateInterface interface { GetBalanceByStateRoot(ctx context.Context, address common.Address, root common.Hash) (*big.Int, error) GetNonceByStateRoot(ctx context.Context, address common.Address, root common.Hash) (*big.Int, error) GetLastStateRoot(ctx context.Context, dbTx pgx.Tx) (common.Hash, error) - ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, error) + ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, string, error) CloseBatch(ctx context.Context, receipt state.ProcessingReceipt, dbTx pgx.Tx) error CloseWIPBatch(ctx context.Context, receipt state.ProcessingReceipt, dbTx pgx.Tx) error GetForcedBatch(ctx context.Context, forcedBatchNumber uint64, dbTx pgx.Tx) (*state.ForcedBatch, error) @@ -84,15 +84,16 @@ type stateInterface interface { } type workerInterface interface { - GetBestFittingTx(resources state.BatchResources) (*TxTracker, error) + GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters) (*TxTracker, error) UpdateAfterSingleSuccessfulTxExecution(from common.Address, touchedAddresses map[common.Address]*state.InfoReadWrite) []*TxTracker UpdateTxZKCounters(txHash common.Hash, from common.Address, usedZKCounters state.ZKCounters, reservedZKCounters state.ZKCounters) AddTxTracker(ctx context.Context, txTracker *TxTracker) (replacedTx *TxTracker, dropReason error) MoveTxToNotReady(txHash common.Hash, from common.Address, actualNonce *uint64, actualBalance *big.Int) []*TxTracker DeleteTx(txHash common.Hash, from common.Address) - AddPendingTxToStore(txHash common.Hash, addr common.Address) - DeletePendingTxToStore(txHash common.Hash, addr common.Address) + MoveTxPendingToStore(txHash common.Hash, addr common.Address) + DeleteTxPendingToStore(txHash common.Hash, addr common.Address) NewTxTracker(tx types.Transaction, usedZKcounters state.ZKCounters, reservedZKCouners state.ZKCounters, ip string) (*TxTracker, error) AddForcedTx(txHash common.Hash, addr common.Address) DeleteForcedTx(txHash common.Hash, addr common.Address) + RestoreTxsPendingToStore(ctx context.Context) ([]*TxTracker, []*TxTracker) } diff --git a/sequencer/l2block.go b/sequencer/l2block.go index ed7ae314f6..b64a6db902 100644 --- a/sequencer/l2block.go +++ b/sequencer/l2block.go @@ -24,9 +24,11 @@ type L2Block struct { l1InfoTreeExitRoot state.L1InfoTreeExitRootStorageEntry l1InfoTreeExitRootChanged bool bytes uint64 - usedZKCounters state.ZKCounters - reservedZKCounters state.ZKCounters + usedZKCountersOnNew state.ZKCounters + reservedZKCountersOnNew state.ZKCounters + highReservedZKCounters state.ZKCounters transactions []*TxTracker + batch *Batch batchResponse *state.ProcessBatchResponse metrics metrics } @@ -85,10 +87,6 @@ func (f *finalizer) addPendingL2BlockToProcess(ctx context.Context, l2Block *L2B func (f *finalizer) addPendingL2BlockToStore(ctx context.Context, l2Block *L2Block) { f.pendingL2BlocksToStoreWG.Add(1) - for _, tx := range l2Block.transactions { - f.workerIntf.AddPendingTxToStore(tx.Hash, tx.From) - } - select { case f.pendingL2BlocksToStore <- l2Block: case <-ctx.Done(): @@ -96,13 +94,15 @@ func (f *finalizer) addPendingL2BlockToStore(ctx context.Context, l2Block *L2Blo // delete the pending TxToStore added in the worker f.pendingL2BlocksToStoreWG.Done() for _, tx := range l2Block.transactions { - f.workerIntf.DeletePendingTxToStore(tx.Hash, tx.From) + f.workerIntf.DeleteTxPendingToStore(tx.Hash, tx.From) } } } // processPendingL2Blocks processes (executor) the pending to process L2 blocks func (f *finalizer) processPendingL2Blocks(ctx context.Context) { + //rand.Seed(time.Now().UnixNano()) + for { select { case l2Block, ok := <-f.pendingL2BlocksToProcess: @@ -111,12 +111,36 @@ func (f *finalizer) processPendingL2Blocks(ctx context.Context) { return } + // if l2BlockReorg we need to "flush" the channel to discard pending L2Blocks + if f.l2BlockReorg.Load() { + f.pendingL2BlocksToProcessWG.Done() + continue + } + err := f.processL2Block(ctx, l2Block) if err != nil { + halt := false + if f.lastL2BlockWasReorg { + // We had 2 consecutives reorg in the same L2 block, we halt after log/dump the info + halt = true + } else { + f.l2BlockReorg.Store(true) + f.lastL2BlockWasReorg = true + } + + warnmsg := fmt.Sprintf("sequencer L2 block [%d] reorg detected, batch: %d, processing it...", l2Block.trackingNum, l2Block.batch.batchNumber) + log.Warnf(warnmsg) + f.LogEvent(ctx, event.Level_Critical, event.EventID_L2BlockReorg, warnmsg, nil) + // Dump L2Block info f.dumpL2Block(l2Block) - f.Halt(ctx, fmt.Errorf("error processing L2 block [%d], error: %v", l2Block.trackingNum, err), false) + + if halt { + f.Halt(ctx, fmt.Errorf("consecutives L2 block reorgs in the same L2 block [%d]", l2Block.trackingNum), false) + } + } else { + f.lastL2BlockWasReorg = false } f.pendingL2BlocksToProcessWG.Done() @@ -164,13 +188,23 @@ func (f *finalizer) storePendingL2Blocks(ctx context.Context) { func (f *finalizer) processL2Block(ctx context.Context, l2Block *L2Block) error { processStart := time.Now() - initialStateRoot := f.wipBatch.finalStateRoot + if f.pipBatch == nil { + f.pipBatch = l2Block.batch + } else if f.pipBatch.batchNumber != l2Block.batch.batchNumber { + // We have received the first L2 block of the next batch to process + // We need to "propagate" finalStateRoot to the new batch as initalStateRoot/finalStateRoot and set it as the current pipBatch + l2Block.batch.initialStateRoot = f.pipBatch.finalStateRoot + l2Block.batch.finalStateRoot = f.pipBatch.finalStateRoot + f.pipBatch = l2Block.batch + } + + initialStateRoot := f.pipBatch.finalStateRoot log.Infof("processing L2 block [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, initialStateRoot: %s txs: %d", - l2Block.trackingNum, f.wipBatch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, + l2Block.trackingNum, l2Block.batch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, l2Block.l1InfoTreeExitRootChanged, initialStateRoot, len(l2Block.transactions)) - batchResponse, batchL2DataSize, err := f.executeL2Block(ctx, initialStateRoot, l2Block) + batchResponse, batchL2DataSize, contextId, err := f.executeL2Block(ctx, initialStateRoot, l2Block) if err != nil { return fmt.Errorf("failed to execute L2 block [%d], error: %v", l2Block.trackingNum, err) @@ -199,39 +233,55 @@ func (f *finalizer) processL2Block(ctx context.Context, l2Block *L2Block) error l2Block.batchResponse = batchResponse + // Check if needed resources of the L2 block fits in the remaining batch resources + // Needed resources are the used resources plus the max difference between used and reserved of all the L2 blocks (including this) in the batch + neededZKCounters, newHighZKCounters := getNeededZKCounters(l2Block.batch.finalHighReservedZKCounters, batchResponse.UsedZkCounters, batchResponse.ReservedZkCounters) + // Update finalRemainingResources of the batch - fits, overflowResource := f.wipBatch.finalRemainingResources.Fits(state.BatchResources{ZKCounters: batchResponse.ReservedZkCounters, Bytes: batchL2DataSize}) + fits, overflowResource := l2Block.batch.finalRemainingResources.Fits(state.BatchResources{ZKCounters: neededZKCounters, Bytes: batchL2DataSize}) if fits { - subOverflow, overflowResource := f.wipBatch.finalRemainingResources.Sub(state.BatchResources{ZKCounters: batchResponse.UsedZkCounters, Bytes: batchL2DataSize}) + subOverflow, overflowResource := l2Block.batch.finalRemainingResources.Sub(state.BatchResources{ZKCounters: batchResponse.UsedZkCounters, Bytes: batchL2DataSize}) if subOverflow { // Sanity check, this cannot happen as reservedZKCounters should be >= that usedZKCounters - return fmt.Errorf("error subtracting L2 block %d [%d] used resources from the batch %d, overflow resource: %s, batch counters: %s, L2 block used counters: %s, batch bytes: %d, L2 block bytes: %d", - blockResponse.BlockNumber, l2Block.trackingNum, f.wipBatch.batchNumber, overflowResource, f.logZKCounters(f.wipBatch.finalRemainingResources.ZKCounters), f.logZKCounters(batchResponse.UsedZkCounters), f.wipBatch.finalRemainingResources.Bytes, batchL2DataSize) + return fmt.Errorf("error subtracting L2 block %d [%d] needed resources from the batch %d, overflow resource: %s, batch bytes: %d, L2 block bytes: %d, counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}", + blockResponse.BlockNumber, l2Block.trackingNum, l2Block.batch.batchNumber, overflowResource, l2Block.batch.finalRemainingResources.Bytes, batchL2DataSize, + f.logZKCounters(l2Block.batch.finalRemainingResources.ZKCounters), f.logZKCounters(batchResponse.UsedZkCounters), f.logZKCounters(batchResponse.ReservedZkCounters), f.logZKCounters(neededZKCounters), f.logZKCounters(l2Block.batch.imHighReservedZKCounters)) } - } else { - overflowLog := fmt.Sprintf("L2 block %d [%d] reserved resources exceeds the remaining batch %d resources, overflow resource: %s, batch counters: %s, L2 block reserved counters: %s, batch bytes: %d, L2 block bytes: %d", - blockResponse.BlockNumber, l2Block.trackingNum, f.wipBatch.batchNumber, overflowResource, f.logZKCounters(f.wipBatch.finalRemainingResources.ZKCounters), f.logZKCounters(batchResponse.ReservedZkCounters), f.wipBatch.finalRemainingResources.Bytes, batchL2DataSize) - log.Warnf(overflowLog) + l2Block.batch.finalHighReservedZKCounters = newHighZKCounters + l2Block.highReservedZKCounters = l2Block.batch.finalHighReservedZKCounters + } else { + overflowLog := fmt.Sprintf("L2 block %d [%d] needed resources exceeds the remaining batch %d resources, overflow resource: %s, batch bytes: %d, L2 block bytes: %d, counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}", + blockResponse.BlockNumber, l2Block.trackingNum, l2Block.batch.batchNumber, overflowResource, l2Block.batch.finalRemainingResources.Bytes, batchL2DataSize, + f.logZKCounters(l2Block.batch.finalRemainingResources.ZKCounters), f.logZKCounters(batchResponse.UsedZkCounters), f.logZKCounters(batchResponse.ReservedZkCounters), f.logZKCounters(neededZKCounters), f.logZKCounters(l2Block.batch.imHighReservedZKCounters)) f.LogEvent(ctx, event.Level_Warning, event.EventID_ReservedZKCountersOverflow, overflowLog, nil) + + return fmt.Errorf(overflowLog) } // Update finalStateRoot of the batch to the newStateRoot for the L2 block - f.wipBatch.finalStateRoot = l2Block.batchResponse.NewStateRoot + l2Block.batch.finalStateRoot = l2Block.batchResponse.NewStateRoot f.updateFlushIDs(batchResponse.FlushID, batchResponse.StoredFlushID) + if f.pendingL2BlocksToStoreWG.Count() > 0 { + startWait := time.Now() + f.pendingL2BlocksToStoreWG.Wait() + log.Debugf("waiting for previous L2 block to be stored took: %v", time.Since(startWait)) + } f.addPendingL2BlockToStore(ctx, l2Block) // metrics l2Block.metrics.l2BlockTimes.sequencer = time.Since(processStart) - l2Block.metrics.l2BlockTimes.executor - l2Block.metrics.close(l2Block.createdAt, int64(len(l2Block.transactions))) + if f.cfg.SequentialProcessL2Block { + l2Block.metrics.close(l2Block.createdAt, int64(len(l2Block.transactions)), f.cfg.SequentialProcessL2Block) + } f.metrics.addL2BlockMetrics(l2Block.metrics) - log.Infof("processed L2 block %d [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, initialStateRoot: %s, newStateRoot: %s, txs: %d/%d, blockHash: %s, infoRoot: %s, used counters: %s, reserved counters: %s", - blockResponse.BlockNumber, l2Block.trackingNum, f.wipBatch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, l2Block.l1InfoTreeExitRootChanged, initialStateRoot, l2Block.batchResponse.NewStateRoot, + log.Infof("processed L2 block %d [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, initialStateRoot: %s, newStateRoot: %s, txs: %d/%d, blockHash: %s, infoRoot: %s, counters: {used: %s, reserved: %s, needed: %s, high: %s}, contextId: %s", + blockResponse.BlockNumber, l2Block.trackingNum, l2Block.batch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, l2Block.l1InfoTreeExitRootChanged, initialStateRoot, l2Block.batchResponse.NewStateRoot, len(l2Block.transactions), len(blockResponse.TransactionResponses), blockResponse.BlockHash, blockResponse.BlockInfoRoot, - f.logZKCounters(batchResponse.UsedZkCounters), f.logZKCounters(batchResponse.ReservedZkCounters)) + f.logZKCounters(batchResponse.UsedZkCounters), f.logZKCounters(batchResponse.ReservedZkCounters), f.logZKCounters(neededZKCounters), f.logZKCounters(l2Block.batch.finalHighReservedZKCounters), contextId) if f.cfg.Metrics.EnableLog { log.Infof("metrics-log: {l2block: {num: %d, trackingNum: %d, metrics: {%s}}, interval: {startAt: %d, metrics: {%s}}}", @@ -242,12 +292,12 @@ func (f *finalizer) processL2Block(ctx context.Context, l2Block *L2Block) error } // executeL2Block executes a L2 Block in the executor and returns the batch response from the executor and the batchL2Data size -func (f *finalizer) executeL2Block(ctx context.Context, initialStateRoot common.Hash, l2Block *L2Block) (*state.ProcessBatchResponse, uint64, error) { +func (f *finalizer) executeL2Block(ctx context.Context, initialStateRoot common.Hash, l2Block *L2Block) (*state.ProcessBatchResponse, uint64, string, error) { executeL2BLockError := func(err error) { - log.Errorf("execute L2 block [%d] error %v, batch: %d, initialStateRoot: %s", l2Block.trackingNum, err, f.wipBatch.batchNumber, initialStateRoot) + log.Errorf("execute L2 block [%d] error %v, batch: %d, initialStateRoot: %s", l2Block.trackingNum, err, l2Block.batch.batchNumber, initialStateRoot) // Log batch detailed info for i, tx := range l2Block.transactions { - log.Infof("batch: %d, block: [%d], tx position: %d, tx hash: %s", f.wipBatch.batchNumber, l2Block.trackingNum, i, tx.HashStr) + log.Infof("batch: %d, block: [%d], tx position: %d, tx hash: %s", l2Block.batch.batchNumber, l2Block.trackingNum, i, tx.HashStr) } } @@ -262,7 +312,7 @@ func (f *finalizer) executeL2Block(ctx context.Context, initialStateRoot common. epHex, err := hex.DecodeHex(fmt.Sprintf("%x", tx.EGPPercentage)) if err != nil { log.Errorf("error decoding hex value for effective gas price percentage for tx %s, error: %v", tx.HashStr, err) - return nil, 0, err + return nil, 0, "", err } txData := append(tx.RawTx, epHex...) @@ -271,16 +321,16 @@ func (f *finalizer) executeL2Block(ctx context.Context, initialStateRoot common. } batchRequest := state.ProcessRequest{ - BatchNumber: f.wipBatch.batchNumber, + BatchNumber: l2Block.batch.batchNumber, OldStateRoot: initialStateRoot, - Coinbase: f.wipBatch.coinbase, + Coinbase: l2Block.batch.coinbase, L1InfoRoot_V2: state.GetMockL1InfoRoot(), TimestampLimit_V2: l2Block.timestamp, Transactions: batchL2Data, SkipFirstChangeL2Block_V2: false, SkipWriteBlockInfoRoot_V2: false, Caller: stateMetrics.DiscardCallerLabel, - ForkID: f.stateIntf.GetForkIDByBatchNumber(f.wipBatch.batchNumber), + ForkID: f.stateIntf.GetForkIDByBatchNumber(l2Block.batch.batchNumber), SkipVerifyL1InfoRoot_V2: true, L1InfoTreeData_V2: map[uint32]state.L1DataV2{}, } @@ -290,31 +340,26 @@ func (f *finalizer) executeL2Block(ctx context.Context, initialStateRoot common. MinTimestamp: uint64(l2Block.l1InfoTreeExitRoot.GlobalExitRoot.Timestamp.Unix()), } - var ( - err error - batchResponse *state.ProcessBatchResponse - ) - executionStart := time.Now() - batchResponse, err = f.stateIntf.ProcessBatchV2(ctx, batchRequest, true) + batchResponse, contextId, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, true) l2Block.metrics.l2BlockTimes.executor = time.Since(executionStart) if err != nil { executeL2BLockError(err) - return nil, 0, err + return nil, 0, contextId, err } if batchResponse.ExecutorError != nil { executeL2BLockError(batchResponse.ExecutorError) - return nil, 0, ErrExecutorError + return nil, 0, contextId, ErrExecutorError } if batchResponse.IsRomOOCError { executeL2BLockError(batchResponse.RomError_V2) - return nil, 0, ErrProcessBatchOOC + return nil, 0, contextId, ErrProcessBatchOOC } - return batchResponse, uint64(len(batchL2Data)), nil + return batchResponse, uint64(len(batchL2Data)), contextId, nil } // storeL2Block stores the L2 block in the state and updates the related batch and transactions @@ -331,7 +376,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { // If the L2 block has txs now f.storedFlushID >= l2BlockToStore.flushId, we can store tx blockResponse := l2Block.batchResponse.BlockResponses[0] log.Infof("storing L2 block %d [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, txs: %d/%d, blockHash: %s, infoRoot: %s", - blockResponse.BlockNumber, l2Block.trackingNum, f.wipBatch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, + blockResponse.BlockNumber, l2Block.trackingNum, l2Block.batch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, l2Block.l1InfoTreeExitRootChanged, len(l2Block.transactions), len(blockResponse.TransactionResponses), blockResponse.BlockHash, blockResponse.BlockInfoRoot.String()) dbTx, err := f.stateIntf.BeginStateTransaction(ctx) @@ -347,7 +392,24 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { return retError } - forkID := f.stateIntf.GetForkIDByBatchNumber(f.wipBatch.batchNumber) + if (f.sipBatch == nil) || (f.sipBatch.batchNumber != l2Block.batch.batchNumber) { + // We have l2 blocks to store from a new batch, therefore we insert this new batch in the statedb + // First we need to close the current sipBatch + if f.sipBatch != nil { + err := f.closeSIPBatch(ctx, dbTx) + if err != nil { + return rollbackOnError(fmt.Errorf("error when closing sip batch %d, initialStateRoot: %s, error: %v", f.sipBatch.batchNumber, f.sipBatch.initialStateRoot, err)) + } + } + // We insert new SIP batch in the statedb + err := f.insertSIPBatch(ctx, l2Block.batch.batchNumber, l2Block.batch.initialStateRoot, dbTx) + if err != nil { + return rollbackOnError(fmt.Errorf("error when inserting new sip batch %d, initialStateRoot: %s, error: %v", l2Block.batch.batchNumber, l2Block.batch.initialStateRoot, err)) + } + f.sipBatch = l2Block.batch + } + + forkID := f.stateIntf.GetForkIDByBatchNumber(l2Block.batch.batchNumber) txsEGPLog := []*state.EffectiveGasPriceLog{} for _, tx := range l2Block.transactions { @@ -356,16 +418,16 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { } // Store L2 block in the state - err = f.stateIntf.StoreL2Block(ctx, f.wipBatch.batchNumber, blockResponse, txsEGPLog, dbTx) + err = f.stateIntf.StoreL2Block(ctx, l2Block.batch.batchNumber, blockResponse, txsEGPLog, dbTx) if err != nil { return rollbackOnError(fmt.Errorf("database error on storing L2 block %d [%d], error: %v", blockResponse.BlockNumber, l2Block.trackingNum, err)) } // Now we need to update de BatchL2Data of the wip batch and also update the status of the L2 block txs in the pool - batch, err := f.stateIntf.GetBatchByNumber(ctx, f.wipBatch.batchNumber, dbTx) + batch, err := f.stateIntf.GetBatchByNumber(ctx, l2Block.batch.batchNumber, dbTx) if err != nil { - return rollbackOnError(fmt.Errorf("error when getting batch %d from the state, error: %v", f.wipBatch.batchNumber, err)) + return rollbackOnError(fmt.Errorf("error when getting batch %d from the state, error: %v", l2Block.batch.batchNumber, err)) } // Add changeL2Block to batch.BatchL2Data @@ -384,13 +446,15 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { batch.BatchL2Data = append(batch.BatchL2Data, blockL2Data...) batch.Resources.SumUp(state.BatchResources{ZKCounters: l2Block.batchResponse.UsedZkCounters, Bytes: uint64(len(blockL2Data))}) + batch.HighReservedZKCounters = l2Block.highReservedZKCounters receipt := state.ProcessingReceipt{ - BatchNumber: f.wipBatch.batchNumber, - StateRoot: l2Block.batchResponse.NewStateRoot, - LocalExitRoot: l2Block.batchResponse.NewLocalExitRoot, - BatchL2Data: batch.BatchL2Data, - BatchResources: batch.Resources, + BatchNumber: l2Block.batch.batchNumber, + StateRoot: l2Block.batchResponse.NewStateRoot, + LocalExitRoot: l2Block.batchResponse.NewLocalExitRoot, + BatchL2Data: batch.BatchL2Data, + BatchResources: batch.Resources, + HighReservedZKCounters: batch.HighReservedZKCounters, } // We need to update the batch GER only in the GER of the block (response) is not zero, since the final GER stored in the batch @@ -403,7 +467,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { err = f.stateIntf.UpdateWIPBatch(ctx, receipt, dbTx) if err != nil { - return rollbackOnError(fmt.Errorf("error when updating wip batch %d, error: %v", f.wipBatch.batchNumber, err)) + return rollbackOnError(fmt.Errorf("error when updating wip batch %d, error: %v", l2Block.batch.batchNumber, err)) } err = dbTx.Commit(ctx) @@ -411,8 +475,8 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { return err } - //TODO: remove this log - log.Infof("l2 block %d [%d] stored in statedb", blockResponse.BlockNumber, l2Block.trackingNum) + //TODO: remove this Log + log.Infof("[ds-debug] l2 block %d [%d] stored in statedb", blockResponse.BlockNumber, l2Block.trackingNum) // Update txs status in the pool for _, txResponse := range blockResponse.TransactionResponses { @@ -424,7 +488,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { } //TODO: remove this log - log.Infof("l2 block %d [%d] transactions updated as selected in the pooldb", blockResponse.BlockNumber, l2Block.trackingNum) + log.Infof("[ds-debug] l2 block %d [%d] transactions updated as selected in the pooldb", blockResponse.BlockNumber, l2Block.trackingNum) // Send L2 block to data streamer err = f.DSSendL2Block(f.wipBatch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex()) @@ -434,17 +498,17 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { } //TODO: remove this log - log.Infof("l2 block %d [%d] sent to datastream", blockResponse.BlockNumber, l2Block.trackingNum) + log.Infof("[ds-debug] l2 block %d [%d] sent to datastream", blockResponse.BlockNumber, l2Block.trackingNum) for _, tx := range l2Block.transactions { // Delete the tx from the pending list in the worker (addrQueue) - f.workerIntf.DeletePendingTxToStore(tx.Hash, tx.From) + f.workerIntf.DeleteTxPendingToStore(tx.Hash, tx.From) } endStoring := time.Now() log.Infof("stored L2 block %d [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, txs: %d/%d, blockHash: %s, infoRoot: %s, time: %v", - blockResponse.BlockNumber, l2Block.trackingNum, f.wipBatch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, + blockResponse.BlockNumber, l2Block.trackingNum, l2Block.batch.batchNumber, l2Block.deltaTimestamp, l2Block.timestamp, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, l2Block.l1InfoTreeExitRootChanged, len(l2Block.transactions), len(blockResponse.TransactionResponses), blockResponse.BlockHash, blockResponse.BlockInfoRoot.String(), endStoring.Sub(startStoring)) return nil @@ -452,7 +516,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { // finalizeWIPL2Block closes the wip L2 block and opens a new one func (f *finalizer) finalizeWIPL2Block(ctx context.Context) { - log.Debugf("finalizing WIP L2 block [%d]", f.wipL2Block.trackingNum) + log.Debugf("finalizing wip L2 block [%d]", f.wipL2Block.trackingNum) prevTimestamp := f.wipL2Block.timestamp prevL1InfoTreeIndex := f.wipL2Block.l1InfoTreeExitRoot.L1InfoTreeIndex @@ -464,7 +528,7 @@ func (f *finalizer) finalizeWIPL2Block(ctx context.Context) { // closeWIPL2Block closes the wip L2 block func (f *finalizer) closeWIPL2Block(ctx context.Context) { - log.Debugf("closing WIP L2 block [%d]", f.wipL2Block.trackingNum) + log.Debugf("closing wip L2 block [%d]", f.wipL2Block.trackingNum) f.wipBatch.countOfL2Blocks++ @@ -478,7 +542,46 @@ func (f *finalizer) closeWIPL2Block(ctx context.Context) { // We update imStateRoot (used in tx-by-tx execution) to the finalStateRoot that has been updated after process the WIP L2 Block f.wipBatch.imStateRoot = f.wipBatch.finalStateRoot } else { + if f.pendingL2BlocksToProcessWG.Count() > 0 { + startWait := time.Now() + f.pendingL2BlocksToProcessWG.Wait() + waitTime := time.Since(startWait) + log.Debugf("waiting for previous L2 block to be processed took: %v", waitTime) + f.wipL2Block.metrics.waitl2BlockTime = waitTime + } + f.addPendingL2BlockToProcess(ctx, f.wipL2Block) + + f.wipL2Block.metrics.close(f.wipL2Block.createdAt, int64(len(f.wipL2Block.transactions)), f.cfg.SequentialProcessL2Block) + + l2BlockResourcesUsed := state.BatchResources{} + l2BlockResourcesReserved := state.BatchResources{} + + for _, tx := range f.wipL2Block.transactions { + l2BlockResourcesUsed.ZKCounters.SumUp(tx.UsedZKCounters) + l2BlockResourcesReserved.ZKCounters.SumUp(tx.ReservedZKCounters) + } + l2BlockResourcesUsed.ZKCounters.SumUp(f.wipL2Block.usedZKCountersOnNew) + l2BlockResourcesReserved.ZKCounters.SumUp(f.wipL2Block.reservedZKCountersOnNew) + + log.Infof("closed wip L2 block [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, txs: %d, used counters: %s, reserved counters: %s", + f.wipL2Block.trackingNum, f.wipL2Block.batch.batchNumber, f.wipL2Block.deltaTimestamp, f.wipL2Block.timestamp, f.wipL2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, + f.wipL2Block.l1InfoTreeExitRootChanged, len(f.wipL2Block.transactions), f.logZKCounters(l2BlockResourcesUsed.ZKCounters), f.logZKCounters(l2BlockResourcesReserved.ZKCounters)) + + if f.nextStateRootSync.Before(time.Now()) { + log.Debug("sync stateroot time reached") + f.waitPendingL2Blocks() + + // Sanity-check: At this point f.sipBatch should be the same as the batch of the last L2 block processed + // (only if we haven't had a L2 block reorg just in the last block and it's the first one of the wipBatch) + if f.wipBatch.batchNumber != f.sipBatch.batchNumber && !(f.l2BlockReorg.Load() && f.wipBatch.countOfL2Blocks <= 2) { + f.Halt(ctx, fmt.Errorf("wipBatch %d doesn't match sipBatch %d after all pending L2 blocks has been processed/stored", f.wipBatch.batchNumber, f.sipBatch.batchNumber), false) + } + + f.wipBatch.imStateRoot = f.wipBatch.finalStateRoot + f.scheduleNextStateRootSync() + log.Infof("stateroot synced on L2 block [%d] to %s, next sync at %v", f.wipL2Block.trackingNum, f.wipBatch.imStateRoot, f.nextStateRootSync) + } } f.wipL2Block = nil @@ -489,15 +592,15 @@ func (f *finalizer) openNewWIPL2Block(ctx context.Context, prevTimestamp uint64, processStart := time.Now() newL2Block := &L2Block{} - newL2Block.createdAt = time.Now() + now := time.Now() + newL2Block.createdAt = now + newL2Block.deltaTimestamp = uint32(uint64(now.Unix()) - prevTimestamp) + newL2Block.timestamp = prevTimestamp + uint64(newL2Block.deltaTimestamp) // Tracking number f.l2BlockCounter++ newL2Block.trackingNum = f.l2BlockCounter - newL2Block.deltaTimestamp = uint32(uint64(now().Unix()) - prevTimestamp) - newL2Block.timestamp = prevTimestamp + uint64(newL2Block.deltaTimestamp) - newL2Block.transactions = []*TxTracker{} f.lastL1InfoTreeMux.Lock() @@ -521,13 +624,13 @@ func (f *finalizer) openNewWIPL2Block(ctx context.Context, prevTimestamp uint64, f.wipL2Block = newL2Block - log.Debugf("creating new WIP L2 block [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v", + log.Debugf("creating new wip L2 block [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v", f.wipL2Block.trackingNum, f.wipBatch.batchNumber, f.wipL2Block.deltaTimestamp, f.wipL2Block.timestamp, f.wipL2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, f.wipL2Block.l1InfoTreeExitRootChanged) // We process (execute) the new wip L2 block to update the imStateRoot and also get the counters used by the wip l2block - batchResponse, err := f.executeNewWIPL2Block(ctx) + batchResponse, contextId, err := f.executeNewWIPL2Block(ctx) if err != nil { - f.Halt(ctx, fmt.Errorf("failed to execute new WIP L2 block [%d], error: %v ", f.wipL2Block.trackingNum, err), false) + f.Halt(ctx, fmt.Errorf("failed to execute new wip L2 block [%d], error: %v ", f.wipL2Block.trackingNum, err), false) } if len(batchResponse.BlockResponses) != 1 { @@ -541,23 +644,28 @@ func (f *finalizer) openNewWIPL2Block(ctx context.Context, prevTimestamp uint64, // Save the resources used/reserved and subtract the ZKCounters reserved by the new WIP L2 block from the WIP batch // We need to increase the poseidon hashes to reserve in the batch the hashes needed to write the L1InfoRoot when processing the final L2 Block (SkipWriteBlockInfoRoot_V2=false) - f.wipL2Block.usedZKCounters = batchResponse.UsedZkCounters - f.wipL2Block.usedZKCounters.PoseidonHashes = (batchResponse.UsedZkCounters.PoseidonHashes * 2) + 2 // nolint:gomnd - f.wipL2Block.reservedZKCounters = batchResponse.ReservedZkCounters - f.wipL2Block.reservedZKCounters.PoseidonHashes = (batchResponse.ReservedZkCounters.PoseidonHashes * 2) + 2 // nolint:gomnd + f.wipL2Block.usedZKCountersOnNew = batchResponse.UsedZkCounters + f.wipL2Block.usedZKCountersOnNew.PoseidonHashes = (batchResponse.UsedZkCounters.PoseidonHashes * 2) + 2 // nolint:gomnd + f.wipL2Block.reservedZKCountersOnNew = batchResponse.ReservedZkCounters + f.wipL2Block.reservedZKCountersOnNew.PoseidonHashes = (batchResponse.ReservedZkCounters.PoseidonHashes * 2) + 2 // nolint:gomnd f.wipL2Block.bytes = changeL2BlockSize + neededZKCounters, newHighZKCounters := getNeededZKCounters(f.wipBatch.imHighReservedZKCounters, f.wipL2Block.usedZKCountersOnNew, f.wipL2Block.reservedZKCountersOnNew) subOverflow := false - fits, overflowResource := f.wipBatch.imRemainingResources.Fits(state.BatchResources{ZKCounters: f.wipL2Block.reservedZKCounters, Bytes: f.wipL2Block.bytes}) + fits, overflowResource := f.wipBatch.imRemainingResources.Fits(state.BatchResources{ZKCounters: neededZKCounters, Bytes: f.wipL2Block.bytes}) if fits { - subOverflow, overflowResource = f.wipBatch.imRemainingResources.Sub(state.BatchResources{ZKCounters: f.wipL2Block.usedZKCounters, Bytes: f.wipL2Block.bytes}) + subOverflow, overflowResource = f.wipBatch.imRemainingResources.Sub(state.BatchResources{ZKCounters: f.wipL2Block.usedZKCountersOnNew, Bytes: f.wipL2Block.bytes}) if subOverflow { // Sanity check, this cannot happen as reservedZKCounters should be >= that usedZKCounters - log.Infof("new WIP L2 block [%d] used resources exceeds the remaining batch resources, overflow resource: %s, closing WIP batch and creating new one. Batch counters: %s, L2 block used counters: %s", - f.wipL2Block.trackingNum, overflowResource, f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(f.wipL2Block.usedZKCounters)) + log.Infof("new wip L2 block [%d] used resources exceeds the remaining batch resources, overflow resource: %s, closing WIP batch and creating new one. counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}", + f.wipL2Block.trackingNum, overflowResource, + f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(f.wipL2Block.usedZKCountersOnNew), f.logZKCounters(f.wipL2Block.reservedZKCountersOnNew), f.logZKCounters(neededZKCounters), f.logZKCounters(f.wipBatch.imHighReservedZKCounters)) } + + f.wipBatch.imHighReservedZKCounters = newHighZKCounters } else { - log.Infof("new WIP L2 block [%d] reserved resources exceeds the remaining batch resources, overflow resource: %s, closing WIP batch and creating new one. Batch counters: %s, L2 block reserved counters: %s", - f.wipL2Block.trackingNum, overflowResource, f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(f.wipL2Block.reservedZKCounters)) + log.Infof("new wip L2 block [%d] reserved resources exceeds the remaining batch resources, overflow resource: %s, closing WIP batch and creating new one. counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}", + f.wipL2Block.trackingNum, overflowResource, + f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(f.wipL2Block.usedZKCountersOnNew), f.logZKCounters(f.wipL2Block.reservedZKCountersOnNew), f.logZKCounters(neededZKCounters), f.logZKCounters(f.wipBatch.imHighReservedZKCounters)) } // If reserved WIP L2 block resources don't fit in the remaining batch resources (or we got an overflow when trying to subtract the used resources) @@ -565,19 +673,22 @@ func (f *finalizer) openNewWIPL2Block(ctx context.Context, prevTimestamp uint64, if !fits || subOverflow { err := f.closeAndOpenNewWIPBatch(ctx, state.ResourceExhaustedClosingReason) if err != nil { - f.Halt(ctx, fmt.Errorf("failed to create new WIP batch [%d], error: %v", f.wipL2Block.trackingNum, err), true) + f.Halt(ctx, fmt.Errorf("failed to create new wip batch [%d], error: %v", f.wipL2Block.trackingNum, err), true) } } + // We assign the wipBatch as the batch where this wipL2Block belongs + f.wipL2Block.batch = f.wipBatch + f.wipL2Block.metrics.newL2BlockTimes.sequencer = time.Since(processStart) - f.wipL2Block.metrics.newL2BlockTimes.executor - log.Infof("created new WIP L2 block [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, oldStateRoot: %s, imStateRoot: %s, used counters: %s, reserved counters: %s", - f.wipL2Block.trackingNum, f.wipBatch.batchNumber, f.wipL2Block.deltaTimestamp, f.wipL2Block.timestamp, f.wipL2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, - f.wipL2Block.l1InfoTreeExitRootChanged, oldIMStateRoot, f.wipL2Block.imStateRoot, f.logZKCounters(f.wipL2Block.usedZKCounters), f.logZKCounters(f.wipL2Block.reservedZKCounters)) + log.Infof("created new wip L2 block [%d], batch: %d, deltaTimestamp: %d, timestamp: %d, l1InfoTreeIndex: %d, l1InfoTreeIndexChanged: %v, oldStateRoot: %s, imStateRoot: %s, counters: {used: %s, reserved: %s, needed: %s, high: %s}, contextId: %s", + f.wipL2Block.trackingNum, f.wipBatch.batchNumber, f.wipL2Block.deltaTimestamp, f.wipL2Block.timestamp, f.wipL2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, f.wipL2Block.l1InfoTreeExitRootChanged, oldIMStateRoot, f.wipL2Block.imStateRoot, + f.logZKCounters(f.wipL2Block.usedZKCountersOnNew), f.logZKCounters(f.wipL2Block.usedZKCountersOnNew), f.logZKCounters(f.wipL2Block.reservedZKCountersOnNew), f.logZKCounters(f.wipBatch.imHighReservedZKCounters), contextId) } // executeNewWIPL2Block executes an empty L2 Block in the executor and returns the batch response from the executor -func (f *finalizer) executeNewWIPL2Block(ctx context.Context) (*state.ProcessBatchResponse, error) { +func (f *finalizer) executeNewWIPL2Block(ctx context.Context) (*state.ProcessBatchResponse, string, error) { batchRequest := state.ProcessRequest{ BatchNumber: f.wipBatch.batchNumber, OldStateRoot: f.wipBatch.imStateRoot, @@ -600,22 +711,38 @@ func (f *finalizer) executeNewWIPL2Block(ctx context.Context) (*state.ProcessBat } executorTime := time.Now() - batchResponse, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, false) + batchResponse, contextId, err := f.stateIntf.ProcessBatchV2(ctx, batchRequest, false) f.wipL2Block.metrics.newL2BlockTimes.executor = time.Since(executorTime) if err != nil { - return nil, err + return nil, contextId, err } if batchResponse.ExecutorError != nil { - return nil, ErrExecutorError + return nil, contextId, ErrExecutorError } if batchResponse.IsRomOOCError { - return nil, ErrProcessBatchOOC + return nil, contextId, ErrProcessBatchOOC } - return batchResponse, nil + return batchResponse, contextId, nil +} + +func (f *finalizer) scheduleNextStateRootSync() { + f.nextStateRootSync = time.Now().Add(f.cfg.StateRootSyncInterval.Duration) +} + +func (f *finalizer) waitPendingL2Blocks() { + // Wait until all L2 blocks are processed/discarded + startWait := time.Now() + f.pendingL2BlocksToProcessWG.Wait() + log.Debugf("waiting for pending L2 blocks to be processed took: %v", time.Since(startWait)) + + // Wait until all L2 blocks are stored + startWait = time.Now() + f.pendingL2BlocksToStoreWG.Wait() + log.Debugf("waiting for pending L2 blocks to be stored took: %v", time.Since(startWait)) } func (f *finalizer) dumpL2Block(l2Block *L2Block) { @@ -628,12 +755,12 @@ func (f *finalizer) dumpL2Block(l2Block *L2Block) { sLog := "" for i, tx := range l2Block.transactions { - sLog += fmt.Sprintf(" tx[%d] hash: %s, from: %s, nonce: %d, gas: %d, gasPrice: %d, bytes: %d, egpPct: %d, used counters: %s, reserved counters: %s\n", + sLog += fmt.Sprintf(" tx[%d] hash: %s, from: %s, nonce: %d, gas: %d, gasPrice: %d, bytes: %d, egpPct: %d, countersOnNew: {used: %s, reserved: %s}\n", i, tx.HashStr, tx.FromStr, tx.Nonce, tx.Gas, tx.GasPrice, tx.Bytes, tx.EGPPercentage, f.logZKCounters(tx.UsedZKCounters), f.logZKCounters(tx.ReservedZKCounters)) } - log.Infof("DUMP L2 block [%d], timestamp: %d, deltaTimestamp: %d, imStateRoot: %s, l1InfoTreeIndex: %d, bytes: %d, used counters: %s, reserved counters: %s\n%s", + log.Infof("dump L2 block [%d], timestamp: %d, deltaTimestamp: %d, imStateRoot: %s, l1InfoTreeIndex: %d, bytes: %d, used counters: %s, reserved counters: %s\n%s", l2Block.trackingNum, l2Block.timestamp, l2Block.deltaTimestamp, l2Block.imStateRoot, l2Block.l1InfoTreeExitRoot.L1InfoTreeIndex, l2Block.bytes, - f.logZKCounters(l2Block.usedZKCounters), f.logZKCounters(l2Block.reservedZKCounters), sLog) + f.logZKCounters(l2Block.usedZKCountersOnNew), f.logZKCounters(l2Block.reservedZKCountersOnNew), sLog) sLog = "" if blockResp != nil { @@ -643,7 +770,7 @@ func (f *finalizer) dumpL2Block(l2Block *L2Block) { txResp.EffectivePercentage, txResp.HasGaspriceOpcode, txResp.HasBalanceOpcode) } - log.Infof("DUMP L2 block %d [%d] response, timestamp: %d, parentHash: %s, coinbase: %s, ger: %s, blockHashL1: %s, gasUsed: %d, blockInfoRoot: %s, blockHash: %s, used counters: %s, reserved counters: %s\n%s", + log.Infof("dump L2 block %d [%d] response, timestamp: %d, parentHash: %s, coinbase: %s, ger: %s, blockHashL1: %s, gasUsed: %d, blockInfoRoot: %s, blockHash: %s, counters: {used: %s, reserved: %s}\n%s", blockResp.BlockNumber, l2Block.trackingNum, blockResp.Timestamp, blockResp.ParentHash, blockResp.Coinbase, blockResp.GlobalExitRoot, blockResp.BlockHashL1, blockResp.GasUsed, blockResp.BlockInfoRoot, blockResp.BlockHash, f.logZKCounters(l2Block.batchResponse.UsedZkCounters), f.logZKCounters(l2Block.batchResponse.ReservedZkCounters), sLog) } diff --git a/sequencer/metrics.go b/sequencer/metrics.go index 2be977e23e..5481587399 100644 --- a/sequencer/metrics.go +++ b/sequencer/metrics.go @@ -6,6 +6,7 @@ import ( "time" ) +// SEQUENTIAL L2 BLOCK PROCESSING // |-----------------------------------------------------------------------------| -> totalTime // |------------| |-------------------------| -> transactionsTime // |-newL2Block-|----tx 1----| |---tx 2---|-----tx 3-----| |-----l2Block-----| @@ -14,6 +15,20 @@ import ( // idle | |iiii| | |ii| | -> idleTime // +// PARALLEL L2 BLOCK PROCESSING +// |---------------------------------------------------------------------------------------------| -> totalTime +// |-----------------------L2 block 1-----------------------| |-----------L2 block 2------------| +// |------------| |-------------------------| |--------------------| -> transactionsTime +// |-newL2Block-|----tx 1----| |---tx 2---|-----tx 3-----| |-newL2Block-|--tx 4---|---tx 5---| +// sequencer |sssss ss|sss ss| |sss ss|sss ss| |sssss ss|ss ss|sss ss| -> sequencerTime +// executor | xxxxx | xxxxxxx | | xxxxx | xxxxxxxxx | | xxxxx | xxxxxx | xxxxx | -> executorTime +// idle | |iiii| | |ii| | -> idleTime + +// | -> L2 block 1 | +// seq-l2block | |ssss ss| +// exe-l2block | | xxxxxxxxxxx | +// + type processTimes struct { sequencer time.Duration executor time.Duration @@ -41,9 +56,11 @@ type metrics struct { newL2BlockTimes processTimes transactionsTimes processTimes l2BlockTimes processTimes + waitl2BlockTime time.Duration gas uint64 estimatedTxsPerSec float64 estimatedGasPerSec uint64 + sequential bool } func (m *metrics) sub(mSub metrics) { @@ -53,6 +70,7 @@ func (m *metrics) sub(mSub metrics) { m.newL2BlockTimes.sub(mSub.newL2BlockTimes) m.transactionsTimes.sub(mSub.transactionsTimes) m.l2BlockTimes.sub(mSub.l2BlockTimes) + m.waitl2BlockTime -= mSub.waitl2BlockTime m.gas -= mSub.gas } @@ -63,32 +81,57 @@ func (m *metrics) sumUp(mSumUp metrics) { m.newL2BlockTimes.sumUp(mSumUp.newL2BlockTimes) m.transactionsTimes.sumUp(mSumUp.transactionsTimes) m.l2BlockTimes.sumUp(mSumUp.l2BlockTimes) + m.waitl2BlockTime += mSumUp.waitl2BlockTime m.gas += mSumUp.gas } func (m *metrics) executorTime() time.Duration { - return m.newL2BlockTimes.executor + m.transactionsTimes.executor + m.l2BlockTimes.executor + if m.sequential { + return m.newL2BlockTimes.executor + m.transactionsTimes.executor + m.l2BlockTimes.executor + } else { + return m.newL2BlockTimes.executor + m.transactionsTimes.executor + m.waitl2BlockTime + } } func (m *metrics) sequencerTime() time.Duration { - return m.newL2BlockTimes.sequencer + m.transactionsTimes.sequencer + m.l2BlockTimes.sequencer + if m.sequential { + return m.newL2BlockTimes.sequencer + m.transactionsTimes.sequencer + m.l2BlockTimes.sequencer + } else { + return m.newL2BlockTimes.sequencer + m.transactionsTimes.sequencer + } } func (m *metrics) totalTime() time.Duration { - return m.newL2BlockTimes.total() + m.transactionsTimes.total() + m.l2BlockTimes.total() + m.idleTime + if m.sequential { + return m.newL2BlockTimes.total() + m.transactionsTimes.total() + m.l2BlockTimes.total() + m.idleTime + } else { + return m.newL2BlockTimes.total() + m.transactionsTimes.total() + m.waitl2BlockTime + m.idleTime + } } -func (m *metrics) close(createdAt time.Time, l2BlockTxsCount int64) { +func (m *metrics) close(createdAt time.Time, l2BlockTxsCount int64, sequential bool) { // Compute pending fields m.closedAt = time.Now() totalTime := time.Since(createdAt) + m.sequential = sequential m.l2BlockTxsCount = l2BlockTxsCount - m.transactionsTimes.sequencer = totalTime - m.idleTime - m.newL2BlockTimes.total() - m.transactionsTimes.executor - m.l2BlockTimes.total() + + if m.sequential { + m.transactionsTimes.sequencer = totalTime - m.idleTime - m.newL2BlockTimes.total() - m.transactionsTimes.executor - m.l2BlockTimes.total() + } else { + m.transactionsTimes.sequencer = totalTime - m.idleTime - m.newL2BlockTimes.total() - m.transactionsTimes.executor - m.waitl2BlockTime + } // Compute performance if m.processedTxsCount > 0 { - // timePerTxuS is the average time spent per tx. This includes the l2Block time since the processing time of this section is proportional to the number of txs - timePerTxuS := (m.transactionsTimes.total() + m.l2BlockTimes.total()).Microseconds() / m.processedTxsCount + var timePerTxuS int64 + if m.sequential { + // timePerTxuS is the average time spent per tx. This includes the l2Block time since the processing time of this section is proportional to the number of txs + timePerTxuS = (m.transactionsTimes.total() + m.l2BlockTimes.total()).Microseconds() / m.processedTxsCount + } else { + // timePerTxuS is the average time spent per tx. This includes the waitl2Block + timePerTxuS = (m.transactionsTimes.total() + m.waitl2BlockTime).Microseconds() / m.processedTxsCount + } // estimatedTxs is the number of transactions that we estimate could have been processed in the block estimatedTxs := float64(totalTime.Microseconds()-m.newL2BlockTimes.total().Microseconds()) / float64(timePerTxuS) // estimatedTxxPerSec is the estimated transactions per second (rounded to 2 decimal digits) @@ -102,8 +145,8 @@ func (m *metrics) close(createdAt time.Time, l2BlockTxsCount int64) { } func (m *metrics) log() string { - return fmt.Sprintf("blockTxs: %d, txs: %d, gas: %d, txsSec: %.2f, gasSec: %d, time: {total: %d, idle: %d, sequencer: {total: %d, newL2Block: %d, txs: %d, l2Block: %d}, executor: {total: %d, newL2Block: %d, txs: %d, l2Block: %d}", - m.l2BlockTxsCount, m.processedTxsCount, m.gas, m.estimatedTxsPerSec, m.estimatedGasPerSec, m.totalTime().Microseconds(), m.idleTime.Microseconds(), + return fmt.Sprintf("blockTxs: %d, txs: %d, gas: %d, txsSec: %.2f, gasSec: %d, time: {total: %d, idle: %d, waitL2Block: %d, sequencer: {total: %d, newL2Block: %d, txs: %d, l2Block: %d}, executor: {total: %d, newL2Block: %d, txs: %d, l2Block: %d}", + m.l2BlockTxsCount, m.processedTxsCount, m.gas, m.estimatedTxsPerSec, m.estimatedGasPerSec, m.totalTime().Microseconds(), m.idleTime.Microseconds(), m.waitl2BlockTime.Microseconds(), m.sequencerTime().Microseconds(), m.newL2BlockTimes.sequencer.Microseconds(), m.transactionsTimes.sequencer.Microseconds(), m.l2BlockTimes.sequencer.Microseconds(), m.executorTime().Microseconds(), m.newL2BlockTimes.executor.Microseconds(), m.transactionsTimes.executor.Microseconds(), m.l2BlockTimes.executor.Microseconds()) } diff --git a/sequencer/mock_state.go b/sequencer/mock_state.go index 2a53e28c25..f7f3861d4b 100644 --- a/sequencer/mock_state.go +++ b/sequencer/mock_state.go @@ -982,7 +982,7 @@ func (_m *StateMock) OpenWIPBatch(ctx context.Context, batch state.Batch, dbTx p } // ProcessBatchV2 provides a mock function with given fields: ctx, request, updateMerkleTree -func (_m *StateMock) ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, error) { +func (_m *StateMock) ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, string, error) { ret := _m.Called(ctx, request, updateMerkleTree) if len(ret) == 0 { @@ -990,8 +990,9 @@ func (_m *StateMock) ProcessBatchV2(ctx context.Context, request state.ProcessRe } var r0 *state.ProcessBatchResponse - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, error)); ok { + var r1 string + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, string, error)); ok { return rf(ctx, request, updateMerkleTree) } if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) *state.ProcessBatchResponse); ok { @@ -1002,13 +1003,19 @@ func (_m *StateMock) ProcessBatchV2(ctx context.Context, request state.ProcessRe } } - if rf, ok := ret.Get(1).(func(context.Context, state.ProcessRequest, bool) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, state.ProcessRequest, bool) string); ok { r1 = rf(ctx, request, updateMerkleTree) } else { - r1 = ret.Error(1) + r1 = ret.Get(1).(string) } - return r0, r1 + if rf, ok := ret.Get(2).(func(context.Context, state.ProcessRequest, bool) error); ok { + r2 = rf(ctx, request, updateMerkleTree) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 } // StoreL2Block provides a mock function with given fields: ctx, batchNumber, l2Block, txsEGPLog, dbTx diff --git a/sequencer/mock_worker.go b/sequencer/mock_worker.go index 215cd08c8e..3ff546f724 100644 --- a/sequencer/mock_worker.go +++ b/sequencer/mock_worker.go @@ -25,11 +25,6 @@ func (_m *WorkerMock) AddForcedTx(txHash common.Hash, addr common.Address) { _m.Called(txHash, addr) } -// AddPendingTxToStore provides a mock function with given fields: txHash, addr -func (_m *WorkerMock) AddPendingTxToStore(txHash common.Hash, addr common.Address) { - _m.Called(txHash, addr) -} - // AddTxTracker provides a mock function with given fields: ctx, txTracker func (_m *WorkerMock) AddTxTracker(ctx context.Context, txTracker *TxTracker) (*TxTracker, error) { ret := _m.Called(ctx, txTracker) @@ -65,19 +60,19 @@ func (_m *WorkerMock) DeleteForcedTx(txHash common.Hash, addr common.Address) { _m.Called(txHash, addr) } -// DeletePendingTxToStore provides a mock function with given fields: txHash, addr -func (_m *WorkerMock) DeletePendingTxToStore(txHash common.Hash, addr common.Address) { - _m.Called(txHash, addr) -} - // DeleteTx provides a mock function with given fields: txHash, from func (_m *WorkerMock) DeleteTx(txHash common.Hash, from common.Address) { _m.Called(txHash, from) } -// GetBestFittingTx provides a mock function with given fields: resources -func (_m *WorkerMock) GetBestFittingTx(resources state.BatchResources) (*TxTracker, error) { - ret := _m.Called(resources) +// DeleteTxPendingToStore provides a mock function with given fields: txHash, addr +func (_m *WorkerMock) DeleteTxPendingToStore(txHash common.Hash, addr common.Address) { + _m.Called(txHash, addr) +} + +// GetBestFittingTx provides a mock function with given fields: remainingResources, highReservedCounters +func (_m *WorkerMock) GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters) (*TxTracker, error) { + ret := _m.Called(remainingResources, highReservedCounters) if len(ret) == 0 { panic("no return value specified for GetBestFittingTx") @@ -85,19 +80,19 @@ func (_m *WorkerMock) GetBestFittingTx(resources state.BatchResources) (*TxTrack var r0 *TxTracker var r1 error - if rf, ok := ret.Get(0).(func(state.BatchResources) (*TxTracker, error)); ok { - return rf(resources) + if rf, ok := ret.Get(0).(func(state.BatchResources, state.ZKCounters) (*TxTracker, error)); ok { + return rf(remainingResources, highReservedCounters) } - if rf, ok := ret.Get(0).(func(state.BatchResources) *TxTracker); ok { - r0 = rf(resources) + if rf, ok := ret.Get(0).(func(state.BatchResources, state.ZKCounters) *TxTracker); ok { + r0 = rf(remainingResources, highReservedCounters) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*TxTracker) } } - if rf, ok := ret.Get(1).(func(state.BatchResources) error); ok { - r1 = rf(resources) + if rf, ok := ret.Get(1).(func(state.BatchResources, state.ZKCounters) error); ok { + r1 = rf(remainingResources, highReservedCounters) } else { r1 = ret.Error(1) } @@ -105,6 +100,11 @@ func (_m *WorkerMock) GetBestFittingTx(resources state.BatchResources) (*TxTrack return r0, r1 } +// MoveTxPendingToStore provides a mock function with given fields: txHash, addr +func (_m *WorkerMock) MoveTxPendingToStore(txHash common.Hash, addr common.Address) { + _m.Called(txHash, addr) +} + // MoveTxToNotReady provides a mock function with given fields: txHash, from, actualNonce, actualBalance func (_m *WorkerMock) MoveTxToNotReady(txHash common.Hash, from common.Address, actualNonce *uint64, actualBalance *big.Int) []*TxTracker { ret := _m.Called(txHash, from, actualNonce, actualBalance) @@ -155,6 +155,38 @@ func (_m *WorkerMock) NewTxTracker(tx types.Transaction, usedZKcounters state.ZK return r0, r1 } +// RestoreTxsPendingToStore provides a mock function with given fields: ctx +func (_m *WorkerMock) RestoreTxsPendingToStore(ctx context.Context) ([]*TxTracker, []*TxTracker) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for RestoreTxsPendingToStore") + } + + var r0 []*TxTracker + var r1 []*TxTracker + if rf, ok := ret.Get(0).(func(context.Context) ([]*TxTracker, []*TxTracker)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []*TxTracker); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*TxTracker) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) []*TxTracker); ok { + r1 = rf(ctx) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).([]*TxTracker) + } + } + + return r0, r1 +} + // UpdateAfterSingleSuccessfulTxExecution provides a mock function with given fields: from, touchedAddresses func (_m *WorkerMock) UpdateAfterSingleSuccessfulTxExecution(from common.Address, touchedAddresses map[common.Address]*state.InfoReadWrite) []*TxTracker { ret := _m.Called(from, touchedAddresses) diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go index 22201776ce..b79ad26c17 100644 --- a/sequencer/sequencer.go +++ b/sequencer/sequencer.go @@ -75,7 +75,7 @@ func (s *Sequencer) Start(ctx context.Context) { err := s.pool.MarkWIPTxsAsPending(ctx) if err != nil { - log.Fatalf("failed to mark WIP txs as pending, error: %v", err) + log.Fatalf("failed to mark wip txs as pending, error: %v", err) } // Start stream server if enabled @@ -93,8 +93,6 @@ func (s *Sequencer) Start(ctx context.Context) { s.updateDataStreamerFile(ctx, s.cfg.StreamServer.ChainID) } - go s.loadFromPool(ctx) - if s.streamServer != nil { go s.sendDataToStreamer(s.cfg.StreamServer.ChainID) } @@ -104,6 +102,8 @@ func (s *Sequencer) Start(ctx context.Context) { s.finalizer = newFinalizer(s.cfg.Finalizer, s.poolCfg, s.worker, s.pool, s.stateIntf, s.etherman, s.address, s.isSynced, s.batchCfg.Constraints, s.eventLog, s.streamServer, s.workerReadyTxsCond, s.dataToStream) go s.finalizer.Start(ctx) + go s.loadFromPool(ctx) + go s.deleteOldPoolTxs(ctx) go s.expireOldWorkerTxs(ctx) @@ -147,6 +147,11 @@ func (s *Sequencer) updateDataStreamerFile(ctx context.Context, chainID uint64) func (s *Sequencer) deleteOldPoolTxs(ctx context.Context) { for { time.Sleep(s.cfg.DeletePoolTxsCheckInterval.Duration) + + if s.finalizer.haltFinalizer.Load() { + return + } + log.Infof("trying to get txs to delete from the pool...") earliestTxHash, err := s.pool.GetEarliestProcessedTx(ctx) if err != nil { @@ -181,6 +186,11 @@ func (s *Sequencer) deleteOldPoolTxs(ctx context.Context) { func (s *Sequencer) expireOldWorkerTxs(ctx context.Context) { for { time.Sleep(s.cfg.TxLifetimeCheckInterval.Duration) + + if s.finalizer.haltFinalizer.Load() { + return + } + txTrackers := s.worker.ExpireTransactions(s.cfg.TxLifetimeMax.Duration) failedReason := ErrExpiredTransaction.Error() for _, txTracker := range txTrackers { @@ -195,6 +205,10 @@ func (s *Sequencer) expireOldWorkerTxs(ctx context.Context) { // loadFromPool keeps loading transactions from the pool func (s *Sequencer) loadFromPool(ctx context.Context) { for { + if s.finalizer.haltFinalizer.Load() { + return + } + poolTransactions, err := s.pool.GetNonWIPPendingTxs(ctx) if err != nil && err != pool.ErrNotFound { log.Errorf("error loading txs from pool, error: %v", err) @@ -257,7 +271,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { l2Block := data //TODO: remove this log - log.Infof("start atomic op for l2block %d", l2Block.L2BlockNumber) + log.Infof("[ds-debug] start atomic op for l2block %d", l2Block.L2BlockNumber) err = s.streamServer.StartAtomicOp() if err != nil { log.Errorf("failed to start atomic op for l2block %d, error: %v ", l2Block.L2BlockNumber, err) @@ -270,7 +284,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { } //TODO: remove this log - log.Infof("add stream bookmark for l2block %d", l2Block.L2BlockNumber) + log.Infof("[ds-debug] add stream bookmark for l2block %d", l2Block.L2BlockNumber) _, err = s.streamServer.AddStreamBookmark(bookMark.Encode()) if err != nil { log.Errorf("failed to add stream bookmark for l2block %d, error: %v", l2Block.L2BlockNumber, err) @@ -286,7 +300,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { } //TODO: remove this log - log.Infof("get previous l2block %d", l2Block.L2BlockNumber-1) + log.Infof("[ds-debug] get previous l2block %d", l2Block.L2BlockNumber-1) previousL2BlockEntry, err := s.streamServer.GetFirstEventAfterBookmark(bookMark.Encode()) if err != nil { log.Errorf("failed to get previous l2block %d, error: %v", l2Block.L2BlockNumber-1, err) @@ -310,7 +324,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { } //TODO: remove this log - log.Infof("add l2blockStart stream entry for l2block %d", l2Block.L2BlockNumber) + log.Infof("[ds-debug] add l2blockStart stream entry for l2block %d", l2Block.L2BlockNumber) _, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockStart, blockStart.Encode()) if err != nil { log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err) @@ -318,7 +332,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { } //TODO: remove this log - log.Infof("adding l2tx stream entries for l2block %d", l2Block.L2BlockNumber) + log.Infof("[ds-debug] adding l2tx stream entries for l2block %d", l2Block.L2BlockNumber) for _, l2Transaction := range l2Block.Txs { _, err = s.streamServer.AddStreamEntry(state.EntryTypeL2Tx, l2Transaction.Encode()) if err != nil { @@ -334,7 +348,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { } //TODO: remove this log - log.Infof("add l2blockEnd stream entry for l2block %d", l2Block.L2BlockNumber) + log.Infof("[ds-debug] add l2blockEnd stream entry for l2block %d", l2Block.L2BlockNumber) _, err = s.streamServer.AddStreamEntry(state.EntryTypeL2BlockEnd, blockEnd.Encode()) if err != nil { log.Errorf("failed to add stream entry for l2block %d, error: %v", l2Block.L2BlockNumber, err) @@ -342,7 +356,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { } //TODO: remove this log - log.Infof("commit atomic op for l2block %d", l2Block.L2BlockNumber) + log.Infof("[ds-debug] commit atomic op for l2block %d", l2Block.L2BlockNumber) err = s.streamServer.CommitAtomicOp() if err != nil { log.Errorf("failed to commit atomic op for l2block %d, error: %v ", l2Block.L2BlockNumber, err) @@ -350,7 +364,7 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) { } //TODO: remove this log - log.Infof("l2block %d sent to datastream", l2Block.L2BlockNumber) + log.Infof("[ds-debug] l2block %d sent to datastream", l2Block.L2BlockNumber) // Stream a bookmark case state.DSBookMark: diff --git a/sequencer/waitgroupcount.go b/sequencer/waitgroupcount.go new file mode 100644 index 0000000000..436f088514 --- /dev/null +++ b/sequencer/waitgroupcount.go @@ -0,0 +1,29 @@ +package sequencer + +import ( + "sync" + "sync/atomic" +) + +// WaitGroupCount implements a sync.WaitGroup that also has a field to get the WaitGroup counter +type WaitGroupCount struct { + sync.WaitGroup + count atomic.Int32 +} + +// Add adds delta to the WaitGroup and increase the counter +func (wg *WaitGroupCount) Add(delta int) { + wg.count.Add(int32(delta)) + wg.WaitGroup.Add(delta) +} + +// Done decrements the WaitGroup and counter by one +func (wg *WaitGroupCount) Done() { + wg.count.Add(-1) + wg.WaitGroup.Done() +} + +// Count returns the counter of the WaitGroup +func (wg *WaitGroupCount) Count() int { + return int(wg.count.Load()) +} diff --git a/sequencer/worker.go b/sequencer/worker.go index 0d0b378872..c6be5ed5ab 100644 --- a/sequencer/worker.go +++ b/sequencer/worker.go @@ -19,7 +19,9 @@ import ( type Worker struct { pool map[string]*addrQueue txSortedList *txSortedList - workerMutex sync.Mutex + pendingToStore []*TxTracker + reorgedTxs []*TxTracker + workerMutex *sync.Mutex state stateInterface batchConstraints state.BatchConstraintsCfg readyTxsCond *timeoutCond @@ -30,7 +32,9 @@ type Worker struct { func NewWorker(state stateInterface, constraints state.BatchConstraintsCfg, readyTxsCond *timeoutCond) *Worker { w := Worker{ pool: make(map[string]*addrQueue), + workerMutex: new(sync.Mutex), txSortedList: newTxSortedList(), + pendingToStore: []*TxTracker{}, state: state, batchConstraints: constraints, readyTxsCond: readyTxsCond, @@ -46,31 +50,36 @@ func (w *Worker) NewTxTracker(tx types.Transaction, usedZKCounters state.ZKCount // AddTxTracker adds a new Tx to the Worker func (w *Worker) AddTxTracker(ctx context.Context, tx *TxTracker) (replacedTx *TxTracker, dropReason error) { - w.workerMutex.Lock() + return w.addTxTracker(ctx, tx, w.workerMutex) +} + +// addTxTracker adds a new Tx to the Worker +func (w *Worker) addTxTracker(ctx context.Context, tx *TxTracker, mutex *sync.Mutex) (replacedTx *TxTracker, dropReason error) { + mutexLock(mutex) // Make sure the IP is valid. if tx.IP != "" && !pool.IsValidIP(tx.IP) { - w.workerMutex.Unlock() + mutexUnlock(mutex) return nil, pool.ErrInvalidIP } // Make sure the transaction's reserved ZKCounters are within the constraints. if !w.batchConstraints.IsWithinConstraints(tx.ReservedZKCounters) { log.Errorf("outOfCounters error (node level) for tx %s", tx.Hash.String()) - w.workerMutex.Unlock() + mutexUnlock(mutex) return nil, pool.ErrOutOfCounters } if (w.wipTx != nil) && (w.wipTx.FromStr == tx.FromStr) && (w.wipTx.Nonce == tx.Nonce) { log.Infof("adding tx %s (nonce %d) from address %s that matches current processing tx %s (nonce %d), rejecting it as duplicated nonce", tx.Hash, tx.Nonce, tx.From, w.wipTx.Hash, w.wipTx.Nonce) - w.workerMutex.Unlock() + mutexUnlock(mutex) return nil, ErrDuplicatedNonce } addr, found := w.pool[tx.FromStr] if !found { // Unlock the worker to let execute other worker functions while creating the new AddrQueue - w.workerMutex.Unlock() + mutexUnlock(mutex) root, err := w.state.GetLastStateRoot(ctx, nil) if err != nil { @@ -94,7 +103,7 @@ func (w *Worker) AddTxTracker(ctx context.Context, tx *TxTracker) (replacedTx *T addr = newAddrQueue(tx.From, nonce.Uint64(), balance) // Lock again the worker - w.workerMutex.Lock() + mutexLock(mutex) w.pool[tx.FromStr] = addr log.Debugf("new addrQueue %s created (nonce: %d, balance: %s)", tx.FromStr, nonce.Uint64(), balance.String()) @@ -106,7 +115,7 @@ func (w *Worker) AddTxTracker(ctx context.Context, tx *TxTracker) (replacedTx *T newReadyTx, prevReadyTx, repTx, dropReason = addr.addTx(tx) if dropReason != nil { log.Infof("dropped tx %s from addrQueue %s, reason: %s", tx.HashStr, tx.FromStr, dropReason.Error()) - w.workerMutex.Unlock() + mutexUnlock(mutex) return repTx, dropReason } @@ -124,7 +133,7 @@ func (w *Worker) AddTxTracker(ctx context.Context, tx *TxTracker) (replacedTx *T log.Debugf("tx %s (nonce: %d, gasPrice: %d, addr: %s) has been replaced", repTx.HashStr, repTx.Nonce, repTx.GasPrice, tx.FromStr) } - w.workerMutex.Unlock() + mutexUnlock(mutex) return repTx, nil } @@ -199,6 +208,28 @@ func (w *Worker) MoveTxToNotReady(txHash common.Hash, from common.Address, actua return txsToDelete } +// deleteTx deletes a regular tx from the addrQueue +func (w *Worker) deleteTx(txHash common.Hash, addr common.Address) *TxTracker { + addrQueue, found := w.pool[addr.String()] + if found { + deletedTx, isReady := addrQueue.deleteTx(txHash) + if deletedTx != nil { + if isReady { + log.Debugf("tx %s deleted from TxSortedList", deletedTx.Hash) + w.txSortedList.delete(deletedTx) + } + } else { + log.Warnf("tx %s not found in addrQueue %s", txHash, addr) + } + + return deletedTx + } else { + log.Warnf("addrQueue %s not found", addr) + + return nil + } +} + // DeleteTx deletes a regular tx from the addrQueue func (w *Worker) DeleteTx(txHash common.Hash, addr common.Address) { w.workerMutex.Lock() @@ -206,16 +237,7 @@ func (w *Worker) DeleteTx(txHash common.Hash, addr common.Address) { w.resetWipTx(txHash) - addrQueue, found := w.pool[addr.String()] - if found { - deletedReadyTx := addrQueue.deleteTx(txHash) - if deletedReadyTx != nil { - log.Debugf("tx %s deleted from TxSortedList", deletedReadyTx.Hash.String()) - w.txSortedList.delete(deletedReadyTx) - } - } else { - log.Warnf("addrQueue %s not found", addr.String()) - } + w.deleteTx(txHash, addr) } // DeleteForcedTx deletes a forced tx from the addrQueue @@ -257,55 +279,153 @@ func (w *Worker) UpdateTxZKCounters(txHash common.Hash, addr common.Address, use } } -// AddPendingTxToStore adds a tx to the addrQueue list of pending txs to store in the DB (trusted state) -func (w *Worker) AddPendingTxToStore(txHash common.Hash, addr common.Address) { +// MoveTxPendingToStore moves a tx to pending to store list +func (w *Worker) MoveTxPendingToStore(txHash common.Hash, addr common.Address) { + // TODO: Add test for this function + w.workerMutex.Lock() defer w.workerMutex.Unlock() - addrQueue, found := w.pool[addr.String()] + // Delete from worker pool and addrQueue + deletedTx := w.deleteTx(txHash, addr) - if found { + // Add tx to pending to store list in worker + if deletedTx != nil { + w.pendingToStore = append(w.pendingToStore, deletedTx) + log.Debugf("tx %s add to pendingToStore, order: %d", deletedTx.Hash, len(w.pendingToStore)) + } else { + log.Warnf("tx %s not found when moving it to pending to store, address: %s", txHash, addr) + } + + // Add tx to pending to store list in addrQueue + if addrQueue, found := w.pool[addr.String()]; found { addrQueue.addPendingTxToStore(txHash) } else { - log.Warnf("addrQueue %s not found", addr.String()) + log.Warnf("addrQueue %s not found when moving tx %s to pending to store", addr, txHash) } } +// RestoreTxsPendingToStore restores the txs pending to store and move them to the worker pool to be processed again +func (w *Worker) RestoreTxsPendingToStore(ctx context.Context) ([]*TxTracker, []*TxTracker) { + // TODO: Add test for this function + // TODO: We need to process restored txs in the same order we processed initially + + w.workerMutex.Lock() + + addrList := make(map[common.Address]struct{}) + txsList := []*TxTracker{} + w.reorgedTxs = []*TxTracker{} + + // Add txs pending to store to the list that will include all the txs to reprocess again + // Add txs to the reorgedTxs list to get them in the order which they were processed before the L2 block reorg + // Get also the addresses of theses txs since we will need to recreate them + for _, txToStore := range w.pendingToStore { + txsList = append(txsList, txToStore) + w.reorgedTxs = append(w.reorgedTxs, txToStore) + addrList[txToStore.From] = struct{}{} + } + + // Add txs from addrQueues that will be recreated and delete addrQueues from the pool list + for addr := range addrList { + addrQueue, found := w.pool[addr.String()] + if found { + txsList = append(txsList, addrQueue.getTransactions()...) + if addrQueue.readyTx != nil { + // Delete readyTx from the txSortedList + w.txSortedList.delete(addrQueue.readyTx) + } + // Delete the addrQueue to recreate it later + delete(w.pool, addr.String()) + } + } + + // Clear pendingToStore list + w.pendingToStore = []*TxTracker{} + // Clear wip tx + w.wipTx = nil + + for _, tx := range w.reorgedTxs { + log.Infof("reorged tx %s, nonce %d, from: %s", tx.Hash, tx.Nonce, tx.From) + } + + replacedTxs := []*TxTracker{} + droppedTxs := []*TxTracker{} + // Add again in the worker the txs to restore (this will recreate addrQueues) + for _, restoredTx := range txsList { + replacedTx, dropReason := w.addTxTracker(ctx, restoredTx, nil) + if dropReason != nil { + droppedTxs = append(droppedTxs, restoredTx) + } + if replacedTx != nil { + droppedTxs = append(replacedTxs, restoredTx) + } + } + + w.workerMutex.Unlock() + + // In this scenario we shouldn't have dropped or replaced txs but we return it just in case + return droppedTxs, replacedTxs +} + // AddForcedTx adds a forced tx to the addrQueue func (w *Worker) AddForcedTx(txHash common.Hash, addr common.Address) { w.workerMutex.Lock() defer w.workerMutex.Unlock() - addrQueue, found := w.pool[addr.String()] - - if found { + if addrQueue, found := w.pool[addr.String()]; found { addrQueue.addForcedTx(txHash) } else { log.Warnf("addrQueue %s not found", addr.String()) } } -// DeletePendingTxToStore delete a tx from the addrQueue list of pending txs to store in the DB (trusted state) -func (w *Worker) DeletePendingTxToStore(txHash common.Hash, addr common.Address) { +// DeleteTxPendingToStore delete a tx from the addrQueue list of pending txs to store in the DB (trusted state) +func (w *Worker) DeleteTxPendingToStore(txHash common.Hash, addr common.Address) { w.workerMutex.Lock() defer w.workerMutex.Unlock() - addrQueue, found := w.pool[addr.String()] + // Delete tx from pending to store list in worker + found := false + for i, txToStore := range w.pendingToStore { + if txToStore.Hash == txHash { + found = true + w.pendingToStore = append(w.pendingToStore[:i], w.pendingToStore[i+1:]...) + } + } + if !found { + log.Warnf("tx %s not found when deleting it from worker pool", txHash) + } - if found { + // Delete tx from pending to store list in addrQueue + if addrQueue, found := w.pool[addr.String()]; found { addrQueue.deletePendingTxToStore(txHash) } else { - log.Warnf("addrQueue %s not found", addr.String()) + log.Warnf("addrQueue %s not found when deleting pending to store tx %s", addr, txHash) } } // GetBestFittingTx gets the most efficient tx that fits in the available batch resources -func (w *Worker) GetBestFittingTx(resources state.BatchResources) (*TxTracker, error) { +func (w *Worker) GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters) (*TxTracker, error) { w.workerMutex.Lock() defer w.workerMutex.Unlock() w.wipTx = nil + // If we are processing a L2 block reorg we return the next tx in the reorg list + for len(w.reorgedTxs) > 0 { + reorgedTx := w.reorgedTxs[0] + w.reorgedTxs = w.reorgedTxs[1:] + if addrQueue, found := w.pool[reorgedTx.FromStr]; found { + if addrQueue.readyTx != nil && addrQueue.readyTx.Hash == reorgedTx.Hash { + return reorgedTx, nil + } else { + log.Warnf("reorged tx %s is not the ready tx for addrQueue %s, this shouldn't happen", reorgedTx.Hash, reorgedTx.From) + } + } else { + log.Warnf("addrQueue %s for reorged tx %s not found, this shouldn't happen", reorgedTx.From, reorgedTx.Hash) + } + } + if w.txSortedList.len() == 0 { return nil, ErrTransactionsListEmpty } @@ -334,8 +454,9 @@ func (w *Worker) GetBestFittingTx(resources state.BatchResources) (*TxTracker, e foundMutex.RUnlock() txCandidate := w.txSortedList.getByIndex(i) - overflow, _ := bresources.Sub(state.BatchResources{ZKCounters: txCandidate.ReservedZKCounters, Bytes: txCandidate.Bytes}) - if overflow { + needed, _ := getNeededZKCounters(highReservedCounters, txCandidate.UsedZKCounters, txCandidate.ReservedZKCounters) + fits, _ := bresources.Fits(state.BatchResources{ZKCounters: needed, Bytes: txCandidate.Bytes}) + if !fits { // We don't add this Tx continue } @@ -349,7 +470,7 @@ func (w *Worker) GetBestFittingTx(resources state.BatchResources) (*TxTracker, e return } - }(i, resources) + }(i, remainingResources) } wg.Wait() @@ -402,3 +523,15 @@ func (w *Worker) resetWipTx(txHash common.Hash) { w.wipTx = nil } } + +func mutexLock(mutex *sync.Mutex) { + if mutex != nil { + mutex.Lock() + } +} + +func mutexUnlock(mutex *sync.Mutex) { + if mutex != nil { + mutex.Unlock() + } +} diff --git a/sequencer/worker_test.go b/sequencer/worker_test.go index a86d7a2f3f..0e2375ad37 100644 --- a/sequencer/worker_test.go +++ b/sequencer/worker_test.go @@ -258,7 +258,7 @@ func TestWorkerGetBestTx(t *testing.T) { ct := 0 for { - tx, _ := worker.GetBestFittingTx(rc) + tx, _ := worker.GetBestFittingTx(rc, state.ZKCounters{}) if tx != nil { if ct >= len(expectedGetBestTx) { t.Fatalf("Error getting more best tx than expected. Expected=%d, Actual=%d", len(expectedGetBestTx), ct+1) diff --git a/state/batch.go b/state/batch.go index 7cf10ebeab..f5325a08c7 100644 --- a/state/batch.go +++ b/state/batch.go @@ -42,11 +42,12 @@ type Batch struct { AccInputHash common.Hash // Timestamp (<=incaberry) -> batch time // (>incaberry) -> minTimestamp used in batch creation, real timestamp is in virtual_batch.batch_timestamp - Timestamp time.Time - Transactions []types.Transaction - GlobalExitRoot common.Hash - ForcedBatchNum *uint64 - Resources BatchResources + Timestamp time.Time + Transactions []types.Transaction + GlobalExitRoot common.Hash + ForcedBatchNum *uint64 + Resources BatchResources + HighReservedZKCounters ZKCounters // WIP: if WIP == true is a openBatch WIP bool } @@ -83,6 +84,8 @@ const ( MaxDeltaTimestampClosingReason ClosingReason = "Max delta timestamp" // NoTxFitsClosingReason is the closing reason used when any of the txs in the pool (worker) fits in the remaining resources of the batch NoTxFitsClosingReason ClosingReason = "No transaction fits" + // L2BlockReorgClonsingReason is the closing reason used when we have a L2 block reorg (unexpected error, like OOC, when processing L2 block) + L2BlockReorgClonsingReason ClosingReason = "L2 block reorg" // Reason due Synchronizer // ------------------------------------------------------------------------------------------ @@ -109,9 +112,10 @@ type ProcessingReceipt struct { GlobalExitRoot common.Hash AccInputHash common.Hash // Txs []types.Transaction - BatchL2Data []byte - ClosingReason ClosingReason - BatchResources BatchResources + BatchL2Data []byte + ClosingReason ClosingReason + BatchResources BatchResources + HighReservedZKCounters ZKCounters } // VerifiedBatch represents a VerifiedBatch diff --git a/state/batchV2.go b/state/batchV2.go index 9de0f39949..32f6fd856b 100644 --- a/state/batchV2.go +++ b/state/batchV2.go @@ -38,7 +38,7 @@ type ProcessingContextV2 struct { } // ProcessBatchV2 processes a batch for forkID >= ETROG -func (s *State) ProcessBatchV2(ctx context.Context, request ProcessRequest, updateMerkleTree bool) (*ProcessBatchResponse, error) { +func (s *State) ProcessBatchV2(ctx context.Context, request ProcessRequest, updateMerkleTree bool) (*ProcessBatchResponse, string, error) { updateMT := uint32(cFalse) if updateMerkleTree { updateMT = cTrue @@ -85,16 +85,16 @@ func (s *State) ProcessBatchV2(ctx context.Context, request ProcessRequest, upda res, err := s.sendBatchRequestToExecutorV2(ctx, processBatchRequest, request.Caller) if err != nil { - return nil, err + return nil, "", err } var result *ProcessBatchResponse result, err = s.convertToProcessBatchResponseV2(res) if err != nil { - return nil, err + return nil, "", err } - return result, nil + return result, processBatchRequest.ContextId, nil } // ExecuteBatchV2 is used by the synchronizer to reprocess batches to compare generated state root vs stored one diff --git a/state/pgstatestorage/batch.go b/state/pgstatestorage/batch.go index 5b1d1f57fd..843c725b12 100644 --- a/state/pgstatestorage/batch.go +++ b/state/pgstatestorage/batch.go @@ -84,7 +84,7 @@ func (p *PostgresStorage) GetVerifiedBatch(ctx context.Context, batchNumber uint // GetLastNBatches returns the last numBatches batches. func (p *PostgresStorage) GetLastNBatches(ctx context.Context, numBatches uint, dbTx pgx.Tx) ([]*state.Batch, error) { - const getLastNBatchesSQL = "SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, wip from state.batch ORDER BY batch_num DESC LIMIT $1" + const getLastNBatchesSQL = "SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, high_reserved_counters, wip from state.batch ORDER BY batch_num DESC LIMIT $1" e := p.getExecQuerier(dbTx) rows, err := e.Query(ctx, getLastNBatchesSQL, numBatches) @@ -257,7 +257,7 @@ func (p *PostgresStorage) SetInitSyncBatch(ctx context.Context, batchNumber uint // GetBatchByNumber returns the batch with the given number. func (p *PostgresStorage) GetBatchByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.Batch, error) { const getBatchByNumberSQL = ` - SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, wip + SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, high_reserved_counters, wip FROM state.batch WHERE batch_num = $1` @@ -277,7 +277,7 @@ func (p *PostgresStorage) GetBatchByNumber(ctx context.Context, batchNumber uint // GetBatchByTxHash returns the batch including the given tx func (p *PostgresStorage) GetBatchByTxHash(ctx context.Context, transactionHash common.Hash, dbTx pgx.Tx) (*state.Batch, error) { const getBatchByTxHashSQL = ` - SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data, b.forced_batch_num, b.batch_resources, b.wip + SELECT b.batch_num, b.global_exit_root, b.local_exit_root, b.acc_input_hash, b.state_root, b.timestamp, b.coinbase, b.raw_txs_data, b.forced_batch_num, b.batch_resources, b.high_reserved_counters, b.wip FROM state.transaction t, state.batch b, state.l2block l WHERE t.hash = $1 AND l.block_num = t.l2_block_num AND b.batch_num = l.batch_num` @@ -296,7 +296,7 @@ func (p *PostgresStorage) GetBatchByTxHash(ctx context.Context, transactionHash // GetBatchByL2BlockNumber returns the batch related to the l2 block accordingly to the provided l2 block number. func (p *PostgresStorage) GetBatchByL2BlockNumber(ctx context.Context, l2BlockNumber uint64, dbTx pgx.Tx) (*state.Batch, error) { const getBatchByL2BlockNumberSQL = ` - SELECT bt.batch_num, bt.global_exit_root, bt.local_exit_root, bt.acc_input_hash, bt.state_root, bt.timestamp, bt.coinbase, bt.raw_txs_data, bt.forced_batch_num, bt.batch_resources, bt.wip + SELECT bt.batch_num, bt.global_exit_root, bt.local_exit_root, bt.acc_input_hash, bt.state_root, bt.timestamp, bt.coinbase, bt.raw_txs_data, bt.forced_batch_num, bt.batch_resources, bt.high_reserved_counters, bt.wip FROM state.batch bt INNER JOIN state.l2block bl ON bt.batch_num = bl.batch_num @@ -329,6 +329,7 @@ func (p *PostgresStorage) GetVirtualBatchByNumber(ctx context.Context, batchNumb raw_txs_data, forced_batch_num, batch_resources, + high_reserved_counters, wip FROM state.batch @@ -386,13 +387,14 @@ func (p *PostgresStorage) IsSequencingTXSynced(ctx context.Context, transactionH func scanBatch(row pgx.Row) (state.Batch, error) { batch := state.Batch{} var ( - gerStr string - lerStr *string - aihStr *string - stateStr *string - coinbaseStr string - resourcesData []byte - wip bool + gerStr string + lerStr *string + aihStr *string + stateStr *string + coinbaseStr string + resourcesData []byte + highReservedCounters []byte + wip bool ) err := row.Scan( &batch.BatchNumber, @@ -405,6 +407,7 @@ func scanBatch(row pgx.Row) (state.Batch, error) { &batch.BatchL2Data, &batch.ForcedBatchNum, &resourcesData, + &highReservedCounters, &wip, ) if err != nil { @@ -427,6 +430,14 @@ func scanBatch(row pgx.Row) (state.Batch, error) { return batch, err } } + + if highReservedCounters != nil { + err = json.Unmarshal(highReservedCounters, &batch.HighReservedZKCounters) + if err != nil { + return batch, err + } + } + batch.WIP = wip batch.Coinbase = common.HexToAddress(coinbaseStr) @@ -663,7 +674,7 @@ func (p *PostgresStorage) CloseWIPBatchInStorage(ctx context.Context, receipt st // GetWIPBatchInStorage returns the wip batch in the state func (p *PostgresStorage) GetWIPBatchInStorage(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.Batch, error) { const getWIPBatchByNumberSQL = ` - SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, wip + SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, high_reserved_counters, wip FROM state.batch WHERE batch_num = $1 AND wip = TRUE` @@ -778,6 +789,7 @@ func (p *PostgresStorage) GetVirtualBatchToProve(ctx context.Context, lastVerfie b.raw_txs_data, b.forced_batch_num, b.batch_resources, + b.high_reserved_counters, b.wip FROM state.batch b, @@ -842,7 +854,7 @@ func (p *PostgresStorage) GetSequences(ctx context.Context, lastVerifiedBatchNum // GetLastClosedBatch returns the latest closed batch func (p *PostgresStorage) GetLastClosedBatch(ctx context.Context, dbTx pgx.Tx) (*state.Batch, error) { const getLastClosedBatchSQL = ` - SELECT bt.batch_num, bt.global_exit_root, bt.local_exit_root, bt.acc_input_hash, bt.state_root, bt.timestamp, bt.coinbase, bt.raw_txs_data, bt.forced_batch_num, bt.batch_resources, bt.wip + SELECT bt.batch_num, bt.global_exit_root, bt.local_exit_root, bt.acc_input_hash, bt.state_root, bt.timestamp, bt.coinbase, bt.raw_txs_data, bt.forced_batch_num, bt.batch_resources, bt.high_reserved_counters, bt.wip FROM state.batch bt WHERE wip = FALSE ORDER BY bt.batch_num DESC @@ -891,14 +903,20 @@ func (p *PostgresStorage) UpdateBatchL2Data(ctx context.Context, batchNumber uin // UpdateWIPBatch updates the data in a batch func (p *PostgresStorage) UpdateWIPBatch(ctx context.Context, receipt state.ProcessingReceipt, dbTx pgx.Tx) error { - const updateL2DataSQL = "UPDATE state.batch SET raw_txs_data = $2, global_exit_root = $3, state_root = $4, local_exit_root = $5, batch_resources = $6 WHERE batch_num = $1" + const updateL2DataSQL = "UPDATE state.batch SET raw_txs_data = $2, global_exit_root = $3, state_root = $4, local_exit_root = $5, batch_resources = $6, high_reserved_counters = $7 WHERE batch_num = $1" e := p.getExecQuerier(dbTx) batchResourcesJsonBytes, err := json.Marshal(receipt.BatchResources) if err != nil { return err } - _, err = e.Exec(ctx, updateL2DataSQL, receipt.BatchNumber, receipt.BatchL2Data, receipt.GlobalExitRoot.String(), receipt.StateRoot.String(), receipt.LocalExitRoot.String(), string(batchResourcesJsonBytes)) + + highReservedCounters, err := json.Marshal(receipt.HighReservedZKCounters) + if err != nil { + return err + } + + _, err = e.Exec(ctx, updateL2DataSQL, receipt.BatchNumber, receipt.BatchL2Data, receipt.GlobalExitRoot.String(), receipt.StateRoot.String(), receipt.LocalExitRoot.String(), string(batchResourcesJsonBytes), string(highReservedCounters)) return err } @@ -1050,7 +1068,7 @@ func (p *PostgresStorage) GetLatestBatchGlobalExitRoot(ctx context.Context, dbTx // GetNotCheckedBatches returns the batches that are closed but not checked func (p *PostgresStorage) GetNotCheckedBatches(ctx context.Context, dbTx pgx.Tx) ([]*state.Batch, error) { const getBatchesNotCheckedSQL = ` - SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, wip + SELECT batch_num, global_exit_root, local_exit_root, acc_input_hash, state_root, timestamp, coinbase, raw_txs_data, forced_batch_num, batch_resources, high_reserved_counters, wip from state.batch WHERE wip IS FALSE AND checked IS FALSE ORDER BY batch_num ASC` e := p.getExecQuerier(dbTx) diff --git a/state/test/forkid_etrog/etrog_test.go b/state/test/forkid_etrog/etrog_test.go index d8dfd77398..55f7ef48fb 100644 --- a/state/test/forkid_etrog/etrog_test.go +++ b/state/test/forkid_etrog/etrog_test.go @@ -125,7 +125,7 @@ func TestStateTransition(t *testing.T) { SkipVerifyL1InfoRoot_V2: testCase.L1InfoTree.SkipVerifyL1InfoRoot, } - processResponse, _ := testState.ProcessBatchV2(ctx, processRequest, true) + processResponse, _, _ := testState.ProcessBatchV2(ctx, processRequest, true) require.Nil(t, processResponse.ExecutorError) require.Equal(t, testCase.ExpectedNewStateRoot, processResponse.NewStateRoot.String()) } diff --git a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go index fa570dbe7f..81fe9a430e 100644 --- a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go +++ b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go @@ -2429,7 +2429,7 @@ func (_c *StateFullInterface_ProcessBatch_Call) RunAndReturn(run func(context.Co } // ProcessBatchV2 provides a mock function with given fields: ctx, request, updateMerkleTree -func (_m *StateFullInterface) ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, error) { +func (_m *StateFullInterface) ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, string, error) { ret := _m.Called(ctx, request, updateMerkleTree) if len(ret) == 0 { @@ -2437,8 +2437,9 @@ func (_m *StateFullInterface) ProcessBatchV2(ctx context.Context, request state. } var r0 *state.ProcessBatchResponse - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, error)); ok { + var r1 string + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, string, error)); ok { return rf(ctx, request, updateMerkleTree) } if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) *state.ProcessBatchResponse); ok { @@ -2449,13 +2450,19 @@ func (_m *StateFullInterface) ProcessBatchV2(ctx context.Context, request state. } } - if rf, ok := ret.Get(1).(func(context.Context, state.ProcessRequest, bool) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, state.ProcessRequest, bool) string); ok { r1 = rf(ctx, request, updateMerkleTree) } else { - r1 = ret.Error(1) + r1 = ret.Get(1).(string) } - return r0, r1 + if rf, ok := ret.Get(2).(func(context.Context, state.ProcessRequest, bool) error); ok { + r2 = rf(ctx, request, updateMerkleTree) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 } // StateFullInterface_ProcessBatchV2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProcessBatchV2' @@ -2478,12 +2485,12 @@ func (_c *StateFullInterface_ProcessBatchV2_Call) Run(run func(ctx context.Conte return _c } -func (_c *StateFullInterface_ProcessBatchV2_Call) Return(_a0 *state.ProcessBatchResponse, _a1 error) *StateFullInterface_ProcessBatchV2_Call { - _c.Call.Return(_a0, _a1) +func (_c *StateFullInterface_ProcessBatchV2_Call) Return(_a0 *state.ProcessBatchResponse, _a1 string, _a2 error) *StateFullInterface_ProcessBatchV2_Call { + _c.Call.Return(_a0, _a1, _a2) return _c } -func (_c *StateFullInterface_ProcessBatchV2_Call) RunAndReturn(run func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, error)) *StateFullInterface_ProcessBatchV2_Call { +func (_c *StateFullInterface_ProcessBatchV2_Call) RunAndReturn(run func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, string, error)) *StateFullInterface_ProcessBatchV2_Call { _c.Call.Return(run) return _c } diff --git a/synchronizer/common/syncinterfaces/state.go b/synchronizer/common/syncinterfaces/state.go index cafae4104e..0b3e248cbf 100644 --- a/synchronizer/common/syncinterfaces/state.go +++ b/synchronizer/common/syncinterfaces/state.go @@ -44,7 +44,7 @@ type StateFullInterface interface { OpenBatch(ctx context.Context, processingContext state.ProcessingContext, dbTx pgx.Tx) error CloseBatch(ctx context.Context, receipt state.ProcessingReceipt, dbTx pgx.Tx) error ProcessBatch(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, error) - ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, error) + ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, string, error) StoreTransaction(ctx context.Context, batchNumber uint64, processedTx *state.ProcessTransactionResponse, coinbase common.Address, timestamp uint64, egpLog *state.EffectiveGasPriceLog, globalExitRoot, blockInfoRoot common.Hash, dbTx pgx.Tx) (*state.L2Header, error) GetStateRootByBatchNumber(ctx context.Context, batchNum uint64, dbTx pgx.Tx) (common.Hash, error) ExecuteBatch(ctx context.Context, batch state.Batch, updateMerkleTree bool, dbTx pgx.Tx) (*executor.ProcessBatchResponse, error) 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 ea8bbd7fa8..75aebc942c 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 @@ -36,7 +36,7 @@ type StateInterface interface { UpdateWIPBatch(ctx context.Context, receipt state.ProcessingReceipt, dbTx pgx.Tx) error ResetTrustedState(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) error OpenBatch(ctx context.Context, processingContext state.ProcessingContext, dbTx pgx.Tx) error - ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, error) + ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, string, error) StoreL2Block(ctx context.Context, batchNumber uint64, l2Block *state.ProcessBlockResponse, txsEGPLog []*state.EffectiveGasPriceLog, dbTx pgx.Tx) error GetL1InfoTreeDataFromBatchL2Data(ctx context.Context, batchL2Data []byte, dbTx pgx.Tx) (map[uint32]state.L1DataV2, common.Hash, common.Hash, error) GetLastVirtualBatchNum(ctx context.Context, dbTx pgx.Tx) (uint64, error) @@ -375,7 +375,7 @@ func (b *SyncTrustedBatchExecutorForEtrog) processAndStoreTxs(ctx context.Contex if request.OldStateRoot == state.ZeroHash { log.Warnf("%s Processing batch with oldStateRoot == zero....", debugPrefix) } - processBatchResp, err := b.state.ProcessBatchV2(ctx, request, true) + processBatchResp, _, err := b.state.ProcessBatchV2(ctx, request, true) if err != nil { log.Errorf("%s error processing sequencer batch for batch: %v error:%v ", debugPrefix, request.BatchNumber, err) return nil, err diff --git a/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go b/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go index 1fc1b46afa..ce09f0ba14 100644 --- a/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go +++ b/synchronizer/l2_sync/l2_sync_etrog/executor_trusted_batch_sync_test.go @@ -76,7 +76,7 @@ func TestIncrementalProcessUpdateBatchL2DataOnCache(t *testing.T) { processBatchResp := &state.ProcessBatchResponse{ NewStateRoot: expectedStateRoot, } - stateMock.EXPECT().ProcessBatchV2(ctx, mock.Anything, true).Return(processBatchResp, nil).Once() + stateMock.EXPECT().ProcessBatchV2(ctx, mock.Anything, true).Return(processBatchResp, "", nil).Once() syncMock.EXPECT().PendingFlushID(mock.Anything, mock.Anything).Once() syncMock.EXPECT().CheckFlushID(mock.Anything).Return(nil).Maybe() @@ -140,7 +140,7 @@ func TestIncrementalProcessUpdateBatchL2DataAndGER(t *testing.T) { processBatchResp := &state.ProcessBatchResponse{ NewStateRoot: expectedStateRoot, } - stateMock.EXPECT().ProcessBatchV2(ctx, mock.Anything, true).Return(processBatchResp, nil).Once() + stateMock.EXPECT().ProcessBatchV2(ctx, mock.Anything, true).Return(processBatchResp, "", nil).Once() syncMock.EXPECT().PendingFlushID(mock.Anything, mock.Anything).Once() syncMock.EXPECT().CheckFlushID(mock.Anything).Return(nil).Maybe() @@ -274,7 +274,7 @@ func TestNothingProcessDoesntMatchBatchReprocess(t *testing.T) { processBatchResp := &state.ProcessBatchResponse{ NewStateRoot: data.TrustedBatch.StateRoot, } - testData.stateMock.EXPECT().ProcessBatchV2(testData.ctx, mock.Anything, true).Return(processBatchResp, nil).Once() + testData.stateMock.EXPECT().ProcessBatchV2(testData.ctx, mock.Anything, true).Return(processBatchResp, "", nil).Once() testData.stateMock.EXPECT().GetBatchByNumber(testData.ctx, data.BatchNumber, mock.Anything).Return(&state.Batch{}, nil).Once() _, err := testData.sut.NothingProcess(testData.ctx, &data, nil) require.NoError(t, err) diff --git a/synchronizer/l2_sync/l2_sync_etrog/mocks/state_interface.go b/synchronizer/l2_sync/l2_sync_etrog/mocks/state_interface.go index 5101bb4b6a..43e84ffba5 100644 --- a/synchronizer/l2_sync/l2_sync_etrog/mocks/state_interface.go +++ b/synchronizer/l2_sync/l2_sync_etrog/mocks/state_interface.go @@ -423,7 +423,7 @@ func (_c *StateInterface_OpenBatch_Call) RunAndReturn(run func(context.Context, } // ProcessBatchV2 provides a mock function with given fields: ctx, request, updateMerkleTree -func (_m *StateInterface) ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, error) { +func (_m *StateInterface) ProcessBatchV2(ctx context.Context, request state.ProcessRequest, updateMerkleTree bool) (*state.ProcessBatchResponse, string, error) { ret := _m.Called(ctx, request, updateMerkleTree) if len(ret) == 0 { @@ -431,8 +431,9 @@ func (_m *StateInterface) ProcessBatchV2(ctx context.Context, request state.Proc } var r0 *state.ProcessBatchResponse - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, error)); ok { + var r1 string + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, string, error)); ok { return rf(ctx, request, updateMerkleTree) } if rf, ok := ret.Get(0).(func(context.Context, state.ProcessRequest, bool) *state.ProcessBatchResponse); ok { @@ -443,13 +444,19 @@ func (_m *StateInterface) ProcessBatchV2(ctx context.Context, request state.Proc } } - if rf, ok := ret.Get(1).(func(context.Context, state.ProcessRequest, bool) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, state.ProcessRequest, bool) string); ok { r1 = rf(ctx, request, updateMerkleTree) } else { - r1 = ret.Error(1) + r1 = ret.Get(1).(string) } - return r0, r1 + if rf, ok := ret.Get(2).(func(context.Context, state.ProcessRequest, bool) error); ok { + r2 = rf(ctx, request, updateMerkleTree) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 } // StateInterface_ProcessBatchV2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProcessBatchV2' @@ -472,12 +479,12 @@ func (_c *StateInterface_ProcessBatchV2_Call) Run(run func(ctx context.Context, return _c } -func (_c *StateInterface_ProcessBatchV2_Call) Return(_a0 *state.ProcessBatchResponse, _a1 error) *StateInterface_ProcessBatchV2_Call { - _c.Call.Return(_a0, _a1) +func (_c *StateInterface_ProcessBatchV2_Call) Return(_a0 *state.ProcessBatchResponse, _a1 string, _a2 error) *StateInterface_ProcessBatchV2_Call { + _c.Call.Return(_a0, _a1, _a2) return _c } -func (_c *StateInterface_ProcessBatchV2_Call) RunAndReturn(run func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, error)) *StateInterface_ProcessBatchV2_Call { +func (_c *StateInterface_ProcessBatchV2_Call) RunAndReturn(run func(context.Context, state.ProcessRequest, bool) (*state.ProcessBatchResponse, string, error)) *StateInterface_ProcessBatchV2_Call { _c.Call.Return(run) return _c } diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index d136d6fef0..73bebe5a12 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -890,7 +890,7 @@ func expectedCallsForsyncTrustedState(t *testing.T, m *mocks, sync *ClientSynchr if etrogMode { m.State.EXPECT().GetL1InfoTreeDataFromBatchL2Data(mock.Anything, mock.Anything, mock.Anything).Return(map[uint32]state.L1DataV2{}, common.Hash{}, common.Hash{}, nil).Times(1) m.State.EXPECT().ProcessBatchV2(mock.Anything, mock.Anything, mock.Anything). - Return(&processedBatch, nil).Times(1) + Return(&processedBatch, "", nil).Times(1) m.State.EXPECT().StoreL2Block(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(nil).Times(1) m.State.EXPECT().UpdateWIPBatch(mock.Anything, mock.Anything, mock.Anything). diff --git a/test/config/debug.node.config.toml b/test/config/debug.node.config.toml index 5072e9f5a1..ccd423daee 100644 --- a/test/config/debug.node.config.toml +++ b/test/config/debug.node.config.toml @@ -100,9 +100,10 @@ StateConsistencyCheckInterval = "5s" BatchMaxDeltaTimestamp = "60s" L2BlockMaxDeltaTimestamp = "3s" ResourceExhaustedMarginPct = 10 + StateRootSyncInterval = "120s" HaltOnBatchNumber = 0 SequentialBatchSanityCheck = false - SequentialProcessL2Block = true + SequentialProcessL2Block = false [Sequencer.Finalizer.Metrics] Interval = "60m" EnableLog = true diff --git a/test/config/test.node.config.toml b/test/config/test.node.config.toml index 6a7a7efd0b..506dde2466 100644 --- a/test/config/test.node.config.toml +++ b/test/config/test.node.config.toml @@ -37,8 +37,8 @@ MaxTxDataBytesSize=100000 DefaultMinGasPriceAllowed = 1000000000 MinAllowedGasPriceInterval = "5m" PollMinAllowedGasPriceInterval = "15s" -AccountQueue = 64 -GlobalQueue = 1024 +AccountQueue = 0 +GlobalQueue = 0 [Pool.EffectiveGasPrice] Enabled = false L1GasPriceFactor = 0.25 @@ -115,9 +115,10 @@ StateConsistencyCheckInterval = "5s" BatchMaxDeltaTimestamp = "20s" L2BlockMaxDeltaTimestamp = "4s" ResourceExhaustedMarginPct = 10 + StateRootSyncInterval = "60s" HaltOnBatchNumber = 0 SequentialBatchSanityCheck = false - SequentialProcessL2Block = true + SequentialProcessL2Block = false [Sequencer.Finalizer.Metrics] Interval = "60m" EnableLog = true diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 08dbc93431..feead65a40 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.5" networks: default: name: zkevm @@ -26,7 +25,7 @@ services: volumes: - ./config/telegraf.conf:/etc/telegraf/telegraf.conf:ro - /var/run/docker.sock:/var/run/docker.sock:ro - user: telegraf:${DOCKERGID} + user: telegraf:${DOCKERGID:-} environment: - POSTGRES_HOST=grafana-db - POSTGRES_USER=user @@ -56,8 +55,8 @@ services: environment: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - ZKEVM_NODE_POOL_DB_HOST=zkevm-pool-db - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} volumes: - ./config/test.node.config.toml:/app/config.toml - ./config/test.genesis.config.json:/app/genesis.json @@ -77,8 +76,8 @@ services: environment: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - ZKEVM_NODE_POOL_DB_HOST=zkevm-pool-db - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} - ZKEVM_NODE_ETHERMAN_URL=http://zkevm-v1tov2-l1-network:8545 volumes: - ./config/test.node.config.toml:/app/config.toml @@ -96,8 +95,8 @@ services: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - ZKEVM_NODE_POOL_DB_HOST=zkevm-pool-db - ZKEVM_NODE_SEQUENCER_SENDER_ADDRESS=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} volumes: - ./sequencer.keystore:/pk/sequencer.keystore - ./config/test.node.config.toml:/app/config.toml @@ -114,8 +113,8 @@ services: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - ZKEVM_NODE_POOL_DB_HOST=zkevm-pool-db - ZKEVM_NODE_SEQUENCER_SENDER_ADDRESS=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} - ZKEVM_NODE_ETHERMAN_URL=http://zkevm-v1tov2-l1-network:8545 volumes: - ./sequencer.keystore:/pk/sequencer.keystore @@ -136,8 +135,8 @@ services: environment: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - ZKEVM_NODE_POOL_DB_HOST=zkevm-pool-db - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} volumes: - ./config/test.node.config.toml:/app/config.toml - ./config/test.genesis.config.json:/app/genesis.json @@ -156,8 +155,8 @@ services: environment: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - ZKEVM_NODE_POOL_DB_HOST=zkevm-pool-db - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} - ZKEVM_NODE_ETHERMAN_URL=http://zkevm-v1tov2-l1-network:8545 volumes: - ./config/test.node.config.toml:/app/config.toml @@ -210,8 +209,8 @@ services: - 9095:9091 # needed if metrics enabled environment: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} volumes: - ./config/test.node.config.toml:/app/config.toml - ./config/test.genesis.config.json:/app/genesis.json @@ -227,8 +226,8 @@ services: - 9095:9091 # needed if metrics enabled environment: - ZKEVM_NODE_STATE_DB_HOST=zkevm-state-db - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} - ZKEVM_NODE_ETHERMAN_URL=http://zkevm-v1tov2-l1-network:8545 volumes: - ./config/test.node.config.toml:/app/config.toml @@ -430,8 +429,8 @@ services: - ZKEVM_NODE_POOL_DB_HOST=zkevm-pool-db - ZKEVM_NODE_RPC_PORT=8124 - ZKEVM_NODE_RPC_WEBSOCKETS_PORT=8134 - - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI} - - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI} + - ZKEVM_NODE_MTCLIENT_URI=${ZKEVM_NODE_MTCLIENT_URI:-} + - ZKEVM_NODE_EXECUTOR_URI=${ZKEVM_NODE_EXECUTOR_URI:-} volumes: - ./config/test.node.config.toml:/app/config.toml - ./config/test.genesis.config.json:/app/genesis.json From e3cd4151e46fcee48cb7984c449ae3fd0cf203ad Mon Sep 17 00:00:00 2001 From: Joan Esteban <129153821+joanestebanr@users.noreply.github.com> Date: Fri, 3 May 2024 13:38:07 +0200 Subject: [PATCH 20/23] fix #3613 timestamp needs to be greater or equal (#3614) syncrhonizer update the tstamp from table state.batch when the batch is sequenced --- state/interfaces.go | 1 + state/mocks/mock_storage.go | 49 +++++++++++++++++++ state/pgstatestorage/batch.go | 8 +++ .../etrog/processor_l1_sequence_batches.go | 14 +++++- .../processor_l1_sequence_batches_test.go | 10 +++- .../mocks/state_full_interface.go | 49 +++++++++++++++++++ synchronizer/common/syncinterfaces/state.go | 1 + synchronizer/synchronizer_test.go | 2 + 8 files changed, 132 insertions(+), 2 deletions(-) diff --git a/state/interfaces.go b/state/interfaces.go index cc1f0127a9..33e8bc01be 100644 --- a/state/interfaces.go +++ b/state/interfaces.go @@ -163,4 +163,5 @@ type storage interface { GetNotCheckedBatches(ctx context.Context, dbTx pgx.Tx) ([]*Batch, error) GetLastL2BlockByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*L2Block, error) GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*Block, error) + UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx) error } diff --git a/state/mocks/mock_storage.go b/state/mocks/mock_storage.go index 27964e0247..57b72a61f6 100644 --- a/state/mocks/mock_storage.go +++ b/state/mocks/mock_storage.go @@ -8333,6 +8333,55 @@ func (_c *StorageMock_UpdateBatchL2Data_Call) RunAndReturn(run func(context.Cont return _c } +// UpdateBatchTimestamp provides a mock function with given fields: ctx, batchNumber, timestamp, dbTx +func (_m *StorageMock) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx) error { + ret := _m.Called(ctx, batchNumber, timestamp, dbTx) + + if len(ret) == 0 { + panic("no return value specified for UpdateBatchTimestamp") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, time.Time, pgx.Tx) error); ok { + r0 = rf(ctx, batchNumber, timestamp, dbTx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// StorageMock_UpdateBatchTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateBatchTimestamp' +type StorageMock_UpdateBatchTimestamp_Call struct { + *mock.Call +} + +// UpdateBatchTimestamp is a helper method to define mock.On call +// - ctx context.Context +// - batchNumber uint64 +// - timestamp time.Time +// - dbTx pgx.Tx +func (_e *StorageMock_Expecter) UpdateBatchTimestamp(ctx interface{}, batchNumber interface{}, timestamp interface{}, dbTx interface{}) *StorageMock_UpdateBatchTimestamp_Call { + return &StorageMock_UpdateBatchTimestamp_Call{Call: _e.mock.On("UpdateBatchTimestamp", ctx, batchNumber, timestamp, dbTx)} +} + +func (_c *StorageMock_UpdateBatchTimestamp_Call) Run(run func(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx)) *StorageMock_UpdateBatchTimestamp_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(time.Time), args[3].(pgx.Tx)) + }) + return _c +} + +func (_c *StorageMock_UpdateBatchTimestamp_Call) Return(_a0 error) *StorageMock_UpdateBatchTimestamp_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *StorageMock_UpdateBatchTimestamp_Call) RunAndReturn(run func(context.Context, uint64, time.Time, pgx.Tx) error) *StorageMock_UpdateBatchTimestamp_Call { + _c.Call.Return(run) + return _c +} + // UpdateCheckedBlockByNumber provides a mock function with given fields: ctx, blockNumber, newCheckedStatus, dbTx func (_m *StorageMock) UpdateCheckedBlockByNumber(ctx context.Context, blockNumber uint64, newCheckedStatus bool, dbTx pgx.Tx) error { ret := _m.Called(ctx, blockNumber, newCheckedStatus, dbTx) diff --git a/state/pgstatestorage/batch.go b/state/pgstatestorage/batch.go index 843c725b12..b0b1aa6389 100644 --- a/state/pgstatestorage/batch.go +++ b/state/pgstatestorage/batch.go @@ -1092,3 +1092,11 @@ func (p *PostgresStorage) GetNotCheckedBatches(ctx context.Context, dbTx pgx.Tx) return batches, nil } + +// UpdateBatchTimestamp updates the timestamp of the state.batch with the given number. +func (p *PostgresStorage) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx) error { + const sql = "UPDATE state.batch SET timestamp = $1 WHERE batch_num = $2" + e := p.getExecQuerier(dbTx) + _, err := e.Exec(ctx, sql, timestamp.UTC(), batchNumber) + return err +} diff --git a/synchronizer/actions/etrog/processor_l1_sequence_batches.go b/synchronizer/actions/etrog/processor_l1_sequence_batches.go index 65e713137e..2f91d8a9d9 100644 --- a/synchronizer/actions/etrog/processor_l1_sequence_batches.go +++ b/synchronizer/actions/etrog/processor_l1_sequence_batches.go @@ -32,6 +32,7 @@ type stateProcessSequenceBatches interface { AddVirtualBatch(ctx context.Context, virtualBatch *state.VirtualBatch, dbTx pgx.Tx) error AddTrustedReorg(ctx context.Context, trustedReorg *state.TrustedReorg, dbTx pgx.Tx) error GetL1InfoTreeDataFromBatchL2Data(ctx context.Context, batchL2Data []byte, dbTx pgx.Tx) (map[uint32]state.L1DataV2, common.Hash, common.Hash, error) + UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx) error } type syncProcessSequenceBatchesInterface interface { @@ -158,7 +159,7 @@ func (p *ProcessorL1SequenceBatchesEtrog) ProcessSequenceBatches(ctx context.Con SkipVerifyL1InfoRoot: 1, ClosingReason: state.SyncL1EventSequencedForcedBatchClosingReason, } - } else if sbatch.PolygonRollupBaseEtrogBatchData.ForcedTimestamp > 0 && sbatch.BatchNumber == 1 { + } else if sbatch.PolygonRollupBaseEtrogBatchData.ForcedTimestamp > 0 && sbatch.BatchNumber == 1 { // This is the initial batch (injected) log.Debug("Processing initial batch") batch.GlobalExitRoot = sbatch.PolygonRollupBaseEtrogBatchData.ForcedGlobalExitRoot var fBHL1 common.Hash = sbatch.PolygonRollupBaseEtrogBatchData.ForcedBlockHashL1 @@ -251,6 +252,17 @@ func (p *ProcessorL1SequenceBatchesEtrog) ProcessSequenceBatches(ctx context.Con return err } } else { + // Batch already exists + // We update the timestamp of the batch to match the timestamp + err := p.state.UpdateBatchTimestamp(ctx, batch.BatchNumber, *processCtx.Timestamp, dbTx) + if err != nil { + log.Errorf("error updating batch timestamp %s. BatchNumber: %d, BlockNumber: %d, error: %v", processCtx.Timestamp, batch.BatchNumber, blockNumber, err) + rollbackErr := dbTx.Rollback(ctx) + if rollbackErr != nil { + log.Errorf("error rolling back state because error updating batch timestamp. BatchNumber: %d, BlockNumber: %d, rollbackErr: %s, error : %v", batch.BatchNumber, blockNumber, rollbackErr.Error(), err) + return rollbackErr + } + } // Reprocess batch to compare the stateRoot with tBatch.StateRoot and get accInputHash batchRespose, err := p.state.ExecuteBatchV2(ctx, batch, processCtx.L1InfoRoot, leaves, *processCtx.Timestamp, false, processCtx.SkipVerifyL1InfoRoot, processCtx.ForcedBlockHashL1, dbTx) if err != nil { diff --git a/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go b/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go index 4d6a47e95f..3b30db1c50 100644 --- a/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go +++ b/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go @@ -101,9 +101,12 @@ func TestL1SequenceBatchesTrustedBatchSequencedThatAlreadyExistsHappyPath(t *tes expectationsPreExecution(t, mocks, ctx, batch, nil) executionResponse := newProcessBatchResponseV2(batch) expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse) + mocks.State.EXPECT().UpdateBatchTimestamp(ctx, batch.BatchNumber, l1Block.ReceivedAt, mocks.DbTx).Return(nil) mocks.State.EXPECT().AddAccumulatedInputHash(ctx, executionResponse.NewBatchNum, common.BytesToHash(executionResponse.NewAccInputHash), mocks.DbTx).Return(nil) expectationsAddSequencedBatch(t, mocks, ctx, executionResponse) + err := sut.Process(ctx, etherman.Order{Pos: 1}, l1Block, mocks.DbTx) + require.NoError(t, err) } @@ -117,9 +120,12 @@ func TestL1SequenceBatchesPermissionlessBatchSequencedThatAlreadyExistsHappyPath expectationsPreExecution(t, mocks, ctx, batch, nil) executionResponse := newProcessBatchResponseV2(batch) expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse) + mocks.State.EXPECT().UpdateBatchTimestamp(ctx, batch.BatchNumber, l1Block.ReceivedAt, mocks.DbTx).Return(nil) mocks.State.EXPECT().AddAccumulatedInputHash(ctx, executionResponse.NewBatchNum, common.BytesToHash(executionResponse.NewAccInputHash), mocks.DbTx).Return(nil) expectationsAddSequencedBatch(t, mocks, ctx, executionResponse) + err := sut.Process(ctx, etherman.Order{Pos: 1}, l1Block, mocks.DbTx) + require.NoError(t, err) } @@ -139,6 +145,7 @@ func TestL1SequenceBatchesPermissionlessBatchSequencedThatAlreadyExistsMismatch( executionResponse := newProcessBatchResponseV2(batch) executionResponse.NewStateRoot = common.HexToHash(hashExamplesValues[2]).Bytes() expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse) + mocks.State.EXPECT().UpdateBatchTimestamp(ctx, batch.BatchNumber, l1Block.ReceivedAt, mocks.DbTx).Return(nil) mocks.State.EXPECT().AddAccumulatedInputHash(ctx, executionResponse.NewBatchNum, common.BytesToHash(executionResponse.NewAccInputHash), mocks.DbTx).Return(nil) mocks.Synchronizer.EXPECT().IsTrustedSequencer().Return(false) mocks.State.EXPECT().AddTrustedReorg(ctx, mock.Anything, mocks.DbTx).Return(nil) @@ -177,6 +184,7 @@ func TestL1SequenceBatchesTrustedBatchSequencedThatAlreadyExistsMismatch(t *test executionResponse := newProcessBatchResponseV2(batch) executionResponse.NewStateRoot = common.HexToHash(hashExamplesValues[2]).Bytes() expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse) + mocks.State.EXPECT().UpdateBatchTimestamp(ctx, batch.BatchNumber, l1Block.ReceivedAt, mocks.DbTx).Return(nil) mocks.State.EXPECT().AddAccumulatedInputHash(ctx, executionResponse.NewBatchNum, common.BytesToHash(executionResponse.NewAccInputHash), mocks.DbTx).Return(nil) mocks.Synchronizer.EXPECT().IsTrustedSequencer().Return(true) @@ -295,7 +303,7 @@ func newL1Block(mocks *mocksEtrogProcessorL1, batch *state.Batch, l1InfoRoot com func newComposedL1Block(mocks *mocksEtrogProcessorL1, forcedBatch *etherman.SequencedBatch, l1InfoRoot common.Hash) *etherman.Block { l1Block := etherman.Block{ BlockNumber: 123, - ReceivedAt: mocks.TimeProvider.Now(), + ReceivedAt: time.Date(2024, 1, 1, 1, 0, 0, 0, time.UTC), SequencedBatches: [][]etherman.SequencedBatch{}, } l1Block.SequencedBatches = append(l1Block.SequencedBatches, []etherman.SequencedBatch{}) diff --git a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go index 81fe9a430e..ec779c4854 100644 --- a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go +++ b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go @@ -2963,6 +2963,55 @@ func (_c *StateFullInterface_UpdateBatchL2Data_Call) RunAndReturn(run func(conte return _c } +// UpdateBatchTimestamp provides a mock function with given fields: ctx, batchNumber, timestamp, dbTx +func (_m *StateFullInterface) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx) error { + ret := _m.Called(ctx, batchNumber, timestamp, dbTx) + + if len(ret) == 0 { + panic("no return value specified for UpdateBatchTimestamp") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, time.Time, pgx.Tx) error); ok { + r0 = rf(ctx, batchNumber, timestamp, dbTx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// StateFullInterface_UpdateBatchTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateBatchTimestamp' +type StateFullInterface_UpdateBatchTimestamp_Call struct { + *mock.Call +} + +// UpdateBatchTimestamp is a helper method to define mock.On call +// - ctx context.Context +// - batchNumber uint64 +// - timestamp time.Time +// - dbTx pgx.Tx +func (_e *StateFullInterface_Expecter) UpdateBatchTimestamp(ctx interface{}, batchNumber interface{}, timestamp interface{}, dbTx interface{}) *StateFullInterface_UpdateBatchTimestamp_Call { + return &StateFullInterface_UpdateBatchTimestamp_Call{Call: _e.mock.On("UpdateBatchTimestamp", ctx, batchNumber, timestamp, dbTx)} +} + +func (_c *StateFullInterface_UpdateBatchTimestamp_Call) Run(run func(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx)) *StateFullInterface_UpdateBatchTimestamp_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(time.Time), args[3].(pgx.Tx)) + }) + return _c +} + +func (_c *StateFullInterface_UpdateBatchTimestamp_Call) Return(_a0 error) *StateFullInterface_UpdateBatchTimestamp_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *StateFullInterface_UpdateBatchTimestamp_Call) RunAndReturn(run func(context.Context, uint64, time.Time, pgx.Tx) error) *StateFullInterface_UpdateBatchTimestamp_Call { + _c.Call.Return(run) + return _c +} + // UpdateCheckedBlockByNumber provides a mock function with given fields: ctx, blockNumber, newCheckedStatus, dbTx func (_m *StateFullInterface) UpdateCheckedBlockByNumber(ctx context.Context, blockNumber uint64, newCheckedStatus bool, dbTx pgx.Tx) error { ret := _m.Called(ctx, blockNumber, newCheckedStatus, dbTx) diff --git a/synchronizer/common/syncinterfaces/state.go b/synchronizer/common/syncinterfaces/state.go index 0b3e248cbf..2fb9ea2f16 100644 --- a/synchronizer/common/syncinterfaces/state.go +++ b/synchronizer/common/syncinterfaces/state.go @@ -78,4 +78,5 @@ type StateFullInterface interface { GetL2BlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.L2Block, error) GetUncheckedBlocks(ctx context.Context, fromBlockNumber uint64, toBlockNumber uint64, dbTx pgx.Tx) ([]*state.Block, error) GetPreviousBlockToBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.Block, error) + UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, timestamp time.Time, dbTx pgx.Tx) error } diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go index 73bebe5a12..ed063cac1e 100644 --- a/synchronizer/synchronizer_test.go +++ b/synchronizer/synchronizer_test.go @@ -368,6 +368,8 @@ func TestForcedBatchEtrog(t *testing.T) { Return(nil). Once() + m.State.EXPECT().UpdateBatchTimestamp(ctx, sequencedBatch.BatchNumber, fb[0].ForcedAt, m.DbTx).Return(nil) + m.State. On("AddAccumulatedInputHash", ctx, sequencedBatch.BatchNumber, common.Hash{}, m.DbTx). Return(nil). From f34d60ac412306488a6e8b420c41c319aeef97a9 Mon Sep 17 00:00:00 2001 From: agnusmor <100322135+agnusmor@users.noreply.github.com> Date: Fri, 3 May 2024 15:48:28 +0200 Subject: [PATCH 21/23] Fix DSSendL2Block batch number (#3616) --- sequencer/l2block.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sequencer/l2block.go b/sequencer/l2block.go index b64a6db902..8370918106 100644 --- a/sequencer/l2block.go +++ b/sequencer/l2block.go @@ -491,7 +491,7 @@ func (f *finalizer) storeL2Block(ctx context.Context, l2Block *L2Block) error { log.Infof("[ds-debug] l2 block %d [%d] transactions updated as selected in the pooldb", blockResponse.BlockNumber, l2Block.trackingNum) // Send L2 block to data streamer - err = f.DSSendL2Block(f.wipBatch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex()) + err = f.DSSendL2Block(l2Block.batch.batchNumber, blockResponse, l2Block.getL1InfoTreeIndex()) if err != nil { //TODO: we need to halt/rollback the L2 block if we had an error sending to the data streamer? log.Errorf("error sending L2 block %d [%d] to data streamer, error: %v", blockResponse.BlockNumber, l2Block.trackingNum, err) From 3fc88206374e3edcbedc372b647401967da30b76 Mon Sep 17 00:00:00 2001 From: zhangkai Date: Thu, 9 May 2024 16:11:16 +0800 Subject: [PATCH 22/23] t# This is a combination of 2 commits. change mock eth l1 image add genesis --- ci/e2e-group-dac-1/cli_test.go | 2 +- docs/config-file/node-config-doc.html | 4 +- docs/config-file/node-config-doc.md | 9 +- state/mocks/mock_storage_xlayer.go | 5 - .../processor_l1_sequence_batches_test.go | 3 - .../processor_l1_sequence_batches_xlayer.go | 28 --- .../mocks/state_full_interface_xlayer.go | 5 - synchronizer/synchronizer.go | 2 +- synchronizer/synchronizer_test.go | 10 +- test/config/test.da.toml | 4 +- test/config/test.genesis.config.json | 194 +++++++++--------- test/docker-compose.yml | 2 +- test/e2e/debug_test.go | 2 +- test/e2e/ethtransfer_test.go | 4 +- test/e2e/jsonrpc2_test.go | 2 +- test/e2e/permissionlessrpc_test.go | 2 +- test/e2e/preEIP155_test.go | 2 +- test/e2e/sc_test.go | 2 +- test/e2e/shared.go | 4 +- test/operations/manager_xlayer.go | 4 +- 20 files changed, 124 insertions(+), 166 deletions(-) delete mode 100644 synchronizer/actions/etrog/processor_l1_sequence_batches_xlayer.go diff --git a/ci/e2e-group-dac-1/cli_test.go b/ci/e2e-group-dac-1/cli_test.go index 4799fab023..becc3dd2b9 100644 --- a/ci/e2e-group-dac-1/cli_test.go +++ b/ci/e2e-group-dac-1/cli_test.go @@ -35,7 +35,7 @@ func TestSetDataAvailabilityProtocol(t *testing.T) { clientL1, err := ethclient.Dial(operations.DefaultL1NetworkURL) require.NoError(t, err) - auth, err := operations.GetAuth("0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38", operations.DefaultL1ChainID) + auth, err := operations.GetAuth("0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2", operations.DefaultL1ChainID) require.NoError(t, err) // New DAC Setup diff --git a/docs/config-file/node-config-doc.html b/docs/config-file/node-config-doc.html index ec1368868e..3128178abd 100644 --- a/docs/config-file/node-config-doc.html +++ b/docs/config-file/node-config-doc.html @@ -58,9 +58,9 @@
"300ms"
 

Default: "1h0m0s"Type: string

StateRootSyncInterval indicates how often the stateroot generated by the L2 block process will be synchronized with
the stateroot used in the tx-by-tx execution


Examples:

"1m"
 
"300ms"
-

Default: 0Type: integer

HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches.
The Sequencer will halt after it closes the batch equal to this number


Default: falseType: boolean

SequentialBatchSanityCheck indicates if the reprocess of a closed batch (sanity check) must be done in a
sequential way (instead than in parallel)


Default: trueType: boolean

SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead
in the processPendingL2Blocks go func


Default: "0s"Type: string

XLayer config
FullBatchSleepDuration is the time the finalizer sleeps between each full batch iteration


Examples:

"1m"
+

Default: 0Type: integer

HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches.
The Sequencer will halt after it closes the batch equal to this number


Default: falseType: boolean

SequentialBatchSanityCheck indicates if the reprocess of a closed batch (sanity check) must be done in a
sequential way (instead than in parallel)


Default: falseType: boolean

SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead
in the processPendingL2Blocks go func


Default: "0s"Type: string

XLayer config
FullBatchSleepDuration is the time the finalizer sleeps between each full batch iteration


Examples:

"1m"
 
"300ms"
-

Default: 0Type: integer

HaltOnBatchNumber specifies the batch number where the Sequencer will stop to process more transactions and generate new batches.
The Sequencer will halt after it closes the batch equal to this number


Default: falseType: boolean

SequentialBatchSanityCheck indicates if the reprocess of a closed batch (sanity check) must be done in a
sequential way (instead than in parallel)


Default: falseType: boolean

SequentialProcessL2Block indicates if the processing of a L2 Block must be done in the same finalizer go func instead
in the processPendingL2Blocks go func


Metrics is the config for the sequencer metrics
Default: "1h0m0s"Type: string

Interval is the interval of time to calculate sequencer metrics


Examples:

"1m"
+

Metrics is the config for the sequencer metrics
Default: "1h0m0s"Type: string

Interval is the interval of time to calculate sequencer metrics


Examples:

"1m"
 
"300ms"
 

Default: trueType: boolean

EnableLog is a flag to enable/disable metrics logs


StreamServerCfg is the config for the stream server
Default: 0Type: integer

Port to listen on


Default: ""Type: string

Filename of the binary data file


Default: 0Type: integer

Version of the binary data file


Default: 0Type: integer

ChainID is the chain ID


Default: falseType: boolean

Enabled is a flag to enable/disable the data streamer


Log is the log configuration
Default: ""Type: enum (of string)

Must be one of:

  • "production"
  • "development"

Default: ""Type: enum (of string)

Must be one of:

  • "debug"
  • "info"
  • "warn"
  • "error"
  • "dpanic"
  • "panic"
  • "fatal"

Type: array of string

Each item of this array must be:


Default: 0Type: integer

UpgradeEtrogBatchNumber is the batch number of the upgrade etrog


Type: array of string

XLayer config
PackBatchSpacialList is the list of addresses that will have a special gas price

Each item of this array must be:


Default: 0Type: number

GasPriceMultiple is the multiple of the gas price


Default: 0Type: integer

QueryPendingTxsLimit is used to limit amount txs from the db


Configuration of the sequence sender service
Default: "5s"Type: string

WaitPeriodSendSequence is the time the sequencer waits until
trying to send a sequence to L1


Examples:

"1m"
 
"300ms"
diff --git a/docs/config-file/node-config-doc.md b/docs/config-file/node-config-doc.md
index 7f3a3d43ba..78cfbd2f0c 100644
--- a/docs/config-file/node-config-doc.md
+++ b/docs/config-file/node-config-doc.md
@@ -3199,8 +3199,7 @@ in the processPendingL2Blocks go func
 SequentialProcessL2Block=false
 ```
 
-#### 10.7.14. `[Sequencer.Finalizer.Metrics]`
-#### 10.7.13. `Sequencer.Finalizer.FullBatchSleepDuration`
+#### 10.7.14. `Sequencer.Finalizer.FullBatchSleepDuration`
 
 **Title:** Duration
 
@@ -3227,7 +3226,7 @@ FullBatchSleepDuration is the time the finalizer sleeps between each full batch
 FullBatchSleepDuration="0s"
 ```
 
-#### 10.7.14. `[Sequencer.Finalizer.Metrics]`
+#### 10.7.15. `[Sequencer.Finalizer.Metrics]`
 
 **Type:** : `object`
 **Description:** Metrics is the config for the sequencer metrics
@@ -3237,7 +3236,7 @@ FullBatchSleepDuration="0s"
 | - [Interval](#Sequencer_Finalizer_Metrics_Interval )   | No      | string  | No         | -          | Duration                                           |
 | - [EnableLog](#Sequencer_Finalizer_Metrics_EnableLog ) | No      | boolean | No         | -          | EnableLog is a flag to enable/disable metrics logs |
 
-##### 10.7.14.1. `Sequencer.Finalizer.Metrics.Interval`
+##### 10.7.15.1. `Sequencer.Finalizer.Metrics.Interval`
 
 **Title:** Duration
 
@@ -3263,7 +3262,7 @@ FullBatchSleepDuration="0s"
 Interval="1h0m0s"
 ```
 
-##### 10.7.14.2. `Sequencer.Finalizer.Metrics.EnableLog`
+##### 10.7.15.2. `Sequencer.Finalizer.Metrics.EnableLog`
 
 **Type:** : `boolean`
 
diff --git a/state/mocks/mock_storage_xlayer.go b/state/mocks/mock_storage_xlayer.go
index b240f0900b..99a912c025 100644
--- a/state/mocks/mock_storage_xlayer.go
+++ b/state/mocks/mock_storage_xlayer.go
@@ -4,7 +4,6 @@ package mocks
 
 import (
 	context "context"
-	"time"
 
 	pgx "github.com/jackc/pgx/v4"
 )
@@ -15,8 +14,4 @@ func (_m *StorageMock) GetBatchL2DataByNumber(ctx context.Context, batchNumber u
 
 func (_m *StorageMock) GetBatchL2DataByNumbers(ctx context.Context, batchNumbers []uint64, dbTx pgx.Tx) (map[uint64][]byte, error){
 	return nil, nil
-}
-
-func (_m *StorageMock) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error {
-	return nil
 }
\ No newline at end of file
diff --git a/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go b/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go
index f23dedd1ef..11ed117dc7 100644
--- a/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go
+++ b/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go
@@ -99,8 +99,6 @@ func TestL1SequenceBatchesTrustedBatchSequencedThatAlreadyExistsHappyPath(t *tes
 	l1InfoRoot := common.HexToHash(hashExamplesValues[0])
 	l1Block := newL1Block(mocks, batch, l1InfoRoot)
 	expectationsPreExecution(t, mocks, ctx, batch, nil)
-
-	mocks.Synchronizer.EXPECT().IsTrustedSequencer().Return(false)
 	executionResponse := newProcessBatchResponseV2(batch)
 	expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse)
 	mocks.State.EXPECT().UpdateBatchTimestamp(ctx, batch.BatchNumber, l1Block.ReceivedAt, mocks.DbTx).Return(nil)
@@ -121,7 +119,6 @@ func TestL1SequenceBatchesPermissionlessBatchSequencedThatAlreadyExistsHappyPath
 	l1Block := newL1Block(mocks, batch, l1InfoRoot)
 	expectationsPreExecution(t, mocks, ctx, batch, nil)
 	executionResponse := newProcessBatchResponseV2(batch)
-	mocks.Synchronizer.EXPECT().IsTrustedSequencer().Return(false)
 	expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse)
 	mocks.State.EXPECT().UpdateBatchTimestamp(ctx, batch.BatchNumber, l1Block.ReceivedAt, mocks.DbTx).Return(nil)
 	mocks.State.EXPECT().AddAccumulatedInputHash(ctx, executionResponse.NewBatchNum, common.BytesToHash(executionResponse.NewAccInputHash), mocks.DbTx).Return(nil)
diff --git a/synchronizer/actions/etrog/processor_l1_sequence_batches_xlayer.go b/synchronizer/actions/etrog/processor_l1_sequence_batches_xlayer.go
deleted file mode 100644
index 51fc05a841..0000000000
--- a/synchronizer/actions/etrog/processor_l1_sequence_batches_xlayer.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package etrog
-
-import (
-	"context"
-	"time"
-
-	"github.com/0xPolygonHermez/zkevm-node/log"
-	"github.com/jackc/pgx/v4"
-)
-
-func (p *ProcessorL1SequenceBatchesEtrog) updatePermissionLessBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error {
-	if p.sync.IsTrustedSequencer() {
-		return nil
-	}
-
-	log.Infof("Permission less rpc updates batch timestamp for batch: %v with new timestamp:%v", batchNumber, batchTime)
-	err := p.state.UpdateBatchTimestamp(ctx, batchNumber, batchTime, dbTx)
-	if err != nil {
-		log.Errorf("error update batch timestamp for batch: %v, batchTime:%v, . Error; %v", batchNumber, batchTime, err)
-		rollbackErr := dbTx.Rollback(ctx)
-		if rollbackErr != nil {
-			log.Errorf("error rolling back state. BatchNumber: %d, batchTime:%v, rollbackErr: %v", batchNumber, batchTime, rollbackErr)
-			return rollbackErr
-		}
-		return err
-	}
-	return nil
-}
diff --git a/synchronizer/common/syncinterfaces/mocks/state_full_interface_xlayer.go b/synchronizer/common/syncinterfaces/mocks/state_full_interface_xlayer.go
index ede7db21d9..188370d55c 100644
--- a/synchronizer/common/syncinterfaces/mocks/state_full_interface_xlayer.go
+++ b/synchronizer/common/syncinterfaces/mocks/state_full_interface_xlayer.go
@@ -4,15 +4,10 @@ package mock_syncinterfaces
 
 import (
 	context "context"
-	"time"
 
 	"github.com/jackc/pgx/v4"
 )
 
 func (_m *StateFullInterface) GetBatchL2DataByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) ([]byte, error){
 	return nil, nil
-}
-
-func (_m *StateFullInterface) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error {
-	return nil
 }
\ No newline at end of file
diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go
index 3027eec1df..3fdcd5f7ad 100644
--- a/synchronizer/synchronizer.go
+++ b/synchronizer/synchronizer.go
@@ -1003,7 +1003,7 @@ func (s *ClientSynchronizer) newCheckReorg(latestStoredBlock *state.Block, synce
 		log.Infof("[checkReorg function] reorgedBlockNumber: %d reorgedBlockHash already synced: %s", reorgedBlock.BlockNumber, reorgedBlock.BlockHash.String())
 
 		// Compare hashes
-		if (block.BlockHash != reorgedBlock.BlockHash || block.ParentHash != reorgedBlock.ParentHash) && reorgedBlock.BlockNumber > s.genesis.RollupBlockNumber{
+		if (block.BlockHash != reorgedBlock.BlockHash || block.ParentHash != reorgedBlock.ParentHash) && reorgedBlock.BlockNumber > s.genesis.RollupBlockNumber {
 			log.Infof("checkReorg: Bad block %d hashOk %t parentHashOk %t", reorgedBlock.BlockNumber, block.BlockHash == reorgedBlock.BlockHash, block.ParentHash == reorgedBlock.ParentHash)
 			log.Debug("[checkReorg function] => latestBlockNumber: ", reorgedBlock.BlockNumber)
 			log.Debug("[checkReorg function] => latestBlockHash: ", reorgedBlock.BlockHash)
diff --git a/synchronizer/synchronizer_test.go b/synchronizer/synchronizer_test.go
index 9c5126b40e..9b6d6f036f 100644
--- a/synchronizer/synchronizer_test.go
+++ b/synchronizer/synchronizer_test.go
@@ -923,7 +923,7 @@ func expectedCallsForsyncTrustedState(t *testing.T, m *mocks, sync *ClientSynchr
 
 func TestReorg(t *testing.T) {
 	genesis := state.Genesis{
-		BlockNumber: uint64(0),
+		RollupBlockNumber: uint64(0),
 	}
 	cfg := Config{
 		SyncInterval:          cfgTypes.Duration{Duration: 1 * time.Second},
@@ -1243,7 +1243,7 @@ func TestReorg(t *testing.T) {
 
 func TestLatestSyncedBlockEmpty(t *testing.T) {
 	genesis := state.Genesis{
-		BlockNumber: uint64(0),
+		RollupBlockNumber: uint64(0),
 	}
 	cfg := Config{
 		SyncInterval:          cfgTypes.Duration{Duration: 1 * time.Second},
@@ -1457,7 +1457,7 @@ func TestLatestSyncedBlockEmpty(t *testing.T) {
 
 func TestRegularReorg(t *testing.T) {
 	genesis := state.Genesis{
-		BlockNumber: uint64(0),
+		RollupBlockNumber: uint64(0),
 	}
 	cfg := Config{
 		SyncInterval:          cfgTypes.Duration{Duration: 1 * time.Second},
@@ -1739,7 +1739,7 @@ func TestRegularReorg(t *testing.T) {
 
 func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) {
 	genesis := state.Genesis{
-		BlockNumber: uint64(0),
+		RollupBlockNumber: uint64(0),
 	}
 	cfg := Config{
 		SyncInterval:          cfgTypes.Duration{Duration: 1 * time.Second},
@@ -2015,7 +2015,7 @@ func TestLatestSyncedBlockEmptyWithExtraReorg(t *testing.T) {
 
 func TestCallFromEmptyBlockAndReorg(t *testing.T) {
 	genesis := state.Genesis{
-		BlockNumber: uint64(0),
+		RollupBlockNumber: uint64(0),
 	}
 	cfg := Config{
 		SyncInterval:          cfgTypes.Duration{Duration: 1 * time.Second},
diff --git a/test/config/test.da.toml b/test/config/test.da.toml
index 0d1596782d..56057eb5c2 100644
--- a/test/config/test.da.toml
+++ b/test/config/test.da.toml
@@ -3,8 +3,8 @@ PrivateKey = {Path = "/pk/test-member.keystore", Password = "testonly"}
 [L1]
 WsURL = "ws://xlayer-mock-l1-network:8546"
 RpcURL = "http://xlayer-mock-l1-network:8545"
-PolygonValidiumAddress = "0x975725832B4909Aab87D3604A0b501569dbBE7A9"
-DataCommitteeAddress = "0x2f08F654B896208dD968aFdAEf733edC5FF62c03"
+PolygonValidiumAddress = "0xeb173087729c88a47568AF87b17C653039377BA6"
+DataCommitteeAddress = "0x3bFa19E4588962D1834B2e4007F150f4447Aa9fe"
 Timeout = "3m"
 RetryPeriod = "5s"
 BlockBatchSize = 32
diff --git a/test/config/test.genesis.config.json b/test/config/test.genesis.config.json
index 4ae9a0a8f2..6cc3d64dd6 100644
--- a/test/config/test.genesis.config.json
+++ b/test/config/test.genesis.config.json
@@ -1,102 +1,102 @@
 {
     "l1Config": {
         "chainId": 1337,
-        "polygonZkEVMAddress": "0x975725832B4909Aab87D3604A0b501569dbBE7A9",
-        "polygonRollupManagerAddress": "0xF5336Cb12989c0673071dF0c8a930900D7DF8D3e",
-        "polTokenAddress": "0xcFE6D77a653b988203BfAc9C6a69eA9D583bdC2b",
-        "polygonZkEVMGlobalExitRootAddress": "0x6Ae5b0863dBF3477335c0102DBF432aFf04ceb22"
+        "polygonZkEVMAddress": "0xeb173087729c88a47568AF87b17C653039377BA6",
+        "polygonRollupManagerAddress": "0x2d42E2899662EFf08b13eeb65b154b904C7a1c8a",
+        "polTokenAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3",
+        "polygonZkEVMGlobalExitRootAddress": "0xB8cedD4B9eF683f0887C44a6E4312dC7A6e2fcdB"
     },
-    "genesisBlockNumber": 199,
-	"rollupCreationBlockNumber": 199,
-	"rollupManagerCreationBlockNumber": 199,
-    "root": "0xe6ae9579cda5787ab533bf97a8a5aa4ca1e0d40c8890b01f2d714fce71a5873c",
-    "genesis": [
-	    {
-		    "contractName": "PolygonZkEVMDeployer",
-		    "balance": "0",
-		    "nonce": "4",
-		    "address": "0xb169BC523B5399B94c7BDe7108fc543004F09aad",
-		    "bytecode": "0x6080604052600436106100705760003560e01c8063715018a61161004e578063715018a6146100e65780638da5cb5b146100fb578063e11ae6cb14610126578063f2fde38b1461013957600080fd5b80632b79805a146100755780634a94d4871461008a5780636d07dbf81461009d575b600080fd5b610088610083366004610927565b610159565b005b6100886100983660046109c7565b6101cb565b3480156100a957600080fd5b506100bd6100b8366004610a1e565b61020d565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b50610088610220565b34801561010757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100bd565b610088610134366004610a40565b610234565b34801561014557600080fd5b50610088610154366004610a90565b61029b565b610161610357565b600061016e8585856103d8565b905061017a8183610537565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a15050505050565b6101d3610357565b6101de83838361057b565b506040517f25adb19089b6a549831a273acdf7908cff8b7ee5f551f8d1d37996cf01c5df5b90600090a1505050565b600061021983836105a9565b9392505050565b610228610357565b61023260006105b6565b565b61023c610357565b60006102498484846103d8565b60405173ffffffffffffffffffffffffffffffffffffffff821681529091507fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a150505050565b6102a3610357565b73ffffffffffffffffffffffffffffffffffffffff811661034b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610354816105b6565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610232576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610342565b600083471015610444576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610342565b81516000036104af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610342565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610219576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610342565b6060610219838360006040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c6564000081525061062b565b60606105a1848484604051806060016040528060298152602001610b3d6029913961062b565b949350505050565b6000610219838330610744565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060824710156106bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610342565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516106e69190610acf565b60006040518083038185875af1925050503d8060008114610723576040519150601f19603f3d011682016040523d82523d6000602084013e610728565b606091505b50915091506107398783838761076e565b979650505050505050565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b606083156108045782516000036107fd5773ffffffffffffffffffffffffffffffffffffffff85163b6107fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610342565b50816105a1565b6105a183838151156108195781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103429190610aeb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261088d57600080fd5b813567ffffffffffffffff808211156108a8576108a861084d565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156108ee576108ee61084d565b8160405283815286602085880101111561090757600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806080858703121561093d57600080fd5b8435935060208501359250604085013567ffffffffffffffff8082111561096357600080fd5b61096f8883890161087c565b9350606087013591508082111561098557600080fd5b506109928782880161087c565b91505092959194509250565b803573ffffffffffffffffffffffffffffffffffffffff811681146109c257600080fd5b919050565b6000806000606084860312156109dc57600080fd5b6109e58461099e565b9250602084013567ffffffffffffffff811115610a0157600080fd5b610a0d8682870161087c565b925050604084013590509250925092565b60008060408385031215610a3157600080fd5b50508035926020909101359150565b600080600060608486031215610a5557600080fd5b8335925060208401359150604084013567ffffffffffffffff811115610a7a57600080fd5b610a868682870161087c565b9150509250925092565b600060208284031215610aa257600080fd5b6102198261099e565b60005b83811015610ac6578181015183820152602001610aae565b50506000910152565b60008251610ae1818460208701610aab565b9190910192915050565b6020815260008251806020840152610b0a816040850160208701610aab565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220964619cee0e0baf94c6f8763f013be157da5d54c89e5cff4a8caf4266e13f13a64736f6c63430008140033",
-		    "storage": {
-			    "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000002ecf31ece36ccac2d3222a303b1409233ecbb225"
-		    }
-	    },
-	    {
-		    "contractName": "ProxyAdmin",
-		    "balance": "0",
-		    "nonce": "1",
-		    "address": "0xa6791C91168866769273e6AFFe603e00269b16ae",
-		    "bytecode": "0x60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461012b57806399a88ec41461013e578063f2fde38b1461015e578063f3b7dead1461017e57600080fd5b8063204e1c7a14610080578063715018a6146100c95780637eff275e146100e05780638da5cb5b14610100575b600080fd5b34801561008c57600080fd5b506100a061009b366004610608565b61019e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d557600080fd5b506100de610255565b005b3480156100ec57600080fd5b506100de6100fb36600461062c565b610269565b34801561010c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100a0565b6100de610139366004610694565b6102f7565b34801561014a57600080fd5b506100de61015936600461062c565b61038c565b34801561016a57600080fd5b506100de610179366004610608565b6103e8565b34801561018a57600080fd5b506100a0610199366004610608565b6104a4565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b600060405180830381855afa9150503d8060008114610225576040519150601f19603f3d011682016040523d82523d6000602084013e61022a565b606091505b50915091508161023957600080fd5b8080602001905181019061024d9190610788565b949350505050565b61025d6104f0565b6102676000610571565b565b6102716104f0565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b600060405180830381600087803b1580156102db57600080fd5b505af11580156102ef573d6000803e3d6000fd5b505050505050565b6102ff6104f0565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef28690349061035590869086906004016107a5565b6000604051808303818588803b15801561036e57600080fd5b505af1158015610382573d6000803e3d6000fd5b5050505050505050565b6103946104f0565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102c1565b6103f06104f0565b73ffffffffffffffffffffffffffffffffffffffff8116610498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6104a181610571565b50565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b60005473ffffffffffffffffffffffffffffffffffffffff163314610267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161048f565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff811681146104a157600080fd5b60006020828403121561061a57600080fd5b8135610625816105e6565b9392505050565b6000806040838503121561063f57600080fd5b823561064a816105e6565b9150602083013561065a816105e6565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156106a957600080fd5b83356106b4816105e6565b925060208401356106c4816105e6565b9150604084013567ffffffffffffffff808211156106e157600080fd5b818601915086601f8301126106f557600080fd5b81358181111561070757610707610665565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561074d5761074d610665565b8160405282815289602084870101111561076657600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561079a57600080fd5b8151610625816105e6565b73ffffffffffffffffffffffffffffffffffffffff8316815260006020604081840152835180604085015260005b818110156107ef578581018301518582016060015282016107d3565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050939250505056fea2646970667358221220c9867ffac53151bdb1305d8f5e3e883cd83e5270c7ec09cdc24e837b2e65239064736f6c63430008140033",
-		    "storage": {
-			    "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000d4289c477602498dff4d0a7024f5dd4e060d531b"
-		    }
-	    },
-	    {
-		    "contractName": "PolygonZkEVMBridge implementation",
-		    "balance": "0",
-		    "nonce": "1",
-		    "address": "0x611732751B6857dFc02974cD019771b190E2e84C",
-		    "bytecode": "0x6080604052600436106101e35760003560e01c806383f2440311610102578063ccaa2d1111610095578063ee25560b11610064578063ee25560b146105ce578063f5efcd79146105fb578063f811bff71461061b578063fb5708341461063b57600080fd5b8063ccaa2d111461055d578063cd5865791461057d578063d02103ca14610590578063dbc16976146105b957600080fd5b8063bab161bf116100d1578063bab161bf146104d7578063be5831c7146104f9578063c00f14ab1461051d578063cc4616321461053d57600080fd5b806383f24403146104575780638ed7e3f214610477578063aaa13cc214610497578063b8b284d0146104b757600080fd5b80633cbc795b1161017a5780637843298b116101495780637843298b146103d757806379e2cf97146103f757806381b1c1741461040c57806383c43a551461044257600080fd5b80633cbc795b146103495780633e197043146103825780634b2f336d146103a25780635ca1e165146103c257600080fd5b806327aef4e8116101b657806327aef4e8146102795780632dfdf0b51461029b578063318aee3d146102bf5780633c351e101461032957600080fd5b806315064c96146101e85780632072f6c51461021757806322e95f2c1461022e578063240ff37814610266575b600080fd5b3480156101f457600080fd5b506068546102029060ff1681565b60405190151581526020015b60405180910390f35b34801561022357600080fd5b5061022c61065b565b005b34801561023a57600080fd5b5061024e61024936600461307c565b610690565b6040516001600160a01b03909116815260200161020e565b61022c61027436600461310a565b6106fb565b34801561028557600080fd5b5061028e610784565b60405161020e91906131d4565b3480156102a757600080fd5b506102b160535481565b60405190815260200161020e565b3480156102cb57600080fd5b506103056102da3660046131ee565b606b6020526000908152604090205463ffffffff81169064010000000090046001600160a01b031682565b6040805163ffffffff90931683526001600160a01b0390911660208301520161020e565b34801561033557600080fd5b50606d5461024e906001600160a01b031681565b34801561035557600080fd5b50606d5461036d90600160a01b900463ffffffff1681565b60405163ffffffff909116815260200161020e565b34801561038e57600080fd5b506102b161039d36600461321a565b610812565b3480156103ae57600080fd5b50606f5461024e906001600160a01b031681565b3480156103ce57600080fd5b506102b16108bc565b3480156103e357600080fd5b5061024e6103f2366004613299565b610999565b34801561040357600080fd5b5061022c6109c3565b34801561041857600080fd5b5061024e6104273660046132e2565b606a602052600090815260409020546001600160a01b031681565b34801561044e57600080fd5b5061028e6109e4565b34801561046357600080fd5b506102b161047236600461330d565b610a03565b34801561048357600080fd5b50606c5461024e906001600160a01b031681565b3480156104a357600080fd5b5061024e6104b2366004613419565b610ad9565b3480156104c357600080fd5b5061022c6104d23660046134b5565b610c1a565b3480156104e357600080fd5b5060685461036d90610100900463ffffffff1681565b34801561050557600080fd5b5060685461036d90600160c81b900463ffffffff1681565b34801561052957600080fd5b5061028e6105383660046131ee565b610cfa565b34801561054957600080fd5b50610202610558366004613538565b610d3f565b34801561056957600080fd5b5061022c61057836600461356b565b610dc9565b61022c61058b366004613657565b61131c565b34801561059c57600080fd5b5060685461024e906501000000000090046001600160a01b031681565b3480156105c557600080fd5b5061022c61179f565b3480156105da57600080fd5b506102b16105e93660046132e2565b60696020526000908152604090205481565b34801561060757600080fd5b5061022c61061636600461356b565b6117d2565b34801561062757600080fd5b5061022c6106363660046136ed565b611aa5565b34801561064757600080fd5b50610202610656366004613796565b611dc7565b606c546001600160a01b0316331461068657604051631736745960e31b815260040160405180910390fd5b61068e611ddf565b565b6040805160e084901b6001600160e01b031916602080830191909152606084901b6bffffffffffffffffffffffff1916602483015282516018818403018152603890920183528151918101919091206000908152606a90915220546001600160a01b03165b92915050565b60685460ff161561071f57604051630bc011ff60e21b815260040160405180910390fd5b34158015906107385750606f546001600160a01b031615155b1561076f576040517f6f625c4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61077d858534868686611e3b565b5050505050565b606e8054610791906137de565b80601f01602080910402602001604051908101604052809291908181526020018280546107bd906137de565b801561080a5780601f106107df5761010080835404028352916020019161080a565b820191906000526020600020905b8154815290600101906020018083116107ed57829003601f168201915b505050505081565b6040517fff0000000000000000000000000000000000000000000000000000000000000060f889901b1660208201526001600160e01b031960e088811b821660218401526bffffffffffffffffffffffff19606089811b821660258601529188901b909216603984015285901b16603d8201526051810183905260718101829052600090609101604051602081830303815290604052805190602001209050979650505050505050565b605354600090819081805b6020811015610990578083901c60011660010361092457603381602081106108f1576108f1613818565b01546040805160208101929092528101859052606001604051602081830303815290604052805190602001209350610951565b60408051602081018690529081018390526060016040516020818303038152906040528051906020012093505b6040805160208101849052908101839052606001604051602081830303815290604052805190602001209150808061098890613844565b9150506108c7565b50919392505050565b60006109bb84846109a985611f05565b6109b286611ff3565b6104b2876120d8565b949350505050565b605354606854600160c81b900463ffffffff16101561068e5761068e6121a9565b60405180611ba00160405280611b668152602001613ec4611b66913981565b600083815b6020811015610ad057600163ffffffff8516821c81169003610a7357848160208110610a3657610a36613818565b602002013582604051602001610a56929190918252602082015260400190565b604051602081830303815290604052805190602001209150610abe565b81858260208110610a8657610a86613818565b6020020135604051602001610aa5929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b80610ac881613844565b915050610a08565b50949350505050565b6040516001600160e01b031960e087901b1660208201526bffffffffffffffffffffffff19606086901b1660248201526000908190603801604051602081830303815290604052805190602001209050600060ff60f81b308360405180611ba00160405280611b668152602001613ec4611b669139898989604051602001610b639392919061385d565b60408051601f1981840301815290829052610b819291602001613896565b60405160208183030381529060405280519060200120604051602001610bf694939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051808303601f19018152919052805160209091012098975050505050505050565b60685460ff1615610c3e57604051630bc011ff60e21b815260040160405180910390fd5b606f546001600160a01b0316610c80576040517fdde3cda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f54604051632770a7eb60e21b8152336004820152602481018690526001600160a01b0390911690639dc29fac90604401600060405180830381600087803b158015610ccc57600080fd5b505af1158015610ce0573d6000803e3d6000fd5b50505050610cf2868686868686611e3b565b505050505050565b6060610d0582611f05565b610d0e83611ff3565b610d17846120d8565b604051602001610d299392919061385d565b6040516020818303038152906040529050919050565b6068546000908190610100900463ffffffff16158015610d65575063ffffffff83166001145b15610d77575063ffffffff8316610d9f565b610d8c64010000000063ffffffff85166138c5565b610d9c9063ffffffff86166138dc565b90505b600881901c600090815260696020526040902054600160ff9092169190911b908116149392505050565b60685460ff1615610ded57604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff8681166101009092041614610e1d576040516302caf51760e11b815260040160405180910390fd5b610e518c8c8c8c8c610e4c60008e8e8e8e8e8e8e604051610e3f9291906138ef565b6040518091039020610812565b61225c565b6001600160a01b038616610fa457606f546001600160a01b0316610f395760006001600160a01b03851684825b6040519080825280601f01601f191660200182016040528015610ea8576020820181803683370190505b50604051610eb691906138ff565b60006040518083038185875af1925050503d8060008114610ef3576040519150601f19603f3d011682016040523d82523d6000602084013e610ef8565b606091505b5050905080610f33576040517f6747a28800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506112b2565b606f546040516340c10f1960e01b81526001600160a01b03868116600483015260248201869052909116906340c10f1990604401600060405180830381600087803b158015610f8757600080fd5b505af1158015610f9b573d6000803e3d6000fd5b505050506112b2565b606d546001600160a01b038781169116148015610fd25750606d5463ffffffff888116600160a01b90920416145b15610fea5760006001600160a01b0385168482610e7e565b60685463ffffffff61010090910481169088160361101b576110166001600160a01b03871685856123f4565b6112b2565b6040516001600160e01b031960e089901b1660208201526bffffffffffffffffffffffff19606088901b16602482015260009060380160408051601f1981840301815291815281516020928301206000818152606a9093529120549091506001600160a01b03168061124c5760006110c98386868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061247592505050565b6040516340c10f1960e01b81526001600160a01b03898116600483015260248201899052919250908216906340c10f1990604401600060405180830381600087803b15801561111757600080fd5b505af115801561112b573d6000803e3d6000fd5b5050505080606a600085815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060405180604001604052808b63ffffffff1681526020018a6001600160a01b0316815250606b6000836001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f490e59a1701b938786ac72570a1efeac994a3dbe96e2e883e19e902ace6e6a398a8a83888860405161123e959493929190613944565b60405180910390a1506112af565b6040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f1990604401600060405180830381600087803b15801561129657600080fd5b505af11580156112aa573d6000803e3d6000fd5b505050505b50505b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b60685460ff161561134057604051630bc011ff60e21b815260040160405180910390fd5b61134861250a565b60685463ffffffff610100909104811690881603611379576040516302caf51760e11b815260040160405180910390fd5b6000806060876001600160a01b038816611478578834146113c6576040517fb89240f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606d54606e80546001600160a01b0383169650600160a01b90920463ffffffff169450906113f3906137de565b80601f016020809104026020016040519081016040528092919081815260200182805461141f906137de565b801561146c5780601f106114415761010080835404028352916020019161146c565b820191906000526020600020905b81548152906001019060200180831161144f57829003601f168201915b50505050509150611714565b34156114b0576040517f798ee6f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546001600160a01b039081169089160361152b57604051632770a7eb60e21b8152336004820152602481018a90526001600160a01b03891690639dc29fac90604401600060405180830381600087803b15801561150e57600080fd5b505af1158015611522573d6000803e3d6000fd5b50505050611714565b6001600160a01b038089166000908152606b602090815260409182902082518084019093525463ffffffff81168352640100000000900490921691810182905290156115e457604051632770a7eb60e21b8152336004820152602481018b90526001600160a01b038a1690639dc29fac90604401600060405180830381600087803b1580156115b957600080fd5b505af11580156115cd573d6000803e3d6000fd5b505050508060200151945080600001519350611707565b85156115f6576115f6898b8989612563565b6040516370a0823160e01b81523060048201526000906001600160a01b038b16906370a0823190602401602060405180830381865afa15801561163d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611661919061397d565b90506116786001600160a01b038b1633308e61290d565b6040516370a0823160e01b81523060048201526000906001600160a01b038c16906370a0823190602401602060405180830381865afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e3919061397d565b90506116ef8282613996565b6068548c9850610100900463ffffffff169650935050505b61171089610cfa565b9250505b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b600084868e8e86886053546040516117549897969594939291906139a9565b60405180910390a161177b611776600085878f8f878980519060200120610812565b61295e565b8615611789576117896121a9565b5050505061179660018055565b50505050505050565b606c546001600160a01b031633146117ca57604051631736745960e31b815260040160405180910390fd5b61068e612a62565b60685460ff16156117f657604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff8681166101009092041614611826576040516302caf51760e11b815260040160405180910390fd5b6118488c8c8c8c8c610e4c60018e8e8e8e8e8e8e604051610e3f9291906138ef565b606f546000906001600160a01b03166118ff57846001600160a01b031684888a868660405160240161187d9493929190613a13565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b179052516118b291906138ff565b60006040518083038185875af1925050503d80600081146118ef576040519150601f19603f3d011682016040523d82523d6000602084013e6118f4565b606091505b505080915050611a03565b606f546040516340c10f1960e01b81526001600160a01b03878116600483015260248201879052909116906340c10f1990604401600060405180830381600087803b15801561194d57600080fd5b505af1158015611961573d6000803e3d6000fd5b50505050846001600160a01b0316878985856040516024016119869493929190613a13565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b179052516119bb91906138ff565b6000604051808303816000865af19150503d80600081146119f8576040519150601f19603f3d011682016040523d82523d6000602084013e6119fd565b606091505b50909150505b80611a3a576040517f37e391c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518c815263ffffffff8a1660208201526001600160a01b0389811682840152871660608201526080810186905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a150505050505050505050505050565b600054610100900460ff1615808015611ac55750600054600160ff909116105b80611adf5750303b158015611adf575060005460ff166001145b611b565760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b6000805460ff191660011790558015611b79576000805461ff0019166101001790555b606880547fffffffffffffff000000000000000000000000000000000000000000000000ff1661010063ffffffff8a16027fffffffffffffff0000000000000000000000000000000000000000ffffffffff1617650100000000006001600160a01b038781169190910291909117909155606c805473ffffffffffffffffffffffffffffffffffffffff19168583161790558616611c545763ffffffff851615611c4f576040517f1a874c1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d71565b606d805463ffffffff8716600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009091166001600160a01b03891617179055606e611ca38382613a92565b50611d436000801b6012604051602001611d2f91906060808252600d908201527f5772617070656420457468657200000000000000000000000000000000000000608082015260a0602082018190526004908201527f574554480000000000000000000000000000000000000000000000000000000060c082015260ff91909116604082015260e00190565b604051602081830303815290604052612475565b606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555b611d79612ad3565b8015611796576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b600081611dd5868686610a03565b1495945050505050565b60685460ff1615611e0357604051630bc011ff60e21b815260040160405180910390fd5b6068805460ff191660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a549790600090a1565b60685463ffffffff610100909104811690871603611e6c576040516302caf51760e11b815260040160405180910390fd5b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b6001606860019054906101000a900463ffffffff16338989898888605354604051611ec099989796959493929190613b52565b60405180910390a1611ef76117766001606860019054906101000a900463ffffffff16338a8a8a8989604051610e3f9291906138ef565b8215610cf257610cf26121a9565b60408051600481526024810182526020810180516001600160e01b03167f06fdde0300000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b03861691611f6591906138ff565b600060405180830381855afa9150503d8060008114611fa0576040519150601f19603f3d011682016040523d82523d6000602084013e611fa5565b606091505b509150915081611fea576040518060400160405280600781526020017f4e4f5f4e414d45000000000000000000000000000000000000000000000000008152506109bb565b6109bb81612b46565b60408051600481526024810182526020810180516001600160e01b03167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009182916001600160a01b0386169161205391906138ff565b600060405180830381855afa9150503d806000811461208e576040519150601f19603f3d011682016040523d82523d6000602084013e612093565b606091505b509150915081611fea576040518060400160405280600981526020017f4e4f5f53594d424f4c00000000000000000000000000000000000000000000008152506109bb565b60408051600481526024810182526020810180516001600160e01b03167f313ce567000000000000000000000000000000000000000000000000000000001790529051600091829182916001600160a01b0386169161213791906138ff565b600060405180830381855afa9150503d8060008114612172576040519150601f19603f3d011682016040523d82523d6000602084013e612177565b606091505b509150915081801561218a575080516020145b6121955760126109bb565b808060200190518101906109bb9190613bbe565b6053546068805463ffffffff909216600160c81b027fffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117908190556001600160a01b0365010000000000909104166333d6247d61220a6108bc565b6040518263ffffffff1660e01b815260040161222891815260200190565b600060405180830381600087803b15801561224257600080fd5b505af1158015612256573d6000803e3d6000fd5b50505050565b606854604080516020808201879052818301869052825180830384018152606083019384905280519101207f257b36320000000000000000000000000000000000000000000000000000000090925260648101919091526000916501000000000090046001600160a01b03169063257b3632906084016020604051808303816000875af11580156122f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612315919061397d565b905080600003612350576040517e2f6fad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806801000000000000000087161561239557869150612373848a8489611dc7565b612390576040516338105f3b60e21b815260040160405180910390fd5b6123df565b602087901c6123a5816001613bdb565b91508792506123c06123b8868c86610a03565b8a8389611dc7565b6123dd576040516338105f3b60e21b815260040160405180910390fd5b505b6123e98282612d1b565b505050505050505050565b6040516001600160a01b0383166024820152604481018290526124709084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612ddd565b505050565b60008060405180611ba00160405280611b668152602001613ec4611b669139836040516020016124a6929190613896565b6040516020818303038152906040529050838151602083016000f591506001600160a01b038216612503576040517fbefb092000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092915050565b60026001540361255c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611b4d565b6002600155565b60006125726004828486613bf8565b61257b91613c22565b90507f2afa5331000000000000000000000000000000000000000000000000000000006001600160e01b031982160161275a5760008080808080806125c3896004818d613bf8565b8101906125d09190613c52565b9650965096509650965096509650336001600160a01b0316876001600160a01b0316146126105760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03861630146126395760405163750643af60e01b815260040160405180910390fd5b8a8514612672576040517f03fffc4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b0389811660248301528881166044830152606482018890526084820187905260ff861660a483015260c4820185905260e48083018590528351808403909101815261010490920183526020820180516001600160e01b03167fd505accf000000000000000000000000000000000000000000000000000000001790529151918e169161270991906138ff565b6000604051808303816000865af19150503d8060008114612746576040519150601f19603f3d011682016040523d82523d6000602084013e61274b565b606091505b5050505050505050505061077d565b6001600160e01b031981166323f2ebc360e21b146127a4576040517fe282c0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808080808080806127ba8a6004818e613bf8565b8101906127c79190613ca6565b97509750975097509750975097509750336001600160a01b0316886001600160a01b0316146128095760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03871630146128325760405163750643af60e01b815260040160405180910390fd5b604080516001600160a01b038a811660248301528981166044830152606482018990526084820188905286151560a483015260ff861660c483015260e482018590526101048083018590528351808403909101815261012490920183526020820180516001600160e01b03166323f2ebc360e21b1790529151918f16916128b991906138ff565b6000604051808303816000865af19150503d80600081146128f6576040519150601f19603f3d011682016040523d82523d6000602084013e6128fb565b606091505b50505050505050505050505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526122569085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612439565b80600161296d60206002613e0d565b6129779190613996565b605354106129b1576040517fef5ccf6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006053600081546129c290613844565b9182905550905060005b6020811015612a53578082901c6001166001036129ff5782603382602081106129f7576129f7613818565b015550505050565b60338160208110612a1257612a12613818565b015460408051602081019290925281018490526060016040516020818303038152906040528051906020012092508080612a4b90613844565b9150506129cc565b50612470613e19565b60018055565b60685460ff16612a9e576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6068805460ff191690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b390600090a1565b600054610100900460ff16612b3e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611b4d565b61068e612ec2565b60606040825110612b6557818060200190518101906106f59190613e2f565b8151602003612cdd5760005b602081108015612bb85750828181518110612b8e57612b8e613818565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612bcf5780612bc781613844565b915050612b71565b80600003612c1257505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b60008167ffffffffffffffff811115612c2d57612c2d61334c565b6040519080825280601f01601f191660200182016040528015612c57576020820181803683370190505b50905060005b82811015612cd557848181518110612c7757612c77613818565b602001015160f81c60f81b828281518110612c9457612c94613818565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080612ccd81613844565b915050612c5d565b509392505050565b505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b919050565b606854600090610100900463ffffffff16158015612d3f575063ffffffff82166001145b15612d51575063ffffffff8216612d79565b612d6664010000000063ffffffff84166138c5565b612d769063ffffffff85166138dc565b90505b600881901c60008181526069602052604081208054600160ff861690811b91821892839055929091908183169003611796576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612e32826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612f2d9092919063ffffffff16565b8051909150156124705780806020019051810190612e509190613ea6565b6124705760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611b4d565b600054610100900460ff16612a5c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611b4d565b60606109bb848460008585600080866001600160a01b03168587604051612f5491906138ff565b60006040518083038185875af1925050503d8060008114612f91576040519150601f19603f3d011682016040523d82523d6000602084013e612f96565b606091505b5091509150612fa787838387612fb2565b979650505050505050565b6060831561302157825160000361301a576001600160a01b0385163b61301a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611b4d565b50816109bb565b6109bb83838151156130365781518083602001fd5b8060405162461bcd60e51b8152600401611b4d91906131d4565b803563ffffffff81168114612d1657600080fd5b6001600160a01b038116811461307957600080fd5b50565b6000806040838503121561308f57600080fd5b61309883613050565b915060208301356130a881613064565b809150509250929050565b801515811461307957600080fd5b60008083601f8401126130d357600080fd5b50813567ffffffffffffffff8111156130eb57600080fd5b60208301915083602082850101111561310357600080fd5b9250929050565b60008060008060006080868803121561312257600080fd5b61312b86613050565b9450602086013561313b81613064565b9350604086013561314b816130b3565b9250606086013567ffffffffffffffff81111561316757600080fd5b613173888289016130c1565b969995985093965092949392505050565b60005b8381101561319f578181015183820152602001613187565b50506000910152565b600081518084526131c0816020860160208601613184565b601f01601f19169290920160200192915050565b6020815260006131e760208301846131a8565b9392505050565b60006020828403121561320057600080fd5b81356131e781613064565b60ff8116811461307957600080fd5b600080600080600080600060e0888a03121561323557600080fd5b87356132408161320b565b965061324e60208901613050565b9550604088013561325e81613064565b945061326c60608901613050565b9350608088013561327c81613064565b9699959850939692959460a0840135945060c09093013592915050565b6000806000606084860312156132ae57600080fd5b6132b784613050565b925060208401356132c781613064565b915060408401356132d781613064565b809150509250925092565b6000602082840312156132f457600080fd5b5035919050565b8061040081018310156106f557600080fd5b6000806000610440848603121561332357600080fd5b8335925061333485602086016132fb565b91506133436104208501613050565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561338b5761338b61334c565b604052919050565b600067ffffffffffffffff8211156133ad576133ad61334c565b50601f01601f191660200190565b60006133ce6133c984613393565b613362565b90508281528383830111156133e257600080fd5b828260208301376000602084830101529392505050565b600082601f83011261340a57600080fd5b6131e7838335602085016133bb565b600080600080600060a0868803121561343157600080fd5b61343a86613050565b9450602086013561344a81613064565b9350604086013567ffffffffffffffff8082111561346757600080fd5b61347389838a016133f9565b9450606088013591508082111561348957600080fd5b50613496888289016133f9565b92505060808601356134a78161320b565b809150509295509295909350565b60008060008060008060a087890312156134ce57600080fd5b6134d787613050565b955060208701356134e781613064565b94506040870135935060608701356134fe816130b3565b9250608087013567ffffffffffffffff81111561351a57600080fd5b61352689828a016130c1565b979a9699509497509295939492505050565b6000806040838503121561354b57600080fd5b61355483613050565b915061356260208401613050565b90509250929050565b6000806000806000806000806000806000806109208d8f03121561358e57600080fd5b6135988e8e6132fb565b9b506135a88e6104008f016132fb565b9a506108008d013599506108208d013598506108408d013597506135cf6108608e01613050565b96506135df6108808e0135613064565b6108808d013595506135f46108a08e01613050565b94506136046108c08e0135613064565b6108c08d013593506108e08d0135925067ffffffffffffffff6109008e0135111561362e57600080fd5b61363f8e6109008f01358f016130c1565b81935080925050509295989b509295989b509295989b565b600080600080600080600060c0888a03121561367257600080fd5b61367b88613050565b9650602088013561368b81613064565b95506040880135945060608801356136a281613064565b935060808801356136b2816130b3565b925060a088013567ffffffffffffffff8111156136ce57600080fd5b6136da8a828b016130c1565b989b979a50959850939692959293505050565b60008060008060008060c0878903121561370657600080fd5b61370f87613050565b9550602087013561371f81613064565b945061372d60408801613050565b9350606087013561373d81613064565b9250608087013561374d81613064565b915060a087013567ffffffffffffffff81111561376957600080fd5b8701601f8101891361377a57600080fd5b613789898235602084016133bb565b9150509295509295509295565b60008060008061046085870312156137ad57600080fd5b843593506137be86602087016132fb565b92506137cd6104208601613050565b939692955092936104400135925050565b600181811c908216806137f257607f821691505b60208210810361381257634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016138565761385661382e565b5060010190565b60608152600061387060608301866131a8565b828103602084015261388281866131a8565b91505060ff83166040830152949350505050565b600083516138a8818460208801613184565b8351908301906138bc818360208801613184565b01949350505050565b80820281158282048414176106f5576106f561382e565b808201808211156106f5576106f561382e565b8183823760009101908152919050565b60008251613911818460208701613184565b9190910192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b63ffffffff8616815260006001600160a01b03808716602084015280861660408401525060806060830152612fa760808301848661391b565b60006020828403121561398f57600080fd5b5051919050565b818103818111156106f5576106f561382e565b600061010060ff8b16835263ffffffff808b1660208501526001600160a01b03808b166040860152818a1660608601528089166080860152508660a08501528160c08501526139fa828501876131a8565b925080851660e085015250509998505050505050505050565b6001600160a01b038516815263ffffffff84166020820152606060408201526000613a4260608301848661391b565b9695505050505050565b601f82111561247057600081815260208120601f850160051c81016020861015613a735750805b601f850160051c820191505b81811015610cf257828155600101613a7f565b815167ffffffffffffffff811115613aac57613aac61334c565b613ac081613aba84546137de565b84613a4c565b602080601f831160018114613af55760008415613add5750858301515b600019600386901b1c1916600185901b178555610cf2565b600085815260208120601f198616915b82811015613b2457888601518255948401946001909101908401613b05565b5085821015613b425787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600061010060ff8c16835263ffffffff808c1660208501526001600160a01b03808c166040860152818b166060860152808a166080860152508760a08501528160c0850152613ba4828501878961391b565b925080851660e085015250509a9950505050505050505050565b600060208284031215613bd057600080fd5b81516131e78161320b565b63ffffffff8181168382160190808211156125035761250361382e565b60008085851115613c0857600080fd5b83861115613c1557600080fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613c4a5780818660040360031b1b83161692505b505092915050565b600080600080600080600060e0888a031215613c6d57600080fd5b8735613c7881613064565b96506020880135613c8881613064565b95506040880135945060608801359350608088013561327c8161320b565b600080600080600080600080610100898b031215613cc357600080fd5b8835613cce81613064565b97506020890135613cde81613064565b965060408901359550606089013594506080890135613cfc816130b3565b935060a0890135613d0c8161320b565b979a969950949793969295929450505060c08201359160e0013590565b600181815b80851115613d64578160001904821115613d4a57613d4a61382e565b80851615613d5757918102915b93841c9390800290613d2e565b509250929050565b600082613d7b575060016106f5565b81613d88575060006106f5565b8160018114613d9e5760028114613da857613dc4565b60019150506106f5565b60ff841115613db957613db961382e565b50506001821b6106f5565b5060208310610133831016604e8410600b8410161715613de7575081810a6106f5565b613df18383613d29565b8060001904821115613e0557613e0561382e565b029392505050565b60006131e78383613d6c565b634e487b7160e01b600052600160045260246000fd5b600060208284031215613e4157600080fd5b815167ffffffffffffffff811115613e5857600080fd5b8201601f81018413613e6957600080fd5b8051613e776133c982613393565b818152856020838501011115613e8c57600080fd5b613e9d826020830160208601613184565b95945050505050565b600060208284031215613eb857600080fd5b81516131e7816130b356fe6101006040523480156200001257600080fd5b5060405162001b6638038062001b6683398101604081905262000035916200028d565b82826003620000458382620003a1565b506004620000548282620003a1565b50503360c0525060ff811660e052466080819052620000739062000080565b60a052506200046d915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620000ad6200012e565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6060600380546200013f9062000312565b80601f01602080910402602001604051908101604052809291908181526020018280546200016d9062000312565b8015620001be5780601f106200019257610100808354040283529160200191620001be565b820191906000526020600020905b815481529060010190602001808311620001a057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f057600080fd5b81516001600160401b03808211156200020d576200020d620001c8565b604051601f8301601f19908116603f01168101908282118183101715620002385762000238620001c8565b816040528381526020925086838588010111156200025557600080fd5b600091505b838210156200027957858201830151818301840152908201906200025a565b600093810190920192909252949350505050565b600080600060608486031215620002a357600080fd5b83516001600160401b0380821115620002bb57600080fd5b620002c987838801620001de565b94506020860151915080821115620002e057600080fd5b50620002ef86828701620001de565b925050604084015160ff811681146200030757600080fd5b809150509250925092565b600181811c908216806200032757607f821691505b6020821081036200034857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039c57600081815260208120601f850160051c81016020861015620003775750805b601f850160051c820191505b81811015620003985782815560010162000383565b5050505b505050565b81516001600160401b03811115620003bd57620003bd620001c8565b620003d581620003ce845462000312565b846200034e565b602080601f8311600181146200040d5760008415620003f45750858301515b600019600386901b1c1916600185901b17855562000398565b600085815260208120601f198616915b828110156200043e578886015182559484019460019091019084016200041d565b50858210156200045d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516116aa620004bc6000396000610237015260008181610307015281816105c001526106a70152600061053a015260008181610379015261050401526116aa6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806370a08231116100d8578063a457c2d71161008c578063d505accf11610066578063d505accf1461039b578063dd62ed3e146103ae578063ffa1ad74146103f457600080fd5b8063a457c2d71461034e578063a9059cbb14610361578063cd0d00961461037457600080fd5b806395d89b41116100bd57806395d89b41146102e75780639dc29fac146102ef578063a3c573eb1461030257600080fd5b806370a08231146102915780637ecebe00146102c757600080fd5b806330adf81f1161012f5780633644e515116101145780633644e51514610261578063395093511461026957806340c10f191461027c57600080fd5b806330adf81f14610209578063313ce5671461023057600080fd5b806318160ddd1161016057806318160ddd146101bd57806320606b70146101cf57806323b872dd146101f657600080fd5b806306fdde031461017c578063095ea7b31461019a575b600080fd5b610184610430565b60405161019191906113e4565b60405180910390f35b6101ad6101a8366004611479565b6104c2565b6040519015158152602001610191565b6002545b604051908152602001610191565b6101c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6101ad6102043660046114a3565b6104dc565b6101c17f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610191565b6101c1610500565b6101ad610277366004611479565b61055c565b61028f61028a366004611479565b6105a8565b005b6101c161029f3660046114df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101c16102d53660046114df565b60056020526000908152604090205481565b610184610680565b61028f6102fd366004611479565b61068f565b6103297f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101ad61035c366004611479565b61075e565b6101ad61036f366004611479565b61082f565b6101c17f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103a9366004611501565b61083d565b6101c16103bc366004611574565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101846040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b60606003805461043f906115a7565b80601f016020809104026020016040519081016040528092919081815260200182805461046b906115a7565b80156104b85780601f1061048d576101008083540402835291602001916104b8565b820191906000526020600020905b81548152906001019060200180831161049b57829003601f168201915b5050505050905090565b6000336104d0818585610b73565b60019150505b92915050565b6000336104ea858285610d27565b6104f5858585610dfe565b506001949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610537576105324661106d565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104d090829086906105a3908790611629565b610b73565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084015b60405180910390fd5b61067c8282611135565b5050565b60606004805461043f906115a7565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d427269646765000000000000000000000000000000006064820152608401610669565b61067c8282611228565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610822576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610669565b6104f58286868403610b73565b6000336104d0818585610dfe565b834211156108cc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f546f6b656e577261707065643a3a7065726d69743a204578706972656420706560448201527f726d6974000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a9190866109268361163c565b9091555060408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610991610500565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610a55573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610ad057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f546f6b656e577261707065643a3a7065726d69743a20496e76616c696420736960448201527f676e6174757265000000000000000000000000000000000000000000000000006064820152608401610669565b610b678a8a8a610b73565b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316610c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610df85781811015610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610669565b610df88484848403610b73565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610df8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611098610430565b8051602091820120604080518082018252600181527f310000000000000000000000000000000000000000000000000000000000000090840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b73ffffffffffffffffffffffffffffffffffffffff82166111b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610669565b80600260008282546111c49190611629565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166112cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610d1a565b600060208083528351808285015260005b81811015611411578581018301518582016040015282016113f5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461147457600080fd5b919050565b6000806040838503121561148c57600080fd5b61149583611450565b946020939093013593505050565b6000806000606084860312156114b857600080fd5b6114c184611450565b92506114cf60208501611450565b9150604084013590509250925092565b6000602082840312156114f157600080fd5b6114fa82611450565b9392505050565b600080600080600080600060e0888a03121561151c57600080fd5b61152588611450565b965061153360208901611450565b95506040880135945060608801359350608088013560ff8116811461155757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561158757600080fd5b61159083611450565b915061159e60208401611450565b90509250929050565b600181811c908216806115bb57607f821691505b6020821081036115f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104d6576104d66115fa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361166d5761166d6115fa565b506001019056fea26469706673582212208d88fee561cff7120d381c345cfc534cef8229a272dc5809d4bbb685ad67141164736f6c63430008110033a264697066735822122078dbdc367e7857d7cdf8e3cb8d3102a00d09ea40655a67a85436f80d2c7ba06664736f6c63430008140033"
-	    },
-	    {
-		    "contractName": "PolygonZkEVMBridge proxy",
-		    "balance": "340282366920938463463374607431768211455",
-		    "nonce": "1",
-		    "address": "0x1dDA31e2F009E7479dE78445C1540f55627a85f4",
-		    "bytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b61009036600461086f565b610135565b61006b6100a336600461088a565b61017f565b3480156100b457600080fd5b506100bd6101f3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b61010136600461086f565b610231565b34801561011257600080fd5b506100bd61025e565b61012361028c565b61013361012e610363565b61036d565b565b61013d610391565b73ffffffffffffffffffffffffffffffffffffffff16330361017757610174816040518060200160405280600081525060006103d1565b50565b61017461011b565b610187610391565b73ffffffffffffffffffffffffffffffffffffffff1633036101eb576101e68383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506103d1915050565b505050565b6101e661011b565b60006101fd610391565b73ffffffffffffffffffffffffffffffffffffffff16330361022657610221610363565b905090565b61022e61011b565b90565b610239610391565b73ffffffffffffffffffffffffffffffffffffffff16330361017757610174816103fc565b6000610268610391565b73ffffffffffffffffffffffffffffffffffffffff16330361022657610221610391565b610294610391565b73ffffffffffffffffffffffffffffffffffffffff163303610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b600061022161045d565b3660008037600080366000845af43d6000803e80801561038c573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6103da83610485565b6000825111806103e75750805b156101e6576103f683836104d2565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610425610391565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a1610174816104fe565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103b5565b61048e8161060a565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606104f7838360405180606001604052806027815260200161099f602791396106d5565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff81166105a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161035a565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b73ffffffffffffffffffffffffffffffffffffffff81163b6106ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161035a565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105c4565b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516106ff9190610931565b600060405180830381855af49150503d806000811461073a576040519150601f19603f3d011682016040523d82523d6000602084013e61073f565b606091505b50915091506107508683838761075a565b9695505050505050565b606083156107f05782516000036107e95773ffffffffffffffffffffffffffffffffffffffff85163b6107e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161035a565b50816107fa565b6107fa8383610802565b949350505050565b8151156108125781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161035a919061094d565b803573ffffffffffffffffffffffffffffffffffffffff8116811461086a57600080fd5b919050565b60006020828403121561088157600080fd5b6104f782610846565b60008060006040848603121561089f57600080fd5b6108a884610846565b9250602084013567ffffffffffffffff808211156108c557600080fd5b818601915086601f8301126108d957600080fd5b8135818111156108e857600080fd5b8760208285010111156108fa57600080fd5b6020830194508093505050509250925092565b60005b83811015610928578181015183820152602001610910565b50506000910152565b6000825161094381846020870161090d565b9190910192915050565b602081526000825180602084015261096c81604085016020870161090d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220701a0c26bdd76686e63fc3c65e4f28a20ba3ecc8a60246733c0627e679c9804e64736f6c63430008140033",
-		    "storage": {
-			    "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000a6791c91168866769273e6affe603e00269b16ae",
-			    "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x000000000000000000000000611732751b6857dfc02974cd019771b190e2e84c"
-		    }
-	    },
-	    {
-		    "contractName": "PolygonZkEVMGlobalExitRootL2 implementation",
-		    "balance": "0",
-		    "nonce": "1",
-		    "address": "0x6C71cb798D098f8Aa3C1c13286A2EB4A7c4fa2a9",
-		    "bytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806301fd904414610051578063257b36321461006d57806333d6247d1461008d578063a3c573eb146100a2575b600080fd5b61005a60015481565b6040519081526020015b60405180910390f35b61005a61007b366004610162565b60006020819052908152604090205481565b6100a061009b366004610162565b6100ee565b005b6100c97f0000000000000000000000001dda31e2f009e7479de78445c1540f55627a85f481565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610064565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001dda31e2f009e7479de78445c1540f55627a85f4161461015d576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b60006020828403121561017457600080fd5b503591905056fea2646970667358221220ea2171e2c85c8bff947affc409ef6fc6a8fe82fb8c174ddeda988651e595d66564736f6c63430008140033"
-	    },
-	    {
-		    "contractName": "PolygonZkEVMGlobalExitRootL2 proxy",
-		    "balance": "0",
-		    "nonce": "1",
-		    "address": "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa",
-		    "bytecode": "0x60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033",
-		    "storage": {
-			    "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x000000000000000000000000a6791c91168866769273e6affe603e00269b16ae",
-			    "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000000000000000000000006c71cb798d098f8aa3c1c13286a2eb4a7c4fa2a9"
-		    }
-	    },
-	    {
-		    "contractName": "PolygonZkEVMTimelock",
-		    "balance": "0",
-		    "nonce": "1",
-		    "address": "0xD4289C477602498Dff4d0A7024f5DD4E060d531b",
-		    "bytecode": "0x6080604052600436106101c65760003560e01c806364d62353116100f7578063b1c5f42711610095578063d547741f11610064578063d547741f14610661578063e38335e514610681578063f23a6e6114610694578063f27a0c92146106d957600080fd5b8063b1c5f427146105af578063bc197c81146105cf578063c4d252f514610614578063d45c44351461063457600080fd5b80638f61f4f5116100d15780638f61f4f5146104e157806391d1485414610515578063a217fddf14610566578063b08e51c01461057b57600080fd5b806364d62353146104815780638065657f146104a15780638f2a0bb0146104c157600080fd5b8063248a9ca31161016457806331d507501161013e57806331d50750146103c857806336568abe146103e85780633a6aae7214610408578063584b153e1461046157600080fd5b8063248a9ca3146103475780632ab0f529146103775780632f2ff15d146103a857600080fd5b80630d3cf6fc116101a05780630d3cf6fc1461026b578063134008d31461029f57806313bc9f20146102b2578063150b7a02146102d257600080fd5b806301d5062a146101d257806301ffc9a7146101f457806307bd02651461022957600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506101f26101ed366004611c52565b6106ee565b005b34801561020057600080fd5b5061021461020f366004611cc7565b610783565b60405190151581526020015b60405180910390f35b34801561023557600080fd5b5061025d7fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610220565b34801561027757600080fd5b5061025d7f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101f26102ad366004611d09565b6107df565b3480156102be57600080fd5b506102146102cd366004611d75565b6108d7565b3480156102de57600080fd5b506103166102ed366004611e9a565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610220565b34801561035357600080fd5b5061025d610362366004611d75565b60009081526020819052604090206001015490565b34801561038357600080fd5b50610214610392366004611d75565b6000908152600160208190526040909120541490565b3480156103b457600080fd5b506101f26103c3366004611f02565b6108fd565b3480156103d457600080fd5b506102146103e3366004611d75565b610927565b3480156103f457600080fd5b506101f2610403366004611f02565b610940565b34801561041457600080fd5b5061043c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610220565b34801561046d57600080fd5b5061021461047c366004611d75565b6109f8565b34801561048d57600080fd5b506101f261049c366004611d75565b610a0e565b3480156104ad57600080fd5b5061025d6104bc366004611d09565b610ade565b3480156104cd57600080fd5b506101f26104dc366004611f73565b610b1d565b3480156104ed57600080fd5b5061025d7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b34801561052157600080fd5b50610214610530366004611f02565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561057257600080fd5b5061025d600081565b34801561058757600080fd5b5061025d7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b3480156105bb57600080fd5b5061025d6105ca366004612025565b610d4f565b3480156105db57600080fd5b506103166105ea36600461214e565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b34801561062057600080fd5b506101f261062f366004611d75565b610d94565b34801561064057600080fd5b5061025d61064f366004611d75565b60009081526001602052604090205490565b34801561066d57600080fd5b506101f261067c366004611f02565b610e8f565b6101f261068f366004612025565b610eb4565b3480156106a057600080fd5b506103166106af3660046121f8565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106e557600080fd5b5061025d611161565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc161071881611244565b6000610728898989898989610ade565b90506107348184611251565b6000817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a604051610770969594939291906122a6565b60405180910390a3505050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107d957506107d98261139e565b92915050565b600080527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661085c5761085c8133611435565b600061086c888888888888610ade565b905061087881856114ed565b6108848888888861162a565b6000817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a6040516108bc94939291906122f1565b60405180910390a36108cd8161172e565b5050505050505050565b6000818152600160205260408120546001811180156108f65750428111155b9392505050565b60008281526020819052604090206001015461091881611244565b61092283836117d7565b505050565b60008181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109f482826118c7565b5050565b6000818152600160208190526040822054610939565b333014610a9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109e1565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b6000868686868686604051602001610afb969594939291906122a6565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b4781611244565b888714610bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b888514610c65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b6000610c778b8b8b8b8b8b8b8b610d4f565b9050610c838184611251565b60005b8a811015610d415780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610cc357610cc3612331565b9050602002016020810190610cd89190612360565b8d8d86818110610cea57610cea612331565b905060200201358c8c87818110610d0357610d03612331565b9050602002810190610d15919061237b565b8c8b604051610d29969594939291906122a6565b60405180910390a3610d3a8161240f565b9050610c86565b505050505050505050505050565b60008888888888888888604051602001610d709897969594939291906124f7565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610dbe81611244565b610dc7826109f8565b610e53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109e1565b6000828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b600082815260208190526040902060010154610eaa81611244565b61092283836118c7565b600080527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610f3157610f318133611435565b878614610fc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b87841461104f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109e1565b60006110618a8a8a8a8a8a8a8a610d4f565b905061106d81856114ed565b60005b8981101561114b5760008b8b8381811061108c5761108c612331565b90506020020160208101906110a19190612360565b905060008a8a848181106110b7576110b7612331565b9050602002013590503660008a8a868181106110d5576110d5612331565b90506020028101906110e7919061237b565b915091506110f78484848461162a565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588686868660405161112e94939291906122f1565b60405180910390a350505050806111449061240f565b9050611070565b506111558161172e565b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161580159061123257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa15801561120e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123291906125be565b1561123d5750600090565b5060025490565b61124e8133611435565b50565b61125a82610927565b156112e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109e1565b6112ef611161565b81101561137e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109e1565b61138881426125e0565b6000928352600160205260409092209190915550565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107d957507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107d9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109f4576114738161197e565b61147e83602061199d565b60405160200161148f929190612617565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109e191600401612698565b6114f6826108d7565b611582576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109e1565b80158061159e5750600081815260016020819052604090912054145b6109f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109e1565b60008473ffffffffffffffffffffffffffffffffffffffff168484846040516116549291906126e9565b60006040518083038185875af1925050503d8060008114611691576040519150601f19603f3d011682016040523d82523d6000602084013e611696565b606091505b5050905080611727576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109e1565b5050505050565b611737816108d7565b6117c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109e1565b600090815260016020819052604090912055565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109f45760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556118693390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109f45760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107d973ffffffffffffffffffffffffffffffffffffffff831660145b606060006119ac8360026126f9565b6119b79060026125e0565b67ffffffffffffffff8111156119cf576119cf611d8e565b6040519080825280601f01601f1916602001820160405280156119f9576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611a3057611a30612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a9357611a93612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000611acf8460026126f9565b611ada9060016125e0565b90505b6001811115611b77577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611b1b57611b1b612331565b1a60f81b828281518110611b3157611b31612331565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93611b7081612710565b9050611add565b5083156108f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109e1565b803573ffffffffffffffffffffffffffffffffffffffff81168114611c0457600080fd5b919050565b60008083601f840112611c1b57600080fd5b50813567ffffffffffffffff811115611c3357600080fd5b602083019150836020828501011115611c4b57600080fd5b9250929050565b600080600080600080600060c0888a031215611c6d57600080fd5b611c7688611be0565b965060208801359550604088013567ffffffffffffffff811115611c9957600080fd5b611ca58a828b01611c09565b989b979a50986060810135976080820135975060a09091013595509350505050565b600060208284031215611cd957600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108f657600080fd5b60008060008060008060a08789031215611d2257600080fd5b611d2b87611be0565b955060208701359450604087013567ffffffffffffffff811115611d4e57600080fd5b611d5a89828a01611c09565b979a9699509760608101359660809091013595509350505050565b600060208284031215611d8757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611e0457611e04611d8e565b604052919050565b600082601f830112611e1d57600080fd5b813567ffffffffffffffff811115611e3757611e37611d8e565b611e6860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611dbd565b818152846020838601011115611e7d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611eb057600080fd5b611eb985611be0565b9350611ec760208601611be0565b925060408501359150606085013567ffffffffffffffff811115611eea57600080fd5b611ef687828801611e0c565b91505092959194509250565b60008060408385031215611f1557600080fd5b82359150611f2560208401611be0565b90509250929050565b60008083601f840112611f4057600080fd5b50813567ffffffffffffffff811115611f5857600080fd5b6020830191508360208260051b8501011115611c4b57600080fd5b600080600080600080600080600060c08a8c031215611f9157600080fd5b893567ffffffffffffffff80821115611fa957600080fd5b611fb58d838e01611f2e565b909b50995060208c0135915080821115611fce57600080fd5b611fda8d838e01611f2e565b909950975060408c0135915080821115611ff357600080fd5b506120008c828d01611f2e565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b60008060008060008060008060a0898b03121561204157600080fd5b883567ffffffffffffffff8082111561205957600080fd5b6120658c838d01611f2e565b909a50985060208b013591508082111561207e57600080fd5b61208a8c838d01611f2e565b909850965060408b01359150808211156120a357600080fd5b506120b08b828c01611f2e565b999c989b509699959896976060870135966080013595509350505050565b600082601f8301126120df57600080fd5b8135602067ffffffffffffffff8211156120fb576120fb611d8e565b8160051b61210a828201611dbd565b928352848101820192828101908785111561212457600080fd5b83870192505b848310156121435782358252918301919083019061212a565b979650505050505050565b600080600080600060a0868803121561216657600080fd5b61216f86611be0565b945061217d60208701611be0565b9350604086013567ffffffffffffffff8082111561219a57600080fd5b6121a689838a016120ce565b945060608801359150808211156121bc57600080fd5b6121c889838a016120ce565b935060808801359150808211156121de57600080fd5b506121eb88828901611e0c565b9150509295509295909350565b600080600080600060a0868803121561221057600080fd5b61221986611be0565b945061222760208701611be0565b93506040860135925060608601359150608086013567ffffffffffffffff81111561225157600080fd5b6121eb88828901611e0c565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a0604082015260006122dc60a08301868861225d565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015260606040820152600061232760608301848661225d565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561237257600080fd5b6108f682611be0565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126123b057600080fd5b83018035915067ffffffffffffffff8211156123cb57600080fd5b602001915036819003821315611c4b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612440576124406123e0565b5060010190565b81835260006020808501808196508560051b810191508460005b878110156124ea57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126124a057600080fd5b8701858101903567ffffffffffffffff8111156124bc57600080fd5b8036038213156124cb57600080fd5b6124d686828461225d565b9a87019a9550505090840190600101612461565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156125455773ffffffffffffffffffffffffffffffffffffffff61253084611be0565b1682526020928301929091019060010161250a565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89111561257e57600080fd5b8860051b9150818a602083013701828103602090810160408501526125a69082018789612447565b60608401959095525050608001529695505050505050565b6000602082840312156125d057600080fd5b815180151581146108f657600080fd5b808201808211156107d9576107d96123e0565b60005b8381101561260e5781810151838201526020016125f6565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161264f8160178501602088016125f3565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161268c8160288401602088016125f3565b01602801949350505050565b60208152600082518060208401526126b78160408501602087016125f3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b8183823760009101908152919050565b80820281158282048414176107d9576107d96123e0565b60008161271f5761271f6123e0565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220d4ff1a49185b3c2eaf58aefd333a2a50a107fd10a8faba8e2063893453ad0e1c64736f6c63430008140033",
-		    "storage": {
-			    "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000e10",
-			    "0xd52c425d569449de3ea8e96b6f4f0056c8b90231a08ce274f929eac5ca5b70c5": "0x0000000000000000000000000000000000000000000000000000000000000001",
-			    "0xc9d8eca0788029234fc9f7531913a7be3fed1b0438d68195b63e370bf6ac88b7": "0x0000000000000000000000000000000000000000000000000000000000000001",
-			    "0x64494413541ff93b31aa309254e3fed72a7456e9845988b915b4c7a7ceba8814": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5",
-			    "0x0dbd82eed89d73822865d402eb9d73d4609cb01c0aa3d785a17d7a9d0cb5ee06": "0x0000000000000000000000000000000000000000000000000000000000000001",
-			    "0x3412d5605ac6cd444957cedb533e5dacad6378b4bc819ebe3652188a665066d6": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5",
-			    "0x9d38bd476745c975feef1b204358c9d3e7719e09369f43fb65a1097848fb43d1": "0x0000000000000000000000000000000000000000000000000000000000000001",
-			    "0xdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d706a": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5",
-			    "0x89eab0dbc58be726d54f3116480f80e75a19870aa9750471514a47a86f365aef": "0x0000000000000000000000000000000000000000000000000000000000000001",
-			    "0xc3ad33e20b0c56a223ad5104fff154aa010f8715b9c981fd38fdc60a4d1a52fc": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5"
-		    }
-	    },
-	    {
-		    "accountName": "keyless Deployer",
-		    "balance": "0",
-		    "nonce": "1",
-		    "address": "0xc0124DeE8494E155eFf900100D2AF4CC0BC9a76e"
-	    },
-	    {
-		    "accountName": "deployer",
-		    "balance": "100000000000000000000000",
-		    "nonce": "8",
-		    "address": "0x2ECF31eCe36ccaC2d3222A303b1409233ECBB225"
-	    }
-    ]
+    "genesisBlockNumber": 368,
+	"rollupCreationBlockNumber": 374,
+	"rollupManagerCreationBlockNumber": 368,
+	"root": "0xc48ca035cf2fe444dbedf708ec5ee7e7d1f1fffaccaac6a206f1e14fb488e7c0",
+	"genesis": [
+		{
+			"contractName": "PolygonZkEVMDeployer",
+			"balance": "0",
+			"nonce": "4",
+			"address": "0x18c279c3Ed0b54b9f9D815cD12bee2d2d68a4B42",
+			"bytecode": "0x60806040526004361061006e575f3560e01c8063715018a61161004c578063715018a6146100e25780638da5cb5b146100f6578063e11ae6cb1461011f578063f2fde38b14610132575f80fd5b80632b79805a146100725780634a94d487146100875780636d07dbf81461009a575b5f80fd5b610085610080366004610908565b610151565b005b6100856100953660046109a2565b6101c2565b3480156100a5575f80fd5b506100b96100b43660046109f5565b610203565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ed575f80fd5b50610085610215565b348015610101575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166100b9565b61008561012d366004610a15565b610228565b34801561013d575f80fd5b5061008561014c366004610a61565b61028e565b61015961034a565b5f6101658585856103ca565b90506101718183610527565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a15050505050565b6101ca61034a565b6101d583838361056a565b506040517f25adb19089b6a549831a273acdf7908cff8b7ee5f551f8d1d37996cf01c5df5b905f90a1505050565b5f61020e8383610598565b9392505050565b61021d61034a565b6102265f6105a4565b565b61023061034a565b5f61023c8484846103ca565b60405173ffffffffffffffffffffffffffffffffffffffff821681529091507fba82f25fed02cd2a23d9f5d11c2ef588d22af5437cbf23bfe61d87257c480e4c9060200160405180910390a150505050565b61029661034a565b73ffffffffffffffffffffffffffffffffffffffff811661033e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610347816105a4565b50565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610226576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610335565b5f83471015610435576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610335565b81515f0361049f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610335565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff811661020e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610335565b606061020e83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250610618565b6060610590848484604051806060016040528060298152602001610b0860299139610618565b949350505050565b5f61020e83833061072d565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060824710156106aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610335565b5f808673ffffffffffffffffffffffffffffffffffffffff1685876040516106d29190610a9c565b5f6040518083038185875af1925050503d805f811461070c576040519150601f19603f3d011682016040523d82523d5f602084013e610711565b606091505b509150915061072287838387610756565b979650505050505050565b5f604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b606083156107eb5782515f036107e45773ffffffffffffffffffffffffffffffffffffffff85163b6107e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610335565b5081610590565b61059083838151156108005781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103359190610ab7565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112610870575f80fd5b813567ffffffffffffffff8082111561088b5761088b610834565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156108d1576108d1610834565b816040528381528660208588010111156108e9575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f805f806080858703121561091b575f80fd5b8435935060208501359250604085013567ffffffffffffffff80821115610940575f80fd5b61094c88838901610861565b93506060870135915080821115610961575f80fd5b5061096e87828801610861565b91505092959194509250565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099d575f80fd5b919050565b5f805f606084860312156109b4575f80fd5b6109bd8461097a565b9250602084013567ffffffffffffffff8111156109d8575f80fd5b6109e486828701610861565b925050604084013590509250925092565b5f8060408385031215610a06575f80fd5b50508035926020909101359150565b5f805f60608486031215610a27575f80fd5b8335925060208401359150604084013567ffffffffffffffff811115610a4b575f80fd5b610a5786828701610861565b9150509250925092565b5f60208284031215610a71575f80fd5b61020e8261097a565b5f5b83811015610a94578181015183820152602001610a7c565b50505f910152565b5f8251610aad818460208701610a7a565b9190910192915050565b602081525f8251806020840152610ad5816040850160208701610a7a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564a2646970667358221220330b94dc698c4d290bf55c23f13b473cde6a6bae0030cb902de18af54e35839f64736f6c63430008140033",
+			"storage": {
+				"0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000008f8e2d6cf621f30e9a11309d6a56a876281fd534"
+			}
+		},
+		{
+			"contractName": "ProxyAdmin",
+			"balance": "0",
+			"nonce": "1",
+			"address": "0x8558c487E08473154eD6E48953Fc4c4D72757220",
+			"bytecode": "0x608060405260043610610079575f3560e01c80639623609d1161004c5780639623609d1461012357806399a88ec414610136578063f2fde38b14610155578063f3b7dead14610174575f80fd5b8063204e1c7a1461007d578063715018a6146100c55780637eff275e146100db5780638da5cb5b146100fa575b5f80fd5b348015610088575f80fd5b5061009c6100973660046105e8565b610193565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d0575f80fd5b506100d9610244565b005b3480156100e6575f80fd5b506100d96100f536600461060a565b610257565b348015610105575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff1661009c565b6100d961013136600461066e565b6102e0565b348015610141575f80fd5b506100d961015036600461060a565b610371565b348015610160575f80fd5b506100d961016f3660046105e8565b6103cd565b34801561017f575f80fd5b5061009c61018e3660046105e8565b610489565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b5f60405180830381855afa9150503d805f8114610215576040519150601f19603f3d011682016040523d82523d5f602084013e61021a565b606091505b509150915081610228575f80fd5b8080602001905181019061023c919061075b565b949350505050565b61024c6104d3565b6102555f610553565b565b61025f6104d3565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b5f604051808303815f87803b1580156102c6575f80fd5b505af11580156102d8573d5f803e3d5ffd5b505050505050565b6102e86104d3565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef28690349061033e9086908690600401610776565b5f604051808303818588803b158015610355575f80fd5b505af1158015610367573d5f803e3d5ffd5b5050505050505050565b6103796104d3565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102af565b6103d56104d3565b73ffffffffffffffffffffffffffffffffffffffff811661047d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61048681610553565b50565b5f805f8373ffffffffffffffffffffffffffffffffffffffff166040516101dd907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610255576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610474565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81168114610486575f80fd5b5f602082840312156105f8575f80fd5b8135610603816105c7565b9392505050565b5f806040838503121561061b575f80fd5b8235610626816105c7565b91506020830135610636816105c7565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f805f60608486031215610680575f80fd5b833561068b816105c7565b9250602084013561069b816105c7565b9150604084013567ffffffffffffffff808211156106b7575f80fd5b818601915086601f8301126106ca575f80fd5b8135818111156106dc576106dc610641565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561072257610722610641565b8160405282815289602084870101111561073a575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f6020828403121561076b575f80fd5b8151610603816105c7565b73ffffffffffffffffffffffffffffffffffffffff831681525f602060408184015283518060408501525f5b818110156107be578581018301518582016060015282016107a2565b505f6060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010192505050939250505056fea26469706673582212203083a4ccc2e42eed60bd19037f2efa77ed086dc7a5403f75bebb995dcba2221c64736f6c63430008140033",
+			"storage": {
+				"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000027284dba79e6df953fbd232a9d8d87029f03bbf5"
+			}
+		},
+		{
+			"contractName": "PolygonZkEVMBridge implementation",
+			"balance": "0",
+			"nonce": "1",
+			"address": "0x0E64359621Ff57496fbc0E5A5f9bdf27bDDA370a",
+			"bytecode": "0x6080604052600436106101db575f3560e01c806383f24403116100fd578063ccaa2d1111610092578063ee25560b11610062578063ee25560b146105a9578063f5efcd79146105d4578063f811bff7146105f3578063fb57083414610612575f80fd5b8063ccaa2d111461053b578063cd5865791461055a578063d02103ca1461056d578063dbc1697614610595575f80fd5b8063bab161bf116100cd578063bab161bf146104b9578063be5831c7146104da578063c00f14ab146104fd578063cc4616321461051c575f80fd5b806383f244031461043d5780638ed7e3f21461045c578063aaa13cc21461047b578063b8b284d01461049a575f80fd5b80633cbc795b116101735780637843298b116101435780637843298b146103c257806379e2cf97146103e157806381b1c174146103f557806383c43a5514610429575f80fd5b80633cbc795b146103385780633e197043146103705780634b2f336d1461038f5780635ca1e165146103ae575f80fd5b806327aef4e8116101ae57806327aef4e81461026d5780632dfdf0b51461028e578063318aee3d146102b15780633c351e1014610319575f80fd5b806315064c96146101df5780632072f6c51461020d57806322e95f2c14610223578063240ff3781461025a575b5f80fd5b3480156101ea575f80fd5b506068546101f89060ff1681565b60405190151581526020015b60405180910390f35b348015610218575f80fd5b50610221610631565b005b34801561022e575f80fd5b5061024261023d366004612fb9565b610666565b6040516001600160a01b039091168152602001610204565b610221610268366004613040565b6106d0565b348015610278575f80fd5b50610281610759565b6040516102049190613102565b348015610299575f80fd5b506102a360535481565b604051908152602001610204565b3480156102bc575f80fd5b506102f56102cb36600461311b565b606b6020525f908152604090205463ffffffff81169064010000000090046001600160a01b031682565b6040805163ffffffff90931683526001600160a01b03909116602083015201610204565b348015610324575f80fd5b50606d54610242906001600160a01b031681565b348015610343575f80fd5b50606d5461035b90600160a01b900463ffffffff1681565b60405163ffffffff9091168152602001610204565b34801561037b575f80fd5b506102a361038a366004613144565b6107e5565b34801561039a575f80fd5b50606f54610242906001600160a01b031681565b3480156103b9575f80fd5b506102a361088e565b3480156103cd575f80fd5b506102426103dc3660046131be565b61096a565b3480156103ec575f80fd5b50610221610993565b348015610400575f80fd5b5061024261040f366004613204565b606a6020525f90815260409020546001600160a01b031681565b348015610434575f80fd5b506102816109b4565b348015610448575f80fd5b506102a361045736600461322c565b6109d3565b348015610467575f80fd5b50606c54610242906001600160a01b031681565b348015610486575f80fd5b5061024261049536600461332d565b610aa8565b3480156104a5575f80fd5b506102216104b43660046133c3565b610be7565b3480156104c4575f80fd5b5060685461035b90610100900463ffffffff1681565b3480156104e5575f80fd5b5060685461035b90600160c81b900463ffffffff1681565b348015610508575f80fd5b5061028161051736600461311b565b610cc2565b348015610527575f80fd5b506101f8610536366004613441565b610d07565b348015610546575f80fd5b50610221610555366004613472565b610d8f565b610221610568366004613556565b6112c0565b348015610578575f80fd5b50606854610242906501000000000090046001600160a01b031681565b3480156105a0575f80fd5b5061022161172c565b3480156105b4575f80fd5b506102a36105c3366004613204565b60696020525f908152604090205481565b3480156105df575f80fd5b506102216105ee366004613472565b61175f565b3480156105fe575f80fd5b5061022161060d3660046135e6565b611a25565b34801561061d575f80fd5b506101f861062c366004613689565b611d40565b606c546001600160a01b0316331461065c57604051631736745960e31b815260040160405180910390fd5b610664611d57565b565b6040805160e084901b6001600160e01b031916602080830191909152606084901b6bffffffffffffffffffffffff1916602483015282516018818403018152603890920183528151918101919091205f908152606a90915220546001600160a01b03165b92915050565b60685460ff16156106f457604051630bc011ff60e21b815260040160405180910390fd5b341580159061070d5750606f546001600160a01b031615155b15610744576040517f6f625c4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610752858534868686611db2565b5050505050565b606e8054610766906136ce565b80601f0160208091040260200160405190810160405280929190818152602001828054610792906136ce565b80156107dd5780601f106107b4576101008083540402835291602001916107dd565b820191905f5260205f20905b8154815290600101906020018083116107c057829003601f168201915b505050505081565b6040517fff0000000000000000000000000000000000000000000000000000000000000060f889901b1660208201526001600160e01b031960e088811b821660218401526bffffffffffffffffffffffff19606089811b821660258601529188901b909216603984015285901b16603d82015260518101839052607181018290525f90609101604051602081830303815290604052805190602001209050979650505050505050565b6053545f90819081805b6020811015610961578083901c6001166001036108f557603381602081106108c2576108c2613706565b01546040805160208101929092528101859052606001604051602081830303815290604052805190602001209350610922565b60408051602081018690529081018390526060016040516020818303038152906040528051906020012093505b604080516020810184905290810183905260600160405160208183030381529060405280519060200120915080806109599061372e565b915050610898565b50919392505050565b5f61098b848461097985611e7c565b61098286611f66565b61049587612047565b949350505050565b605354606854600160c81b900463ffffffff16101561066457610664612114565b60405180611ba00160405280611b668152602001613d80611b66913981565b5f83815b6020811015610a9f57600163ffffffff8516821c81169003610a4257848160208110610a0557610a05613706565b602002013582604051602001610a25929190918252602082015260400190565b604051602081830303815290604052805190602001209150610a8d565b81858260208110610a5557610a55613706565b6020020135604051602001610a74929190918252602082015260400190565b6040516020818303038152906040528051906020012091505b80610a978161372e565b9150506109d7565b50949350505050565b6040516001600160e01b031960e087901b1660208201526bffffffffffffffffffffffff19606086901b1660248201525f9081906038016040516020818303038152906040528051906020012090505f60ff60f81b308360405180611ba00160405280611b668152602001613d80611b669139898989604051602001610b3093929190613746565b60408051601f1981840301815290829052610b4e929160200161377e565b60405160208183030381529060405280519060200120604051602001610bc394939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b60408051808303601f19018152919052805160209091012098975050505050505050565b60685460ff1615610c0b57604051630bc011ff60e21b815260040160405180910390fd5b606f546001600160a01b0316610c4d576040517fdde3cda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f54604051632770a7eb60e21b8152336004820152602481018690526001600160a01b0390911690639dc29fac906044015f604051808303815f87803b158015610c96575f80fd5b505af1158015610ca8573d5f803e3d5ffd5b50505050610cba868686868686611db2565b505050505050565b6060610ccd82611e7c565b610cd683611f66565b610cdf84612047565b604051602001610cf193929190613746565b6040516020818303038152906040529050919050565b6068545f908190610100900463ffffffff16158015610d2c575063ffffffff83166001145b15610d3e575063ffffffff8316610d66565b610d5364010000000063ffffffff85166137ac565b610d639063ffffffff86166137c3565b90505b600881901c5f90815260696020526040902054600160ff9092169190911b908116149392505050565b60685460ff1615610db357604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff8681166101009092041614610de3576040516302caf51760e11b815260040160405180910390fd5b610e168c8c8c8c8c610e115f8e8e8e8e8e8e8e604051610e049291906137d6565b60405180910390206107e5565b6121c2565b6001600160a01b038616610f6057606f546001600160a01b0316610efa575f6001600160a01b03851684825b6040519080825280601f01601f191660200182016040528015610e6c576020820181803683370190505b50604051610e7a91906137e5565b5f6040518083038185875af1925050503d805f8114610eb4576040519150601f19603f3d011682016040523d82523d5f602084013e610eb9565b606091505b5050905080610ef4576040517f6747a28800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50611256565b606f546040516340c10f1960e01b81526001600160a01b03868116600483015260248201869052909116906340c10f19906044015f604051808303815f87803b158015610f45575f80fd5b505af1158015610f57573d5f803e3d5ffd5b50505050611256565b606d546001600160a01b038781169116148015610f8e5750606d5463ffffffff888116600160a01b90920416145b15610fa5575f6001600160a01b0385168482610e42565b60685463ffffffff610100909104811690881603610fd657610fd16001600160a01b0387168585612354565b611256565b6040516001600160e01b031960e089901b1660208201526bffffffffffffffffffffffff19606088901b1660248201525f9060380160408051601f1981840301815291815281516020928301205f818152606a9093529120549091506001600160a01b0316806111f5575f6110808386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506123d592505050565b6040516340c10f1960e01b81526001600160a01b03898116600483015260248201899052919250908216906340c10f19906044015f604051808303815f87803b1580156110cb575f80fd5b505af11580156110dd573d5f803e3d5ffd5b5050505080606a5f8581526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060405180604001604052808b63ffffffff1681526020018a6001600160a01b0316815250606b5f836001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548163ffffffff021916908363ffffffff1602179055506020820151815f0160046101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507f490e59a1701b938786ac72570a1efeac994a3dbe96e2e883e19e902ace6e6a398a8a8388886040516111e7959493929190613828565b60405180910390a150611253565b6040516340c10f1960e01b81526001600160a01b038781166004830152602482018790528216906340c10f19906044015f604051808303815f87803b15801561123c575f80fd5b505af115801561124e573d5f803e3d5ffd5b505050505b50505b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b60685460ff16156112e457604051630bc011ff60e21b815260040160405180910390fd5b6112ec612468565b60685463ffffffff61010090910481169088160361131d576040516302caf51760e11b815260040160405180910390fd5b5f806060876001600160a01b03881661141957883414611369576040517fb89240f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606d54606e80546001600160a01b0383169650600160a01b90920463ffffffff16945090611396906136ce565b80601f01602080910402602001604051908101604052809291908181526020018280546113c2906136ce565b801561140d5780601f106113e45761010080835404028352916020019161140d565b820191905f5260205f20905b8154815290600101906020018083116113f057829003601f168201915b505050505091506116a3565b3415611451576040517f798ee6f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606f546001600160a01b03908116908916036114c757604051632770a7eb60e21b8152336004820152602481018a90526001600160a01b03891690639dc29fac906044015f604051808303815f87803b1580156114ac575f80fd5b505af11580156114be573d5f803e3d5ffd5b505050506116a3565b6001600160a01b038089165f908152606b602090815260409182902082518084019093525463ffffffff811683526401000000009004909216918101829052901561157957604051632770a7eb60e21b8152336004820152602481018b90526001600160a01b038a1690639dc29fac906044015f604051808303815f87803b158015611551575f80fd5b505af1158015611563573d5f803e3d5ffd5b5050505080602001519450805f01519350611696565b851561158b5761158b898b89896124c1565b6040516370a0823160e01b81523060048201525f906001600160a01b038b16906370a0823190602401602060405180830381865afa1580156115cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f39190613860565b905061160a6001600160a01b038b1633308e612860565b6040516370a0823160e01b81523060048201525f906001600160a01b038c16906370a0823190602401602060405180830381865afa15801561164e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116729190613860565b905061167e8282613877565b6068548c9850610100900463ffffffff169650935050505b61169f89610cc2565b9250505b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b5f84868e8e86886053546040516116e298979695949392919061388a565b60405180910390a16117086117035f85878f8f8789805190602001206107e5565b6128b1565b861561171657611716612114565b5050505061172360018055565b50505050505050565b606c546001600160a01b0316331461175757604051631736745960e31b815260040160405180910390fd5b6106646129b2565b60685460ff161561178357604051630bc011ff60e21b815260040160405180910390fd5b60685463ffffffff86811661010090920416146117b3576040516302caf51760e11b815260040160405180910390fd5b6117d58c8c8c8c8c610e1160018e8e8e8e8e8e8e604051610e049291906137d6565b606f545f906001600160a01b031661188857846001600160a01b031684888a868660405160240161180994939291906138f3565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161183e91906137e5565b5f6040518083038185875af1925050503d805f8114611878576040519150601f19603f3d011682016040523d82523d5f602084013e61187d565b606091505b505080915050611983565b606f546040516340c10f1960e01b81526001600160a01b03878116600483015260248201879052909116906340c10f19906044015f604051808303815f87803b1580156118d3575f80fd5b505af11580156118e5573d5f803e3d5ffd5b50505050846001600160a01b03168789858560405160240161190a94939291906138f3565b60408051601f198184030181529181526020820180516001600160e01b0316630c035af960e11b1790525161193f91906137e5565b5f604051808303815f865af19150503d805f8114611978576040519150601f19603f3d011682016040523d82523d5f602084013e61197d565b606091505b50909150505b806119ba576040517f37e391c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518c815263ffffffff8a1660208201526001600160a01b0389811682840152871660608201526080810186905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a150505050505050505050505050565b5f54610100900460ff1615808015611a4357505f54600160ff909116105b80611a5c5750303b158015611a5c57505f5460ff166001145b611ad35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f805460ff191660011790558015611af4575f805461ff0019166101001790555b606880547fffffffffffffff000000000000000000000000000000000000000000000000ff1661010063ffffffff8a16027fffffffffffffff0000000000000000000000000000000000000000ffffffffff1617650100000000006001600160a01b038781169190910291909117909155606c805473ffffffffffffffffffffffffffffffffffffffff19168583161790558616611bcf5763ffffffff851615611bca576040517f1a874c1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ceb565b606d805463ffffffff8716600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009091166001600160a01b03891617179055606e611c1e8382613970565b50611cbd5f801b6012604051602001611ca991906060808252600d908201527f5772617070656420457468657200000000000000000000000000000000000000608082015260a0602082018190526004908201527f574554480000000000000000000000000000000000000000000000000000000060c082015260ff91909116604082015260e00190565b6040516020818303038152906040526123d5565b606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790555b611cf3612a22565b8015611723575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b5f81611d4d8686866109d3565b1495945050505050565b60685460ff1615611d7b57604051630bc011ff60e21b815260040160405180910390fd5b6068805460ff191660011790556040517f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a5497905f90a1565b60685463ffffffff610100909104811690871603611de3576040516302caf51760e11b815260040160405180910390fd5b7f501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b6001606860019054906101000a900463ffffffff16338989898888605354604051611e3799989796959493929190613a2c565b60405180910390a1611e6e6117036001606860019054906101000a900463ffffffff16338a8a8a8989604051610e049291906137d6565b8215610cba57610cba612114565b60408051600481526024810182526020810180516001600160e01b03167f06fdde030000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611edb91906137e5565b5f60405180830381855afa9150503d805f8114611f13576040519150601f19603f3d011682016040523d82523d5f602084013e611f18565b606091505b509150915081611f5d576040518060400160405280600781526020017f4e4f5f4e414d450000000000000000000000000000000000000000000000000081525061098b565b61098b81612a94565b60408051600481526024810182526020810180516001600160e01b03167f95d89b410000000000000000000000000000000000000000000000000000000017905290516060915f9182916001600160a01b03861691611fc591906137e5565b5f60405180830381855afa9150503d805f8114611ffd576040519150601f19603f3d011682016040523d82523d5f602084013e612002565b606091505b509150915081611f5d576040518060400160405280600981526020017f4e4f5f53594d424f4c000000000000000000000000000000000000000000000081525061098b565b60408051600481526024810182526020810180516001600160e01b03167f313ce5670000000000000000000000000000000000000000000000000000000017905290515f91829182916001600160a01b038616916120a591906137e5565b5f60405180830381855afa9150503d805f81146120dd576040519150601f19603f3d011682016040523d82523d5f602084013e6120e2565b606091505b50915091508180156120f5575080516020145b61210057601261098b565b8080602001905181019061098b9190613a97565b6053546068805463ffffffff909216600160c81b027fffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117908190556001600160a01b0365010000000000909104166333d6247d61217561088e565b6040518263ffffffff1660e01b815260040161219391815260200190565b5f604051808303815f87803b1580156121aa575f80fd5b505af11580156121bc573d5f803e3d5ffd5b50505050565b606854604080516020808201879052818301869052825180830384018152606083019384905280519101207f257b36320000000000000000000000000000000000000000000000000000000090925260648101919091525f916501000000000090046001600160a01b03169063257b3632906084016020604051808303815f875af1158015612253573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122779190613860565b9050805f036122b1576040517e2f6fad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80680100000000000000008716156122f5578691506122d3848a8489611d40565b6122f0576040516338105f3b60e21b815260040160405180910390fd5b61233f565b602087901c612305816001613ab2565b9150879250612320612318868c866109d3565b8a8389611d40565b61233d576040516338105f3b60e21b815260040160405180910390fd5b505b6123498282612c64565b505050505050505050565b6040516001600160a01b0383166024820152604481018290526123d09084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612d24565b505050565b5f8060405180611ba00160405280611b668152602001613d80611b6691398360405160200161240592919061377e565b6040516020818303038152906040529050838151602083015ff591506001600160a01b038216612461576040517fbefb092000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092915050565b6002600154036124ba5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611aca565b6002600155565b5f6124cf6004828486613acf565b6124d891613af6565b90507f2afa5331000000000000000000000000000000000000000000000000000000006001600160e01b03198216016126b2575f80808080808061251f896004818d613acf565b81019061252c9190613b26565b9650965096509650965096509650336001600160a01b0316876001600160a01b03161461256c5760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03861630146125955760405163750643af60e01b815260040160405180910390fd5b8a85146125ce576040517f03fffc4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b0389811660248301528881166044830152606482018890526084820187905260ff861660a483015260c4820185905260e48083018590528351808403909101815261010490920183526020820180516001600160e01b03167fd505accf000000000000000000000000000000000000000000000000000000001790529151918e169161266591906137e5565b5f604051808303815f865af19150503d805f811461269e576040519150601f19603f3d011682016040523d82523d5f602084013e6126a3565b606091505b50505050505050505050610752565b6001600160e01b031981166323f2ebc360e21b146126fc576040517fe282c0ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f808080808080806127118a6004818e613acf565b81019061271e9190613b75565b97509750975097509750975097509750336001600160a01b0316886001600160a01b0316146127605760405163912ecce760e01b815260040160405180910390fd5b6001600160a01b03871630146127895760405163750643af60e01b815260040160405180910390fd5b604080516001600160a01b038a811660248301528981166044830152606482018990526084820188905286151560a483015260ff861660c483015260e482018590526101048083018590528351808403909101815261012490920183526020820180516001600160e01b03166323f2ebc360e21b1790529151918f169161281091906137e5565b5f604051808303815f865af19150503d805f8114612849576040519150601f19603f3d011682016040523d82523d5f602084013e61284e565b606091505b50505050505050505050505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526121bc9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612399565b8060016128c060206002613cd3565b6128ca9190613877565b60535410612904576040517fef5ccf6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60535f81546129139061372e565b918290555090505f5b60208110156129a3578082901c60011660010361294f57826033826020811061294757612947613706565b015550505050565b6033816020811061296257612962613706565b01546040805160208101929092528101849052606001604051602081830303815290604052805190602001209250808061299b9061372e565b91505061291c565b506123d0613cde565b60018055565b60685460ff166129ee576040517f5386698100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6068805460ff191690556040517f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b3905f90a1565b5f54610100900460ff16612a8c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611aca565b610664612e08565b60606040825110612ab357818060200190518101906106ca9190613cf2565b8151602003612c26575f5b602081108015612b055750828181518110612adb57612adb613706565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612b1c5780612b148161372e565b915050612abe565b805f03612b5e57505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e4700000000000000000000000000006020820152919050565b5f8167ffffffffffffffff811115612b7857612b78613268565b6040519080825280601f01601f191660200182016040528015612ba2576020820181803683370190505b5090505f5b82811015612c1e57848181518110612bc157612bc1613706565b602001015160f81c60f81b828281518110612bde57612bde613706565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535080612c168161372e565b915050612ba7565b509392505050565b505060408051808201909152601281527f4e4f545f56414c49445f454e434f44494e470000000000000000000000000000602082015290565b919050565b6068545f90610100900463ffffffff16158015612c87575063ffffffff82166001145b15612c99575063ffffffff8216612cc1565b612cae64010000000063ffffffff84166137ac565b612cbe9063ffffffff85166137c3565b90505b600881901c5f8181526069602052604081208054600160ff861690811b91821892839055929091908183169003611723576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f612d78826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612e729092919063ffffffff16565b8051909150156123d05780806020019051810190612d969190613d64565b6123d05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611aca565b5f54610100900460ff166129ac5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611aca565b606061098b84845f85855f80866001600160a01b03168587604051612e9791906137e5565b5f6040518083038185875af1925050503d805f8114612ed1576040519150601f19603f3d011682016040523d82523d5f602084013e612ed6565b606091505b5091509150612ee787838387612ef2565b979650505050505050565b60608315612f605782515f03612f59576001600160a01b0385163b612f595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611aca565b508161098b565b61098b8383815115612f755781518083602001fd5b8060405162461bcd60e51b8152600401611aca9190613102565b803563ffffffff81168114612c5f575f80fd5b6001600160a01b0381168114612fb6575f80fd5b50565b5f8060408385031215612fca575f80fd5b612fd383612f8f565b91506020830135612fe381612fa2565b809150509250929050565b8015158114612fb6575f80fd5b5f8083601f84011261300b575f80fd5b50813567ffffffffffffffff811115613022575f80fd5b602083019150836020828501011115613039575f80fd5b9250929050565b5f805f805f60808688031215613054575f80fd5b61305d86612f8f565b9450602086013561306d81612fa2565b9350604086013561307d81612fee565b9250606086013567ffffffffffffffff811115613098575f80fd5b6130a488828901612ffb565b969995985093965092949392505050565b5f5b838110156130cf5781810151838201526020016130b7565b50505f910152565b5f81518084526130ee8160208601602086016130b5565b601f01601f19169290920160200192915050565b602081525f61311460208301846130d7565b9392505050565b5f6020828403121561312b575f80fd5b813561311481612fa2565b60ff81168114612fb6575f80fd5b5f805f805f805f60e0888a03121561315a575f80fd5b873561316581613136565b965061317360208901612f8f565b9550604088013561318381612fa2565b945061319160608901612f8f565b935060808801356131a181612fa2565b9699959850939692959460a0840135945060c09093013592915050565b5f805f606084860312156131d0575f80fd5b6131d984612f8f565b925060208401356131e981612fa2565b915060408401356131f981612fa2565b809150509250925092565b5f60208284031215613214575f80fd5b5035919050565b8061040081018310156106ca575f80fd5b5f805f610440848603121561323f575f80fd5b83359250613250856020860161321b565b915061325f6104208501612f8f565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156132a5576132a5613268565b604052919050565b5f67ffffffffffffffff8211156132c6576132c6613268565b50601f01601f191660200190565b5f6132e66132e1846132ad565b61327c565b90508281528383830111156132f9575f80fd5b828260208301375f602084830101529392505050565b5f82601f83011261331e575f80fd5b613114838335602085016132d4565b5f805f805f60a08688031215613341575f80fd5b61334a86612f8f565b9450602086013561335a81612fa2565b9350604086013567ffffffffffffffff80821115613376575f80fd5b61338289838a0161330f565b94506060880135915080821115613397575f80fd5b506133a48882890161330f565b92505060808601356133b581613136565b809150509295509295909350565b5f805f805f8060a087890312156133d8575f80fd5b6133e187612f8f565b955060208701356133f181612fa2565b945060408701359350606087013561340881612fee565b9250608087013567ffffffffffffffff811115613423575f80fd5b61342f89828a01612ffb565b979a9699509497509295939492505050565b5f8060408385031215613452575f80fd5b61345b83612f8f565b915061346960208401612f8f565b90509250929050565b5f805f805f805f805f805f806109208d8f03121561348e575f80fd5b6134988e8e61321b565b9b506134a88e6104008f0161321b565b9a506108008d013599506108208d013598506108408d013597506134cf6108608e01612f8f565b96506134df6108808e0135612fa2565b6108808d013595506134f46108a08e01612f8f565b94506135046108c08e0135612fa2565b6108c08d013593506108e08d0135925067ffffffffffffffff6109008e0135111561352d575f80fd5b61353e8e6109008f01358f01612ffb565b81935080925050509295989b509295989b509295989b565b5f805f805f805f60c0888a03121561356c575f80fd5b61357588612f8f565b9650602088013561358581612fa2565b955060408801359450606088013561359c81612fa2565b935060808801356135ac81612fee565b925060a088013567ffffffffffffffff8111156135c7575f80fd5b6135d38a828b01612ffb565b989b979a50959850939692959293505050565b5f805f805f8060c087890312156135fb575f80fd5b61360487612f8f565b9550602087013561361481612fa2565b945061362260408801612f8f565b9350606087013561363281612fa2565b9250608087013561364281612fa2565b915060a087013567ffffffffffffffff81111561365d575f80fd5b8701601f8101891361366d575f80fd5b61367c898235602084016132d4565b9150509295509295509295565b5f805f80610460858703121561369d575f80fd5b843593506136ae866020870161321b565b92506136bd6104208601612f8f565b939692955092936104400135925050565b600181811c908216806136e257607f821691505b60208210810361370057634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161373f5761373f61371a565b5060010190565b606081525f61375860608301866130d7565b828103602084015261376a81866130d7565b91505060ff83166040830152949350505050565b5f835161378f8184602088016130b5565b8351908301906137a38183602088016130b5565b01949350505050565b80820281158282048414176106ca576106ca61371a565b808201808211156106ca576106ca61371a565b818382375f9101908152919050565b5f82516137f68184602087016130b5565b9190910192915050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b63ffffffff861681525f6001600160a01b03808716602084015280861660408401525060806060830152612ee7608083018486613800565b5f60208284031215613870575f80fd5b5051919050565b818103818111156106ca576106ca61371a565b5f61010060ff8b16835263ffffffff808b1660208501526001600160a01b03808b166040860152818a1660608601528089166080860152508660a08501528160c08501526138da828501876130d7565b925080851660e085015250509998505050505050505050565b6001600160a01b038516815263ffffffff84166020820152606060408201525f613921606083018486613800565b9695505050505050565b601f8211156123d0575f81815260208120601f850160051c810160208610156139515750805b601f850160051c820191505b81811015610cba5782815560010161395d565b815167ffffffffffffffff81111561398a5761398a613268565b61399e8161399884546136ce565b8461392b565b602080601f8311600181146139d1575f84156139ba5750858301515b5f19600386901b1c1916600185901b178555610cba565b5f85815260208120601f198616915b828110156139ff578886015182559484019460019091019084016139e0565b5085821015613a1c57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61010060ff8c16835263ffffffff808c1660208501526001600160a01b03808c166040860152818b166060860152808a166080860152508760a08501528160c0850152613a7d8285018789613800565b925080851660e085015250509a9950505050505050505050565b5f60208284031215613aa7575f80fd5b815161311481613136565b63ffffffff8181168382160190808211156124615761246161371a565b5f8085851115613add575f80fd5b83861115613ae9575f80fd5b5050820193919092039150565b6001600160e01b03198135818116916004851015613b1e5780818660040360031b1b83161692505b505092915050565b5f805f805f805f60e0888a031215613b3c575f80fd5b8735613b4781612fa2565b96506020880135613b5781612fa2565b9550604088013594506060880135935060808801356131a181613136565b5f805f805f805f80610100898b031215613b8d575f80fd5b8835613b9881612fa2565b97506020890135613ba881612fa2565b965060408901359550606089013594506080890135613bc681612fee565b935060a0890135613bd681613136565b979a969950949793969295929450505060c08201359160e0013590565b600181815b80851115613c2d57815f1904821115613c1357613c1361371a565b80851615613c2057918102915b93841c9390800290613bf8565b509250929050565b5f82613c43575060016106ca565b81613c4f57505f6106ca565b8160018114613c655760028114613c6f57613c8b565b60019150506106ca565b60ff841115613c8057613c8061371a565b50506001821b6106ca565b5060208310610133831016604e8410600b8410161715613cae575081810a6106ca565b613cb88383613bf3565b805f1904821115613ccb57613ccb61371a565b029392505050565b5f6131148383613c35565b634e487b7160e01b5f52600160045260245ffd5b5f60208284031215613d02575f80fd5b815167ffffffffffffffff811115613d18575f80fd5b8201601f81018413613d28575f80fd5b8051613d366132e1826132ad565b818152856020838501011115613d4a575f80fd5b613d5b8260208301602086016130b5565b95945050505050565b5f60208284031215613d74575f80fd5b815161311481612fee56fe6101006040523480156200001257600080fd5b5060405162001b6638038062001b6683398101604081905262000035916200028d565b82826003620000458382620003a1565b506004620000548282620003a1565b50503360c0525060ff811660e052466080819052620000739062000080565b60a052506200046d915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f620000ad6200012e565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b6060600380546200013f9062000312565b80601f01602080910402602001604051908101604052809291908181526020018280546200016d9062000312565b8015620001be5780601f106200019257610100808354040283529160200191620001be565b820191906000526020600020905b815481529060010190602001808311620001a057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f057600080fd5b81516001600160401b03808211156200020d576200020d620001c8565b604051601f8301601f19908116603f01168101908282118183101715620002385762000238620001c8565b816040528381526020925086838588010111156200025557600080fd5b600091505b838210156200027957858201830151818301840152908201906200025a565b600093810190920192909252949350505050565b600080600060608486031215620002a357600080fd5b83516001600160401b0380821115620002bb57600080fd5b620002c987838801620001de565b94506020860151915080821115620002e057600080fd5b50620002ef86828701620001de565b925050604084015160ff811681146200030757600080fd5b809150509250925092565b600181811c908216806200032757607f821691505b6020821081036200034857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039c57600081815260208120601f850160051c81016020861015620003775750805b601f850160051c820191505b81811015620003985782815560010162000383565b5050505b505050565b81516001600160401b03811115620003bd57620003bd620001c8565b620003d581620003ce845462000312565b846200034e565b602080601f8311600181146200040d5760008415620003f45750858301515b600019600386901b1c1916600185901b17855562000398565b600085815260208120601f198616915b828110156200043e578886015182559484019460019091019084016200041d565b50858210156200045d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516116aa620004bc6000396000610237015260008181610307015281816105c001526106a70152600061053a015260008181610379015261050401526116aa6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806370a08231116100d8578063a457c2d71161008c578063d505accf11610066578063d505accf1461039b578063dd62ed3e146103ae578063ffa1ad74146103f457600080fd5b8063a457c2d71461034e578063a9059cbb14610361578063cd0d00961461037457600080fd5b806395d89b41116100bd57806395d89b41146102e75780639dc29fac146102ef578063a3c573eb1461030257600080fd5b806370a08231146102915780637ecebe00146102c757600080fd5b806330adf81f1161012f5780633644e515116101145780633644e51514610261578063395093511461026957806340c10f191461027c57600080fd5b806330adf81f14610209578063313ce5671461023057600080fd5b806318160ddd1161016057806318160ddd146101bd57806320606b70146101cf57806323b872dd146101f657600080fd5b806306fdde031461017c578063095ea7b31461019a575b600080fd5b610184610430565b60405161019191906113e4565b60405180910390f35b6101ad6101a8366004611479565b6104c2565b6040519015158152602001610191565b6002545b604051908152602001610191565b6101c17f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b6101ad6102043660046114a3565b6104dc565b6101c17f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610191565b6101c1610500565b6101ad610277366004611479565b61055c565b61028f61028a366004611479565b6105a8565b005b6101c161029f3660046114df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101c16102d53660046114df565b60056020526000908152604090205481565b610184610680565b61028f6102fd366004611479565b61068f565b6103297f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101ad61035c366004611479565b61075e565b6101ad61036f366004611479565b61082f565b6101c17f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103a9366004611501565b61083d565b6101c16103bc366004611574565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b6101846040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b60606003805461043f906115a7565b80601f016020809104026020016040519081016040528092919081815260200182805461046b906115a7565b80156104b85780601f1061048d576101008083540402835291602001916104b8565b820191906000526020600020905b81548152906001019060200180831161049b57829003601f168201915b5050505050905090565b6000336104d0818585610b73565b60019150505b92915050565b6000336104ea858285610d27565b6104f5858585610dfe565b506001949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614610537576105324661106d565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104d090829086906105a3908790611629565b610b73565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d4272696467650000000000000000000000000000000060648201526084015b60405180910390fd5b61067c8282611135565b5050565b60606004805461043f906115a7565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f546f6b656e577261707065643a3a6f6e6c794272696467653a204e6f7420506f60448201527f6c79676f6e5a6b45564d427269646765000000000000000000000000000000006064820152608401610669565b61067c8282611228565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610822576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610669565b6104f58286868403610b73565b6000336104d0818585610dfe565b834211156108cc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f546f6b656e577261707065643a3a7065726d69743a204578706972656420706560448201527f726d6974000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918a918a918a9190866109268361163c565b9091555060408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610991610500565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610a55573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610ad057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610b5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f546f6b656e577261707065643a3a7065726d69743a20496e76616c696420736960448201527f676e6174757265000000000000000000000000000000000000000000000000006064820152608401610669565b610b678a8a8a610b73565b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316610c15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610cb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610df85781811015610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610669565b610df88484848403610b73565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff8216610f44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610df8565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611098610430565b8051602091820120604080518082018252600181527f310000000000000000000000000000000000000000000000000000000000000090840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018390523060a082015260c001604051602081830303815290604052805190602001209050919050565b73ffffffffffffffffffffffffffffffffffffffff82166111b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610669565b80600260008282546111c49190611629565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166112cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015611381576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610669565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610d1a565b600060208083528351808285015260005b81811015611411578581018301518582016040015282016113f5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461147457600080fd5b919050565b6000806040838503121561148c57600080fd5b61149583611450565b946020939093013593505050565b6000806000606084860312156114b857600080fd5b6114c184611450565b92506114cf60208501611450565b9150604084013590509250925092565b6000602082840312156114f157600080fd5b6114fa82611450565b9392505050565b600080600080600080600060e0888a03121561151c57600080fd5b61152588611450565b965061153360208901611450565b95506040880135945060608801359350608088013560ff8116811461155757600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561158757600080fd5b61159083611450565b915061159e60208401611450565b90509250929050565b600181811c908216806115bb57607f821691505b6020821081036115f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104d6576104d66115fa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361166d5761166d6115fa565b506001019056fea26469706673582212208d88fee561cff7120d381c345cfc534cef8229a272dc5809d4bbb685ad67141164736f6c63430008110033a2646970667358221220432f6d6b4446edbe1f73c19fd2115454d5c35d8b03b98a74fd46724151d7672264736f6c63430008140033"
+		},
+		{
+			"contractName": "PolygonZkEVMBridge proxy",
+			"balance": "340282366920938463463374607431768211455",
+			"nonce": "1",
+			"address": "0x1089Af36bD72553008FAd0A1240B4D5641208494",
+			"bytecode": "0x60806040526004361061005d575f3560e01c80635c60da1b116100425780635c60da1b146100a65780638f283970146100e3578063f851a440146101025761006c565b80633659cfe6146100745780634f1ef286146100935761006c565b3661006c5761006a610116565b005b61006a610116565b34801561007f575f80fd5b5061006a61008e366004610854565b610130565b61006a6100a136600461086d565b610178565b3480156100b1575f80fd5b506100ba6101eb565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100ee575f80fd5b5061006a6100fd366004610854565b610228565b34801561010d575f80fd5b506100ba610255565b61011e610282565b61012e610129610359565b610362565b565b610138610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d8160405180602001604052805f8152505f6103bf565b50565b61016d610116565b610180610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101e3576101de8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250600192506103bf915050565b505050565b6101de610116565b5f6101f4610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610359565b905090565b610225610116565b90565b610230610380565b73ffffffffffffffffffffffffffffffffffffffff1633036101705761016d816103e9565b5f61025e610380565b73ffffffffffffffffffffffffffffffffffffffff16330361021d57610218610380565b61028a610380565b73ffffffffffffffffffffffffffffffffffffffff16330361012e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b5f61021861044a565b365f80375f80365f845af43d5f803e80801561037c573d5ff35b3d5ffd5b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6103c883610471565b5f825111806103d45750805b156101de576103e383836104bd565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f610412610380565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161016d816104e9565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103a3565b61047a816105f5565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606104e28383604051806060016040528060278152602001610977602791396106c0565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff811661058c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610350565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b73ffffffffffffffffffffffffffffffffffffffff81163b610699576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610350565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105af565b60605f808573ffffffffffffffffffffffffffffffffffffffff16856040516106e9919061090b565b5f60405180830381855af49150503d805f8114610721576040519150601f19603f3d011682016040523d82523d5f602084013e610726565b606091505b509150915061073786838387610741565b9695505050505050565b606083156107d65782515f036107cf5773ffffffffffffffffffffffffffffffffffffffff85163b6107cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610350565b50816107e0565b6107e083836107e8565b949350505050565b8151156107f85781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103509190610926565b803573ffffffffffffffffffffffffffffffffffffffff8116811461084f575f80fd5b919050565b5f60208284031215610864575f80fd5b6104e28261082c565b5f805f6040848603121561087f575f80fd5b6108888461082c565b9250602084013567ffffffffffffffff808211156108a4575f80fd5b818601915086601f8301126108b7575f80fd5b8135818111156108c5575f80fd5b8760208285010111156108d6575f80fd5b6020830194508093505050509250925092565b5f5b838110156109035781810151838201526020016108eb565b50505f910152565b5f825161091c8184602087016108e9565b9190910192915050565b602081525f82518060208401526109448160408501602087016108e9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202ac98acbfbb3d3ac1b74050e18c4e76db25a3ff2801ec69bf85d0c61414d502b64736f6c63430008140033",
+			"storage": {
+				"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x0000000000000000000000008558c487e08473154ed6e48953fc4c4d72757220",
+				"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000000000000000000000000e64359621ff57496fbc0e5a5f9bdf27bdda370a"
+			}
+		},
+		{
+			"contractName": "PolygonZkEVMGlobalExitRootL2 implementation",
+			"balance": "0",
+			"nonce": "1",
+			"address": "0x21BD2401BA404841c7feC1816F5a0AaAdbc486eF",
+			"bytecode": "0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c806301fd90441461004e578063257b36321461006a57806333d6247d14610089578063a3c573eb1461009e575b5f80fd5b61005760015481565b6040519081526020015b60405180910390f35b61005761007836600461015e565b5f6020819052908152604090205481565b61009c61009736600461015e565b6100ea565b005b6100c57f0000000000000000000000001089af36bd72553008fad0a1240b4d564120849481565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610061565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001089af36bd72553008fad0a1240b4d56412084941614610159576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b5f6020828403121561016e575f80fd5b503591905056fea26469706673582212205108c6c4f924146b736832a1bdf696e20d900450207b7452462368d150f2c71c64736f6c63430008140033"
+		},
+		{
+			"contractName": "PolygonZkEVMGlobalExitRootL2 proxy",
+			"balance": "0",
+			"nonce": "1",
+			"address": "0xa40d5f56745a118d0906a34e69aec8c0db1cb8fa",
+			"bytecode": "0x60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033",
+			"storage": {
+				"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x0000000000000000000000008558c487e08473154ed6e48953fc4c4d72757220",
+				"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x00000000000000000000000021bd2401ba404841c7fec1816f5a0aaadbc486ef"
+			}
+		},
+		{
+			"contractName": "PolygonZkEVMTimelock",
+			"balance": "0",
+			"nonce": "1",
+			"address": "0x27284DBa79e6DF953Fbd232A9d8D87029F03BBf5",
+			"bytecode": "0x6080604052600436106101bd575f3560e01c806364d62353116100f2578063b1c5f42711610092578063d547741f11610062578063d547741f1461063a578063e38335e514610659578063f23a6e611461066c578063f27a0c92146106b0575f80fd5b8063b1c5f4271461058d578063bc197c81146105ac578063c4d252f5146105f0578063d45c44351461060f575f80fd5b80638f61f4f5116100cd5780638f61f4f5146104c557806391d14854146104f8578063a217fddf14610547578063b08e51c01461055a575f80fd5b806364d62353146104685780638065657f146104875780638f2a0bb0146104a6575f80fd5b8063248a9ca31161015d57806331d507501161013857806331d50750146103b357806336568abe146103d25780633a6aae72146103f1578063584b153e14610449575f80fd5b8063248a9ca3146103375780632ab0f529146103655780632f2ff15d14610394575f80fd5b80630d3cf6fc116101985780630d3cf6fc1461025e578063134008d31461029157806313bc9f20146102a4578063150b7a02146102c3575f80fd5b806301d5062a146101c857806301ffc9a7146101e957806307bd02651461021d575f80fd5b366101c457005b5f80fd5b3480156101d3575f80fd5b506101e76101e2366004611bf6565b6106c4565b005b3480156101f4575f80fd5b50610208610203366004611c65565b610757565b60405190151581526020015b60405180910390f35b348015610228575f80fd5b506102507fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610214565b348015610269575f80fd5b506102507f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101e761029f366004611ca4565b6107b2565b3480156102af575f80fd5b506102086102be366004611d0b565b6108a7565b3480156102ce575f80fd5b506103066102dd366004611e28565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610214565b348015610342575f80fd5b50610250610351366004611d0b565b5f9081526020819052604090206001015490565b348015610370575f80fd5b5061020861037f366004611d0b565b5f908152600160208190526040909120541490565b34801561039f575f80fd5b506101e76103ae366004611e8c565b6108cc565b3480156103be575f80fd5b506102086103cd366004611d0b565b6108f5565b3480156103dd575f80fd5b506101e76103ec366004611e8c565b61090d565b3480156103fc575f80fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b348015610454575f80fd5b50610208610463366004611d0b565b6109c5565b348015610473575f80fd5b506101e7610482366004611d0b565b6109da565b348015610492575f80fd5b506102506104a1366004611ca4565b610aaa565b3480156104b1575f80fd5b506101e76104c0366004611ef7565b610ae8565b3480156104d0575f80fd5b506102507fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b348015610503575f80fd5b50610208610512366004611e8c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610552575f80fd5b506102505f81565b348015610565575f80fd5b506102507ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b348015610598575f80fd5b506102506105a7366004611fa0565b610d18565b3480156105b7575f80fd5b506103066105c63660046120be565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b3480156105fb575f80fd5b506101e761060a366004611d0b565b610d5c565b34801561061a575f80fd5b50610250610629366004611d0b565b5f9081526001602052604090205490565b348015610645575f80fd5b506101e7610654366004611e8c565b610e56565b6101e7610667366004611fa0565b610e7a565b348015610677575f80fd5b50610306610686366004612161565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106bb575f80fd5b50610250611121565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc16106ee81611200565b5f6106fd898989898989610aaa565b9050610709818461120d565b5f817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a60405161074496959493929190612208565b60405180910390a3505050505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107ac57506107ac82611359565b92915050565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661082e5761082e81336113ef565b5f61083d888888888888610aaa565b905061084981856114a6565b610855888888886115e2565b5f817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a60405161088c9493929190612252565b60405180910390a361089d816116e2565b5050505050505050565b5f818152600160205260408120546001811180156108c55750428111155b9392505050565b5f828152602081905260409020600101546108e681611200565b6108f0838361178a565b505050565b5f8181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109c18282611878565b5050565b5f818152600160208190526040822054610906565b333014610a69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109ae565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b5f868686868686604051602001610ac696959493929190612208565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b1281611200565b888714610ba1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b888514610c30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f610c418b8b8b8b8b8b8b8b610d18565b9050610c4d818461120d565b5f5b8a811015610d0a5780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610c8c57610c8c612291565b9050602002016020810190610ca191906122be565b8d8d86818110610cb357610cb3612291565b905060200201358c8c87818110610ccc57610ccc612291565b9050602002810190610cde91906122d7565b8c8b604051610cf296959493929190612208565b60405180910390a3610d0381612365565b9050610c4f565b505050505050505050505050565b5f8888888888888888604051602001610d38989796959493929190612447565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610d8681611200565b610d8f826109c5565b610e1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109ae565b5f828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b5f82815260208190526040902060010154610e7081611200565b6108f08383611878565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610ef657610ef681336113ef565b878614610f85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b878414611014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f6110258a8a8a8a8a8a8a8a610d18565b905061103181856114a6565b5f5b8981101561110b575f8b8b8381811061104e5761104e612291565b905060200201602081019061106391906122be565b90505f8a8a8481811061107857611078612291565b905060200201359050365f8a8a8681811061109557611095612291565b90506020028101906110a791906122d7565b915091506110b7848484846115e2565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b58868686866040516110ee9493929190612252565b60405180910390a3505050508061110490612365565b9050611033565b50611115816116e2565b50505050505050505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16158015906111ef57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef919061250c565b156111f957505f90565b5060025490565b61120a81336113ef565b50565b611216826108f5565b156112a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109ae565b6112ab611121565b81101561133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109ae565b611344814261252b565b5f928352600160205260409092209190915550565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107ac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107ac565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c15761142c8161192d565b61143783602061194c565b604051602001611448929190612560565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109ae916004016125e0565b6114af826108a7565b61153b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b80158061155657505f81815260016020819052604090912054145b6109c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f8473ffffffffffffffffffffffffffffffffffffffff1684848460405161160b929190612630565b5f6040518083038185875af1925050503d805f8114611645576040519150601f19603f3d011682016040523d82523d5f602084013e61164a565b606091505b50509050806116db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109ae565b5050505050565b6116eb816108a7565b611777576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b5f90815260016020819052604090912055565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561181a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107ac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61195a83600261263f565b61196590600261252b565b67ffffffffffffffff81111561197d5761197d611d22565b6040519080825280601f01601f1916602001820160405280156119a7576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106119dd576119dd612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a3f57611a3f612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f611a7984600261263f565b611a8490600161252b565b90505b6001811115611b20577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611ac557611ac5612291565b1a60f81b828281518110611adb57611adb612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c93611b1981612656565b9050611a87565b5083156108c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109ae565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bac575f80fd5b919050565b5f8083601f840112611bc1575f80fd5b50813567ffffffffffffffff811115611bd8575f80fd5b602083019150836020828501011115611bef575f80fd5b9250929050565b5f805f805f805f60c0888a031215611c0c575f80fd5b611c1588611b89565b965060208801359550604088013567ffffffffffffffff811115611c37575f80fd5b611c438a828b01611bb1565b989b979a50986060810135976080820135975060a09091013595509350505050565b5f60208284031215611c75575f80fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108c5575f80fd5b5f805f805f8060a08789031215611cb9575f80fd5b611cc287611b89565b955060208701359450604087013567ffffffffffffffff811115611ce4575f80fd5b611cf089828a01611bb1565b979a9699509760608101359660809091013595509350505050565b5f60208284031215611d1b575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d9657611d96611d22565b604052919050565b5f82601f830112611dad575f80fd5b813567ffffffffffffffff811115611dc757611dc7611d22565b611df860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d4f565b818152846020838601011115611e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215611e3b575f80fd5b611e4485611b89565b9350611e5260208601611b89565b925060408501359150606085013567ffffffffffffffff811115611e74575f80fd5b611e8087828801611d9e565b91505092959194509250565b5f8060408385031215611e9d575f80fd5b82359150611ead60208401611b89565b90509250929050565b5f8083601f840112611ec6575f80fd5b50813567ffffffffffffffff811115611edd575f80fd5b6020830191508360208260051b8501011115611bef575f80fd5b5f805f805f805f805f60c08a8c031215611f0f575f80fd5b893567ffffffffffffffff80821115611f26575f80fd5b611f328d838e01611eb6565b909b50995060208c0135915080821115611f4a575f80fd5b611f568d838e01611eb6565b909950975060408c0135915080821115611f6e575f80fd5b50611f7b8c828d01611eb6565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b5f805f805f805f8060a0898b031215611fb7575f80fd5b883567ffffffffffffffff80821115611fce575f80fd5b611fda8c838d01611eb6565b909a50985060208b0135915080821115611ff2575f80fd5b611ffe8c838d01611eb6565b909850965060408b0135915080821115612016575f80fd5b506120238b828c01611eb6565b999c989b509699959896976060870135966080013595509350505050565b5f82601f830112612050575f80fd5b8135602067ffffffffffffffff82111561206c5761206c611d22565b8160051b61207b828201611d4f565b9283528481018201928281019087851115612094575f80fd5b83870192505b848310156120b35782358252918301919083019061209a565b979650505050505050565b5f805f805f60a086880312156120d2575f80fd5b6120db86611b89565b94506120e960208701611b89565b9350604086013567ffffffffffffffff80821115612105575f80fd5b61211189838a01612041565b94506060880135915080821115612126575f80fd5b61213289838a01612041565b93506080880135915080821115612147575f80fd5b5061215488828901611d9e565b9150509295509295909350565b5f805f805f60a08688031215612175575f80fd5b61217e86611b89565b945061218c60208701611b89565b93506040860135925060608601359150608086013567ffffffffffffffff8111156121b5575f80fd5b61215488828901611d9e565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a060408201525f61223d60a0830186886121c1565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f6122876060830184866121c1565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156122ce575f80fd5b6108c582611b89565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261230a575f80fd5b83018035915067ffffffffffffffff821115612324575f80fd5b602001915036819003821315611bef575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361239557612395612338565b5060010190565b8183525f6020808501808196508560051b81019150845f5b8781101561243a57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126123f2575f80fd5b8701858101903567ffffffffffffffff81111561240d575f80fd5b80360382131561241b575f80fd5b6124268682846121c1565b9a87019a95505050908401906001016123b4565b5091979650505050505050565b60a080825281018890525f8960c08301825b8b8110156124945773ffffffffffffffffffffffffffffffffffffffff61247f84611b89565b16825260209283019290910190600101612459565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156124cc575f80fd5b8860051b9150818a602083013701828103602090810160408501526124f4908201878961239c565b60608401959095525050608001529695505050505050565b5f6020828403121561251c575f80fd5b815180151581146108c5575f80fd5b808201808211156107ac576107ac612338565b5f5b83811015612558578181015183820152602001612540565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f835161259781601785016020880161253e565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516125d481602884016020880161253e565b01602801949350505050565b602081525f82518060208401526125fe81604085016020870161253e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b818382375f9101908152919050565b80820281158282048414176107ac576107ac612338565b5f8161266457612664612338565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220e28ae7494480ab1c619fd775dc5ff665588c808a910d66178a982c2e7c76a1e664736f6c63430008140033",
+			"storage": {
+				"0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000e10",
+				"0x73aec4d9eb3be1097d809826691104f0c28da74ebf68d903dc9c6f12562fd822": "0x0000000000000000000000000000000000000000000000000000000000000001",
+				"0x6b347b5397bd05b592ec00f3e3a28ac3cedc5d7ee6994c7533215f223a0cfe84": "0x0000000000000000000000000000000000000000000000000000000000000001",
+				"0x64494413541ff93b31aa309254e3fed72a7456e9845988b915b4c7a7ceba8814": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5",
+				"0x35fa115b92f0a8d03c972ada19f34c3fa238589ba573a59a419692abc6a91f1a": "0x0000000000000000000000000000000000000000000000000000000000000001",
+				"0x3412d5605ac6cd444957cedb533e5dacad6378b4bc819ebe3652188a665066d6": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5",
+				"0xc05edde0499e76380516353a6ad6ced0d360179c67da013977526f6fbac38774": "0x0000000000000000000000000000000000000000000000000000000000000001",
+				"0xdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d706a": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5",
+				"0x3e92e57d702d5fdc47a588386c93df7f5578fb6af324e63318e76ec6cffcab32": "0x0000000000000000000000000000000000000000000000000000000000000001",
+				"0xc3ad33e20b0c56a223ad5104fff154aa010f8715b9c981fd38fdc60a4d1a52fc": "0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5"
+			}
+		},
+		{
+			"accountName": "keyless Deployer",
+			"balance": "0",
+			"nonce": "1",
+			"address": "0xCBb32b7819EC30d41e1399b32dbE32dd5D47a55E"
+		},
+		{
+			"accountName": "deployer",
+			"balance": "100000000000000000000000",
+			"nonce": "8",
+			"address": "0x8f8E2d6cF621f30e9a11309D6A56A876281Fd534"
+		}
+	]
 }
diff --git a/test/docker-compose.yml b/test/docker-compose.yml
index 4784c7c1f6..af2fd80715 100644
--- a/test/docker-compose.yml
+++ b/test/docker-compose.yml
@@ -454,7 +454,7 @@ services:
 
   xlayer-mock-l1-network:
     container_name: xlayer-mock-l1-network
-    image: zjg555543/geth:v0.3.0_20240320_00
+    image: giskook/elderberry-v0.3.9-geth1.13.11
     ports:
       - 8545:8545
       - 8546:8546
diff --git a/test/e2e/debug_test.go b/test/e2e/debug_test.go
index 77baee4e64..bb840a0739 100644
--- a/test/e2e/debug_test.go
+++ b/test/e2e/debug_test.go
@@ -809,7 +809,7 @@ func convertJson(t *testing.T, response json.RawMessage, debugPrefix string) map
 }
 
 func sendToSequencer(t *testing.T, ctx context.Context, client *ethclient.Client, to common.Address) {
-	auth, err := operations.GetAuth("0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38", operations.DefaultL2ChainID)
+	auth, err := operations.GetAuth("0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2", operations.DefaultL2ChainID)
 	require.NoError(t, err)
 	fromBalance, err := client.BalanceAt(ctx, auth.From, nil)
 	log.Debug("from balance:", fromBalance)
diff --git a/test/e2e/ethtransfer_test.go b/test/e2e/ethtransfer_test.go
index ab5467f73d..26d2898f37 100644
--- a/test/e2e/ethtransfer_test.go
+++ b/test/e2e/ethtransfer_test.go
@@ -79,7 +79,7 @@ func TestEthTransfer(t *testing.T) {
 }
 
 func sendToSeq(t *testing.T, ctx context.Context, client *ethclient.Client) {
-	auth, err := operations.GetAuth("0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38", operations.DefaultL2ChainID)
+	auth, err := operations.GetAuth("0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2", operations.DefaultL2ChainID)
 	require.NoError(t, err)
 	senderBalance, err := client.BalanceAt(ctx, auth.From, nil)
 	require.NoError(t, err)
@@ -112,7 +112,7 @@ func sendToSeq(t *testing.T, ctx context.Context, client *ethclient.Client) {
 		Data:     data,
 	})
 
-	privateKey, err := crypto.HexToECDSA(strings.TrimPrefix("0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38", "0x"))
+	privateKey, err := crypto.HexToECDSA(strings.TrimPrefix("0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2", "0x"))
 	require.NoError(t, err)
 
 	signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, privateKey)
diff --git a/test/e2e/jsonrpc2_test.go b/test/e2e/jsonrpc2_test.go
index 090c9473ea..bb4c3f29e8 100644
--- a/test/e2e/jsonrpc2_test.go
+++ b/test/e2e/jsonrpc2_test.go
@@ -457,7 +457,7 @@ func TestCallMissingParameters(t *testing.T) {
 		},
 		{
 			name:   "params has only first parameter",
-			params: []interface{}{map[string]interface{}{"value": "0x1", "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92267"}},
+			params: []interface{}{map[string]interface{}{"value": "0x1", "from": fromAddressHex, "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92267"}},
 		},
 	}
 
diff --git a/test/e2e/permissionlessrpc_test.go b/test/e2e/permissionlessrpc_test.go
index ffc23650a8..a23dd6c716 100644
--- a/test/e2e/permissionlessrpc_test.go
+++ b/test/e2e/permissionlessrpc_test.go
@@ -45,7 +45,7 @@ func TestPermissionlessJRPC(t *testing.T) {
 
 	nTxsStep1 := 10
 	// Load account with balance on local genesis
-	auth, err := operations.GetAuth("0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38", operations.DefaultL2ChainID)
+	auth, err := operations.GetAuth("0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2", operations.DefaultL2ChainID)
 	require.NoError(t, err)
 	// Load eth client (permissionless RPC)
 	client, err := ethclient.Dial(operations.PermissionlessL2NetworkURL)
diff --git a/test/e2e/preEIP155_test.go b/test/e2e/preEIP155_test.go
index 52cf9858a9..7a72dea3e8 100644
--- a/test/e2e/preEIP155_test.go
+++ b/test/e2e/preEIP155_test.go
@@ -61,7 +61,7 @@ func TestPreEIP155Tx(t *testing.T) {
 		client := operations.MustGetClient(network.URL)
 		priKey := network.PrivateKey
 		if network.Name == "Local L2" {
-			priKey = "0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38"
+			priKey = "0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2"
 		}
 		auth := operations.MustGetAuth(priKey, network.ChainID)
 
diff --git a/test/e2e/sc_test.go b/test/e2e/sc_test.go
index 720aa68cd2..5c68a54d87 100644
--- a/test/e2e/sc_test.go
+++ b/test/e2e/sc_test.go
@@ -671,7 +671,7 @@ func TestCounterAndBlock(t *testing.T) {
 		client := operations.MustGetClient(network.URL)
 		priKey := network.PrivateKey
 		if network.Name == "Local L2" {
-			priKey = "0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38"
+			priKey = "0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2"
 		}
 		auth := operations.MustGetAuth(priKey, network.ChainID)
 		log.Infof("auth:%v, chainID:%v", auth.From.String(), network.ChainID)
diff --git a/test/e2e/shared.go b/test/e2e/shared.go
index 523531b6a6..f3e3cf03b7 100644
--- a/test/e2e/shared.go
+++ b/test/e2e/shared.go
@@ -27,8 +27,8 @@ const (
 	invalidParamsErrorCode = -32602
 	toAddressHex           = "0x4d5Cf5032B2a844602278b01199ED191A86c93ff"
 	forkID6                = 6
-	fromPriKey             = "0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38"
-	fromAddressHex         = "0x2ECF31eCe36ccaC2d3222A303b1409233ECBB225"
+	fromPriKey             = "0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2"
+	fromAddressHex         = "0x8f8E2d6cF621f30e9a11309D6A56A876281Fd534"
 )
 
 var (
diff --git a/test/operations/manager_xlayer.go b/test/operations/manager_xlayer.go
index 7c3307cfbd..85f8b2ea55 100644
--- a/test/operations/manager_xlayer.go
+++ b/test/operations/manager_xlayer.go
@@ -2,8 +2,8 @@ package operations
 
 const (
 	DefaultL1DataCommitteeContract        = "0x6Ae5b0863dBF3477335c0102DBF432aFf04ceb22"
-	DefaultL1AdminAddress                 = "0x2ecf31ece36ccac2d3222a303b1409233ecbb225"
-	DefaultL1AdminPrivateKey              = "0xde3ca643a52f5543e84ba984c4419ff40dbabd0e483c31c1d09fee8168d68e38"
+	DefaultL1AdminAddress                 = "0x8f8E2d6cF621f30e9a11309D6A56A876281Fd534"
+	DefaultL1AdminPrivateKey              = "0x815405dddb0e2a99b12af775fd2929e526704e1d1aea6a0b4e74dc33e2f7fcd2"
 	MaxBatchesForL1                uint64 = 10
 )
 

From 650810815387c7747c7f77beedf2f0ece3e501f9 Mon Sep 17 00:00:00 2001
From: zhangkai 
Date: Fri, 10 May 2024 18:09:41 +0800
Subject: [PATCH 23/23] add upgrade sql file

---
 db/migrations/pool/1002.sql | 12 ++++++++++++
 db/migrations/pool/1003.sql |  9 +++++++++
 2 files changed, 21 insertions(+)
 create mode 100644 db/migrations/pool/1002.sql
 create mode 100644 db/migrations/pool/1003.sql

diff --git a/db/migrations/pool/1002.sql b/db/migrations/pool/1002.sql
new file mode 100644
index 0000000000..e6de3962f1
--- /dev/null
+++ b/db/migrations/pool/1002.sql
@@ -0,0 +1,12 @@
+-- +migrate Up
+CREATE TABLE IF NOT EXISTS pool.readytx(
+                             id SERIAL PRIMARY KEY NOT NULL,
+                             count INT,
+                             updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+INSERT INTO pool.readytx(id, count) VALUES(1, 0)
+    ON CONFLICT(id) do UPDATE
+    SET count = 0;
+
+-- +migrate Down
+DROP TABLE IF EXISTS pool.readytx;
diff --git a/db/migrations/pool/1003.sql b/db/migrations/pool/1003.sql
new file mode 100644
index 0000000000..ce1dba2d0a
--- /dev/null
+++ b/db/migrations/pool/1003.sql
@@ -0,0 +1,9 @@
+-- +migrate Up
+CREATE TABLE IF NOT EXISTS pool.innertx (
+                              hash VARCHAR(128) PRIMARY KEY NOT NULL,
+                              innertx text,
+                              created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- +migrate Down
+DROP TABLE IF EXISTS pool.innertx;
\ No newline at end of file