From fc9e3932e3bdf77148ee1961461378e408c1065e Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:37:39 +0200 Subject: [PATCH 01/40] feat: wip --- .../migrations/l1infotreesync0002.sql | 11 ++++++++++ l1infotreesync/processor.go | 20 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 l1infotreesync/migrations/l1infotreesync0002.sql diff --git a/l1infotreesync/migrations/l1infotreesync0002.sql b/l1infotreesync/migrations/l1infotreesync0002.sql new file mode 100644 index 00000000..9f78c633 --- /dev/null +++ b/l1infotreesync/migrations/l1infotreesync0002.sql @@ -0,0 +1,11 @@ +-- +migrate Down +DROP TABLE IF EXISTS initial_info; + +-- +migrate Up + +CREATE TABLE initial_info ( + block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, + leaf_count INTEGER NOT NULL, + l1_info_root VARCHAR NOT NULL, +) + diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index a672c5ef..f7452424 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -77,6 +77,13 @@ type L1InfoTreeLeaf struct { Hash common.Hash `meddler:"hash,hash"` } +// L1InfoTreeInitial representation of the initial info of the L1 Info tree for this rollup +type L1InfoTreeInitial struct { + BlockNumber uint64 `meddler:"block_num"` + LeafCount uint32 `meddler:"leaf_count"` + L1InfoRoot common.Hash `meddler:"l1_info_root,hash"` +} + // Hash as expected by the tree func (l *L1InfoTreeLeaf) hash() common.Hash { var res [treeTypes.DefaultHeight]byte @@ -309,6 +316,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { // TODO: indicate that l1 Info tree indexes before the one on this // event are not safe to use log.Debugf("TODO: handle InitL1InfoRootMap event") + err = processEventInitL1InfoRootMap(tx, b.Num, event.InitL1InfoRootMap) } } @@ -319,6 +327,18 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { return nil } +func processEventInitL1InfoRootMap(tx db.Txer, blockNumber uint64, event *InitL1InfoRootMap) error { + info := L1InfoTreeInitial{ + BlockNumber: blockNumber, + LeafCount: event.LeafCount, + L1InfoRoot: event.CurrentL1InfoRoot, + } + if err := meddler.Insert(tx, "l1info_initial", info); err != nil { + return fmt.Errorf("err: %w", err) + } + return nil +} + func (p *processor) getLastIndex(tx db.Querier) (uint32, error) { var lastProcessedIndex uint32 row := tx.QueryRow("SELECT position FROM l1info_leaf ORDER BY block_num DESC, block_pos DESC LIMIT 1;") From eaab57086a72925cd397f37ab52cba21604fe818 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Fri, 20 Sep 2024 12:10:46 +0200 Subject: [PATCH 02/40] feat: fix local execution --- scripts/local_config | 13 +++++++++++++ test/config/test.kurtosis_template.toml | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/scripts/local_config b/scripts/local_config index ed8aaec3..4f90a1a6 100755 --- a/scripts/local_config +++ b/scripts/local_config @@ -2,6 +2,18 @@ #Include common varaibles source $(dirname $0)/../test/scripts/env.sh +function export_values_of_genesis(){ + local _GENESIS_FILE=$1 + if [ ! -f $_GENESIS_FILE ]; then + echo "Error: genesis file not found: $_GENESIS_FILE" + exit 1 + fi + export l1_chain_id=$(jq -r '.L1Config.chainId' $_GENESIS_FILE | tr -d '"') + export pol_token_address=$(jq -r '.L1Config.polTokenAddress' $_GENESIS_FILE) + export zkevm_rollup_address=$(jq -r '.L1Config.polygonZkEVMAddress' $_GENESIS_FILE) + export zkevm_rollup_manager_address=$(jq -r '.L1Config.polygonRollupManagerAddress' $_GENESIS_FILE) + export zkevm_global_exit_root_address=$(jq -r '.L1Config.polygonZkEVMGlobalExitRootAddress' $_GENESIS_FILE) +} @@ -43,6 +55,7 @@ rm $DEST/* kurtosis files download $ENCLAVE genesis $DEST [ $? -ne 0 ] && echo "Error downloading genesis" && exit 1 export genesis_file=$DEST/genesis.json +export_values_of_genesis $genesis_file kurtosis files download $ENCLAVE sequencer-keystore $DEST [ $? -ne 0 ] && echo "Error downloading sequencer-keystore" && exit 1 export sequencer_keystore_file=$DEST/sequencer.keystore diff --git a/test/config/test.kurtosis_template.toml b/test/config/test.kurtosis_template.toml index 66471c6a..8746355f 100644 --- a/test/config/test.kurtosis_template.toml +++ b/test/config/test.kurtosis_template.toml @@ -1,6 +1,9 @@ ForkUpgradeBatchNumber = 0 ForkUpgradeNewForkId = 0 +[Etherman] + URL = "http://127.0.0.1:${l1_rpc_port}" + [Common] IsValidiumMode = ${zkevm_is_validium} ContractVersions = "elderberry" @@ -124,3 +127,9 @@ SequencerPrivateKey = {} [Aggregator.Synchronizer.Etherman] [Aggregator.Synchronizer.Etherman.Validium] Enabled = ${zkevm_is_validium} +[NetworkConfig.L1] +L1ChainID = ${l1_chain_id} +PolAddr = "${pol_token_address}" +ZkEVMAddr = "${zkevm_rollup_address}" +RollupManagerAddr = "${zkevm_rollup_manager_address}" +GlobalExitRootManagerAddr = "${zkevm_global_exit_root_address}" From f3b3841b829fc1ff04d66416c7dd8126b8b3a7a6 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:42:18 +0200 Subject: [PATCH 03/40] feat: fix local config --- scripts/local_config | 8 ++++++-- test/config/test.kurtosis_template.toml | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/scripts/local_config b/scripts/local_config index 4f90a1a6..1b75f350 100755 --- a/scripts/local_config +++ b/scripts/local_config @@ -62,6 +62,10 @@ export sequencer_keystore_file=$DEST/sequencer.keystore l1_rpc_port=$(kurtosis port print $ENCLAVE el-1-geth-lighthouse rpc | cut -f 3 -d ":") [ $? -ne 0 ] && echo "Error getting l1_rpc_port" && exit 1 || export l1_rpc_port && echo "l1_rpc_port=$l1_rpc_port" +l1_rpc_addr=$(kurtosis port print $ENCLAVE el-1-geth-lighthouse rpc) +[ $? -ne 0 ] && echo "Error getting l1_rpc_addr" && exit 1 || export l1_rpc_addr && echo "l1_rpc_addr=$l1_rpc_addr" +l2_rpc_addr=$(kurtosis port print $ENCLAVE cdk-erigon-node-001 http-rpc) +[ $? -ne 0 ] && echo "Error getting l2_rpc_addr" && exit 1 || export l2_rpc_addr && echo "l2_rpc_addr=$l2_rpc_addr" zkevm_data_streamer_port=$(kurtosis port print $ENCLAVE cdk-erigon-sequencer-001 data-streamer | cut -f 3 -d ":") [ $? -ne 0 ] && echo "Error getting zkevm_data_streamer_port" && exit 1 || export zkevm_data_streamer_port && echo "zkevm_data_streamer_port=$zkevm_data_streamer_port" @@ -80,7 +84,7 @@ if [ "$zkevm_is_validium" == "true" ]; then fi envsubst < test/config/test.kurtosis_template.toml > $DEST/test.kurtosis.toml - +echo "file generated at:" $DEST/test.kurtosis.toml echo "- to restart kurtosis:" echo " kurtosis clean --all; kurtosis run --enclave cdk-v1 --args-file params.yml --image-download always ." echo " " @@ -100,7 +104,7 @@ cat << EOF "run", "-cfg", "$DEST/test.kurtosis.toml", "-components", "sequence-sender,aggregator", - "-custom-network-file", "$DEST/local_config/genesis.json" ] }, EOF + diff --git a/test/config/test.kurtosis_template.toml b/test/config/test.kurtosis_template.toml index 8746355f..cf446e62 100644 --- a/test/config/test.kurtosis_template.toml +++ b/test/config/test.kurtosis_template.toml @@ -14,7 +14,7 @@ ContractVersions = "elderberry" [Log] Environment = "development" # "production" or "development" -Level = "info" +Level = "debug" Outputs = ["stderr"] [SequenceSender] @@ -30,7 +30,7 @@ SequencesTxFileName = "sequencesender.json" GasOffset = 80000 WaitPeriodPurgeTxFile = "15m" MaxPendingTx = 1 -SanityCheckRPCURL = "http://127.0.0.1:8123" +SanityCheckRPCURL = "${l2_rpc_addr}" [SequenceSender.StreamClient] Server = "127.0.0.1:${zkevm_data_streamer_port}" [SequenceSender.EthTxManager] @@ -127,6 +127,20 @@ SequencerPrivateKey = {} [Aggregator.Synchronizer.Etherman] [Aggregator.Synchronizer.Etherman.Validium] Enabled = ${zkevm_is_validium} + + +[L1InfoTreeSync] +DBPath = "/tmp/L1InfoTreeSync.sqlite" +GlobalExitRootAddr="${zkevm_global_exit_root_address}" +RollupManagerAddr="${zkevm_rollup_manager_address}" +SyncBlockChunkSize=100 +BlockFinality="LatestBlock" +# http://el-1-geth-lighthouse:8545 +URLRPCL1="${l1_rpc_addr}" +WaitForNewBlocksPeriod="100ms" +InitialBlock=0 + + [NetworkConfig.L1] L1ChainID = ${l1_chain_id} PolAddr = "${pol_token_address}" From 12a97ebf6d8c6219d51ad76fc80b6fa3e17d99d3 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:42:36 +0200 Subject: [PATCH 04/40] feat: add process InitL1InfoRootMap --- cmd/run.go | 2 +- config/default.go | 22 ++++++- l1infotreesync/downloader.go | 33 ++++++++-- .../migrations/l1infotreesync0002.sql | 9 ++- l1infotreesync/migrations/migrations.go | 7 +++ l1infotreesync/processor.go | 61 +++++++++++++------ l1infotreesync/processor_test.go | 58 ++++++++++++++++++ 7 files changed, 165 insertions(+), 27 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 0b744243..4e5100dd 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -511,7 +511,7 @@ func runL1ClientIfNeeded(components []string, urlRPCL1 string) *ethclient.Client log.Debugf("dialing L1 client at: %s", urlRPCL1) l1CLient, err := ethclient.Dial(urlRPCL1) if err != nil { - log.Fatal(err) + log.Fatalf("failed to create client for L1 using URL: %s. Err:%v", urlRPCL1, err) } return l1CLient diff --git a/config/default.go b/config/default.go index 377e9033..e02a37ac 100644 --- a/config/default.go +++ b/config/default.go @@ -5,6 +5,18 @@ const DefaultValues = ` ForkUpgradeBatchNumber = 0 ForkUpgradeNewForkId = 0 +[Etherman] + URL="http://localhost:8545" + ForkIDChunkSize=100 + [Etherman.EthermanConfig] + URL="http://localhost:8545" + MultiGasProvider=false + L1ChainID=1337 + HTTPHeaders=[] + [Etherman.EthermanConfig.Etherscan] + ApiKey="" + Url="https://api.etherscan.io/api?module=gastracker&action=gasoracle&apikey=" + [Common] NetworkID = 1 IsValidiumMode = false @@ -141,7 +153,7 @@ DBPath = "/tmp/reorgdetectorl1" DBPath = "/tmp/reorgdetectorl2" [L1InfoTreeSync] -DBPath = "/tmp/L1InfoTreeSync" +DBPath = "/tmp/L1InfoTreeSync.sqlite" GlobalExitRootAddr="0x8464135c8F25Da09e49BC8782676a84730C318bC" SyncBlockChunkSize=10 BlockFinality="LatestBlock" @@ -250,4 +262,12 @@ RetryAfterErrorPeriod = "1s" MaxRetryAttemptsAfterError = -1 WaitForNewBlocksPeriod = "1s" DownloadBufferSize = 100 + +[NetworkConfig.L1] +L1ChainID = 0 +PolAddr = "0x0000000000000000000000000000000000000000" +ZkEVMAddr = "0x0000000000000000000000000000000000000000" +RollupManagerAddr = "0x0000000000000000000000000000000000000000" +GlobalExitRootManagerAddr = "0x0000000000000000000000000000000000000000" + ` diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index 2051f7b5..ac082ad7 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -33,15 +33,38 @@ type EthClienter interface { bind.ContractBackend } -func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Address) (sync.LogAppenderMap, error) { - ger, err := polygonzkevmglobalexitrootv2.NewPolygonzkevmglobalexitrootv2(globalExitRoot, client) +func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address) (*polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, + *polygonrollupmanager.Polygonrollupmanager, + error) { + gerContract, err := polygonzkevmglobalexitrootv2.NewPolygonzkevmglobalexitrootv2(globalExitRoot, client) + if err != nil { + return nil, nil, err + } + + rollupManagerContract, err := polygonrollupmanager.NewPolygonrollupmanager(rollupManager, client) + if err != nil { + return nil, nil, err + } + + depositCount, err := gerContract.DepositCount(nil) if err != nil { - return nil, err + return nil, nil, fmt.Errorf("fail sanity check GlobalExitRoot(%s) Contract. Err: %w", globalExitRoot.String(), err) } - rm, err := polygonrollupmanager.NewPolygonrollupmanager(rollupManager, client) + log.Debugf("sanity check GlobalExitRoot OK. DepositCount: %v", depositCount) + bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) if err != nil { - return nil, err + return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) } + log.Debugf("sanity check rollupManager OK. bridgeAddr: %s", bridgeAddr.String()) + return gerContract, rollupManagerContract, nil +} + +func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Address) (sync.LogAppenderMap, error) { + ger, rm, err := createContracts(client, globalExitRoot, rollupManager) + if err != nil { + return nil, fmt.Errorf("buildAppender: fails contracts creation. Err:%w", err) + } + appender := make(sync.LogAppenderMap) appender[initL1InfoRootMapSignature] = func(b *sync.EVMBlock, l types.Log) error { init, err := ger.ParseInitL1InfoRootMap(l) diff --git a/l1infotreesync/migrations/l1infotreesync0002.sql b/l1infotreesync/migrations/l1infotreesync0002.sql index 9f78c633..d1f09481 100644 --- a/l1infotreesync/migrations/l1infotreesync0002.sql +++ b/l1infotreesync/migrations/l1infotreesync0002.sql @@ -1,11 +1,14 @@ -- +migrate Down -DROP TABLE IF EXISTS initial_info; +DROP TABLE IF EXISTS l1info_initial; -- +migrate Up -CREATE TABLE initial_info ( +CREATE TABLE l1info_initial ( + -- single_row_id prevent to have more than 1 row in this table + single_row_id INTEGER check(single_row_id=1) NOT NULL DEFAULT 1, block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, leaf_count INTEGER NOT NULL, l1_info_root VARCHAR NOT NULL, -) + PRIMARY KEY (single_row_id) +); diff --git a/l1infotreesync/migrations/migrations.go b/l1infotreesync/migrations/migrations.go index 768dde37..47fac070 100644 --- a/l1infotreesync/migrations/migrations.go +++ b/l1infotreesync/migrations/migrations.go @@ -16,12 +16,19 @@ const ( //go:embed l1infotreesync0001.sql var mig001 string +//go:embed l1infotreesync0002.sql +var mig002 string + func RunMigrations(dbPath string) error { migrations := []types.Migration{ { ID: "l1infotreesync0001", SQL: mig001, }, + { + ID: "l1infotreesync0002", + SQL: mig002, + }, } for _, tm := range treeMigrations.Migrations { migrations = append(migrations, types.Migration{ diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index f7452424..8cba8a1c 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -84,6 +84,10 @@ type L1InfoTreeInitial struct { L1InfoRoot common.Hash `meddler:"l1_info_root,hash"` } +func (l *L1InfoTreeInitial) String() string { + return fmt.Sprintf("BlockNumber: %d, LeafCount: %d, L1InfoRoot: %s", l.BlockNumber, l.LeafCount, l.L1InfoRoot.String()) +} + // Hash as expected by the tree func (l *L1InfoTreeLeaf) hash() common.Hash { var res [treeTypes.DefaultHeight]byte @@ -198,6 +202,19 @@ func (p *processor) getLastProcessedBlockWithTx(tx db.Querier) (uint64, error) { return lastProcessedBlock, err } +// GetInitL1InfoRootMap returns the initial L1 info root map, nil if no root map has been set +func (p *processor) GetInitL1InfoRootMap(tx db.Querier) (*L1InfoTreeInitial, error) { + if tx == nil { + tx = p.db + } + info := &L1InfoTreeInitial{} + err := meddler.QueryRow(tx, info, `SELECT block_num, leaf_count,l1_info_root FROM l1info_initial`) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return info, err +} + // Reorg triggers a purge and reset process on the processor to leaf it on a state // as if the last block processed was firstReorgedBlock-1 func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { @@ -234,7 +251,7 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { // ProcessBlock process the events of the block to build the rollup exit tree and the l1 info tree // and updates the last processed block (can be called without events for that purpose) -func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { +func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { tx, err := db.NewTx(ctx, p.db) if err != nil { return err @@ -247,8 +264,8 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { } }() - if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, b.Num); err != nil { - return fmt.Errorf("err: %w", err) + if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, block.Num); err != nil { + return fmt.Errorf("insert Block. err: %w", err) } var initialL1InfoIndex uint32 @@ -260,12 +277,12 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { initialL1InfoIndex = 0 err = nil case err != nil: - return fmt.Errorf("err: %w", err) + return fmt.Errorf("getLastIndex err: %w", err) default: initialL1InfoIndex = lastIndex + 1 } - for _, e := range b.Events { + for _, e := range block.Events { event, ok := e.(Event) if !ok { return errors.New("failed to convert from sync.Block.Event into Event") @@ -273,7 +290,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { if event.UpdateL1InfoTree != nil { index := initialL1InfoIndex + l1InfoLeavesAdded info := &L1InfoTreeLeaf{ - BlockNumber: b.Num, + BlockNumber: block.Num, BlockPosition: event.UpdateL1InfoTree.BlockPosition, L1InfoTreeIndex: index, PreviousBlockHash: event.UpdateL1InfoTree.ParentHash, @@ -284,28 +301,29 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { info.GlobalExitRoot = info.globalExitRoot() info.Hash = info.hash() if err = meddler.Insert(tx, "l1info_leaf", info); err != nil { - return fmt.Errorf("err: %w", err) + return fmt.Errorf("insert l1info_leaf. err: %w", err) } err = p.l1InfoTree.AddLeaf(tx, info.BlockNumber, info.BlockPosition, treeTypes.Leaf{ Index: info.L1InfoTreeIndex, Hash: info.Hash, }) if err != nil { - return fmt.Errorf("err: %w", err) + return fmt.Errorf("AddLeaf. err: %w", err) } l1InfoLeavesAdded++ } - - if event.VerifyBatches != nil { - newRoot, err := p.rollupExitTree.UpsertLeaf(tx, b.Num, event.VerifyBatches.BlockPosition, treeTypes.Leaf{ + // TODO: CDK-505 + if event.VerifyBatches != nil && event.VerifyBatches.RollupExitRoot != (common.Hash{}) { + log.Debugf("VerifyBatches: rollupExitTree.UpsertLeaf (block=%d, pos=%d, rollupID=%d, exit_root=%s)", block.Num, event.VerifyBatches.BlockPosition, event.VerifyBatches.RollupID-1, event.VerifyBatches.ExitRoot.String()) + newRoot, err := p.rollupExitTree.UpsertLeaf(tx, block.Num, event.VerifyBatches.BlockPosition, treeTypes.Leaf{ Index: event.VerifyBatches.RollupID - 1, Hash: event.VerifyBatches.ExitRoot, }) if err != nil { - return fmt.Errorf("err: %w", err) + return fmt.Errorf("UpsertLeaf. err: %w", err) } verifyBatches := event.VerifyBatches - verifyBatches.BlockNumber = b.Num + verifyBatches.BlockNumber = block.Num verifyBatches.RollupExitRoot = newRoot if err = meddler.Insert(tx, "verify_batches", verifyBatches); err != nil { return fmt.Errorf("err: %w", err) @@ -315,24 +333,33 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { if event.InitL1InfoRootMap != nil { // TODO: indicate that l1 Info tree indexes before the one on this // event are not safe to use - log.Debugf("TODO: handle InitL1InfoRootMap event") - err = processEventInitL1InfoRootMap(tx, b.Num, event.InitL1InfoRootMap) + log.Debugf("handle InitL1InfoRootMap event") + err = processEventInitL1InfoRootMap(tx, block.Num, event.InitL1InfoRootMap) + if err != nil { + err = fmt.Errorf("initL1InfoRootMap. Err: %w", err) + log.Errorf("error processing InitL1InfoRootMap: %v", err) + return err + } } } if err := tx.Commit(); err != nil { return fmt.Errorf("err: %w", err) } - log.Infof("block %d processed with %d events", b.Num, len(b.Events)) + log.Infof("block %d processed with %d events", block.Num, len(block.Events)) return nil } func processEventInitL1InfoRootMap(tx db.Txer, blockNumber uint64, event *InitL1InfoRootMap) error { - info := L1InfoTreeInitial{ + if event == nil { + return nil + } + info := &L1InfoTreeInitial{ BlockNumber: blockNumber, LeafCount: event.LeafCount, L1InfoRoot: event.CurrentL1InfoRoot, } + log.Infof("insert InitL1InfoRootMap %s ", info.String()) if err := meddler.Insert(tx, "l1info_initial", info); err != nil { return fmt.Errorf("err: %w", err) } diff --git a/l1infotreesync/processor_test.go b/l1infotreesync/processor_test.go index 3da02998..59d84ad0 100644 --- a/l1infotreesync/processor_test.go +++ b/l1infotreesync/processor_test.go @@ -174,3 +174,61 @@ func TestGetInfo(t *testing.T) { require.NoError(t, err) require.Equal(t, expected2, *actual) } + +func TestInitL1InfoRootMap(t *testing.T) { + dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + ctx := context.TODO() + event := InitL1InfoRootMap{ + LeafCount: 1, + CurrentL1InfoRoot: common.HexToHash("beef"), + } + block := sync.Block{ + Num: 1, + Events: []interface{}{ + Event{InitL1InfoRootMap: &event}, + }, + } + + err = sut.ProcessBlock(ctx, block) + require.NoError(t, err) + + info, err := sut.GetInitL1InfoRootMap(nil) + require.NoError(t, err) + require.NotNil(t, info) + require.Equal(t, event.LeafCount, info.LeafCount) + require.Equal(t, event.CurrentL1InfoRoot, info.L1InfoRoot) + require.Equal(t, block.Num, info.BlockNumber) + +} + +func TestInitL1InfoRootMapDontAllow2Rows(t *testing.T) { + dbPath := "file:test?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + ctx := context.TODO() + block := sync.Block{ + Num: 1, + Events: []interface{}{ + Event{InitL1InfoRootMap: &InitL1InfoRootMap{ + LeafCount: 1, + CurrentL1InfoRoot: common.HexToHash("beef"), + }}, + }, + } + err = sut.ProcessBlock(ctx, block) + require.NoError(t, err) + block.Num = 2 + err = sut.ProcessBlock(ctx, block) + require.Error(t, err, "should not allow to insert a second row") +} + +func TestGetInitL1InfoRootMap(t *testing.T) { + dbPath := "file:test?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + info, err := sut.GetInitL1InfoRootMap(nil) + require.NoError(t, err, "should return no error if no row is present, because it returns data=nil") + require.Nil(t, info, "should return nil if no row is present") +} From fe9ea0005070e7b5671f3bf464c70b58ec2fbf14 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:52:42 +0200 Subject: [PATCH 05/40] fix: l1infotreesync. Error UNIQUE constraint failed: rollup_exit_root.hashl1infotreesync --- l1infotreesync/l1infotreesync.go | 11 ++- l1infotreesync/processor.go | 68 +++++++------------ l1infotreesync/processor_initl1inforootmap.go | 37 ++++++++++ l1infotreesync/processor_verifybatches.go | 65 ++++++++++++++++++ sequencesender/txbuilder/banana_base.go | 1 + tree/tree.go | 11 +-- tree/tree_test.go | 10 +++ tree/updatabletree_test.go | 50 ++++++++++++++ 8 files changed, 201 insertions(+), 52 deletions(-) create mode 100644 l1infotreesync/processor_initl1inforootmap.go create mode 100644 l1infotreesync/processor_verifybatches.go create mode 100644 tree/updatabletree_test.go diff --git a/l1infotreesync/l1infotreesync.go b/l1infotreesync/l1infotreesync.go index 4c4b796e..cd9ebf5c 100644 --- a/l1infotreesync/l1infotreesync.go +++ b/l1infotreesync/l1infotreesync.go @@ -129,12 +129,12 @@ func (s *L1InfoTreeSync) GetL1InfoTreeRootByIndex(ctx context.Context, index uin // GetLastRollupExitRoot return the last rollup exit root processed func (s *L1InfoTreeSync) GetLastRollupExitRoot(ctx context.Context) (types.Root, error) { - return s.processor.rollupExitTree.GetLastRoot(ctx) + return s.processor.rollupExitTree.GetLastRoot(nil) } // GetLastL1InfoTreeRoot return the last root and index processed from the L1 Info tree func (s *L1InfoTreeSync) GetLastL1InfoTreeRoot(ctx context.Context) (types.Root, error) { - return s.processor.l1InfoTree.GetLastRoot(ctx) + return s.processor.l1InfoTree.GetLastRoot(nil) } // GetLastProcessedBlock return the last processed block @@ -149,7 +149,7 @@ func (s *L1InfoTreeSync) GetLocalExitRoot( return common.Hash{}, errors.New("network 0 is not a rollup, and it's not part of the rollup exit tree") } - return s.processor.rollupExitTree.GetLeaf(ctx, networkID-1, rollupExitRoot) + return s.processor.rollupExitTree.GetLeaf(nil, networkID-1, rollupExitRoot) } func (s *L1InfoTreeSync) GetLastVerifiedBatches(rollupID uint32) (*VerifyBatches, error) { @@ -190,3 +190,8 @@ func (s *L1InfoTreeSync) GetL1InfoTreeMerkleProofFromIndexToRoot( ) (types.Proof, error) { return s.processor.l1InfoTree.GetProof(ctx, index, root) } + +// GetInitL1InfoRootMap returns the initial L1 info root map, nil if no root map has been set +func (s *L1InfoTreeSync) GetInitL1InfoRootMap(ctx context.Context) (*L1InfoTreeInitial, error) { + return s.processor.GetInitL1InfoRootMap(nil) +} diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 8cba8a1c..30eac3ef 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -53,11 +53,20 @@ type VerifyBatches struct { RollupExitRoot common.Hash `meddler:"rollup_exit_root,hash"` } +func (v *VerifyBatches) String() string { + return fmt.Sprintf("BlockNumber: %d, BlockPosition: %d, RollupID: %d, NumBatch: %d, StateRoot: %s, ExitRoot: %s, Aggregator: %s, RollupExitRoot: %s", + v.BlockNumber, v.BlockPosition, v.RollupID, v.NumBatch, v.StateRoot.String(), v.ExitRoot.String(), v.Aggregator.String(), v.RollupExitRoot.String()) +} + type InitL1InfoRootMap struct { LeafCount uint32 CurrentL1InfoRoot common.Hash } +func (i *InitL1InfoRootMap) String() string { + return fmt.Sprintf("LeafCount: %d, CurrentL1InfoRoot: %s", i.LeafCount, i.CurrentL1InfoRoot.String()) +} + type Event struct { UpdateL1InfoTree *UpdateL1InfoTree VerifyBatches *VerifyBatches @@ -202,19 +211,6 @@ func (p *processor) getLastProcessedBlockWithTx(tx db.Querier) (uint64, error) { return lastProcessedBlock, err } -// GetInitL1InfoRootMap returns the initial L1 info root map, nil if no root map has been set -func (p *processor) GetInitL1InfoRootMap(tx db.Querier) (*L1InfoTreeInitial, error) { - if tx == nil { - tx = p.db - } - info := &L1InfoTreeInitial{} - err := meddler.QueryRow(tx, info, `SELECT block_num, leaf_count,l1_info_root FROM l1info_initial`) - if errors.Is(err, sql.ErrNoRows) { - return nil, nil - } - return info, err -} - // Reorg triggers a purge and reset process on the processor to leaf it on a state // as if the last block processed was firstReorgedBlock-1 func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { @@ -313,27 +309,18 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { l1InfoLeavesAdded++ } // TODO: CDK-505 - if event.VerifyBatches != nil && event.VerifyBatches.RollupExitRoot != (common.Hash{}) { - log.Debugf("VerifyBatches: rollupExitTree.UpsertLeaf (block=%d, pos=%d, rollupID=%d, exit_root=%s)", block.Num, event.VerifyBatches.BlockPosition, event.VerifyBatches.RollupID-1, event.VerifyBatches.ExitRoot.String()) - newRoot, err := p.rollupExitTree.UpsertLeaf(tx, block.Num, event.VerifyBatches.BlockPosition, treeTypes.Leaf{ - Index: event.VerifyBatches.RollupID - 1, - Hash: event.VerifyBatches.ExitRoot, - }) + if event.VerifyBatches != nil { + log.Debugf("handle VerifyBatches event %s", event.VerifyBatches.String()) + err = p.processVerifyBatches(tx, block.Num, event.VerifyBatches) if err != nil { - return fmt.Errorf("UpsertLeaf. err: %w", err) - } - verifyBatches := event.VerifyBatches - verifyBatches.BlockNumber = block.Num - verifyBatches.RollupExitRoot = newRoot - if err = meddler.Insert(tx, "verify_batches", verifyBatches); err != nil { - return fmt.Errorf("err: %w", err) + err = fmt.Errorf("processVerifyBatches. err: %w", err) + log.Errorf("error processing VerifyBatches: %v", err) + return err } } if event.InitL1InfoRootMap != nil { - // TODO: indicate that l1 Info tree indexes before the one on this - // event are not safe to use - log.Debugf("handle InitL1InfoRootMap event") + log.Debugf("handle InitL1InfoRootMap event %s", event.InitL1InfoRootMap.String()) err = processEventInitL1InfoRootMap(tx, block.Num, event.InitL1InfoRootMap) if err != nil { err = fmt.Errorf("initL1InfoRootMap. Err: %w", err) @@ -350,22 +337,6 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { return nil } -func processEventInitL1InfoRootMap(tx db.Txer, blockNumber uint64, event *InitL1InfoRootMap) error { - if event == nil { - return nil - } - info := &L1InfoTreeInitial{ - BlockNumber: blockNumber, - LeafCount: event.LeafCount, - L1InfoRoot: event.CurrentL1InfoRoot, - } - log.Infof("insert InitL1InfoRootMap %s ", info.String()) - if err := meddler.Insert(tx, "l1info_initial", info); err != nil { - return fmt.Errorf("err: %w", err) - } - return nil -} - func (p *processor) getLastIndex(tx db.Querier) (uint32, error) { var lastProcessedIndex uint32 row := tx.QueryRow("SELECT position FROM l1info_leaf ORDER BY block_num DESC, block_pos DESC LIMIT 1;") @@ -460,3 +431,10 @@ func (p *processor) GetInfoByGlobalExitRoot(ger common.Hash) (*L1InfoTreeLeaf, e `, ger.Hex()) return info, db.ReturnErrNotFound(err) } + +func (p *processor) getDBQuerier(tx db.Txer) db.Querier { + if tx != nil { + return tx + } + return p.db +} diff --git a/l1infotreesync/processor_initl1inforootmap.go b/l1infotreesync/processor_initl1inforootmap.go new file mode 100644 index 00000000..92732cd9 --- /dev/null +++ b/l1infotreesync/processor_initl1inforootmap.go @@ -0,0 +1,37 @@ +package l1infotreesync + +import ( + "database/sql" + "errors" + "fmt" + + "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/log" + "github.com/russross/meddler" +) + +func processEventInitL1InfoRootMap(tx db.Txer, blockNumber uint64, event *InitL1InfoRootMap) error { + if event == nil { + return nil + } + info := &L1InfoTreeInitial{ + BlockNumber: blockNumber, + LeafCount: event.LeafCount, + L1InfoRoot: event.CurrentL1InfoRoot, + } + log.Infof("insert InitL1InfoRootMap %s ", info.String()) + if err := meddler.Insert(tx, "l1info_initial", info); err != nil { + return fmt.Errorf("err: %w", err) + } + return nil +} + +// GetInitL1InfoRootMap returns the initial L1 info root map, nil if no root map has been set +func (p *processor) GetInitL1InfoRootMap(tx db.Txer) (*L1InfoTreeInitial, error) { + info := &L1InfoTreeInitial{} + err := meddler.QueryRow(p.getDBQuerier(tx), info, `SELECT block_num, leaf_count,l1_info_root FROM l1info_initial`) + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return info, err +} diff --git a/l1infotreesync/processor_verifybatches.go b/l1infotreesync/processor_verifybatches.go new file mode 100644 index 00000000..94e9419d --- /dev/null +++ b/l1infotreesync/processor_verifybatches.go @@ -0,0 +1,65 @@ +package l1infotreesync + +import ( + "errors" + "fmt" + + "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/log" + treeTypes "github.com/0xPolygon/cdk/tree/types" + "github.com/ethereum/go-ethereum/common" + "github.com/russross/meddler" +) + +func (p *processor) processVerifyBatches(tx db.Txer, blockNumber uint64, event *VerifyBatches) error { + log.Debugf("VerifyBatches: rollupExitTree.UpsertLeaf (blockNumber=%d, event=%s)", blockNumber, event.String()) + // If ExitRoot is zero if the leaf doesnt exists doesnt change the root of tree. + // if leaf already exists doesn't make sense to 'empty' the leaf, so we keep previous value + if event.ExitRoot == (common.Hash{}) { + log.Infof("skipping VerifyBatches event with empty ExitRoot (blockNumber=%d, event=%s)", blockNumber, event.String()) + return nil + } + isNewLeaf, err := p.isNewValueForrollupExitTree(tx, event) + if err != nil { + return fmt.Errorf("isNewValueForrollupExitTree. err: %w", err) + } + if !isNewLeaf { + log.Infof("skipping VerifyBatches event with same ExitRoot (blockNumber=%d, event=%s)", blockNumber, event.String()) + return nil + } + log.Infof("UpsertLeaf VerifyBatches event (blockNumber=%d, event=%s)", blockNumber, event.String()) + newRoot, err := p.rollupExitTree.UpsertLeaf(tx, blockNumber, event.BlockPosition, treeTypes.Leaf{ + Index: event.RollupID - 1, + Hash: event.ExitRoot, + }) + if err != nil { + return fmt.Errorf("error rollupExitTree.UpsertLeaf. err: %w", err) + } + verifyBatches := event + verifyBatches.BlockNumber = blockNumber + verifyBatches.RollupExitRoot = newRoot + if err = meddler.Insert(tx, "verify_batches", verifyBatches); err != nil { + return fmt.Errorf("error inserting verify_batches. err: %w", err) + } + return nil +} + +func (p *processor) isNewValueForrollupExitTree(tx db.Querier, event *VerifyBatches) (bool, error) { + currentRoot, err := p.rollupExitTree.GetLastRoot(tx) + if err != nil && errors.Is(err, db.ErrNotFound) { + // The tree is empty, so is a new value for sure + return true, nil + } + if err != nil { + return false, fmt.Errorf("error rollupExitTree.GetLastRoot. err: %w", err) + } + leaf, err := p.rollupExitTree.GetLeaf(tx, event.RollupID-1, currentRoot.Hash) + if err != nil && errors.Is(err, db.ErrNotFound) { + // The leaf doesn't exist, so is a new value + return true, nil + } + if err != nil { + return false, fmt.Errorf("error rollupExitTree.GetLeaf. err: %w", err) + } + return leaf != event.ExitRoot, nil +} diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index 6d191c4a..00736e2b 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -27,6 +27,7 @@ type globalExitRootBananaContractor interface { type l1InfoSyncer interface { GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64) (*l1infotreesync.L1InfoTreeLeaf, error) + GetInitL1InfoRootMap(ctx context.Context) (*l1infotreesync.L1InfoTreeInitial, error) } type l1Client interface { diff --git a/tree/tree.go b/tree/tree.go index 5d307e8a..0e3a0c69 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -172,8 +172,11 @@ func (t *Tree) storeRoot(tx db.Txer, root types.Root) error { } // GetLastRoot returns the last processed root -func (t *Tree) GetLastRoot(ctx context.Context) (types.Root, error) { - return t.getLastRootWithTx(t.db) +func (t *Tree) GetLastRoot(tx db.Querier) (types.Root, error) { + if tx == nil { + tx = t.db + } + return t.getLastRootWithTx(tx) } func (t *Tree) getLastRootWithTx(tx db.Querier) (types.Root, error) { @@ -223,10 +226,10 @@ func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (*types.Root return root, nil } -func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (common.Hash, error) { +func (t *Tree) GetLeaf(tx db.Querier, index uint32, root common.Hash) (common.Hash, error) { currentNodeHash := root for h := int(types.DefaultHeight - 1); h >= 0; h-- { - currentNode, err := t.getRHTNode(t.db, currentNodeHash) + currentNode, err := t.getRHTNode(tx, currentNodeHash) if err != nil { return common.Hash{}, err } diff --git a/tree/tree_test.go b/tree/tree_test.go index b5278723..e77c277f 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -2,6 +2,7 @@ package tree_test import ( "context" + "database/sql" "encoding/json" "fmt" "os" @@ -115,3 +116,12 @@ func TestMTGetProof(t *testing.T) { }) } } + +func createTreeDBForTest(t *testing.T) *sql.DB { + dbPath := "file::memory:?cache=shared" + err := migrations.RunMigrations(dbPath) + require.NoError(t, err) + treeDB, err := db.NewSQLiteDB(dbPath) + require.NoError(t, err) + return treeDB +} diff --git a/tree/updatabletree_test.go b/tree/updatabletree_test.go new file mode 100644 index 00000000..b2ddbb80 --- /dev/null +++ b/tree/updatabletree_test.go @@ -0,0 +1,50 @@ +package tree_test + +import ( + "context" + "testing" + + "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/tree" + "github.com/0xPolygon/cdk/tree/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestUpdatableTreeExploratory(t *testing.T) { + treeDB := createTreeDBForTest(t) + sut := tree.NewUpdatableTree(treeDB, "") + blockNum := uint64(1) + blockPosition := uint64(1) + leaf1 := types.Leaf{ + Index: 10, + Hash: common.HexToHash("0x123456"), + } + leaf2 := types.Leaf{ + Index: 1, + Hash: common.HexToHash("0x123478"), + } + ctx := context.TODO() + + tx, err := db.NewTx(ctx, treeDB) + require.NoError(t, err) + _, err = sut.UpsertLeaf(tx, blockNum, blockPosition, leaf1) + require.NoError(t, err) + + root2, err := sut.UpsertLeaf(tx, blockNum, blockPosition, leaf2) + require.NoError(t, err) + leaf1get, err := sut.GetLeaf(tx, leaf1.Index, root2) + require.NoError(t, err) + require.Equal(t, leaf1.Hash, leaf1get) + // If a leaf dont exist return 'not found' error + _, err = sut.GetLeaf(tx, 99, root2) + require.ErrorIs(t, err, db.ErrNotFound) + leaf99 := types.Leaf{ + Index: 99, + Hash: common.Hash{}, // 0x00000 + } + + _, err = sut.UpsertLeaf(tx, blockNum, blockPosition, leaf99) + require.Error(t, err, "insert 0x000 doesnt change root and return UNIQUE constraint failed: root.hash") + +} From d66a8a6f2f41dd9c5c84b25a4229ae9071a7b2a6 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:06:36 +0200 Subject: [PATCH 06/40] fix: redo mocks, fix lints --- bridgesync/mock_l2_test.go | 24 +++++++- l1infotreesync/downloader.go | 3 +- l1infotreesync/mock_reorgdetector_test.go | 2 +- l1infotreesync/processor.go | 6 +- l1infotreesync/processor_test.go | 1 - reorgdetector/mock_eth_client.go | 2 +- .../mocks_txbuilder/l1_info_syncer.go | 58 +++++++++++++++++++ sync/mock_downloader_test.go | 2 +- sync/mock_l2_test.go | 2 +- sync/mock_processor_test.go | 2 +- sync/mock_reorgdetector_test.go | 2 +- test/helpers/mock_ethtxmanager.go | 2 +- tree/tree_test.go | 7 ++- tree/updatabletree_test.go | 1 - 14 files changed, 98 insertions(+), 16 deletions(-) diff --git a/bridgesync/mock_l2_test.go b/bridgesync/mock_l2_test.go index a8f33ef8..adbff51f 100644 --- a/bridgesync/mock_l2_test.go +++ b/bridgesync/mock_l2_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package bridgesync @@ -12,6 +12,8 @@ import ( mock "github.com/stretchr/testify/mock" + rpc "github.com/ethereum/go-ethereum/rpc" + types "github.com/ethereum/go-ethereum/core/types" ) @@ -138,6 +140,26 @@ func (_m *L2Mock) CallContract(ctx context.Context, call ethereum.CallMsg, block return r0, r1 } +// Client provides a mock function with given fields: +func (_m *L2Mock) Client() *rpc.Client { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Client") + } + + var r0 *rpc.Client + if rf, ok := ret.Get(0).(func() *rpc.Client); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.Client) + } + } + + return r0 +} + // CodeAt provides a mock function with given fields: ctx, contract, blockNumber func (_m *L2Mock) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, contract, blockNumber) diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index ac082ad7..edd60614 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -33,7 +33,8 @@ type EthClienter interface { bind.ContractBackend } -func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address) (*polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, +func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address) ( + *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, *polygonrollupmanager.Polygonrollupmanager, error) { gerContract, err := polygonzkevmglobalexitrootv2.NewPolygonzkevmglobalexitrootv2(globalExitRoot, client) diff --git a/l1infotreesync/mock_reorgdetector_test.go b/l1infotreesync/mock_reorgdetector_test.go index 8255443e..18ac7bc8 100644 --- a/l1infotreesync/mock_reorgdetector_test.go +++ b/l1infotreesync/mock_reorgdetector_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package l1infotreesync diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 30eac3ef..7fcc115c 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -54,8 +54,10 @@ type VerifyBatches struct { } func (v *VerifyBatches) String() string { - return fmt.Sprintf("BlockNumber: %d, BlockPosition: %d, RollupID: %d, NumBatch: %d, StateRoot: %s, ExitRoot: %s, Aggregator: %s, RollupExitRoot: %s", - v.BlockNumber, v.BlockPosition, v.RollupID, v.NumBatch, v.StateRoot.String(), v.ExitRoot.String(), v.Aggregator.String(), v.RollupExitRoot.String()) + return fmt.Sprintf("BlockNumber: %d, BlockPosition: %d, RollupID: %d, NumBatch: %d, StateRoot: %s, "+ + "ExitRoot: %s, Aggregator: %s, RollupExitRoot: %s", + v.BlockNumber, v.BlockPosition, v.RollupID, v.NumBatch, v.StateRoot.String(), + v.ExitRoot.String(), v.Aggregator.String(), v.RollupExitRoot.String()) } type InitL1InfoRootMap struct { diff --git a/l1infotreesync/processor_test.go b/l1infotreesync/processor_test.go index 59d84ad0..bb906565 100644 --- a/l1infotreesync/processor_test.go +++ b/l1infotreesync/processor_test.go @@ -200,7 +200,6 @@ func TestInitL1InfoRootMap(t *testing.T) { require.Equal(t, event.LeafCount, info.LeafCount) require.Equal(t, event.CurrentL1InfoRoot, info.L1InfoRoot) require.Equal(t, block.Num, info.BlockNumber) - } func TestInitL1InfoRootMapDontAllow2Rows(t *testing.T) { diff --git a/reorgdetector/mock_eth_client.go b/reorgdetector/mock_eth_client.go index a76c62f9..0c561ab3 100644 --- a/reorgdetector/mock_eth_client.go +++ b/reorgdetector/mock_eth_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package reorgdetector diff --git a/sequencesender/txbuilder/mocks_txbuilder/l1_info_syncer.go b/sequencesender/txbuilder/mocks_txbuilder/l1_info_syncer.go index 65bf9394..12d641a8 100644 --- a/sequencesender/txbuilder/mocks_txbuilder/l1_info_syncer.go +++ b/sequencesender/txbuilder/mocks_txbuilder/l1_info_syncer.go @@ -22,6 +22,64 @@ func (_m *L1InfoSyncer) EXPECT() *L1InfoSyncer_Expecter { return &L1InfoSyncer_Expecter{mock: &_m.Mock} } +// GetInitL1InfoRootMap provides a mock function with given fields: ctx +func (_m *L1InfoSyncer) GetInitL1InfoRootMap(ctx context.Context) (*l1infotreesync.L1InfoTreeInitial, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetInitL1InfoRootMap") + } + + var r0 *l1infotreesync.L1InfoTreeInitial + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*l1infotreesync.L1InfoTreeInitial, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *l1infotreesync.L1InfoTreeInitial); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*l1infotreesync.L1InfoTreeInitial) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// L1InfoSyncer_GetInitL1InfoRootMap_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInitL1InfoRootMap' +type L1InfoSyncer_GetInitL1InfoRootMap_Call struct { + *mock.Call +} + +// GetInitL1InfoRootMap is a helper method to define mock.On call +// - ctx context.Context +func (_e *L1InfoSyncer_Expecter) GetInitL1InfoRootMap(ctx interface{}) *L1InfoSyncer_GetInitL1InfoRootMap_Call { + return &L1InfoSyncer_GetInitL1InfoRootMap_Call{Call: _e.mock.On("GetInitL1InfoRootMap", ctx)} +} + +func (_c *L1InfoSyncer_GetInitL1InfoRootMap_Call) Run(run func(ctx context.Context)) *L1InfoSyncer_GetInitL1InfoRootMap_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *L1InfoSyncer_GetInitL1InfoRootMap_Call) Return(_a0 *l1infotreesync.L1InfoTreeInitial, _a1 error) *L1InfoSyncer_GetInitL1InfoRootMap_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *L1InfoSyncer_GetInitL1InfoRootMap_Call) RunAndReturn(run func(context.Context) (*l1infotreesync.L1InfoTreeInitial, error)) *L1InfoSyncer_GetInitL1InfoRootMap_Call { + _c.Call.Return(run) + return _c +} + // GetLatestInfoUntilBlock provides a mock function with given fields: ctx, blockNum func (_m *L1InfoSyncer) GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64) (*l1infotreesync.L1InfoTreeLeaf, error) { ret := _m.Called(ctx, blockNum) diff --git a/sync/mock_downloader_test.go b/sync/mock_downloader_test.go index c965efb6..33bd6df4 100644 --- a/sync/mock_downloader_test.go +++ b/sync/mock_downloader_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package sync diff --git a/sync/mock_l2_test.go b/sync/mock_l2_test.go index 78d75191..7a4bae36 100644 --- a/sync/mock_l2_test.go +++ b/sync/mock_l2_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package sync diff --git a/sync/mock_processor_test.go b/sync/mock_processor_test.go index 8e562e9b..afbb34cb 100644 --- a/sync/mock_processor_test.go +++ b/sync/mock_processor_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package sync diff --git a/sync/mock_reorgdetector_test.go b/sync/mock_reorgdetector_test.go index 52cd0cd0..9689f7e7 100644 --- a/sync/mock_reorgdetector_test.go +++ b/sync/mock_reorgdetector_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package sync diff --git a/test/helpers/mock_ethtxmanager.go b/test/helpers/mock_ethtxmanager.go index 848992f4..4dd103af 100644 --- a/test/helpers/mock_ethtxmanager.go +++ b/test/helpers/mock_ethtxmanager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.40.1. DO NOT EDIT. +// Code generated by mockery v2.39.0. DO NOT EDIT. package helpers diff --git a/tree/tree_test.go b/tree/tree_test.go index e77c277f..f8fd6b93 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -52,7 +52,7 @@ func TestMTAddLeaf(t *testing.T) { } require.NoError(t, tx.Commit()) if len(testVector.ExistingLeaves) > 0 { - root, err := merkletree.GetLastRoot(ctx) + root, err := merkletree.GetLastRoot(nil) require.NoError(t, err) require.Equal(t, common.HexToHash(testVector.CurrentRoot), root.Hash) } @@ -67,7 +67,7 @@ func TestMTAddLeaf(t *testing.T) { require.NoError(t, err) require.NoError(t, tx.Commit()) - root, err := merkletree.GetLastRoot(ctx) + root, err := merkletree.GetLastRoot(nil) require.NoError(t, err) require.Equal(t, common.HexToHash(testVector.NewRoot), root.Hash) }) @@ -103,7 +103,7 @@ func TestMTGetProof(t *testing.T) { } require.NoError(t, tx.Commit()) - root, err := tre.GetLastRoot(ctx) + root, err := tre.GetLastRoot(nil) require.NoError(t, err) expectedRoot := common.HexToHash(testVector.ExpectedRoot) require.Equal(t, expectedRoot, root.Hash) @@ -118,6 +118,7 @@ func TestMTGetProof(t *testing.T) { } func createTreeDBForTest(t *testing.T) *sql.DB { + t.Helper() dbPath := "file::memory:?cache=shared" err := migrations.RunMigrations(dbPath) require.NoError(t, err) diff --git a/tree/updatabletree_test.go b/tree/updatabletree_test.go index b2ddbb80..a684fd0e 100644 --- a/tree/updatabletree_test.go +++ b/tree/updatabletree_test.go @@ -46,5 +46,4 @@ func TestUpdatableTreeExploratory(t *testing.T) { _, err = sut.UpsertLeaf(tx, blockNum, blockPosition, leaf99) require.Error(t, err, "insert 0x000 doesnt change root and return UNIQUE constraint failed: root.hash") - } From a52d4029233e2ba0ae45e442b7f3d1398d5a206e Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:14:38 +0200 Subject: [PATCH 07/40] fix: disable sanity check over contract address because breaks some unittest --- l1infotreesync/downloader.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index edd60614..76d13c78 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -33,7 +33,7 @@ type EthClienter interface { bind.ContractBackend } -func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address) ( +func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address, doSanityCheck bool) ( *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, *polygonrollupmanager.Polygonrollupmanager, error) { @@ -46,22 +46,23 @@ func createContracts(client EthClienter, globalExitRoot, rollupManager common.Ad if err != nil { return nil, nil, err } - - depositCount, err := gerContract.DepositCount(nil) - if err != nil { - return nil, nil, fmt.Errorf("fail sanity check GlobalExitRoot(%s) Contract. Err: %w", globalExitRoot.String(), err) - } - log.Debugf("sanity check GlobalExitRoot OK. DepositCount: %v", depositCount) - bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) - if err != nil { - return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) + if doSanityCheck { + depositCount, err := gerContract.DepositCount(nil) + if err != nil { + return nil, nil, fmt.Errorf("fail sanity check GlobalExitRoot(%s) Contract. Err: %w", globalExitRoot.String(), err) + } + log.Debugf("sanity check GlobalExitRoot OK. DepositCount: %v", depositCount) + bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) + if err != nil { + return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) + } + log.Debugf("sanity check rollupManager OK. bridgeAddr: %s", bridgeAddr.String()) } - log.Debugf("sanity check rollupManager OK. bridgeAddr: %s", bridgeAddr.String()) return gerContract, rollupManagerContract, nil } func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Address) (sync.LogAppenderMap, error) { - ger, rm, err := createContracts(client, globalExitRoot, rollupManager) + ger, rm, err := createContracts(client, globalExitRoot, rollupManager, false) if err != nil { return nil, fmt.Errorf("buildAppender: fails contracts creation. Err:%w", err) } From 3261e787cce822a94ff7d5513ccb5b4ca5ec7ba2 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:22:05 +0200 Subject: [PATCH 08/40] fix: unittest --- l1infotreesync/processor_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/l1infotreesync/processor_test.go b/l1infotreesync/processor_test.go index bb906565..2837c987 100644 --- a/l1infotreesync/processor_test.go +++ b/l1infotreesync/processor_test.go @@ -176,7 +176,7 @@ func TestGetInfo(t *testing.T) { } func TestInitL1InfoRootMap(t *testing.T) { - dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" + dbPath := "file:TestInitL1InfoRootMap?mode=memory&cache=shared" sut, err := newProcessor(dbPath) require.NoError(t, err) ctx := context.TODO() @@ -203,7 +203,7 @@ func TestInitL1InfoRootMap(t *testing.T) { } func TestInitL1InfoRootMapDontAllow2Rows(t *testing.T) { - dbPath := "file:test?mode=memory&cache=shared" + dbPath := "file:TestInitL1InfoRootMapDontAllow2Rows?mode=memory&cache=shared" sut, err := newProcessor(dbPath) require.NoError(t, err) ctx := context.TODO() @@ -224,7 +224,7 @@ func TestInitL1InfoRootMapDontAllow2Rows(t *testing.T) { } func TestGetInitL1InfoRootMap(t *testing.T) { - dbPath := "file:test?mode=memory&cache=shared" + dbPath := "file:TestGetInitL1InfoRootMap?mode=memory&cache=shared" sut, err := newProcessor(dbPath) require.NoError(t, err) info, err := sut.GetInitL1InfoRootMap(nil) From 03a66c344c6f6cff115329c280ff590a64293816 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:09:22 +0200 Subject: [PATCH 09/40] fix: unittest --- l1infotreesync/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 146c1924..4127fa33 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -171,7 +171,7 @@ func TestStressAndReorgs(t *testing.T) { ) ctx := context.Background() - dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") + dbPathSyncer := path.Join(t.TempDir(), "file:TestStressAndReorgs:memory:?cache=shared") dbPathReorg := t.TempDir() privateKey, err := crypto.GenerateKey() require.NoError(t, err) From a68a93920d4790141bd36ff2ca58ba64cfcb00d3 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:25:31 +0200 Subject: [PATCH 10/40] fix: relax check address allowing emtpy addr for rollup --- l1infotreesync/downloader.go | 16 +++++++++++----- l1infotreesync/e2e_test.go | 4 ++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index 76d13c78..51c6cfd4 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -52,17 +52,22 @@ func createContracts(client EthClienter, globalExitRoot, rollupManager common.Ad return nil, nil, fmt.Errorf("fail sanity check GlobalExitRoot(%s) Contract. Err: %w", globalExitRoot.String(), err) } log.Debugf("sanity check GlobalExitRoot OK. DepositCount: %v", depositCount) - bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) - if err != nil { - return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) + zeroAddr := common.Address{} + if rollupManager != zeroAddr { + bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) + if err != nil { + return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) + } + log.Debugf("sanity check rollupManager OK. bridgeAddr: %s", bridgeAddr.String()) + } else { + log.Warnf("RollupManager contract addr not set. Skipping sanity check. No VerifyBatches events expected") } - log.Debugf("sanity check rollupManager OK. bridgeAddr: %s", bridgeAddr.String()) } return gerContract, rollupManagerContract, nil } func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Address) (sync.LogAppenderMap, error) { - ger, rm, err := createContracts(client, globalExitRoot, rollupManager, false) + ger, rm, err := createContracts(client, globalExitRoot, rollupManager, true) if err != nil { return nil, fmt.Errorf("buildAppender: fails contracts creation. Err:%w", err) } @@ -115,6 +120,7 @@ func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Addr return nil } + // This event is comming from RollupManager appender[verifyBatchesSignature] = func(b *sync.EVMBlock, l types.Log) error { verifyBatches, err := rm.ParseVerifyBatches(l) if err != nil { diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 4127fa33..673ec67c 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -78,9 +78,9 @@ func TestE2E(t *testing.T) { rdm := l1infotreesync.NewReorgDetectorMock(t) rdm.On("Subscribe", mock.Anything).Return(&reorgdetector.Subscription{}, nil) rdm.On("AddBlockToTrack", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - client, gerAddr, verifyAddr, gerSc, verifySC, err := newSimulatedClient(auth) + client, gerAddr, _, gerSc, verifySC, err := newSimulatedClient(auth) require.NoError(t, err) - syncer, err := l1infotreesync.New(ctx, dbPath, gerAddr, verifyAddr, 10, etherman.LatestBlock, rdm, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) + syncer, err := l1infotreesync.New(ctx, dbPath, gerAddr, common.Address{}, 10, etherman.LatestBlock, rdm, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) require.NoError(t, err) go syncer.Start(ctx) From 7043ef996834cca8674688eb219884f61055ca42 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:52:43 +0200 Subject: [PATCH 11/40] fix: relax rollupmanager checker --- l1infotreesync/downloader.go | 33 +++++++++++++++++++++++++++++---- l1infotreesync/e2e_test.go | 4 ++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index 51c6cfd4..b8b15599 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -1,6 +1,7 @@ package l1infotreesync import ( + "context" "fmt" "github.com/0xPolygon/cdk-contracts-tooling/contracts/banana/polygonzkevmglobalexitrootv2" @@ -33,6 +34,26 @@ type EthClienter interface { bind.ContractBackend } +func checkAddrIsContract(client EthClienter, addr common.Address) error { + code, err := client.CodeAt(context.Background(), addr, nil) + if err != nil { + return err + } + if len(code) == 0 { + return fmt.Errorf("address %s is not a contract", addr.String()) + } + return nil +} + +func checkSMCIsRollupManager(client EthClienter, rollupManagerAddr common.Address, rollupManagerContract *polygonrollupmanager.Polygonrollupmanager) error { + bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) + if err != nil { + return fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManagerAddr.String(), err) + } + log.Debugf("sanity check rollupManager (%s) OK. bridgeAddr: %s", rollupManagerAddr.String(), bridgeAddr.String()) + return nil +} + func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address, doSanityCheck bool) ( *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, *polygonrollupmanager.Polygonrollupmanager, @@ -54,11 +75,15 @@ func createContracts(client EthClienter, globalExitRoot, rollupManager common.Ad log.Debugf("sanity check GlobalExitRoot OK. DepositCount: %v", depositCount) zeroAddr := common.Address{} if rollupManager != zeroAddr { - bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) + err := checkSMCIsRollupManager(client, rollupManager, rollupManagerContract) if err != nil { - return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) + log.Warnf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) + err = checkAddrIsContract(client, rollupManager) + if err != nil { + return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract addr doesnt contain any contract. Err: %w", rollupManager.String(), err) + } + log.Warnf("RollupManager(%s) is not the expected RollupManager but it is a contract", rollupManager.String()) } - log.Debugf("sanity check rollupManager OK. bridgeAddr: %s", bridgeAddr.String()) } else { log.Warnf("RollupManager contract addr not set. Skipping sanity check. No VerifyBatches events expected") } @@ -120,7 +145,7 @@ func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Addr return nil } - // This event is comming from RollupManager + // This event is coming from RollupManager appender[verifyBatchesSignature] = func(b *sync.EVMBlock, l types.Log) error { verifyBatches, err := rm.ParseVerifyBatches(l) if err != nil { diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 673ec67c..4127fa33 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -78,9 +78,9 @@ func TestE2E(t *testing.T) { rdm := l1infotreesync.NewReorgDetectorMock(t) rdm.On("Subscribe", mock.Anything).Return(&reorgdetector.Subscription{}, nil) rdm.On("AddBlockToTrack", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - client, gerAddr, _, gerSc, verifySC, err := newSimulatedClient(auth) + client, gerAddr, verifyAddr, gerSc, verifySC, err := newSimulatedClient(auth) require.NoError(t, err) - syncer, err := l1infotreesync.New(ctx, dbPath, gerAddr, common.Address{}, 10, etherman.LatestBlock, rdm, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) + syncer, err := l1infotreesync.New(ctx, dbPath, gerAddr, verifyAddr, 10, etherman.LatestBlock, rdm, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) require.NoError(t, err) go syncer.Start(ctx) From 62847456b2271d7ccdf4277cc9ff1ad9dd45a9ba Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:58:21 +0200 Subject: [PATCH 12/40] fix: lint --- l1infotreesync/downloader.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index b8b15599..b5d817bb 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -45,7 +45,8 @@ func checkAddrIsContract(client EthClienter, addr common.Address) error { return nil } -func checkSMCIsRollupManager(client EthClienter, rollupManagerAddr common.Address, rollupManagerContract *polygonrollupmanager.Polygonrollupmanager) error { +func checkSMCIsRollupManager(rollupManagerAddr common.Address, + rollupManagerContract *polygonrollupmanager.Polygonrollupmanager) error { bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) if err != nil { return fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManagerAddr.String(), err) @@ -75,12 +76,13 @@ func createContracts(client EthClienter, globalExitRoot, rollupManager common.Ad log.Debugf("sanity check GlobalExitRoot OK. DepositCount: %v", depositCount) zeroAddr := common.Address{} if rollupManager != zeroAddr { - err := checkSMCIsRollupManager(client, rollupManager, rollupManagerContract) + err := checkSMCIsRollupManager(rollupManager, rollupManagerContract) if err != nil { log.Warnf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) err = checkAddrIsContract(client, rollupManager) if err != nil { - return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) Contract addr doesnt contain any contract. Err: %w", rollupManager.String(), err) + return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) "+ + "Contract addr doesnt contain any contract. Err: %w", rollupManager.String(), err) } log.Warnf("RollupManager(%s) is not the expected RollupManager but it is a contract", rollupManager.String()) } From 2872d2fc828d8c6a270a59cf0b195ed227b8b9a3 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:38:42 +0200 Subject: [PATCH 13/40] fix: add a param to avoid checking contracts --- cmd/run.go | 1 + l1infotreesync/downloader.go | 69 +++++++++++++++----------------- l1infotreesync/e2e_test.go | 6 ++- l1infotreesync/l1infotreesync.go | 8 +++- test/helpers/aggoracle_e2e.go | 3 +- 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 4e5100dd..68f4acdd 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -492,6 +492,7 @@ func runL1InfoTreeSyncerIfNeeded( cfg.L1InfoTreeSync.InitialBlock, cfg.L1InfoTreeSync.RetryAfterErrorPeriod.Duration, cfg.L1InfoTreeSync.MaxRetryAttemptsAfterError, + l1infotreesync.FlagNone, ) if err != nil { log.Fatal(err) diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index b5d817bb..628e1ac5 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -1,7 +1,6 @@ package l1infotreesync import ( - "context" "fmt" "github.com/0xPolygon/cdk-contracts-tooling/contracts/banana/polygonzkevmglobalexitrootv2" @@ -34,28 +33,40 @@ type EthClienter interface { bind.ContractBackend } -func checkAddrIsContract(client EthClienter, addr common.Address) error { - code, err := client.CodeAt(context.Background(), addr, nil) +func checkSMCIsRollupManager(rollupManagerAddr common.Address, + rollupManagerContract *polygonrollupmanager.Polygonrollupmanager) error { + bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) if err != nil { - return err + return fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManagerAddr.String(), err) } - if len(code) == 0 { - return fmt.Errorf("address %s is not a contract", addr.String()) + log.Infof("sanity check rollupManager(%s) OK. bridgeAddr: %s", rollupManagerAddr.String(), bridgeAddr.String()) + return nil +} + +func checkSMCIsGlobalExitRoot(globalExitRootAddr common.Address, gerContract *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2) error { + depositCount, err := gerContract.DepositCount(nil) + if err != nil { + return fmt.Errorf("fail sanity check GlobalExitRoot(%s) Contract. Err: %w", globalExitRootAddr.String(), err) } + log.Infof("sanity check GlobalExitRoot(%s) OK. DepositCount: %v", globalExitRootAddr.String(), depositCount) return nil } -func checkSMCIsRollupManager(rollupManagerAddr common.Address, +func sanityCheckContracts(globalExitRoot, rollupManager common.Address, + gerContract *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, rollupManagerContract *polygonrollupmanager.Polygonrollupmanager) error { - bridgeAddr, err := rollupManagerContract.BridgeAddress(nil) - if err != nil { - return fmt.Errorf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManagerAddr.String(), err) + + errGER := checkSMCIsGlobalExitRoot(globalExitRoot, gerContract) + errRollup := checkSMCIsRollupManager(rollupManager, rollupManagerContract) + if errGER != nil || errRollup != nil { + err := fmt.Errorf("sanityCheckContracts: fails sanity check contracts. ErrGER: %w, ErrRollup: %w", errGER, errRollup) + log.Error(err) + return err } - log.Debugf("sanity check rollupManager (%s) OK. bridgeAddr: %s", rollupManagerAddr.String(), bridgeAddr.String()) return nil } -func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address, doSanityCheck bool) ( +func createContracts(client EthClienter, globalExitRoot, rollupManager common.Address) ( *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, *polygonrollupmanager.Polygonrollupmanager, error) { @@ -68,35 +79,19 @@ func createContracts(client EthClienter, globalExitRoot, rollupManager common.Ad if err != nil { return nil, nil, err } - if doSanityCheck { - depositCount, err := gerContract.DepositCount(nil) - if err != nil { - return nil, nil, fmt.Errorf("fail sanity check GlobalExitRoot(%s) Contract. Err: %w", globalExitRoot.String(), err) - } - log.Debugf("sanity check GlobalExitRoot OK. DepositCount: %v", depositCount) - zeroAddr := common.Address{} - if rollupManager != zeroAddr { - err := checkSMCIsRollupManager(rollupManager, rollupManagerContract) - if err != nil { - log.Warnf("fail sanity check RollupManager(%s) Contract. Err: %w", rollupManager.String(), err) - err = checkAddrIsContract(client, rollupManager) - if err != nil { - return nil, nil, fmt.Errorf("fail sanity check RollupManager(%s) "+ - "Contract addr doesnt contain any contract. Err: %w", rollupManager.String(), err) - } - log.Warnf("RollupManager(%s) is not the expected RollupManager but it is a contract", rollupManager.String()) - } - } else { - log.Warnf("RollupManager contract addr not set. Skipping sanity check. No VerifyBatches events expected") - } - } return gerContract, rollupManagerContract, nil } -func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Address) (sync.LogAppenderMap, error) { - ger, rm, err := createContracts(client, globalExitRoot, rollupManager, true) +func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Address, flags CreationFlags) (sync.LogAppenderMap, error) { + ger, rm, err := createContracts(client, globalExitRoot, rollupManager) if err != nil { - return nil, fmt.Errorf("buildAppender: fails contracts creation. Err:%w", err) + err := fmt.Errorf("buildAppender: fails contracts creation. Err:%w", err) + log.Error(err) + return nil, err + } + err = sanityCheckContracts(globalExitRoot, rollupManager, ger, rm) + if err != nil && flags&FlagAllowWrongContractsAddrs == 0 { + return nil, fmt.Errorf("buildAppender: fails sanity check contracts. Err:%w", err) } appender := make(sync.LogAppenderMap) diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 4127fa33..12e00103 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -80,7 +80,8 @@ func TestE2E(t *testing.T) { rdm.On("AddBlockToTrack", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) client, gerAddr, verifyAddr, gerSc, verifySC, err := newSimulatedClient(auth) require.NoError(t, err) - syncer, err := l1infotreesync.New(ctx, dbPath, gerAddr, verifyAddr, 10, etherman.LatestBlock, rdm, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) + syncer, err := l1infotreesync.New(ctx, dbPath, gerAddr, verifyAddr, 10, etherman.LatestBlock, rdm, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3, + l1infotreesync.FlagAllowWrongContractsAddrs) require.NoError(t, err) go syncer.Start(ctx) @@ -182,7 +183,8 @@ func TestStressAndReorgs(t *testing.T) { rd, err := reorgdetector.New(client.Client(), reorgdetector.Config{DBPath: dbPathReorg, CheckReorgsInterval: cdktypes.NewDuration(time.Millisecond * 100)}) require.NoError(t, err) require.NoError(t, rd.Start(ctx)) - syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerAddr, verifyAddr, 10, etherman.LatestBlock, rd, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) + syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerAddr, verifyAddr, 10, etherman.LatestBlock, rd, client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3, + l1infotreesync.FlagAllowWrongContractsAddrs) require.NoError(t, err) go syncer.Start(ctx) diff --git a/l1infotreesync/l1infotreesync.go b/l1infotreesync/l1infotreesync.go index cd9ebf5c..a58be215 100644 --- a/l1infotreesync/l1infotreesync.go +++ b/l1infotreesync/l1infotreesync.go @@ -12,9 +12,14 @@ import ( "github.com/ethereum/go-ethereum/common" ) +type CreationFlags uint64 + const ( reorgDetectorID = "l1infotreesync" downloadBufferSize = 1000 + // CreationFlags defitinion + FlagNone CreationFlags = 0 + FlagAllowWrongContractsAddrs CreationFlags = 1 << iota // Allow to set wrong contracts addresses ) type L1InfoTreeSync struct { @@ -36,6 +41,7 @@ func New( initialBlock uint64, retryAfterErrorPeriod time.Duration, maxRetryAttemptsAfterError int, + flags CreationFlags, ) (*L1InfoTreeSync, error) { processor, err := newProcessor(dbPath) if err != nil { @@ -59,7 +65,7 @@ func New( MaxRetryAttemptsAfterError: maxRetryAttemptsAfterError, } - appender, err := buildAppender(l1Client, globalExitRoot, rollupManager) + appender, err := buildAppender(l1Client, globalExitRoot, rollupManager, flags) if err != nil { return nil, err } diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index 8b5073fb..125d73cf 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -117,7 +117,8 @@ func CommonSetup(t *testing.T) ( require.NoError(t, err) // Syncer dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") - syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, syncBlockChunkSize, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, periodRetry, retries) + syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, syncBlockChunkSize, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, periodRetry, retries, + l1infotreesync.FlagAllowWrongContractsAddrs) require.NoError(t, err) go syncer.Start(ctx) From 6bd937a1b301786bf4520515f0ea4752246a91ac Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:00:16 +0200 Subject: [PATCH 14/40] feat: add coverage --- l1infotreesync/downloader_test.go | 31 +++++++++++++++++++++++++++ test/Makefile | 35 ++++++++++++++++++------------- 2 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 l1infotreesync/downloader_test.go diff --git a/l1infotreesync/downloader_test.go b/l1infotreesync/downloader_test.go new file mode 100644 index 00000000..d81f8d7c --- /dev/null +++ b/l1infotreesync/downloader_test.go @@ -0,0 +1,31 @@ +package l1infotreesync + +import ( + "fmt" + "testing" + + mocks_l1infotreesync "github.com/0xPolygon/cdk/l1infotreesync/mocks" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestBuildAppenderErrorOnBadContractAddr(t *testing.T) { + l1Client := mocks_l1infotreesync.NewEthClienter(t) + globalExitRoot := common.HexToAddress("0x1") + rollupManager := common.HexToAddress("0x2") + l1Client.EXPECT().CallContract(mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("test-error")) + flags := FlagNone + _, err := buildAppender(l1Client, globalExitRoot, rollupManager, flags) + require.Error(t, err) +} + +func TestBuildAppenderBypassBadContractAddr(t *testing.T) { + l1Client := mocks_l1infotreesync.NewEthClienter(t) + globalExitRoot := common.HexToAddress("0x1") + rollupManager := common.HexToAddress("0x2") + l1Client.EXPECT().CallContract(mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("test-error")) + flags := FlagAllowWrongContractsAddrs + _, err := buildAppender(l1Client, globalExitRoot, rollupManager, flags) + require.NoError(t, err) +} diff --git a/test/Makefile b/test/Makefile index 0864b8d2..4833f214 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,5 +1,5 @@ .PHONY: generate-mocks -generate-mocks: generate-mocks-bridgesync generate-mocks-reorgdetector generate-mocks-sequencesender generate-mocks-da generate-mocks-l1infotreesync generate-mocks-helpers generate-mocks-sync +generate-mocks: generate-mocks-bridgesync generate-mocks-reorgdetector generate-mocks-sequencesender generate-mocks-da generate-mocks-l1infotreesync generate-mocks-helpers generate-mocks-sync generate-mocks-l1infotreesync .PHONY: generate-mocks-bridgesync @@ -26,6 +26,25 @@ generate-mocks-rpc: ## Generates mocks for rpc, using mockery tool rm -Rf ../rpc/mocks export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --all --case snake --dir ../rpc --output ../rpc/mocks --outpkg mocks ${COMMON_MOCKERY_PARAMS} +.PHONY: generate-mocks-l1infotreesync +generate-mocks-l1infotreesync: ## Generates mocks for l1infotreesync, using mockery tool + rm -Rf ../l1infotreesync/mocks + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --all --case snake --dir ../l1infotreesync --output ../l1infotreesync/mocks --outpkg mocks_l1infotreesync ${COMMON_MOCKERY_PARAMS} + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ReorgDetector --dir=../sync --output=../l1infotreesync --outpkg=l1infotreesync --structname=ReorgDetectorMock --filename=mock_reorgdetector_test.go + + + +.PHONY: generate-mocks-aggoracle +generate-mocks-helpers: ## Generates mocks for helpers , using mockery tool + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthTxManager --dir=../aggoracle/chaingersender --output=./helpers --outpkg=helpers --structname=EthTxManagerMock --filename=mock_ethtxmanager.go + +.PHONY: generate-mocks-sync +generate-mocks-sync: ## Generates mocks for sync, using mockery tool + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthClienter --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=L2Mock --filename=mock_l2_test.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=evmDownloaderFull --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=EVMDownloaderMock --filename=mock_downloader_test.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=processorInterface --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=ProcessorMock --filename=mock_processor_test.go + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ReorgDetector --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=ReorgDetectorMock --filename=mock_reorgdetector_test.go + .PHONY: test-e2e-elderberry-validium test-e2e-elderberry-validium: stop ## Runs e2e tests checking elderberry/validium @@ -52,17 +71,3 @@ help: ## Prints this help @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ | sort \ | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -.PHONY: generate-mocks-l1infotreesync -generate-mocks-l1infotreesync: ## Generates mocks for l1infotreesync , using mockery tool - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ReorgDetector --dir=../sync --output=../l1infotreesync --outpkg=l1infotreesync --structname=ReorgDetectorMock --filename=mock_reorgdetector_test.go - -.PHONY: generate-mocks-aggoracle -generate-mocks-helpers: ## Generates mocks for helpers , using mockery tool - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthTxManager --dir=../aggoracle/chaingersender --output=./helpers --outpkg=helpers --structname=EthTxManagerMock --filename=mock_ethtxmanager.go - -.PHONY: generate-mocks-sync -generate-mocks-sync: ## Generates mocks for sync, using mockery tool - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=EthClienter --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=L2Mock --filename=mock_l2_test.go - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=evmDownloaderFull --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=EVMDownloaderMock --filename=mock_downloader_test.go - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=processorInterface --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=ProcessorMock --filename=mock_processor_test.go - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/mockery --name=ReorgDetector --dir=../sync --output=../sync --outpkg=sync --inpackage --structname=ReorgDetectorMock --filename=mock_reorgdetector_test.go From 16509ce711e2556b5c7b74412ff235037fc29e35 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:17:22 +0200 Subject: [PATCH 15/40] test: add mocks --- l1infotreesync/mocks/eth_clienter.go | 1086 ++++++++++++++++++++++++++ 1 file changed, 1086 insertions(+) create mode 100644 l1infotreesync/mocks/eth_clienter.go diff --git a/l1infotreesync/mocks/eth_clienter.go b/l1infotreesync/mocks/eth_clienter.go new file mode 100644 index 00000000..270c40d9 --- /dev/null +++ b/l1infotreesync/mocks/eth_clienter.go @@ -0,0 +1,1086 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks_l1infotreesync + +import ( + context "context" + big "math/big" + + common "github.com/ethereum/go-ethereum/common" + + ethereum "github.com/ethereum/go-ethereum" + + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" +) + +// EthClienter is an autogenerated mock type for the EthClienter type +type EthClienter struct { + mock.Mock +} + +type EthClienter_Expecter struct { + mock *mock.Mock +} + +func (_m *EthClienter) EXPECT() *EthClienter_Expecter { + return &EthClienter_Expecter{mock: &_m.Mock} +} + +// BlockByHash provides a mock function with given fields: ctx, hash +func (_m *EthClienter) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { + ret := _m.Called(ctx, hash) + + if len(ret) == 0 { + panic("no return value specified for BlockByHash") + } + + var r0 *types.Block + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Block, error)); ok { + return rf(ctx, hash) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) *types.Block); ok { + r0 = rf(ctx, hash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Block) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + r1 = rf(ctx, hash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_BlockByHash_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockByHash' +type EthClienter_BlockByHash_Call struct { + *mock.Call +} + +// BlockByHash is a helper method to define mock.On call +// - ctx context.Context +// - hash common.Hash +func (_e *EthClienter_Expecter) BlockByHash(ctx interface{}, hash interface{}) *EthClienter_BlockByHash_Call { + return &EthClienter_BlockByHash_Call{Call: _e.mock.On("BlockByHash", ctx, hash)} +} + +func (_c *EthClienter_BlockByHash_Call) Run(run func(ctx context.Context, hash common.Hash)) *EthClienter_BlockByHash_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Hash)) + }) + return _c +} + +func (_c *EthClienter_BlockByHash_Call) Return(_a0 *types.Block, _a1 error) *EthClienter_BlockByHash_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_BlockByHash_Call) RunAndReturn(run func(context.Context, common.Hash) (*types.Block, error)) *EthClienter_BlockByHash_Call { + _c.Call.Return(run) + return _c +} + +// BlockByNumber provides a mock function with given fields: ctx, number +func (_m *EthClienter) 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 +} + +// EthClienter_BlockByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockByNumber' +type EthClienter_BlockByNumber_Call struct { + *mock.Call +} + +// BlockByNumber is a helper method to define mock.On call +// - ctx context.Context +// - number *big.Int +func (_e *EthClienter_Expecter) BlockByNumber(ctx interface{}, number interface{}) *EthClienter_BlockByNumber_Call { + return &EthClienter_BlockByNumber_Call{Call: _e.mock.On("BlockByNumber", ctx, number)} +} + +func (_c *EthClienter_BlockByNumber_Call) Run(run func(ctx context.Context, number *big.Int)) *EthClienter_BlockByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*big.Int)) + }) + return _c +} + +func (_c *EthClienter_BlockByNumber_Call) Return(_a0 *types.Block, _a1 error) *EthClienter_BlockByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_BlockByNumber_Call) RunAndReturn(run func(context.Context, *big.Int) (*types.Block, error)) *EthClienter_BlockByNumber_Call { + _c.Call.Return(run) + return _c +} + +// BlockNumber provides a mock function with given fields: ctx +func (_m *EthClienter) BlockNumber(ctx context.Context) (uint64, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + + 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 +} + +// EthClienter_BlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockNumber' +type EthClienter_BlockNumber_Call struct { + *mock.Call +} + +// BlockNumber is a helper method to define mock.On call +// - ctx context.Context +func (_e *EthClienter_Expecter) BlockNumber(ctx interface{}) *EthClienter_BlockNumber_Call { + return &EthClienter_BlockNumber_Call{Call: _e.mock.On("BlockNumber", ctx)} +} + +func (_c *EthClienter_BlockNumber_Call) Run(run func(ctx context.Context)) *EthClienter_BlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClienter_BlockNumber_Call) Return(_a0 uint64, _a1 error) *EthClienter_BlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_BlockNumber_Call) RunAndReturn(run func(context.Context) (uint64, error)) *EthClienter_BlockNumber_Call { + _c.Call.Return(run) + return _c +} + +// CallContract provides a mock function with given fields: ctx, call, blockNumber +func (_m *EthClienter) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + ret := _m.Called(ctx, call, blockNumber) + + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok { + return rf(ctx, call, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) []byte); ok { + r0 = rf(ctx, call, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg, *big.Int) error); ok { + r1 = rf(ctx, call, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_CallContract_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CallContract' +type EthClienter_CallContract_Call struct { + *mock.Call +} + +// CallContract is a helper method to define mock.On call +// - ctx context.Context +// - call ethereum.CallMsg +// - blockNumber *big.Int +func (_e *EthClienter_Expecter) CallContract(ctx interface{}, call interface{}, blockNumber interface{}) *EthClienter_CallContract_Call { + return &EthClienter_CallContract_Call{Call: _e.mock.On("CallContract", ctx, call, blockNumber)} +} + +func (_c *EthClienter_CallContract_Call) Run(run func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int)) *EthClienter_CallContract_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.CallMsg), args[2].(*big.Int)) + }) + return _c +} + +func (_c *EthClienter_CallContract_Call) Return(_a0 []byte, _a1 error) *EthClienter_CallContract_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_CallContract_Call) RunAndReturn(run func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)) *EthClienter_CallContract_Call { + _c.Call.Return(run) + return _c +} + +// CodeAt provides a mock function with given fields: ctx, contract, blockNumber +func (_m *EthClienter) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { + ret := _m.Called(ctx, contract, blockNumber) + + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]byte, error)); ok { + return rf(ctx, contract, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) []byte); ok { + r0 = rf(ctx, contract, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, contract, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_CodeAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CodeAt' +type EthClienter_CodeAt_Call struct { + *mock.Call +} + +// CodeAt is a helper method to define mock.On call +// - ctx context.Context +// - contract common.Address +// - blockNumber *big.Int +func (_e *EthClienter_Expecter) CodeAt(ctx interface{}, contract interface{}, blockNumber interface{}) *EthClienter_CodeAt_Call { + return &EthClienter_CodeAt_Call{Call: _e.mock.On("CodeAt", ctx, contract, blockNumber)} +} + +func (_c *EthClienter_CodeAt_Call) Run(run func(ctx context.Context, contract common.Address, blockNumber *big.Int)) *EthClienter_CodeAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Address), args[2].(*big.Int)) + }) + return _c +} + +func (_c *EthClienter_CodeAt_Call) Return(_a0 []byte, _a1 error) *EthClienter_CodeAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_CodeAt_Call) RunAndReturn(run func(context.Context, common.Address, *big.Int) ([]byte, error)) *EthClienter_CodeAt_Call { + _c.Call.Return(run) + return _c +} + +// EstimateGas provides a mock function with given fields: ctx, call +func (_m *EthClienter) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { + ret := _m.Called(ctx, call) + + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) (uint64, error)); ok { + return rf(ctx, call) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) uint64); ok { + r0 = rf(ctx, call) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg) error); ok { + r1 = rf(ctx, call) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_EstimateGas_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateGas' +type EthClienter_EstimateGas_Call struct { + *mock.Call +} + +// EstimateGas is a helper method to define mock.On call +// - ctx context.Context +// - call ethereum.CallMsg +func (_e *EthClienter_Expecter) EstimateGas(ctx interface{}, call interface{}) *EthClienter_EstimateGas_Call { + return &EthClienter_EstimateGas_Call{Call: _e.mock.On("EstimateGas", ctx, call)} +} + +func (_c *EthClienter_EstimateGas_Call) Run(run func(ctx context.Context, call ethereum.CallMsg)) *EthClienter_EstimateGas_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.CallMsg)) + }) + return _c +} + +func (_c *EthClienter_EstimateGas_Call) Return(_a0 uint64, _a1 error) *EthClienter_EstimateGas_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_EstimateGas_Call) RunAndReturn(run func(context.Context, ethereum.CallMsg) (uint64, error)) *EthClienter_EstimateGas_Call { + _c.Call.Return(run) + return _c +} + +// FilterLogs provides a mock function with given fields: ctx, q +func (_m *EthClienter) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + ret := _m.Called(ctx, q) + + if len(ret) == 0 { + panic("no return value specified for FilterLogs") + } + + var r0 []types.Log + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) ([]types.Log, error)); ok { + return rf(ctx, q) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) []types.Log); ok { + r0 = rf(ctx, q) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.Log) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.FilterQuery) error); ok { + r1 = rf(ctx, q) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_FilterLogs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterLogs' +type EthClienter_FilterLogs_Call struct { + *mock.Call +} + +// FilterLogs is a helper method to define mock.On call +// - ctx context.Context +// - q ethereum.FilterQuery +func (_e *EthClienter_Expecter) FilterLogs(ctx interface{}, q interface{}) *EthClienter_FilterLogs_Call { + return &EthClienter_FilterLogs_Call{Call: _e.mock.On("FilterLogs", ctx, q)} +} + +func (_c *EthClienter_FilterLogs_Call) Run(run func(ctx context.Context, q ethereum.FilterQuery)) *EthClienter_FilterLogs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.FilterQuery)) + }) + return _c +} + +func (_c *EthClienter_FilterLogs_Call) Return(_a0 []types.Log, _a1 error) *EthClienter_FilterLogs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_FilterLogs_Call) RunAndReturn(run func(context.Context, ethereum.FilterQuery) ([]types.Log, error)) *EthClienter_FilterLogs_Call { + _c.Call.Return(run) + return _c +} + +// HeaderByHash provides a mock function with given fields: ctx, hash +func (_m *EthClienter) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + ret := _m.Called(ctx, hash) + + if len(ret) == 0 { + panic("no return value specified for HeaderByHash") + } + + var r0 *types.Header + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Header, error)); ok { + return rf(ctx, hash) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) *types.Header); ok { + r0 = rf(ctx, hash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Header) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + r1 = rf(ctx, hash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_HeaderByHash_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeaderByHash' +type EthClienter_HeaderByHash_Call struct { + *mock.Call +} + +// HeaderByHash is a helper method to define mock.On call +// - ctx context.Context +// - hash common.Hash +func (_e *EthClienter_Expecter) HeaderByHash(ctx interface{}, hash interface{}) *EthClienter_HeaderByHash_Call { + return &EthClienter_HeaderByHash_Call{Call: _e.mock.On("HeaderByHash", ctx, hash)} +} + +func (_c *EthClienter_HeaderByHash_Call) Run(run func(ctx context.Context, hash common.Hash)) *EthClienter_HeaderByHash_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Hash)) + }) + return _c +} + +func (_c *EthClienter_HeaderByHash_Call) Return(_a0 *types.Header, _a1 error) *EthClienter_HeaderByHash_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_HeaderByHash_Call) RunAndReturn(run func(context.Context, common.Hash) (*types.Header, error)) *EthClienter_HeaderByHash_Call { + _c.Call.Return(run) + return _c +} + +// HeaderByNumber provides a mock function with given fields: ctx, number +func (_m *EthClienter) 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 +} + +// EthClienter_HeaderByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeaderByNumber' +type EthClienter_HeaderByNumber_Call struct { + *mock.Call +} + +// HeaderByNumber is a helper method to define mock.On call +// - ctx context.Context +// - number *big.Int +func (_e *EthClienter_Expecter) HeaderByNumber(ctx interface{}, number interface{}) *EthClienter_HeaderByNumber_Call { + return &EthClienter_HeaderByNumber_Call{Call: _e.mock.On("HeaderByNumber", ctx, number)} +} + +func (_c *EthClienter_HeaderByNumber_Call) Run(run func(ctx context.Context, number *big.Int)) *EthClienter_HeaderByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*big.Int)) + }) + return _c +} + +func (_c *EthClienter_HeaderByNumber_Call) Return(_a0 *types.Header, _a1 error) *EthClienter_HeaderByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_HeaderByNumber_Call) RunAndReturn(run func(context.Context, *big.Int) (*types.Header, error)) *EthClienter_HeaderByNumber_Call { + _c.Call.Return(run) + return _c +} + +// PendingCodeAt provides a mock function with given fields: ctx, account +func (_m *EthClienter) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { + ret := _m.Called(ctx, account) + + if len(ret) == 0 { + panic("no return value specified for PendingCodeAt") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]byte, error)); ok { + return rf(ctx, account) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address) []byte); ok { + r0 = rf(ctx, account) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { + r1 = rf(ctx, account) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_PendingCodeAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PendingCodeAt' +type EthClienter_PendingCodeAt_Call struct { + *mock.Call +} + +// PendingCodeAt is a helper method to define mock.On call +// - ctx context.Context +// - account common.Address +func (_e *EthClienter_Expecter) PendingCodeAt(ctx interface{}, account interface{}) *EthClienter_PendingCodeAt_Call { + return &EthClienter_PendingCodeAt_Call{Call: _e.mock.On("PendingCodeAt", ctx, account)} +} + +func (_c *EthClienter_PendingCodeAt_Call) Run(run func(ctx context.Context, account common.Address)) *EthClienter_PendingCodeAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Address)) + }) + return _c +} + +func (_c *EthClienter_PendingCodeAt_Call) Return(_a0 []byte, _a1 error) *EthClienter_PendingCodeAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_PendingCodeAt_Call) RunAndReturn(run func(context.Context, common.Address) ([]byte, error)) *EthClienter_PendingCodeAt_Call { + _c.Call.Return(run) + return _c +} + +// PendingNonceAt provides a mock function with given fields: ctx, account +func (_m *EthClienter) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { + ret := _m.Called(ctx, account) + + if len(ret) == 0 { + panic("no return value specified for PendingNonceAt") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint64, error)); ok { + return rf(ctx, account) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address) uint64); ok { + r0 = rf(ctx, account) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { + r1 = rf(ctx, account) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_PendingNonceAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PendingNonceAt' +type EthClienter_PendingNonceAt_Call struct { + *mock.Call +} + +// PendingNonceAt is a helper method to define mock.On call +// - ctx context.Context +// - account common.Address +func (_e *EthClienter_Expecter) PendingNonceAt(ctx interface{}, account interface{}) *EthClienter_PendingNonceAt_Call { + return &EthClienter_PendingNonceAt_Call{Call: _e.mock.On("PendingNonceAt", ctx, account)} +} + +func (_c *EthClienter_PendingNonceAt_Call) Run(run func(ctx context.Context, account common.Address)) *EthClienter_PendingNonceAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Address)) + }) + return _c +} + +func (_c *EthClienter_PendingNonceAt_Call) Return(_a0 uint64, _a1 error) *EthClienter_PendingNonceAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_PendingNonceAt_Call) RunAndReturn(run func(context.Context, common.Address) (uint64, error)) *EthClienter_PendingNonceAt_Call { + _c.Call.Return(run) + return _c +} + +// SendTransaction provides a mock function with given fields: ctx, tx +func (_m *EthClienter) SendTransaction(ctx context.Context, tx *types.Transaction) error { + ret := _m.Called(ctx, tx) + + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { + r0 = rf(ctx, tx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// EthClienter_SendTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendTransaction' +type EthClienter_SendTransaction_Call struct { + *mock.Call +} + +// SendTransaction is a helper method to define mock.On call +// - ctx context.Context +// - tx *types.Transaction +func (_e *EthClienter_Expecter) SendTransaction(ctx interface{}, tx interface{}) *EthClienter_SendTransaction_Call { + return &EthClienter_SendTransaction_Call{Call: _e.mock.On("SendTransaction", ctx, tx)} +} + +func (_c *EthClienter_SendTransaction_Call) Run(run func(ctx context.Context, tx *types.Transaction)) *EthClienter_SendTransaction_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*types.Transaction)) + }) + return _c +} + +func (_c *EthClienter_SendTransaction_Call) Return(_a0 error) *EthClienter_SendTransaction_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EthClienter_SendTransaction_Call) RunAndReturn(run func(context.Context, *types.Transaction) error) *EthClienter_SendTransaction_Call { + _c.Call.Return(run) + return _c +} + +// SubscribeFilterLogs provides a mock function with given fields: ctx, q, ch +func (_m *EthClienter) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { + ret := _m.Called(ctx, q, ch) + + if len(ret) == 0 { + panic("no return value specified for SubscribeFilterLogs") + } + + var r0 ethereum.Subscription + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)); ok { + return rf(ctx, q, ch) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) ethereum.Subscription); ok { + r0 = rf(ctx, q, ch) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ethereum.Subscription) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) error); ok { + r1 = rf(ctx, q, ch) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_SubscribeFilterLogs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeFilterLogs' +type EthClienter_SubscribeFilterLogs_Call struct { + *mock.Call +} + +// SubscribeFilterLogs is a helper method to define mock.On call +// - ctx context.Context +// - q ethereum.FilterQuery +// - ch chan<- types.Log +func (_e *EthClienter_Expecter) SubscribeFilterLogs(ctx interface{}, q interface{}, ch interface{}) *EthClienter_SubscribeFilterLogs_Call { + return &EthClienter_SubscribeFilterLogs_Call{Call: _e.mock.On("SubscribeFilterLogs", ctx, q, ch)} +} + +func (_c *EthClienter_SubscribeFilterLogs_Call) Run(run func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log)) *EthClienter_SubscribeFilterLogs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.FilterQuery), args[2].(chan<- types.Log)) + }) + return _c +} + +func (_c *EthClienter_SubscribeFilterLogs_Call) Return(_a0 ethereum.Subscription, _a1 error) *EthClienter_SubscribeFilterLogs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_SubscribeFilterLogs_Call) RunAndReturn(run func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)) *EthClienter_SubscribeFilterLogs_Call { + _c.Call.Return(run) + return _c +} + +// SubscribeNewHead provides a mock function with given fields: ctx, ch +func (_m *EthClienter) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) { + ret := _m.Called(ctx, ch) + + if len(ret) == 0 { + panic("no return value specified for SubscribeNewHead") + } + + var r0 ethereum.Subscription + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, chan<- *types.Header) (ethereum.Subscription, error)); ok { + return rf(ctx, ch) + } + if rf, ok := ret.Get(0).(func(context.Context, chan<- *types.Header) ethereum.Subscription); ok { + r0 = rf(ctx, ch) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ethereum.Subscription) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, chan<- *types.Header) error); ok { + r1 = rf(ctx, ch) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_SubscribeNewHead_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeNewHead' +type EthClienter_SubscribeNewHead_Call struct { + *mock.Call +} + +// SubscribeNewHead is a helper method to define mock.On call +// - ctx context.Context +// - ch chan<- *types.Header +func (_e *EthClienter_Expecter) SubscribeNewHead(ctx interface{}, ch interface{}) *EthClienter_SubscribeNewHead_Call { + return &EthClienter_SubscribeNewHead_Call{Call: _e.mock.On("SubscribeNewHead", ctx, ch)} +} + +func (_c *EthClienter_SubscribeNewHead_Call) Run(run func(ctx context.Context, ch chan<- *types.Header)) *EthClienter_SubscribeNewHead_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(chan<- *types.Header)) + }) + return _c +} + +func (_c *EthClienter_SubscribeNewHead_Call) Return(_a0 ethereum.Subscription, _a1 error) *EthClienter_SubscribeNewHead_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_SubscribeNewHead_Call) RunAndReturn(run func(context.Context, chan<- *types.Header) (ethereum.Subscription, error)) *EthClienter_SubscribeNewHead_Call { + _c.Call.Return(run) + return _c +} + +// SuggestGasPrice provides a mock function with given fields: ctx +func (_m *EthClienter) SuggestGasPrice(ctx context.Context) (*big.Int, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for SuggestGasPrice") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_SuggestGasPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SuggestGasPrice' +type EthClienter_SuggestGasPrice_Call struct { + *mock.Call +} + +// SuggestGasPrice is a helper method to define mock.On call +// - ctx context.Context +func (_e *EthClienter_Expecter) SuggestGasPrice(ctx interface{}) *EthClienter_SuggestGasPrice_Call { + return &EthClienter_SuggestGasPrice_Call{Call: _e.mock.On("SuggestGasPrice", ctx)} +} + +func (_c *EthClienter_SuggestGasPrice_Call) Run(run func(ctx context.Context)) *EthClienter_SuggestGasPrice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClienter_SuggestGasPrice_Call) Return(_a0 *big.Int, _a1 error) *EthClienter_SuggestGasPrice_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_SuggestGasPrice_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *EthClienter_SuggestGasPrice_Call { + _c.Call.Return(run) + return _c +} + +// SuggestGasTipCap provides a mock function with given fields: ctx +func (_m *EthClienter) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for SuggestGasTipCap") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_SuggestGasTipCap_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SuggestGasTipCap' +type EthClienter_SuggestGasTipCap_Call struct { + *mock.Call +} + +// SuggestGasTipCap is a helper method to define mock.On call +// - ctx context.Context +func (_e *EthClienter_Expecter) SuggestGasTipCap(ctx interface{}) *EthClienter_SuggestGasTipCap_Call { + return &EthClienter_SuggestGasTipCap_Call{Call: _e.mock.On("SuggestGasTipCap", ctx)} +} + +func (_c *EthClienter_SuggestGasTipCap_Call) Run(run func(ctx context.Context)) *EthClienter_SuggestGasTipCap_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClienter_SuggestGasTipCap_Call) Return(_a0 *big.Int, _a1 error) *EthClienter_SuggestGasTipCap_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_SuggestGasTipCap_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *EthClienter_SuggestGasTipCap_Call { + _c.Call.Return(run) + return _c +} + +// TransactionCount provides a mock function with given fields: ctx, blockHash +func (_m *EthClienter) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) { + ret := _m.Called(ctx, blockHash) + + if len(ret) == 0 { + panic("no return value specified for TransactionCount") + } + + var r0 uint + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (uint, error)); ok { + return rf(ctx, blockHash) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) uint); ok { + r0 = rf(ctx, blockHash) + } else { + r0 = ret.Get(0).(uint) + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + r1 = rf(ctx, blockHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_TransactionCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransactionCount' +type EthClienter_TransactionCount_Call struct { + *mock.Call +} + +// TransactionCount is a helper method to define mock.On call +// - ctx context.Context +// - blockHash common.Hash +func (_e *EthClienter_Expecter) TransactionCount(ctx interface{}, blockHash interface{}) *EthClienter_TransactionCount_Call { + return &EthClienter_TransactionCount_Call{Call: _e.mock.On("TransactionCount", ctx, blockHash)} +} + +func (_c *EthClienter_TransactionCount_Call) Run(run func(ctx context.Context, blockHash common.Hash)) *EthClienter_TransactionCount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Hash)) + }) + return _c +} + +func (_c *EthClienter_TransactionCount_Call) Return(_a0 uint, _a1 error) *EthClienter_TransactionCount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_TransactionCount_Call) RunAndReturn(run func(context.Context, common.Hash) (uint, error)) *EthClienter_TransactionCount_Call { + _c.Call.Return(run) + return _c +} + +// TransactionInBlock provides a mock function with given fields: ctx, blockHash, index +func (_m *EthClienter) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { + ret := _m.Called(ctx, blockHash, index) + + if len(ret) == 0 { + panic("no return value specified for TransactionInBlock") + } + + var r0 *types.Transaction + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash, uint) (*types.Transaction, error)); ok { + return rf(ctx, blockHash, index) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Hash, uint) *types.Transaction); ok { + r0 = rf(ctx, blockHash, index) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Transaction) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Hash, uint) error); ok { + r1 = rf(ctx, blockHash, index) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClienter_TransactionInBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransactionInBlock' +type EthClienter_TransactionInBlock_Call struct { + *mock.Call +} + +// TransactionInBlock is a helper method to define mock.On call +// - ctx context.Context +// - blockHash common.Hash +// - index uint +func (_e *EthClienter_Expecter) TransactionInBlock(ctx interface{}, blockHash interface{}, index interface{}) *EthClienter_TransactionInBlock_Call { + return &EthClienter_TransactionInBlock_Call{Call: _e.mock.On("TransactionInBlock", ctx, blockHash, index)} +} + +func (_c *EthClienter_TransactionInBlock_Call) Run(run func(ctx context.Context, blockHash common.Hash, index uint)) *EthClienter_TransactionInBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Hash), args[2].(uint)) + }) + return _c +} + +func (_c *EthClienter_TransactionInBlock_Call) Return(_a0 *types.Transaction, _a1 error) *EthClienter_TransactionInBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClienter_TransactionInBlock_Call) RunAndReturn(run func(context.Context, common.Hash, uint) (*types.Transaction, error)) *EthClienter_TransactionInBlock_Call { + _c.Call.Return(run) + return _c +} + +// NewEthClienter creates a new instance of EthClienter. 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 NewEthClienter(t interface { + mock.TestingT + Cleanup(func()) +}) *EthClienter { + mock := &EthClienter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 8bd2ad3402c9b7b697389205dbaa1ba7b5448638 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:46:26 +0200 Subject: [PATCH 16/40] fix: wip --- l1infotreesync/downloader.go | 7 ++++--- sonar-project.properties | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index 628e1ac5..cccb5175 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -43,7 +43,8 @@ func checkSMCIsRollupManager(rollupManagerAddr common.Address, return nil } -func checkSMCIsGlobalExitRoot(globalExitRootAddr common.Address, gerContract *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2) error { +func checkSMCIsGlobalExitRoot(globalExitRootAddr common.Address, + gerContract *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2) error { depositCount, err := gerContract.DepositCount(nil) if err != nil { return fmt.Errorf("fail sanity check GlobalExitRoot(%s) Contract. Err: %w", globalExitRootAddr.String(), err) @@ -55,7 +56,6 @@ func checkSMCIsGlobalExitRoot(globalExitRootAddr common.Address, gerContract *po func sanityCheckContracts(globalExitRoot, rollupManager common.Address, gerContract *polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2, rollupManagerContract *polygonrollupmanager.Polygonrollupmanager) error { - errGER := checkSMCIsGlobalExitRoot(globalExitRoot, gerContract) errRollup := checkSMCIsRollupManager(rollupManager, rollupManagerContract) if errGER != nil || errRollup != nil { @@ -82,7 +82,8 @@ func createContracts(client EthClienter, globalExitRoot, rollupManager common.Ad return gerContract, rollupManagerContract, nil } -func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Address, flags CreationFlags) (sync.LogAppenderMap, error) { +func buildAppender(client EthClienter, globalExitRoot, + rollupManager common.Address, flags CreationFlags) (sync.LogAppenderMap, error) { ger, rm, err := createContracts(client, globalExitRoot, rollupManager) if err != nil { err := fmt.Errorf("buildAppender: fails contracts creation. Err:%w", err) diff --git a/sonar-project.properties b/sonar-project.properties index 559f7073..b8f78410 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,11 +7,11 @@ sonar.projectName=cdk sonar.organization=0xpolygon sonar.sources=. -sonar.exclusions=**/test/**,**/vendor/**,**/mocks/**,**/build/**,**/target/**,**/proto/include/**,**/*.pb.go,**/docs/**,**/*.sql +sonar.exclusions=**/test/**,**/vendor/**,**/mocks/**,**/build/**,**/target/**,**/proto/include/**,**/*.pb.go,**/docs/**,**/*.sql,**/mocks_*/* sonar.tests=. sonar.test.inclusions=**/*_test.go -sonar.test.exclusions=**/vendor/**,**/docs/**,**/mocks/**,**/*.pb.go,**/*.yml,**/*.yaml,**/*.json,**/*.xml,**/*.toml +sonar.test.exclusions=**/vendor/**,**/docs/**,**/mocks/**,**/*.pb.go,**/*.yml,**/*.yaml,**/*.json,**/*.xml,**/*.toml,**/mocks_*/* sonar.issue.enforceSemantic=true # ===================================================== From 51c654b2f5b67f3d03f8e7ef8db6cd6c19562b89 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:50:04 +0200 Subject: [PATCH 17/40] test: increase coverage --- l1infotreesync/downloader_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/l1infotreesync/downloader_test.go b/l1infotreesync/downloader_test.go index d81f8d7c..1a5dbbeb 100644 --- a/l1infotreesync/downloader_test.go +++ b/l1infotreesync/downloader_test.go @@ -2,9 +2,14 @@ package l1infotreesync import ( "fmt" + "math/big" + "strings" "testing" + "github.com/0xPolygon/cdk-contracts-tooling/contracts/banana/polygonzkevmglobalexitrootv2" mocks_l1infotreesync "github.com/0xPolygon/cdk/l1infotreesync/mocks" + + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -29,3 +34,23 @@ func TestBuildAppenderBypassBadContractAddr(t *testing.T) { _, err := buildAppender(l1Client, globalExitRoot, rollupManager, flags) require.NoError(t, err) } + +func TestBuildAppenderVerifiedContractAddr(t *testing.T) { + l1Client := mocks_l1infotreesync.NewEthClienter(t) + globalExitRoot := common.HexToAddress("0x1") + rollupManager := common.HexToAddress("0x2") + + smcAbi, err := abi.JSON(strings.NewReader(polygonzkevmglobalexitrootv2.Polygonzkevmglobalexitrootv2ABI)) + require.NoError(t, err) + bigInt := big.NewInt(1) + returnGER, err := smcAbi.Methods["depositCount"].Outputs.Pack(bigInt) + require.NoError(t, err) + l1Client.EXPECT().CallContract(mock.Anything, mock.Anything, mock.Anything).Return(returnGER, nil).Once() + v := common.HexToAddress("0x1234") + returnRM, err := smcAbi.Methods["bridgeAddress"].Outputs.Pack(v) + require.NoError(t, err) + l1Client.EXPECT().CallContract(mock.Anything, mock.Anything, mock.Anything).Return(returnRM, nil).Once() + flags := FlagNone + _, err = buildAppender(l1Client, globalExitRoot, rollupManager, flags) + require.NoError(t, err) +} From b8aa2350dad6e53fbb0ce9464d8ae705868827d5 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:20:11 +0200 Subject: [PATCH 18/40] test: increase coverage --- l1infotreesync/processor_verifybatches.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/l1infotreesync/processor_verifybatches.go b/l1infotreesync/processor_verifybatches.go index 94e9419d..1562d4ff 100644 --- a/l1infotreesync/processor_verifybatches.go +++ b/l1infotreesync/processor_verifybatches.go @@ -12,6 +12,12 @@ import ( ) func (p *processor) processVerifyBatches(tx db.Txer, blockNumber uint64, event *VerifyBatches) error { + if event == nil { + return fmt.Errorf("processVerifyBatches: event is nil") + } + if tx == nil { + return fmt.Errorf("processVerifyBatches: tx is nil, is mandatory to pass a tx") + } log.Debugf("VerifyBatches: rollupExitTree.UpsertLeaf (blockNumber=%d, event=%s)", blockNumber, event.String()) // If ExitRoot is zero if the leaf doesnt exists doesnt change the root of tree. // if leaf already exists doesn't make sense to 'empty' the leaf, so we keep previous value From 445717d6639db6b41f6087b716869bfb0f379d21 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:43:33 +0200 Subject: [PATCH 19/40] fix: wip --- l1infotreesync/processor.go | 33 ---------- l1infotreesync/processor_verifybatches.go | 33 ++++++++++ .../processor_verifybatches_test.go | 60 +++++++++++++++++++ 3 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 l1infotreesync/processor_verifybatches_test.go diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 7fcc115c..9c40f2fb 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -349,39 +349,6 @@ func (p *processor) getLastIndex(tx db.Querier) (uint32, error) { return lastProcessedIndex, err } -func (p *processor) GetLastVerifiedBatches(rollupID uint32) (*VerifyBatches, error) { - verified := &VerifyBatches{} - err := meddler.QueryRow(p.db, verified, ` - SELECT * FROM verify_batches - WHERE rollup_id = $1 - ORDER BY block_num DESC, block_pos DESC - LIMIT 1; - `, rollupID) - return verified, db.ReturnErrNotFound(err) -} - -func (p *processor) GetFirstVerifiedBatches(rollupID uint32) (*VerifyBatches, error) { - verified := &VerifyBatches{} - err := meddler.QueryRow(p.db, verified, ` - SELECT * FROM verify_batches - WHERE rollup_id = $1 - ORDER BY block_num ASC, block_pos ASC - LIMIT 1; - `, rollupID) - return verified, db.ReturnErrNotFound(err) -} - -func (p *processor) GetFirstVerifiedBatchesAfterBlock(rollupID uint32, blockNum uint64) (*VerifyBatches, error) { - verified := &VerifyBatches{} - err := meddler.QueryRow(p.db, verified, ` - SELECT * FROM verify_batches - WHERE rollup_id = $1 AND block_num >= $2 - ORDER BY block_num ASC, block_pos ASC - LIMIT 1; - `, rollupID, blockNum) - return verified, db.ReturnErrNotFound(err) -} - func (p *processor) GetFirstL1InfoWithRollupExitRoot(rollupExitRoot common.Hash) (*L1InfoTreeLeaf, error) { info := &L1InfoTreeLeaf{} err := meddler.QueryRow(p.db, info, ` diff --git a/l1infotreesync/processor_verifybatches.go b/l1infotreesync/processor_verifybatches.go index 1562d4ff..ebc7e826 100644 --- a/l1infotreesync/processor_verifybatches.go +++ b/l1infotreesync/processor_verifybatches.go @@ -69,3 +69,36 @@ func (p *processor) isNewValueForrollupExitTree(tx db.Querier, event *VerifyBatc } return leaf != event.ExitRoot, nil } + +func (p *processor) GetLastVerifiedBatches(rollupID uint32) (*VerifyBatches, error) { + verified := &VerifyBatches{} + err := meddler.QueryRow(p.db, verified, ` + SELECT * FROM verify_batches + WHERE rollup_id = $1 + ORDER BY block_num DESC, block_pos DESC + LIMIT 1; + `, rollupID) + return verified, db.ReturnErrNotFound(err) +} + +func (p *processor) GetFirstVerifiedBatches(rollupID uint32) (*VerifyBatches, error) { + verified := &VerifyBatches{} + err := meddler.QueryRow(p.db, verified, ` + SELECT * FROM verify_batches + WHERE rollup_id = $1 + ORDER BY block_num ASC, block_pos ASC + LIMIT 1; + `, rollupID) + return verified, db.ReturnErrNotFound(err) +} + +func (p *processor) GetFirstVerifiedBatchesAfterBlock(rollupID uint32, blockNum uint64) (*VerifyBatches, error) { + verified := &VerifyBatches{} + err := meddler.QueryRow(p.db, verified, ` + SELECT * FROM verify_batches + WHERE rollup_id = $1 AND block_num >= $2 + ORDER BY block_num ASC, block_pos ASC + LIMIT 1; + `, rollupID, blockNum) + return verified, db.ReturnErrNotFound(err) +} diff --git a/l1infotreesync/processor_verifybatches_test.go b/l1infotreesync/processor_verifybatches_test.go new file mode 100644 index 00000000..f6a0c164 --- /dev/null +++ b/l1infotreesync/processor_verifybatches_test.go @@ -0,0 +1,60 @@ +package l1infotreesync + +import ( + "context" + "testing" + + "github.com/0xPolygon/cdk/db" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestProcessVerifyBatchesNil(t *testing.T) { + dbPath := "file:TestProcessVerifyBatchesNil?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + err = sut.processVerifyBatches(nil, 1, nil) + require.Error(t, err) +} + +func TestProcessVerifyBatchesOK(t *testing.T) { + dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + event := VerifyBatches{ + BlockPosition: 1, + RollupID: 1, + NumBatch: 1, + StateRoot: common.HexToHash("5ca1e"), + ExitRoot: common.HexToHash("b455"), + Aggregator: common.HexToAddress("beef"), + RollupExitRoot: common.HexToHash("b455"), + } + ctx := context.TODO() + tx, err := db.NewTx(ctx, sut.db) + require.NoError(t, err) + _, err = tx.Exec(`INSERT INTO block (num) VALUES ($1)`, 1) + require.NoError(t, err) + err = sut.processVerifyBatches(tx, 1, &event) + require.NoError(t, err) +} + +func TestProcessVerifyBatchesSkip0000(t *testing.T) { + dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + event := VerifyBatches{ + BlockPosition: 1, + RollupID: 1, + NumBatch: 1, + StateRoot: common.HexToHash("5ca1e"), + ExitRoot: common.Hash{}, + Aggregator: common.HexToAddress("beef"), + RollupExitRoot: common.HexToHash("b455"), + } + ctx := context.TODO() + tx, err := db.NewTx(ctx, sut.db) + require.NoError(t, err) + err = sut.processVerifyBatches(tx, 1, &event) + require.NoError(t, err) +} From df5cb1336bb59e4b5b83c3a6ff0a63e38ba20c6b Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:16:57 +0200 Subject: [PATCH 20/40] fix: lint --- l1infotreesync/processor_verifybatches_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/l1infotreesync/processor_verifybatches_test.go b/l1infotreesync/processor_verifybatches_test.go index f6a0c164..1cf06b39 100644 --- a/l1infotreesync/processor_verifybatches_test.go +++ b/l1infotreesync/processor_verifybatches_test.go @@ -18,7 +18,7 @@ func TestProcessVerifyBatchesNil(t *testing.T) { } func TestProcessVerifyBatchesOK(t *testing.T) { - dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" + dbPath := "file:TestProcessVerifyBatchesOK?mode=memory&cache=shared" sut, err := newProcessor(dbPath) require.NoError(t, err) event := VerifyBatches{ @@ -40,7 +40,7 @@ func TestProcessVerifyBatchesOK(t *testing.T) { } func TestProcessVerifyBatchesSkip0000(t *testing.T) { - dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" + dbPath := "file:TestProcessVerifyBatchesSkip0000?mode=memory&cache=shared" sut, err := newProcessor(dbPath) require.NoError(t, err) event := VerifyBatches{ From b755cc251317ac0d9f0cc97063a330c670632327 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:05:39 +0200 Subject: [PATCH 21/40] fix: wip --- l1infotreesync/processor_verifybatches.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/l1infotreesync/processor_verifybatches.go b/l1infotreesync/processor_verifybatches.go index ebc7e826..9d1d0efb 100644 --- a/l1infotreesync/processor_verifybatches.go +++ b/l1infotreesync/processor_verifybatches.go @@ -25,7 +25,7 @@ func (p *processor) processVerifyBatches(tx db.Txer, blockNumber uint64, event * log.Infof("skipping VerifyBatches event with empty ExitRoot (blockNumber=%d, event=%s)", blockNumber, event.String()) return nil } - isNewLeaf, err := p.isNewValueForrollupExitTree(tx, event) + isNewLeaf, err := p.isNewValueForRollupExitTree(tx, event) if err != nil { return fmt.Errorf("isNewValueForrollupExitTree. err: %w", err) } @@ -50,7 +50,7 @@ func (p *processor) processVerifyBatches(tx db.Txer, blockNumber uint64, event * return nil } -func (p *processor) isNewValueForrollupExitTree(tx db.Querier, event *VerifyBatches) (bool, error) { +func (p *processor) isNewValueForRollupExitTree(tx db.Querier, event *VerifyBatches) (bool, error) { currentRoot, err := p.rollupExitTree.GetLastRoot(tx) if err != nil && errors.Is(err, db.ErrNotFound) { // The tree is empty, so is a new value for sure From 039f439464095f3c15c1b5e4dd68b0eae0125553 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:36:46 +0200 Subject: [PATCH 22/40] fix: unittest --- l1infotreesync/downloader_test.go | 1 - l1infotreesync/e2e_test.go | 6 ++++-- tree/tree_test.go | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/l1infotreesync/downloader_test.go b/l1infotreesync/downloader_test.go index 1a5dbbeb..6007a3d6 100644 --- a/l1infotreesync/downloader_test.go +++ b/l1infotreesync/downloader_test.go @@ -8,7 +8,6 @@ import ( "github.com/0xPolygon/cdk-contracts-tooling/contracts/banana/polygonzkevmglobalexitrootv2" mocks_l1infotreesync "github.com/0xPolygon/cdk/l1infotreesync/mocks" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 5d2a11cc..c522c73a 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -174,7 +174,8 @@ func TestWithReorgs(t *testing.T) { rd, err := reorgdetector.New(client.Client(), reorgdetector.Config{DBPath: dbPathReorg, CheckReorgsInterval: cdktypes.NewDuration(time.Millisecond * 30)}) require.NoError(t, err) require.NoError(t, rd.Start(ctx)) - syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerAddr, verifyAddr, 10, etherman.LatestBlock, rd, client.Client(), time.Millisecond, 0, time.Second, 25) + syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerAddr, verifyAddr, 10, etherman.LatestBlock, rd, client.Client(), time.Millisecond, 0, time.Second, 25, + l1infotreesync.FlagAllowWrongContractsAddrs) require.NoError(t, err) go syncer.Start(ctx) @@ -293,7 +294,8 @@ func TestStressAndReorgs(t *testing.T) { rd, err := reorgdetector.New(client.Client(), reorgdetector.Config{DBPath: dbPathReorg, CheckReorgsInterval: cdktypes.NewDuration(time.Millisecond * 100)}) require.NoError(t, err) require.NoError(t, rd.Start(ctx)) - syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerAddr, verifyAddr, 10, etherman.LatestBlock, rd, client.Client(), time.Millisecond, 0, time.Second, 100) + syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerAddr, verifyAddr, 10, etherman.LatestBlock, rd, client.Client(), time.Millisecond, 0, time.Second, 100, + l1infotreesync.FlagAllowWrongContractsAddrs) require.NoError(t, err) go syncer.Start(ctx) diff --git a/tree/tree_test.go b/tree/tree_test.go index c26bcded..c2748856 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -55,7 +55,7 @@ func TestCheckExpectedRoot(t *testing.T) { addLeaves(merkleTree, treeDB, numOfLeavesToAdd, 0) - expectedRoot, err := merkleTree.GetLastRoot(context.Background()) + expectedRoot, err := merkleTree.GetLastRoot(nil) require.NoError(t, err) addLeaves(merkleTree, treeDB, numOfLeavesToAdd, numOfLeavesToAdd) @@ -74,7 +74,7 @@ func TestCheckExpectedRoot(t *testing.T) { addLeaves(merkleTree, treeDB, numOfLeavesToAdd, 0) - expectedRoot, err := merkleTree.GetLastRoot(context.Background()) + expectedRoot, err := merkleTree.GetLastRoot(nil) require.NoError(t, err) addLeaves(merkleTree, treeDB, numOfLeavesToAdd, numOfLeavesToAdd) From 1cc0a7c88212a0f3a8c835e5b281c50abebecf08 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:36:33 +0200 Subject: [PATCH 23/40] fix: point to branch of kurtosis with the right params on cdk-node --- .github/workflows/test-e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index af54879b..7a686f4b 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -65,6 +65,7 @@ jobs: uses: actions/checkout@v4 with: repository: 0xPolygon/kurtosis-cdk + ref: fix/missing_cdk_config_rollupmanager path: "kurtosis-cdk" - name: Setup Bats and bats libs From a9dfc3770a9ef12172f7585fe7b87c504558ccc4 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:27:09 +0200 Subject: [PATCH 24/40] fix: wip --- l1infotreesync/l1infotreesync.go | 18 ++- l1infotreesync/processor.go | 1 - l1infotreesync/processor_test.go | 124 +----------------- .../processor_verifybatches_test.go | 67 ++++++++++ sequencesender/txbuilder/banana_base.go | 66 +++++++--- 5 files changed, 137 insertions(+), 139 deletions(-) diff --git a/l1infotreesync/l1infotreesync.go b/l1infotreesync/l1infotreesync.go index a58be215..a7e50128 100644 --- a/l1infotreesync/l1infotreesync.go +++ b/l1infotreesync/l1infotreesync.go @@ -5,6 +5,7 @@ import ( "errors" "time" + "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree" @@ -22,6 +23,10 @@ const ( FlagAllowWrongContractsAddrs CreationFlags = 1 << iota // Allow to set wrong contracts addresses ) +var ( + ErrNotFound = errors.New("l1infotreesync: not found") +) + type L1InfoTreeSync struct { processor *processor driver *sync.EVMDriver @@ -117,10 +122,21 @@ func (s *L1InfoTreeSync) GetRollupExitTreeMerkleProof( return s.processor.rollupExitTree.GetProof(ctx, networkID-1, root) } +func translateError(err error) error { + if errors.Is(err, db.ErrNotFound) { + return ErrNotFound + } + return err +} + // GetLatestInfoUntilBlock returns the most recent L1InfoTreeLeaf that occurred before or at blockNum. // If the blockNum has not been processed yet the error ErrBlockNotProcessed will be returned +// It can returns next errors: +// - ErrBlockNotProcessed, +// - ErrNotFound func (s *L1InfoTreeSync) GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64) (*L1InfoTreeLeaf, error) { - return s.processor.GetLatestInfoUntilBlock(ctx, blockNum) + leaf, err := s.processor.GetLatestInfoUntilBlock(ctx, blockNum) + return leaf, translateError(err) } // GetInfoByIndex returns the value of a leaf (not the hash) of the L1 info tree diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 9c40f2fb..82080fb1 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -310,7 +310,6 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { } l1InfoLeavesAdded++ } - // TODO: CDK-505 if event.VerifyBatches != nil { log.Debugf("handle VerifyBatches event %s", event.VerifyBatches.String()) err = p.processVerifyBatches(tx, block.Num, event.VerifyBatches) diff --git a/l1infotreesync/processor_test.go b/l1infotreesync/processor_test.go index 2837c987..b31d2237 100644 --- a/l1infotreesync/processor_test.go +++ b/l1infotreesync/processor_test.go @@ -10,72 +10,6 @@ import ( "golang.org/x/net/context" ) -func TestGetVerifiedBatches(t *testing.T) { - dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" - p, err := newProcessor(dbPath) - require.NoError(t, err) - ctx := context.Background() - - // Test ErrNotFound returned correctly on all methods - _, err = p.GetLastVerifiedBatches(0) - require.Equal(t, db.ErrNotFound, err) - _, err = p.GetFirstVerifiedBatches(0) - require.Equal(t, db.ErrNotFound, err) - _, err = p.GetFirstVerifiedBatchesAfterBlock(0, 0) - require.Equal(t, db.ErrNotFound, err) - - // First insert - expected1 := &VerifyBatches{ - RollupID: 420, - NumBatch: 69, - StateRoot: common.HexToHash("5ca1e"), - ExitRoot: common.HexToHash("b455"), - Aggregator: common.HexToAddress("beef"), - } - err = p.ProcessBlock(ctx, sync.Block{ - Num: 1, - Events: []interface{}{ - Event{VerifyBatches: expected1}, - }, - }) - require.NoError(t, err) - _, err = p.GetLastVerifiedBatches(0) - require.Equal(t, db.ErrNotFound, err) - actual, err := p.GetLastVerifiedBatches(420) - require.NoError(t, err) - require.Equal(t, expected1, actual) - actual, err = p.GetFirstVerifiedBatches(420) - require.NoError(t, err) - require.Equal(t, expected1, actual) - - // Second insert - expected2 := &VerifyBatches{ - RollupID: 420, - NumBatch: 690, - StateRoot: common.HexToHash("5ca1e3"), - ExitRoot: common.HexToHash("ba55"), - Aggregator: common.HexToAddress("beef3"), - } - err = p.ProcessBlock(ctx, sync.Block{ - Num: 2, - Events: []interface{}{ - Event{VerifyBatches: expected2}, - }, - }) - require.NoError(t, err) - _, err = p.GetLastVerifiedBatches(0) - require.Equal(t, db.ErrNotFound, err) - actual, err = p.GetLastVerifiedBatches(420) - require.NoError(t, err) - require.Equal(t, expected2, actual) - actual, err = p.GetFirstVerifiedBatches(420) - require.NoError(t, err) - require.Equal(t, expected1, actual) - actual, err = p.GetFirstVerifiedBatchesAfterBlock(420, 2) - require.NoError(t, err) - require.Equal(t, expected2, actual) -} - func TestGetInfo(t *testing.T) { dbPath := "file:TestGetInfo?mode=memory&cache=shared" p, err := newProcessor(dbPath) @@ -175,59 +109,15 @@ func TestGetInfo(t *testing.T) { require.Equal(t, expected2, *actual) } -func TestInitL1InfoRootMap(t *testing.T) { - dbPath := "file:TestInitL1InfoRootMap?mode=memory&cache=shared" - sut, err := newProcessor(dbPath) - require.NoError(t, err) - ctx := context.TODO() - event := InitL1InfoRootMap{ - LeafCount: 1, - CurrentL1InfoRoot: common.HexToHash("beef"), - } - block := sync.Block{ - Num: 1, - Events: []interface{}{ - Event{InitL1InfoRootMap: &event}, - }, - } - - err = sut.ProcessBlock(ctx, block) - require.NoError(t, err) - - info, err := sut.GetInitL1InfoRootMap(nil) - require.NoError(t, err) - require.NotNil(t, info) - require.Equal(t, event.LeafCount, info.LeafCount) - require.Equal(t, event.CurrentL1InfoRoot, info.L1InfoRoot) - require.Equal(t, block.Num, info.BlockNumber) -} - -func TestInitL1InfoRootMapDontAllow2Rows(t *testing.T) { - dbPath := "file:TestInitL1InfoRootMapDontAllow2Rows?mode=memory&cache=shared" +func TestGetLatestInfoUntilBlockIfNotFoundReturnsErrNotFound(t *testing.T) { + dbPath := "file:TestGetLatestInfoUntilBlock?mode=memory&cache=shared" sut, err := newProcessor(dbPath) require.NoError(t, err) - ctx := context.TODO() - block := sync.Block{ - Num: 1, - Events: []interface{}{ - Event{InitL1InfoRootMap: &InitL1InfoRootMap{ - LeafCount: 1, - CurrentL1InfoRoot: common.HexToHash("beef"), - }}, - }, - } - err = sut.ProcessBlock(ctx, block) + ctx := context.Background() + // Fake block 1 + _, err = sut.db.Exec(`INSERT INTO block (num) VALUES ($1)`, 1) require.NoError(t, err) - block.Num = 2 - err = sut.ProcessBlock(ctx, block) - require.Error(t, err, "should not allow to insert a second row") -} -func TestGetInitL1InfoRootMap(t *testing.T) { - dbPath := "file:TestGetInitL1InfoRootMap?mode=memory&cache=shared" - sut, err := newProcessor(dbPath) - require.NoError(t, err) - info, err := sut.GetInitL1InfoRootMap(nil) - require.NoError(t, err, "should return no error if no row is present, because it returns data=nil") - require.Nil(t, info, "should return nil if no row is present") + _, err = sut.GetLatestInfoUntilBlock(ctx, 1) + require.Equal(t, db.ErrNotFound, err) } diff --git a/l1infotreesync/processor_verifybatches_test.go b/l1infotreesync/processor_verifybatches_test.go index 1cf06b39..d943b541 100644 --- a/l1infotreesync/processor_verifybatches_test.go +++ b/l1infotreesync/processor_verifybatches_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/sync" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) @@ -58,3 +59,69 @@ func TestProcessVerifyBatchesSkip0000(t *testing.T) { err = sut.processVerifyBatches(tx, 1, &event) require.NoError(t, err) } + +func TestGetVerifiedBatches(t *testing.T) { + dbPath := "file:TestGetVerifiedBatches?mode=memory&cache=shared" + p, err := newProcessor(dbPath) + require.NoError(t, err) + ctx := context.Background() + + // Test ErrNotFound returned correctly on all methods + _, err = p.GetLastVerifiedBatches(0) + require.Equal(t, db.ErrNotFound, err) + _, err = p.GetFirstVerifiedBatches(0) + require.Equal(t, db.ErrNotFound, err) + _, err = p.GetFirstVerifiedBatchesAfterBlock(0, 0) + require.Equal(t, db.ErrNotFound, err) + + // First insert + expected1 := &VerifyBatches{ + RollupID: 420, + NumBatch: 69, + StateRoot: common.HexToHash("5ca1e"), + ExitRoot: common.HexToHash("b455"), + Aggregator: common.HexToAddress("beef"), + } + err = p.ProcessBlock(ctx, sync.Block{ + Num: 1, + Events: []interface{}{ + Event{VerifyBatches: expected1}, + }, + }) + require.NoError(t, err) + _, err = p.GetLastVerifiedBatches(0) + require.Equal(t, db.ErrNotFound, err) + actual, err := p.GetLastVerifiedBatches(420) + require.NoError(t, err) + require.Equal(t, expected1, actual) + actual, err = p.GetFirstVerifiedBatches(420) + require.NoError(t, err) + require.Equal(t, expected1, actual) + + // Second insert + expected2 := &VerifyBatches{ + RollupID: 420, + NumBatch: 690, + StateRoot: common.HexToHash("5ca1e3"), + ExitRoot: common.HexToHash("ba55"), + Aggregator: common.HexToAddress("beef3"), + } + err = p.ProcessBlock(ctx, sync.Block{ + Num: 2, + Events: []interface{}{ + Event{VerifyBatches: expected2}, + }, + }) + require.NoError(t, err) + _, err = p.GetLastVerifiedBatches(0) + require.Equal(t, db.ErrNotFound, err) + actual, err = p.GetLastVerifiedBatches(420) + require.NoError(t, err) + require.Equal(t, expected2, actual) + actual, err = p.GetFirstVerifiedBatches(420) + require.NoError(t, err) + require.Equal(t, expected1, actual) + actual, err = p.GetFirstVerifiedBatchesAfterBlock(420, 2) + require.NoError(t, err) + require.Equal(t, expected2, actual) +} diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index 00736e2b..94a1a08b 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -2,6 +2,7 @@ package txbuilder import ( "context" + "errors" "fmt" "math/big" @@ -75,34 +76,59 @@ func (t *TxBuilderBananaBase) NewBatchFromL2Block(l2Block *datastream.L2Block) s return NewBananaBatch(batch) } -func (t *TxBuilderBananaBase) NewSequence( - ctx context.Context, batches []seqsendertypes.Batch, coinbase common.Address, -) (seqsendertypes.Sequence, error) { - ethBatches := toEthermanBatches(batches) - sequence := etherman.NewSequenceBanana(ethBatches, coinbase) - var greatestL1Index uint32 - for _, b := range sequence.Batches { - if greatestL1Index < b.L1InfoTreeIndex { - greatestL1Index = b.L1InfoTreeIndex +func getHighestL1InfoIndex(batches []etherman.Batch) uint32 { + var highestL1Index uint32 + for _, b := range batches { + if highestL1Index < b.L1InfoTreeIndex { + highestL1Index = b.L1InfoTreeIndex } } + return highestL1Index +} + +// Returns CounterL1InfoRoot to use for this batch +func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL1IndexInBatch uint32) (uint32, error) { header, err := t.ethClient.HeaderByNumber(ctx, t.blockFinality) if err != nil { - return nil, fmt.Errorf("error calling HeaderByNumber, with block finality %d: %w", t.blockFinality.Int64(), err) + return 0, fmt.Errorf("error calling HeaderByNumber, with block finality %d: %w", t.blockFinality.Int64(), err) } info, err := t.l1InfoTree.GetLatestInfoUntilBlock(ctx, header.Number.Uint64()) - if err != nil { - return nil, fmt.Errorf("error calling GetLatestInfoUntilBlock with block num %d: %w", header.Number.Uint64(), err) - } - if info.L1InfoTreeIndex >= greatestL1Index { - sequence.CounterL1InfoRoot = info.L1InfoTreeIndex + 1 - } else { - return nil, fmt.Errorf( - "sequence contained an L1 Info tree index (%d) that is greater than the one synced with the desired finality (%d)", - greatestL1Index, info.L1InfoTreeIndex, - ) + if errors.Is(err, l1infotreesync.ErrNotFound) { + // There are no L1 Info tree leaves yet, so we can try to use L1InfoRootMap event + l1infotreeInitial, err := t.l1InfoTree.GetInitL1InfoRootMap(ctx) + if err != nil { + return 0, fmt.Errorf("error no leaves on L1InfoTree yet and GetInitL1InfoRootMap fails: %w", err) + } + // We use this leaf as first one + info = &l1infotreesync.L1InfoTreeLeaf{ + L1InfoTreeIndex: l1infotreeInitial.LeafCount - 1, + } + } else if err != nil { + return 0, fmt.Errorf("error calling GetLatestInfoUntilBlock with block num %d: %w", header.Number.Uint64(), err) + } + + if info.L1InfoTreeIndex >= highestL1IndexInBatch { + return info.L1InfoTreeIndex + 1, nil } + return 0, fmt.Errorf( + "sequence contained an L1 Info tree index (%d) that is greater than the one synced with the desired finality (%d)", + highestL1IndexInBatch, info.L1InfoTreeIndex, + ) +} + +func (t *TxBuilderBananaBase) NewSequence( + ctx context.Context, batches []seqsendertypes.Batch, coinbase common.Address, +) (seqsendertypes.Sequence, error) { + ethBatches := toEthermanBatches(batches) + sequence := etherman.NewSequenceBanana(ethBatches, coinbase) + greatestL1Index := getHighestL1InfoIndex(sequence.Batches) + + counterL1InfoRoot, err := t.GetCounterL1InfoRoot(ctx, greatestL1Index) + if err != nil { + return nil, err + } + sequence.CounterL1InfoRoot = counterL1InfoRoot l1InfoRoot, err := t.getL1InfoRoot(sequence.CounterL1InfoRoot) if err != nil { return nil, err From 03cc9f3f68135fc079c99134fd9520dc89e1c087 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:27:56 +0200 Subject: [PATCH 25/40] fix: unittest --- .../processor_initl1inforootmap_test.go | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 l1infotreesync/processor_initl1inforootmap_test.go diff --git a/l1infotreesync/processor_initl1inforootmap_test.go b/l1infotreesync/processor_initl1inforootmap_test.go new file mode 100644 index 00000000..753d7a25 --- /dev/null +++ b/l1infotreesync/processor_initl1inforootmap_test.go @@ -0,0 +1,67 @@ +package l1infotreesync + +import ( + "context" + "testing" + + "github.com/0xPolygon/cdk/sync" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestInitL1InfoRootMap(t *testing.T) { + dbPath := "file:TestInitL1InfoRootMap?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + ctx := context.TODO() + event := InitL1InfoRootMap{ + LeafCount: 1, + CurrentL1InfoRoot: common.HexToHash("beef"), + } + block := sync.Block{ + Num: 1, + Events: []interface{}{ + Event{InitL1InfoRootMap: &event}, + }, + } + + err = sut.ProcessBlock(ctx, block) + require.NoError(t, err) + + info, err := sut.GetInitL1InfoRootMap(nil) + require.NoError(t, err) + require.NotNil(t, info) + require.Equal(t, event.LeafCount, info.LeafCount) + require.Equal(t, event.CurrentL1InfoRoot, info.L1InfoRoot) + require.Equal(t, block.Num, info.BlockNumber) +} + +func TestInitL1InfoRootMapDontAllow2Rows(t *testing.T) { + dbPath := "file:TestInitL1InfoRootMapDontAllow2Rows?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + ctx := context.TODO() + block := sync.Block{ + Num: 1, + Events: []interface{}{ + Event{InitL1InfoRootMap: &InitL1InfoRootMap{ + LeafCount: 1, + CurrentL1InfoRoot: common.HexToHash("beef"), + }}, + }, + } + err = sut.ProcessBlock(ctx, block) + require.NoError(t, err) + block.Num = 2 + err = sut.ProcessBlock(ctx, block) + require.Error(t, err, "should not allow to insert a second row") +} + +func TestGetInitL1InfoRootMap(t *testing.T) { + dbPath := "file:TestGetInitL1InfoRootMap?mode=memory&cache=shared" + sut, err := newProcessor(dbPath) + require.NoError(t, err) + info, err := sut.GetInitL1InfoRootMap(nil) + require.NoError(t, err, "should return no error if no row is present, because it returns data=nil") + require.Nil(t, info, "should return nil if no row is present") +} From d43c1daaa60a5caf744914621561931c9def4d12 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:33:46 +0200 Subject: [PATCH 26/40] feat: wip --- l1infotreesync/processor.go | 13 +++++++++++-- scripts/local_config | 26 ++++++++++++------------- sequencesender/txbuilder/banana_base.go | 21 +++++++++++++------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 82080fb1..c6a4ef1a 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -88,6 +88,13 @@ type L1InfoTreeLeaf struct { Hash common.Hash `meddler:"hash,hash"` } +func (l *L1InfoTreeLeaf) String() string { + return fmt.Sprintf("BlockNumber: %d, BlockPosition: %d, L1InfoTreeIndex: %d, PreviousBlockHash: %s, "+ + "Timestamp: %d, MainnetExitRoot: %s, RollupExitRoot: %s, GlobalExitRoot: %s, Hash: %s", + l.BlockNumber, l.BlockPosition, l.L1InfoTreeIndex, l.PreviousBlockHash.String(), + l.Timestamp, l.MainnetExitRoot.String(), l.RollupExitRoot.String(), l.GlobalExitRoot.String(), l.Hash.String()) +} + // L1InfoTreeInitial representation of the initial info of the L1 Info tree for this rollup type L1InfoTreeInitial struct { BlockNumber uint64 `meddler:"block_num"` @@ -299,15 +306,17 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { info.GlobalExitRoot = info.globalExitRoot() info.Hash = info.hash() if err = meddler.Insert(tx, "l1info_leaf", info); err != nil { - return fmt.Errorf("insert l1info_leaf. err: %w", err) + return fmt.Errorf("insert l1info_leaf %s. err: %w", info.String(), err) } + err = p.l1InfoTree.AddLeaf(tx, info.BlockNumber, info.BlockPosition, treeTypes.Leaf{ Index: info.L1InfoTreeIndex, Hash: info.Hash, }) if err != nil { - return fmt.Errorf("AddLeaf. err: %w", err) + return fmt.Errorf("AddLeaf(%s). err: %w", info.String(), err) } + log.Infof("inserted L1InfoTreeLeaf %s", info.String()) l1InfoLeavesAdded++ } if event.VerifyBatches != nil { diff --git a/scripts/local_config b/scripts/local_config index 1b75f350..122346ab 100755 --- a/scripts/local_config +++ b/scripts/local_config @@ -35,16 +35,16 @@ EOF fi -if [ -z $TMP_CDK_FOLDER -o -z $ENCLAVE ]; then - echo "TMP_CDK_FOLDER or ENCLAVE is not set. Must be set on file env.sh" +if [ -z $TMP_CDK_FOLDER -o -z $KURTOSIS_ENCLAVE ]; then + echo "TMP_CDK_FOLDER or KURTOSIS_ENCLAVE is not set. Must be set on file env.sh" exit 1 fi -kurtosis enclave inspect $ENCLAVE > /dev/null +kurtosis enclave inspect $KURTOSIS_ENCLAVE > /dev/null if [ $? -ne 0 ]; then - echo "Error inspecting enclave $ENCLAVE" + echo "Error inspecting enclave $KURTOSIS_ENCLAVE" echo "You must start kurtosis environment before running this script" echo "- start kurtosis:" - echo " kurtosis clean --all; kurtosis run --enclave $ENCLAVE --args-file params.yml --image-download always ." + echo " kurtosis clean --all; kurtosis run --enclave $KURTOSIS_ENCLAVE --args-file params.yml --image-download always ." exit 1 fi @@ -52,25 +52,25 @@ DEST=${TMP_CDK_FOLDER}/local_config [ ! -d ${DEST} ] && mkdir -p ${DEST} rm $DEST/* -kurtosis files download $ENCLAVE genesis $DEST +kurtosis files download $KURTOSIS_ENCLAVE genesis $DEST [ $? -ne 0 ] && echo "Error downloading genesis" && exit 1 export genesis_file=$DEST/genesis.json export_values_of_genesis $genesis_file -kurtosis files download $ENCLAVE sequencer-keystore $DEST +kurtosis files download $KURTOSIS_ENCLAVE sequencer-keystore $DEST [ $? -ne 0 ] && echo "Error downloading sequencer-keystore" && exit 1 export sequencer_keystore_file=$DEST/sequencer.keystore -l1_rpc_port=$(kurtosis port print $ENCLAVE el-1-geth-lighthouse rpc | cut -f 3 -d ":") +l1_rpc_port=$(kurtosis port print $KURTOSIS_ENCLAVE el-1-geth-lighthouse rpc | cut -f 3 -d ":") [ $? -ne 0 ] && echo "Error getting l1_rpc_port" && exit 1 || export l1_rpc_port && echo "l1_rpc_port=$l1_rpc_port" -l1_rpc_addr=$(kurtosis port print $ENCLAVE el-1-geth-lighthouse rpc) +l1_rpc_addr=$(kurtosis port print $KURTOSIS_ENCLAVE el-1-geth-lighthouse rpc) [ $? -ne 0 ] && echo "Error getting l1_rpc_addr" && exit 1 || export l1_rpc_addr && echo "l1_rpc_addr=$l1_rpc_addr" -l2_rpc_addr=$(kurtosis port print $ENCLAVE cdk-erigon-node-001 http-rpc) +l2_rpc_addr=$(kurtosis port print $KURTOSIS_ENCLAVE cdk-erigon-node-001 http-rpc) [ $? -ne 0 ] && echo "Error getting l2_rpc_addr" && exit 1 || export l2_rpc_addr && echo "l2_rpc_addr=$l2_rpc_addr" -zkevm_data_streamer_port=$(kurtosis port print $ENCLAVE cdk-erigon-sequencer-001 data-streamer | cut -f 3 -d ":") +zkevm_data_streamer_port=$(kurtosis port print $KURTOSIS_ENCLAVE cdk-erigon-sequencer-001 data-streamer | cut -f 3 -d ":") [ $? -ne 0 ] && echo "Error getting zkevm_data_streamer_port" && exit 1 || export zkevm_data_streamer_port && echo "zkevm_data_streamer_port=$zkevm_data_streamer_port" -kurtosis files download $ENCLAVE cdk-node-config-artifact $DEST +kurtosis files download $KURTOSIS_ENCLAVE cdk-node-config-artifact $DEST export zkevm_l2_sequencer_address=$(cat $DEST/cdk-node-config.toml |grep L2Coinbase | cut -f 2 -d "="| tr -d '"' | tr -d ' ') export zkevm_l2_keystore_password=$(cat $DEST/cdk-node-config.toml |grep -A1 L2Coinbase | tr ',' '\n' | grep Password | cut -f 2 -d '=' | tr -d '}' | tr -d '"' | tr -d ' ') export l1_chain_id=$(cat $DEST/cdk-node-config.toml | grep L1ChainID | cut -f 2 -d '=' | head -n 1) @@ -79,7 +79,7 @@ export zkevm_is_validium=$(cat $DEST/cdk-node-config.toml | grep IsValidiumMode if [ "$zkevm_is_validium" == "true" ]; then echo "Validium mode detected... Retrieving the dac_port" - dac_port=$(kurtosis port print $ENCLAVE zkevm-dac-001 dac | cut -f 3 -d ":") + dac_port=$(kurtosis port print $KURTOSIS_ENCLAVE zkevm-dac-001 dac | cut -f 3 -d ":") [ $? -ne 0 ] && echo "Error getting dac_port" && exit 1 || export dac_port && echo "dac_port=$dac_port" fi diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index 94a1a08b..54db2032 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -92,7 +92,12 @@ func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL if err != nil { return 0, fmt.Errorf("error calling HeaderByNumber, with block finality %d: %w", t.blockFinality.Int64(), err) } + var resL1InfoCounter uint32 + info, err := t.l1InfoTree.GetLatestInfoUntilBlock(ctx, header.Number.Uint64()) + if err == nil { + resL1InfoCounter = info.L1InfoTreeIndex + 1 + } if errors.Is(err, l1infotreesync.ErrNotFound) { // There are no L1 Info tree leaves yet, so we can try to use L1InfoRootMap event l1infotreeInitial, err := t.l1InfoTree.GetInitL1InfoRootMap(ctx) @@ -100,20 +105,22 @@ func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL return 0, fmt.Errorf("error no leaves on L1InfoTree yet and GetInitL1InfoRootMap fails: %w", err) } // We use this leaf as first one - info = &l1infotreesync.L1InfoTreeLeaf{ - L1InfoTreeIndex: l1infotreeInitial.LeafCount - 1, - } + resL1InfoCounter = l1infotreeInitial.LeafCount } else if err != nil { return 0, fmt.Errorf("error calling GetLatestInfoUntilBlock with block num %d: %w", header.Number.Uint64(), err) } - - if info.L1InfoTreeIndex >= highestL1IndexInBatch { - return info.L1InfoTreeIndex + 1, nil + // This is a very rare case, but it can happen if there are no leaves in L1InfoTree yet, so the batch can use any of them and set 0 + if resL1InfoCounter == 0 && highestL1IndexInBatch == 0 { + log.Infof("No L1 Info tree leaves yet, batch don't use any leaf (index=0), so we use CounterL1InfoRoot=0 that is the empty tree") + return resL1InfoCounter, nil + } + if resL1InfoCounter > highestL1IndexInBatch { + return resL1InfoCounter, nil } return 0, fmt.Errorf( "sequence contained an L1 Info tree index (%d) that is greater than the one synced with the desired finality (%d)", - highestL1IndexInBatch, info.L1InfoTreeIndex, + highestL1IndexInBatch, resL1InfoCounter, ) } From 897744605a47d139c28840ffb7bba1f9193ba954 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:41:18 +0200 Subject: [PATCH 27/40] feat: local config support contract versions --- scripts/local_config | 2 +- test/config/test.kurtosis_template.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/local_config b/scripts/local_config index 122346ab..aeb008b0 100755 --- a/scripts/local_config +++ b/scripts/local_config @@ -76,7 +76,7 @@ export zkevm_l2_keystore_password=$(cat $DEST/cdk-node-config.toml |grep -A1 L2 export l1_chain_id=$(cat $DEST/cdk-node-config.toml | grep L1ChainID | cut -f 2 -d '=' | head -n 1) echo $l1_chain_id export zkevm_is_validium=$(cat $DEST/cdk-node-config.toml | grep IsValidiumMode | cut -f 2 -d '=') - +export zkevm_contract_versions=$(cat $DEST/cdk-node-config.toml | grep ContractVersions | cut -f 2 -d '=' | tr -d '"' | tr -d ' ') if [ "$zkevm_is_validium" == "true" ]; then echo "Validium mode detected... Retrieving the dac_port" dac_port=$(kurtosis port print $KURTOSIS_ENCLAVE zkevm-dac-001 dac | cut -f 3 -d ":") diff --git a/test/config/test.kurtosis_template.toml b/test/config/test.kurtosis_template.toml index cf446e62..c065cd6d 100644 --- a/test/config/test.kurtosis_template.toml +++ b/test/config/test.kurtosis_template.toml @@ -6,7 +6,7 @@ ForkUpgradeNewForkId = 0 [Common] IsValidiumMode = ${zkevm_is_validium} -ContractVersions = "elderberry" +ContractVersions = "${zkevm_contract_versions}" [Common.Translator] FullMatchRules = [ {Old="http://zkevm-dac-001:8484", New="http://127.0.0.1:${dac_port}"}, From b844d9c726bec2209c813795eee3c77a7e17c0b6 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:43:30 +0200 Subject: [PATCH 28/40] fix: lint --- sequencesender/txbuilder/banana_base.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index 54db2032..c8d0e516 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -109,9 +109,9 @@ func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL } else if err != nil { return 0, fmt.Errorf("error calling GetLatestInfoUntilBlock with block num %d: %w", header.Number.Uint64(), err) } - // This is a very rare case, but it can happen if there are no leaves in L1InfoTree yet, so the batch can use any of them and set 0 + // special case: there are no leaves in L1InfoTree yet if resL1InfoCounter == 0 && highestL1IndexInBatch == 0 { - log.Infof("No L1 Info tree leaves yet, batch don't use any leaf (index=0), so we use CounterL1InfoRoot=0 that is the empty tree") + log.Infof("No L1 Info tree leaves yet, batch use no leaf") return resL1InfoCounter, nil } if resL1InfoCounter > highestL1IndexInBatch { From 67536e3e2440b98c940c85d5018b937ec1c130af Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:14:46 +0200 Subject: [PATCH 29/40] fix: unittest --- sequencesender/txbuilder/banana_base_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sequencesender/txbuilder/banana_base_test.go b/sequencesender/txbuilder/banana_base_test.go index 3b449084..827ea8a1 100644 --- a/sequencesender/txbuilder/banana_base_test.go +++ b/sequencesender/txbuilder/banana_base_test.go @@ -124,6 +124,19 @@ func TestBananaSanityCheckNilSeq(t *testing.T) { require.Error(t, err, "nil sequence") } +func TestBananaEmptyL1InfoTree(t *testing.T) { + testData := newBananaBaseTestData(t) + + testData.l1Client.On("HeaderByNumber", mock.Anything, mock.Anything). + Return(&types.Header{Number: big.NewInt(69)}, nil) + testData.l1InfoTreeSync.EXPECT().GetLatestInfoUntilBlock(testData.ctx, uint64(69)).Return(nil, l1infotreesync.ErrNotFound) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(testData.ctx).Return(&l1infotreesync.L1InfoTreeInitial{LeafCount: 10}, nil) + + leafCounter, err := testData.sut.GetCounterL1InfoRoot(testData.ctx, 0) + require.NoError(t, err) + require.Equal(t, uint32(10), leafCounter) +} + type testDataBananaBase struct { rollupContract *mocks_txbuilder.RollupBananaBaseContractor getContract *mocks_txbuilder.GlobalExitRootBananaContractor @@ -131,6 +144,7 @@ type testDataBananaBase struct { sut *txbuilder.TxBuilderBananaBase l1InfoTreeSync *mocks_txbuilder.L1InfoSyncer l1Client *mocks_txbuilder.L1Client + ctx context.Context } func newBananaBaseTestData(t *testing.T) *testDataBananaBase { @@ -155,5 +169,6 @@ func newBananaBaseTestData(t *testing.T) *testDataBananaBase { sut: sut, l1InfoTreeSync: l1InfoSyncer, l1Client: l1Client, + ctx: context.TODO(), } } From 4bf99f6dcb6041b45d1a96bf4858a6bf6a760788 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:24:14 +0200 Subject: [PATCH 30/40] feat: add check of leafCount --- sequencesender/txbuilder/banana_base.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index c8d0e516..f7bc9be0 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -124,6 +124,22 @@ func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL ) } +func (t *TxBuilderBananaBase) CheckL1InfoTreeLeafCounterVsInitL1InfoMap(ctx context.Context, leafCounter uint32) error { + l1infotreeInitial, err := t.l1InfoTree.GetInitL1InfoRootMap(ctx) + if errors.Is(err, l1infotreesync.ErrNotFound) { + log.Warnf("No InitL1InfoRootMap found, skipping check") + return nil + } + if err != nil { + return fmt.Errorf("l1InfoTree.GetInitL1InfoRootMap fails: %w", err) + } + if leafCounter < l1infotreeInitial.LeafCount { + return fmt.Errorf("cant use this leafCounter because is previous to first value on contract Map"+ + "leafCounter(%d) < l1infotreeInitial.LeafCount(%d)", leafCounter, l1infotreeInitial.LeafCount) + } + return nil +} + func (t *TxBuilderBananaBase) NewSequence( ctx context.Context, batches []seqsendertypes.Batch, coinbase common.Address, ) (seqsendertypes.Sequence, error) { @@ -140,7 +156,10 @@ func (t *TxBuilderBananaBase) NewSequence( if err != nil { return nil, err } - + err = t.CheckL1InfoTreeLeafCounterVsInitL1InfoMap(ctx, sequence.CounterL1InfoRoot) + if err != nil { + return nil, err + } sequence.L1InfoRoot = l1InfoRoot accInputHash, err := t.rollupContract.LastAccInputHash(&bind.CallOpts{Pending: false}) From 45bcfa18b651772cfc558f4a7cf8776cff6a2c99 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:34:43 +0200 Subject: [PATCH 31/40] fix: unittest --- sequencesender/txbuilder/banana_base_test.go | 1 + sequencesender/txbuilder/banana_validium_test.go | 4 ++++ sequencesender/txbuilder/banana_zkevm_test.go | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/sequencesender/txbuilder/banana_base_test.go b/sequencesender/txbuilder/banana_base_test.go index 827ea8a1..7944b652 100644 --- a/sequencesender/txbuilder/banana_base_test.go +++ b/sequencesender/txbuilder/banana_base_test.go @@ -31,6 +31,7 @@ func TestBananaBaseNewSequenceEmpty(t *testing.T) { Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 69}, nil) lastAcc := common.HexToHash("0x8aca9664752dbae36135fd0956c956fc4a370feeac67485b49bcd4b99608ae41") testData.rollupContract.EXPECT().LastAccInputHash(mock.Anything).Return(lastAcc, nil) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) seq, err := testData.sut.NewSequence(context.TODO(), nil, common.Address{}) require.NotNil(t, seq) require.NoError(t, err) diff --git a/sequencesender/txbuilder/banana_validium_test.go b/sequencesender/txbuilder/banana_validium_test.go index 8f764595..d7704f7a 100644 --- a/sequencesender/txbuilder/banana_validium_test.go +++ b/sequencesender/txbuilder/banana_validium_test.go @@ -34,6 +34,8 @@ func TestBananaValidiumBuildSequenceBatchesTxSequenceErrorsFromDA(t *testing.T) Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + seq, err := newSequenceBananaValidiumForTest(testData) require.NoError(t, err) ctx := context.TODO() @@ -53,6 +55,8 @@ func TestBananaValidiumBuildSequenceBatchesTxSequenceDAOk(t *testing.T) { Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + seq, err := newSequenceBananaValidiumForTest(testData) require.NoError(t, err) ctx := context.TODO() diff --git a/sequencesender/txbuilder/banana_zkevm_test.go b/sequencesender/txbuilder/banana_zkevm_test.go index a4ff4bd7..f0e05268 100644 --- a/sequencesender/txbuilder/banana_zkevm_test.go +++ b/sequencesender/txbuilder/banana_zkevm_test.go @@ -40,6 +40,8 @@ func TestBananaZkevmBuildSequenceBatchesTxOk(t *testing.T) { Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + seq, err := newSequenceBananaZKEVMForTest(testData) require.NoError(t, err) @@ -61,6 +63,8 @@ func TestBananaZkevmBuildSequenceBatchesTxErr(t *testing.T) { Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + seq, err := newSequenceBananaZKEVMForTest(testData) require.NoError(t, err) From 1eca448e849ce85856a6ca935588707a6ac37b68 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:44:52 +0200 Subject: [PATCH 32/40] fix: unittest --- sequencesender/txbuilder/banana_base_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sequencesender/txbuilder/banana_base_test.go b/sequencesender/txbuilder/banana_base_test.go index 7944b652..c605ff19 100644 --- a/sequencesender/txbuilder/banana_base_test.go +++ b/sequencesender/txbuilder/banana_base_test.go @@ -75,6 +75,8 @@ func TestBananaBaseNewSequenceBatch(t *testing.T) { Coinbase: []byte{1, 2, 3}, GlobalExitRoot: []byte{4, 5, 6}, } + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound).Once() + batch := testData.sut.NewBatchFromL2Block(l2Block) batches := []seqsendertypes.Batch{batch} lastAcc := common.HexToHash("0x8aca9664752dbae36135fd0956c956fc4a370feeac67485b49bcd4b99608ae41") From 60be781794392916f487bda02f27143edc4e7642 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:25:41 +0200 Subject: [PATCH 33/40] fix: e2e fails show logs --- test/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Makefile b/test/Makefile index 4833f214..7f379498 100644 --- a/test/Makefile +++ b/test/Makefile @@ -49,12 +49,12 @@ generate-mocks-sync: ## Generates mocks for sync, using mockery tool .PHONY: test-e2e-elderberry-validium test-e2e-elderberry-validium: stop ## Runs e2e tests checking elderberry/validium ./run-e2e.sh cdk-validium - bats . + bats . || kurtosis service logs --all cdk-v1 cdk-node-001 && false .PHONY: test-e2e-elderberry-rollup test-e2e-elderberry-rollup: stop ## Runs e2e tests checking elderberry/rollup ./run-e2e.sh rollup - bats . + bats . || kurtosis service logs --all cdk-v1 cdk-node-001 && false .PHONY: stop stop: From 0c6c5ddf427f770ef378fd3c1b107d179e2a7152 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:49:06 +0200 Subject: [PATCH 34/40] fix: e2e --- sequencesender/txbuilder/banana_base.go | 10 ++++----- sequencesender/txbuilder/banana_base_test.go | 22 ++++++++++++++++++++ test/Makefile | 4 ++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index f7bc9be0..2868bb4b 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -101,7 +101,7 @@ func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL if errors.Is(err, l1infotreesync.ErrNotFound) { // There are no L1 Info tree leaves yet, so we can try to use L1InfoRootMap event l1infotreeInitial, err := t.l1InfoTree.GetInitL1InfoRootMap(ctx) - if err != nil { + if l1infotreeInitial == nil || err != nil { return 0, fmt.Errorf("error no leaves on L1InfoTree yet and GetInitL1InfoRootMap fails: %w", err) } // We use this leaf as first one @@ -126,13 +126,13 @@ func (t *TxBuilderBananaBase) GetCounterL1InfoRoot(ctx context.Context, highestL func (t *TxBuilderBananaBase) CheckL1InfoTreeLeafCounterVsInitL1InfoMap(ctx context.Context, leafCounter uint32) error { l1infotreeInitial, err := t.l1InfoTree.GetInitL1InfoRootMap(ctx) - if errors.Is(err, l1infotreesync.ErrNotFound) { - log.Warnf("No InitL1InfoRootMap found, skipping check") - return nil - } if err != nil { return fmt.Errorf("l1InfoTree.GetInitL1InfoRootMap fails: %w", err) } + if l1infotreeInitial == nil { + log.Warnf("No InitL1InfoRootMap found, skipping check") + return nil + } if leafCounter < l1infotreeInitial.LeafCount { return fmt.Errorf("cant use this leafCounter because is previous to first value on contract Map"+ "leafCounter(%d) < l1infotreeInitial.LeafCount(%d)", leafCounter, l1infotreeInitial.LeafCount) diff --git a/sequencesender/txbuilder/banana_base_test.go b/sequencesender/txbuilder/banana_base_test.go index c605ff19..964b02f6 100644 --- a/sequencesender/txbuilder/banana_base_test.go +++ b/sequencesender/txbuilder/banana_base_test.go @@ -140,6 +140,28 @@ func TestBananaEmptyL1InfoTree(t *testing.T) { require.Equal(t, uint32(10), leafCounter) } +func TestCheckL1InfoTreeLeafCounterVsInitL1InfoMap(t *testing.T) { + testData := newBananaBaseTestData(t) + + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(testData.ctx).Return(&l1infotreesync.L1InfoTreeInitial{LeafCount: 10}, nil) + err := testData.sut.CheckL1InfoTreeLeafCounterVsInitL1InfoMap(testData.ctx, 10) + require.NoError(t, err, "10 == 10 so is accepted") + + err = testData.sut.CheckL1InfoTreeLeafCounterVsInitL1InfoMap(testData.ctx, 9) + require.Error(t, err, "9 < 10 so is rejected") + + err = testData.sut.CheckL1InfoTreeLeafCounterVsInitL1InfoMap(testData.ctx, 11) + require.NoError(t, err, "11 > 10 so is accepted") +} + +func TestCheckL1InfoTreeLeafCounterVsInitL1InfoMapNotFound(t *testing.T) { + testData := newBananaBaseTestData(t) + + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(testData.ctx).Return(nil, nil) + err := testData.sut.CheckL1InfoTreeLeafCounterVsInitL1InfoMap(testData.ctx, 10) + require.NoError(t, err, "10 == 10 so is accepted") +} + type testDataBananaBase struct { rollupContract *mocks_txbuilder.RollupBananaBaseContractor getContract *mocks_txbuilder.GlobalExitRootBananaContractor diff --git a/test/Makefile b/test/Makefile index 7f379498..4833f214 100644 --- a/test/Makefile +++ b/test/Makefile @@ -49,12 +49,12 @@ generate-mocks-sync: ## Generates mocks for sync, using mockery tool .PHONY: test-e2e-elderberry-validium test-e2e-elderberry-validium: stop ## Runs e2e tests checking elderberry/validium ./run-e2e.sh cdk-validium - bats . || kurtosis service logs --all cdk-v1 cdk-node-001 && false + bats . .PHONY: test-e2e-elderberry-rollup test-e2e-elderberry-rollup: stop ## Runs e2e tests checking elderberry/rollup ./run-e2e.sh rollup - bats . || kurtosis service logs --all cdk-v1 cdk-node-001 && false + bats . .PHONY: stop stop: From 15c1c93204fdfe3b7af05824f8c89ae179e67c7a Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:58:59 +0200 Subject: [PATCH 35/40] fix: e2e --- sequencesender/txbuilder/banana_base_test.go | 4 ++-- sequencesender/txbuilder/banana_validium_test.go | 4 ++-- sequencesender/txbuilder/banana_zkevm_test.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sequencesender/txbuilder/banana_base_test.go b/sequencesender/txbuilder/banana_base_test.go index 964b02f6..44d7a7b1 100644 --- a/sequencesender/txbuilder/banana_base_test.go +++ b/sequencesender/txbuilder/banana_base_test.go @@ -31,7 +31,7 @@ func TestBananaBaseNewSequenceEmpty(t *testing.T) { Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 69}, nil) lastAcc := common.HexToHash("0x8aca9664752dbae36135fd0956c956fc4a370feeac67485b49bcd4b99608ae41") testData.rollupContract.EXPECT().LastAccInputHash(mock.Anything).Return(lastAcc, nil) - testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, nil) seq, err := testData.sut.NewSequence(context.TODO(), nil, common.Address{}) require.NotNil(t, seq) require.NoError(t, err) @@ -75,7 +75,7 @@ func TestBananaBaseNewSequenceBatch(t *testing.T) { Coinbase: []byte{1, 2, 3}, GlobalExitRoot: []byte{4, 5, 6}, } - testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound).Once() + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, nil).Once() batch := testData.sut.NewBatchFromL2Block(l2Block) batches := []seqsendertypes.Batch{batch} diff --git a/sequencesender/txbuilder/banana_validium_test.go b/sequencesender/txbuilder/banana_validium_test.go index d7704f7a..71f059b9 100644 --- a/sequencesender/txbuilder/banana_validium_test.go +++ b/sequencesender/txbuilder/banana_validium_test.go @@ -34,7 +34,7 @@ func TestBananaValidiumBuildSequenceBatchesTxSequenceErrorsFromDA(t *testing.T) Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) - testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, nil) seq, err := newSequenceBananaValidiumForTest(testData) require.NoError(t, err) @@ -55,7 +55,7 @@ func TestBananaValidiumBuildSequenceBatchesTxSequenceDAOk(t *testing.T) { Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) - testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, nil) seq, err := newSequenceBananaValidiumForTest(testData) require.NoError(t, err) diff --git a/sequencesender/txbuilder/banana_zkevm_test.go b/sequencesender/txbuilder/banana_zkevm_test.go index f0e05268..4570729e 100644 --- a/sequencesender/txbuilder/banana_zkevm_test.go +++ b/sequencesender/txbuilder/banana_zkevm_test.go @@ -40,7 +40,7 @@ func TestBananaZkevmBuildSequenceBatchesTxOk(t *testing.T) { Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) - testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, nil) seq, err := newSequenceBananaZKEVMForTest(testData) require.NoError(t, err) @@ -63,7 +63,7 @@ func TestBananaZkevmBuildSequenceBatchesTxErr(t *testing.T) { Return(&types.Header{Number: big.NewInt(69)}, nil) testData.l1InfoTreeSync.On("GetLatestInfoUntilBlock", mock.Anything, mock.Anything). Return(&l1infotreesync.L1InfoTreeLeaf{L1InfoTreeIndex: 7}, nil) - testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, l1infotreesync.ErrNotFound) + testData.l1InfoTreeSync.EXPECT().GetInitL1InfoRootMap(mock.Anything).Return(nil, nil) seq, err := newSequenceBananaZKEVMForTest(testData) require.NoError(t, err) From 54a5bcfbe84982e20375c3b4316b06bca4987f54 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:22:31 +0200 Subject: [PATCH 36/40] feat: override kurtosis config file on e2e tests --- scripts/local_config | 284 ++++++++++++++---- scripts/run_template.go | 63 ++++ .../kurtosis-cdk-node-config.toml.template | 175 +++++++++++ test/config/test.kurtosis_template.toml | 149 --------- test/run-e2e.sh | 2 + 5 files changed, 467 insertions(+), 206 deletions(-) create mode 100644 scripts/run_template.go create mode 100644 test/config/kurtosis-cdk-node-config.toml.template delete mode 100644 test/config/test.kurtosis_template.toml diff --git a/scripts/local_config b/scripts/local_config index aeb008b0..7303b1fd 100755 --- a/scripts/local_config +++ b/scripts/local_config @@ -1,30 +1,180 @@ #!/bin/bash #Include common varaibles source $(dirname $0)/../test/scripts/env.sh +############################################################################### +function log_debug() { + echo -e "\033[0;30mDebug: $*" "\033[0m" +} +############################################################################### +function log_error() { + echo -e "\033[0;31mError: $*" "\033[0m" +} +############################################################################### +function log_fatal() { + log_error $* + exit 1 +} +############################################################################### +function ok_or_fatal(){ + if [ $? -ne 0 ]; then + log_fatal $* + fi +} + +############################################################################### +function get_value_from_toml_file(){ + local _FILE="$1" + # KEY = . + local _SECTION="$2" + local _KEY="$3" + local _LINE + local _inside_section=0 + while read -r _LINE; do + # Clean up line from spaces and tabs + _LINE=$(echo $_LINE | tr -d '[:space:]') + #echo $_LINE + if [ $_inside_section -eq 1 ]; then + if [[ "$_LINE" == [* ]]; then + return 1 + fi + #local _key_splitted=(${_LINE//=/ }) + local _key_name=$(echo $_LINE | cut -f 1 -d "=") + local _key_value=$(echo $_LINE | cut -f 2- -d "=") + if [ "$_key_name" == "$_KEY" ]; then + echo $_key_value + return 0 + fi + elif [ "$_LINE" == "[${_SECTION}]" ]; then + _inside_section=1 + fi + + + done < "$_FILE" + return 2 + +} +############################################################################### +function export_key_from_toml_file_or_fatal(){ + local _EXPORTED_VAR_NAME="$1" + local _FILE="$2" + local _SECTION="$3" + local _KEY="$4" + local _VALUE=$(get_value_from_toml_file $_FILE $_SECTION $_KEY) + if [ -z "$_VALUE" ]; then + log_fatal "$FUNCNAME: key $_KEY not found in section $_SECTION" + fi + export $_EXPORTED_VAR_NAME="$_VALUE" + log_debug "$_EXPORTED_VAR_NAME=${!_EXPORTED_VAR_NAME} \t\t\t# file:$_FILE section:$_SECTION key:$_KEY" +} + +############################################################################### +function export_obj_key_from_toml_file_or_fatal(){ + local _EXPORTED_VAR_NAME="$1" + local _FILE="$2" + local _SECTION="$3" + local _KEY="$4" + local _OBJ_KEY="$5" + local _VALUE=$(get_value_from_toml_file $_FILE $_SECTION $_KEY) + if [ -z "$_VALUE" ]; then + log_fatal "$FUNCNAME: obj_key $_KEY not found in section $_SECTION" + fi + local _CLEAN_VALUE=$(echo $_VALUE | tr -d '{' | tr -d '}' | tr ',' '\n') + while read -r _LINE; do + local _key_splitted=(${_LINE//=/ }) + if [ "${_key_splitted[0]}" == "$_OBJ_KEY" ]; then + export $_EXPORTED_VAR_NAME=${_key_splitted[1]} + log_debug "$_EXPORTED_VAR_NAME=${!_EXPORTED_VAR_NAME} \t\t\t# file:$_FILE section:$_SECTION key:$_KEY obj_key:$_OBJ_KEY" + return 0 + fi + done <<< "$_CLEAN_VALUE" + log_fatal "obj_key $_OBJ_KEY not found in section $_SECTION/ $_KEY = $_VALUE" +} +############################################################################### function export_values_of_genesis(){ local _GENESIS_FILE=$1 if [ ! -f $_GENESIS_FILE ]; then - echo "Error: genesis file not found: $_GENESIS_FILE" - exit 1 + log_fatal "Error: genesis file not found: $_GENESIS_FILE" fi export l1_chain_id=$(jq -r '.L1Config.chainId' $_GENESIS_FILE | tr -d '"') export pol_token_address=$(jq -r '.L1Config.polTokenAddress' $_GENESIS_FILE) export zkevm_rollup_address=$(jq -r '.L1Config.polygonZkEVMAddress' $_GENESIS_FILE) export zkevm_rollup_manager_address=$(jq -r '.L1Config.polygonRollupManagerAddress' $_GENESIS_FILE) export zkevm_global_exit_root_address=$(jq -r '.L1Config.polygonZkEVMGlobalExitRootAddress' $_GENESIS_FILE) + export zkevm_rollup_manager_block_number=$(jq -r '.rollupManagerCreationBlockNumber' $_GENESIS_FILE) } +############################################################################### +function export_values_of_cdk_node_config(){ + local _CDK_CONFIG_FILE=$1 + export_key_from_toml_file_or_fatal zkevm_l2_sequencer_address $_CDK_CONFIG_FILE SequenceSender L2Coinbase + export_obj_key_from_toml_file_or_fatal zkevm_l2_keystore_password $_CDK_CONFIG_FILE SequenceSender PrivateKey Password + export_key_from_toml_file_or_fatal l1_chain_id $_CDK_CONFIG_FILE SequenceSender.EthTxManager.Etherman L1ChainID + export_key_from_toml_file_or_fatal zkevm_is_validium $_CDK_CONFIG_FILE Common IsValidiumMode + export_key_from_toml_file_or_fatal zkevm_contract_versions $_CDK_CONFIG_FILE Common ContractVersions + export_key_from_toml_file_or_fatal l2_chain_id $_CDK_CONFIG_FILE Aggregator ChainID + export_key_from_toml_file_or_fatal zkevm_aggregator_port $_CDK_CONFIG_FILE Aggregator Port + export_key_from_toml_file_or_fatal zkevm_l2_agglayer_address $_CDK_CONFIG_FILE Aggregator SenderAddress + export_key_from_toml_file_or_fatal aggregator_db_name $_CDK_CONFIG_FILE Aggregator.DB Name + export_key_from_toml_file_or_fatal aggregator_db_user $_CDK_CONFIG_FILE Aggregator.DB User + export_key_from_toml_file_or_fatal aggregator_db_password $_CDK_CONFIG_FILE Aggregator.DB Password + export_key_from_toml_file_or_fatal zkevm_rollup_fork_id $_CDK_CONFIG_FILE Aggregator ForkId + export is_cdk_validium=$zkevm_is_validium + export zkevm_rollup_chain_id=$l2_chain_id - + if [ "$zkevm_is_validium" == "true" ]; then + log_debug "Validium mode detected... Retrieving the dac_port" + export_value_from_kurtosis_or_fail dac_port zkevm-dac-001 dac + fi +} ############################################################################### -# MAIN +function export_value_from_kurtosis_or_fail(){ + local _EXPORTED_VAR_NAME="$1" + local _SERVICE="$2" + local _END_POINT="$3" + export $_EXPORTED_VAR_NAME=$(kurtosis port print $KURTOSIS_ENCLAVE $_SERVICE $_END_POINT) + if [ -z $_EXPORTED_VAR_NAME ]; then + log_fatal "Error getting kurtosis port: $KURTOSIS_ENCLAVE $_SERVICE $_END_POINT" + fi + log_debug "$_EXPORTED_VAR_NAME=${!_EXPORTED_VAR_NAME} \t\t\t# Kurtosis $KURTOSIS_ENCLAVE $_SERVICE $_END_POINT" +} ############################################################################### -set -o pipefail # enable strict command pipe error detection +function export_portnum_from_kurtosis_or_fail(){ + local _EXPORTED_VAR_NAME="$1" + export_value_from_kurtosis_or_fail "$1" "$2" "$3" > /dev/null + local _VALUE + eval "_VALUE=\$$1" + local _PORT=$(echo "$_VALUE" | cut -f 3 -d ":") + if [ -z $_PORT ]; then + log_fatal "Error getting port number from kurtosis: $2 $3 -> $_VALUE" + fi + export $_EXPORTED_VAR_NAME=$_PORT + log_debug "$_EXPORTED_VAR_NAME=${!_EXPORTED_VAR_NAME} \t\t\t# Kurtosis $KURTOSIS_ENCLAVE $2 $3" +} +############################################################################### +function export_ports_from_kurtosis(){ + export_portnum_from_kurtosis_or_fail l1_rpc_port el-1-geth-lighthouse rpc + export_value_from_kurtosis_or_fail l1_rpc_url el-1-geth-lighthouse rpc + export_value_from_kurtosis_or_fail l2_rpc_url cdk-erigon-node-001 http-rpc + export_portnum_from_kurtosis_or_fail zkevm_rpc_http_port cdk-erigon-node-001 http-rpc + export_portnum_from_kurtosis_or_fail zkevm_data_streamer_port cdk-erigon-sequencer-001 data-streamer + export_portnum_from_kurtosis_or_fail aggregator_db_port postgres-001 postgres + export_portnum_from_kurtosis_or_fail agglayer_port agglayer agglayer + export aggregator_db_hostname="127.0.0.1" +} -which kurtosis > /dev/null -if [ $? -ne 0 ]; then - echo "kurtosis is not installed. Please install it:" +############################################################################### +function export_forced_values(){ + export global_log_level="debug" + export l2_rpc_name="localhost" + export sequencer_name="localhost" + export deployment_suffix="" +} +############################################################################### +function check_requirements(){ + which kurtosis > /dev/null + if [ $? -ne 0 ]; then + log_error "kurtosis is not installed. Please install it:" cat << EOF echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list @@ -33,58 +183,78 @@ if [ $? -ne 0 ]; then EOF exit 1 -fi + fi + if [ -z $TMP_CDK_FOLDER -o -z $KURTOSIS_ENCLAVE ]; then + log_fatal "TMP_CDK_FOLDER or KURTOSIS_ENCLAVE is not set. Must be set on file env.sh" + fi + kurtosis enclave inspect $KURTOSIS_ENCLAVE > /dev/null + if [ $? -ne 0 ]; then + log_error "Error inspecting enclave $KURTOSIS_ENCLAVE" + echo "You must start kurtosis environment before running this script" + echo "- start kurtosis:" + echo " kurtosis clean --all; kurtosis run --enclave $KURTOSIS_ENCLAVE --args-file params.yml --image-download always ." -if [ -z $TMP_CDK_FOLDER -o -z $KURTOSIS_ENCLAVE ]; then - echo "TMP_CDK_FOLDER or KURTOSIS_ENCLAVE is not set. Must be set on file env.sh" - exit 1 -fi -kurtosis enclave inspect $KURTOSIS_ENCLAVE > /dev/null -if [ $? -ne 0 ]; then - echo "Error inspecting enclave $KURTOSIS_ENCLAVE" - echo "You must start kurtosis environment before running this script" - echo "- start kurtosis:" - echo " kurtosis clean --all; kurtosis run --enclave $KURTOSIS_ENCLAVE --args-file params.yml --image-download always ." + exit 1 + fi +} +############################################################################### +function create_dest_folder(){ + export DEST=${TMP_CDK_FOLDER}/local_config + [ ! -d ${DEST} ] && mkdir -p ${DEST} + rm $DEST/* +} +############################################################################### +function download_kurtosis_artifacts(){ + kurtosis files download $KURTOSIS_ENCLAVE genesis $DEST + ok_or_fatal "Error downloading kurtosis artifact genesis to $DEST" + export genesis_file=$DEST/genesis.json + + kurtosis files download $KURTOSIS_ENCLAVE sequencer-keystore $DEST + ok_or_fatal "Error downloading kurtosis artifact sequencer-keystore to $DEST" + export sequencer_keystore_file=$DEST/sequencer.keystore + + kurtosis files download $KURTOSIS_ENCLAVE cdk-node-config-artifact $DEST + ok_or_fatal "Error downloading kurtosis artifact cdk-node-config-artifact to $DEST" +} +############################################################################### +function check_generated_config_file(){ + grep "" $DEST_TEMPLATE_FILE > /dev/null + if [ $? -ne 1 ]; then + log_error "some values are not set, check $ORIG_TEMPLATE_FILE" + echo "" + echo "missing keys in rendered template: $DEST_TEMPLATE_FILE" + echo " " + grep "" $DEST_TEMPLATE_FILE + exit 1 + fi +} +############################################################################### +# MAIN +############################################################################### +set -o pipefail # enable strict command pipe error detection +check_requirements +create_dest_folder + +download_kurtosis_artifacts - exit 1 -fi -DEST=${TMP_CDK_FOLDER}/local_config - -[ ! -d ${DEST} ] && mkdir -p ${DEST} -rm $DEST/* -kurtosis files download $KURTOSIS_ENCLAVE genesis $DEST -[ $? -ne 0 ] && echo "Error downloading genesis" && exit 1 -export genesis_file=$DEST/genesis.json export_values_of_genesis $genesis_file -kurtosis files download $KURTOSIS_ENCLAVE sequencer-keystore $DEST -[ $? -ne 0 ] && echo "Error downloading sequencer-keystore" && exit 1 -export sequencer_keystore_file=$DEST/sequencer.keystore - -l1_rpc_port=$(kurtosis port print $KURTOSIS_ENCLAVE el-1-geth-lighthouse rpc | cut -f 3 -d ":") -[ $? -ne 0 ] && echo "Error getting l1_rpc_port" && exit 1 || export l1_rpc_port && echo "l1_rpc_port=$l1_rpc_port" -l1_rpc_addr=$(kurtosis port print $KURTOSIS_ENCLAVE el-1-geth-lighthouse rpc) -[ $? -ne 0 ] && echo "Error getting l1_rpc_addr" && exit 1 || export l1_rpc_addr && echo "l1_rpc_addr=$l1_rpc_addr" -l2_rpc_addr=$(kurtosis port print $KURTOSIS_ENCLAVE cdk-erigon-node-001 http-rpc) -[ $? -ne 0 ] && echo "Error getting l2_rpc_addr" && exit 1 || export l2_rpc_addr && echo "l2_rpc_addr=$l2_rpc_addr" - -zkevm_data_streamer_port=$(kurtosis port print $KURTOSIS_ENCLAVE cdk-erigon-sequencer-001 data-streamer | cut -f 3 -d ":") -[ $? -ne 0 ] && echo "Error getting zkevm_data_streamer_port" && exit 1 || export zkevm_data_streamer_port && echo "zkevm_data_streamer_port=$zkevm_data_streamer_port" - -kurtosis files download $KURTOSIS_ENCLAVE cdk-node-config-artifact $DEST -export zkevm_l2_sequencer_address=$(cat $DEST/cdk-node-config.toml |grep L2Coinbase | cut -f 2 -d "="| tr -d '"' | tr -d ' ') -export zkevm_l2_keystore_password=$(cat $DEST/cdk-node-config.toml |grep -A1 L2Coinbase | tr ',' '\n' | grep Password | cut -f 2 -d '=' | tr -d '}' | tr -d '"' | tr -d ' ') -export l1_chain_id=$(cat $DEST/cdk-node-config.toml | grep L1ChainID | cut -f 2 -d '=' | head -n 1) -echo $l1_chain_id -export zkevm_is_validium=$(cat $DEST/cdk-node-config.toml | grep IsValidiumMode | cut -f 2 -d '=') -export zkevm_contract_versions=$(cat $DEST/cdk-node-config.toml | grep ContractVersions | cut -f 2 -d '=' | tr -d '"' | tr -d ' ') -if [ "$zkevm_is_validium" == "true" ]; then - echo "Validium mode detected... Retrieving the dac_port" - dac_port=$(kurtosis port print $KURTOSIS_ENCLAVE zkevm-dac-001 dac | cut -f 3 -d ":") - [ $? -ne 0 ] && echo "Error getting dac_port" && exit 1 || export dac_port && echo "dac_port=$dac_port" -fi - -envsubst < test/config/test.kurtosis_template.toml > $DEST/test.kurtosis.toml +export_ports_from_kurtosis +export_values_of_cdk_node_config $DEST/cdk-node-config.toml +export_forced_values + +ORIG_TEMPLATE_FILE=test/config/kurtosis-cdk-node-config.toml.template +DEST_TEMPLATE_FILE=$DEST/test.kurtosis.toml + +# Generate config file +go run scripts/run_template.go $ORIG_TEMPLATE_FILE > $DEST_TEMPLATE_FILE +ok_or_fatal "Error generating template" + +check_generated_config_file + + +echo " " echo "file generated at:" $DEST/test.kurtosis.toml + echo "- to restart kurtosis:" echo " kurtosis clean --all; kurtosis run --enclave cdk-v1 --args-file params.yml --image-download always ." echo " " @@ -102,7 +272,7 @@ cat << EOF "cwd": "\${workspaceFolder}", "args":[ "run", - "-cfg", "$DEST/test.kurtosis.toml", + "-cfg", "$DEST_TEMPLATE_FILE", "-components", "sequence-sender,aggregator", ] }, diff --git a/scripts/run_template.go b/scripts/run_template.go new file mode 100644 index 00000000..b629de5a --- /dev/null +++ b/scripts/run_template.go @@ -0,0 +1,63 @@ +package main + +import ( + "fmt" + "log" + "os" + "regexp" + "strings" + "text/template" +) + +func main() { + tmpl := template.New("t1") + content, err := readFile(os.Args[1]) + if err != nil { + log.Fatalf("Error loading template: %v", err) + } + content = replaceDotsInTemplateVariables(content) + tmpl = template.Must(tmpl.Parse(content)) + + if err := tmpl.Execute(os.Stdout, environmentToMap()); err != nil { + log.Fatalf("Error executing template: %v", err) + } +} +func replaceDotsInTemplateVariables(template string) string { + re := regexp.MustCompile(`{{\s*\.([^{}]*)\s*}}`) + result := re.ReplaceAllStringFunc(template, func(match string) string { + match = strings.ReplaceAll(match[3:], ".", "_") + return "{{." + match + }) + return result +} + +func readFile(filename string) (string, error) { + content, err := os.ReadFile(filename) + if err != nil { + return "", err + } + return string(content), nil +} + +func environmentToMap() map[string]any { + envVars := make(map[string]any) + for _, e := range os.Environ() { + pair := splitAtFirst(e, '=') + fmt.Printf("zzzz env=%s pair=%v\n", e, pair) + envVars[pair[0]] = pair[1] + } + envVars["aggregator_db"] = map[string]string{ + "user": "user", + "name": "Name", + } + return envVars +} + +func splitAtFirst(s string, sep rune) [2]string { + for i, c := range s { + if c == sep { + return [2]string{s[:i], s[i+1:]} + } + } + return [2]string{s, ""} +} diff --git a/test/config/kurtosis-cdk-node-config.toml.template b/test/config/kurtosis-cdk-node-config.toml.template new file mode 100644 index 00000000..e774ca72 --- /dev/null +++ b/test/config/kurtosis-cdk-node-config.toml.template @@ -0,0 +1,175 @@ +ForkUpgradeBatchNumber = 0 +ForkUpgradeNewForkId = 0 + +[Common] +IsValidiumMode = {{.is_cdk_validium}} + +{{if eq .zkevm_rollup_fork_id "12"}} +ContractVersions = "banana" +{{else}} +ContractVersions = "elderberry" +{{end}} + +[Etherman] +URL = "{{.l1_rpc_url}}" + +[Log] +Environment = "development" # "production" or "development" +Level = "{{.global_log_level}}" +Outputs = ["stderr"] + +[SequenceSender] +WaitPeriodSendSequence = "15s" +LastBatchVirtualizationTimeMaxWaitPeriod = "10s" +MaxTxSizeForL1 = 131072 +L2Coinbase = "{{.zkevm_l2_sequencer_address}}" +PrivateKey = {Path = "/etc/cdk/sequencer.keystore", Password = "{{.zkevm_l2_keystore_password}}"} +SequencesTxFileName = "/data/sequencesender.json" +GasOffset = 80000 +WaitPeriodPurgeTxFile = "15m" +MaxPendingTx = 1 +{{if eq .zkevm_rollup_fork_id "12"}} +MaxBatchesForL1 = 300 +BlockFinality="FinalizedBlock" +RPCURL = "http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" +GetBatchWaitInterval = "10s" +{{end}} + [SequenceSender.StreamClient] + Server = "{{.sequencer_name}}{{.deployment_suffix}}:{{.zkevm_data_streamer_port}}" + [SequenceSender.EthTxManager] + FrequencyToMonitorTxs = "1s" + WaitTxToBeMined = "2m" + ConsolidationL1ConfirmationBlocks = 5 + {{if eq .zkevm_rollup_fork_id "12"}} + FinalizedStatusL1NumberOfBlocks = 10 + WaitReceiptMaxTime = "250ms" + WaitReceiptCheckInterval = "8s" + {{else}} + FinalizationL1ConfirmationBlocks = 10 + WaitReceiptToBeGenerated = "8s" + {{end}} + PrivateKeys = [ + {Path = "/etc/cdk/sequencer.keystore", Password = "{{.zkevm_l2_keystore_password}}"}, + ] + ForcedGas = 0 + GasPriceMarginFactor = 1 + MaxGasPriceLimit = 0 + PersistenceFilename = "/data/ethtxmanager.json" + [SequenceSender.EthTxManager.Etherman] + URL = "{{.l1_rpc_url}}" + L1ChainID = {{.l1_chain_id}} + HTTPHeaders = [] + +[Aggregator] + FinalProofSanityCheckEnabled = false + Host = "0.0.0.0" + Port = "{{.zkevm_aggregator_port}}" + RetryTime = "30s" + VerifyProofInterval = "30s" + ProofStatePollingInterval = "5s" + TxProfitabilityCheckerType = "acceptall" + TxProfitabilityMinReward = "1.1" + IntervalAfterWhichBatchConsolidateAnyway = "0s" + ChainID = "{{.zkevm_rollup_chain_id}}" + ForkId = {{.zkevm_rollup_fork_id}} + CleanupLockedProofsInterval = "2m0s" + GeneratingProofCleanupThreshold = "10m" + GasOffset = 150000 + UpgradeEtrogBatchNumber = "{{.zkevm_rollup_manager_block_number}}" + WitnessURL = "http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" + {{if .is_cdk_validium}} + SenderAddress = "{{.zkevm_l2_agglayer_address}}" + SettlementBackend = "agglayer" + AggLayerTxTimeout = "600s" + AggLayerURL = "http://agglayer:{{.agglayer_port}}" + {{else}} + SenderAddress = "{{.zkevm_l2_aggregator_address}}" + {{end}} + + {{if eq .zkevm_rollup_fork_id "12"}} + UseL1BatchData = true + UseFullWitness = false + MaxWitnessRetrievalWorkers = 2 + SyncModeOnlyEnabled = false + {{end}} + + [Aggregator.SequencerPrivateKey] + Path = "/etc/cdk/sequencer.keystore" + Password = "{{.zkevm_l2_keystore_password}}" + [Aggregator.DB] + Name = "{{.aggregator_db.name}}" + User = "{{.aggregator_db.user}}" + Password = "{{.aggregator_db.password}}" + Host = "{{.aggregator_db.hostname}}" + Port = "{{.aggregator_db.port}}" + EnableLog = false + MaxConns = 200 + [Aggregator.Log] + Environment = "development" # "production" or "development" + Level = "{{.global_log_level}}" + Outputs = ["stderr"] + [Aggregator.StreamClient] + Server = "{{.sequencer_name}}{{.deployment_suffix}}:{{.zkevm_data_streamer_port}}" + [Aggregator.EthTxManager] + FrequencyToMonitorTxs = "1s" + WaitTxToBeMined = "2m" + + {{if eq .zkevm_rollup_fork_id "12"}} + WaitReceiptMaxTime = "250ms" + WaitReceiptCheckInterval = "1s" + {{else}} + GetReceiptMaxTime = "250ms" + GetReceiptWaitInterval = "1s" + {{end}} + + PrivateKeys = [ + {Path = "/etc/cdk/aggregator.keystore", Password = "{{.zkevm_l2_keystore_password}}"}, + ] + ForcedGas = 0 + GasPriceMarginFactor = 1 + MaxGasPriceLimit = 0 + PersistenceFilename = "" + ReadPendingL1Txs = false + SafeStatusL1NumberOfBlocks = 0 + FinalizedStatusL1NumberOfBlocks = 0 + [Aggregator.EthTxManager.Etherman] + URL = "{{.l1_rpc_url}}" + L1ChainID = {{.l1_chain_id}} + HTTPHeaders = [] + [Aggregator.Synchronizer] + [Aggregator.Synchronizer.SQLDB] + DriverName = "sqlite3" + DataSource = "file:/data/aggregator_sync_db.sqlite" + [Aggregator.Synchronizer.Synchronizer] + SyncInterval = "10s" + SyncChunkSize = 1000 + GenesisBlockNumber = "{{.zkevm_rollup_manager_block_number}}" + SyncUpToBlock = "latest" + BlockFinality = "latest" + OverrideStorageCheck = false + [Aggregator.Synchronizer.Etherman] + [Aggregator.Synchronizer.Etherman.Validium] + Enabled = {{.is_cdk_validium}} + +{{if eq .zkevm_rollup_fork_id "12"}} +[L1InfoTreeSync] +DBPath = "/tmp/L1InfoTreeSync" # TODO: put a more realisitic path here +GlobalExitRootAddr = "{{.zkevm_global_exit_root_address}}" +RollupManagerAddr = "{{.zkevm_rollup_manager_address}}" +SyncBlockChunkSize = 10 +BlockFinality = "LatestBlock" +URLRPCL1 = "{{.l1_rpc_url}}" +WaitForNewBlocksPeriod = "1s" +InitialBlock = "{{.zkevm_rollup_manager_block_number}}" +{{end}} + +[NetworkConfig.L1] +{{if eq .zkevm_rollup_fork_id "12"}} +L1ChainID = "{{.l1_chain_id}}" +{{else}} +ChainID = "{{.l1_chain_id}}" +{{end}} +PolAddr = "{{.pol_token_address}}" +ZkEVMAddr = "{{.zkevm_rollup_address}}" +RollupManagerAddr = "{{.zkevm_rollup_manager_address}}" +GlobalExitRootManagerAddr = "{{.zkevm_global_exit_root_address}}" diff --git a/test/config/test.kurtosis_template.toml b/test/config/test.kurtosis_template.toml deleted file mode 100644 index c065cd6d..00000000 --- a/test/config/test.kurtosis_template.toml +++ /dev/null @@ -1,149 +0,0 @@ -ForkUpgradeBatchNumber = 0 -ForkUpgradeNewForkId = 0 - -[Etherman] - URL = "http://127.0.0.1:${l1_rpc_port}" - -[Common] -IsValidiumMode = ${zkevm_is_validium} -ContractVersions = "${zkevm_contract_versions}" -[Common.Translator] - FullMatchRules = [ - {Old="http://zkevm-dac-001:8484", New="http://127.0.0.1:${dac_port}"}, - ] - -[Log] -Environment = "development" # "production" or "development" -Level = "debug" -Outputs = ["stderr"] - -[SequenceSender] -WaitPeriodSendSequence = "15s" -LastBatchVirtualizationTimeMaxWaitPeriod = "10s" -L1BlockTimestampMargin = "30s" -MaxTxSizeForL1 = 131072 -MaxBatchesForL1 = 2 -L2Coinbase = "${zkevm_l2_sequencer_address}" -PrivateKey = {Path = "${sequencer_keystore_file}", Password = "${zkevm_l2_keystore_password}"} - -SequencesTxFileName = "sequencesender.json" -GasOffset = 80000 -WaitPeriodPurgeTxFile = "15m" -MaxPendingTx = 1 -SanityCheckRPCURL = "${l2_rpc_addr}" - [SequenceSender.StreamClient] - Server = "127.0.0.1:${zkevm_data_streamer_port}" - [SequenceSender.EthTxManager] - FrequencyToMonitorTxs = "1s" - WaitTxToBeMined = "2m" - GetReceiptMaxTime = "250ms" - GetReceiptWaitInterval = "1s" - PrivateKeys = [ - {Path = "${sequencer_keystore_file}", Password = "${zkevm_l2_keystore_password}"}, - ] - ForcedGas = 0 - GasPriceMarginFactor = 1 - MaxGasPriceLimit = 0 - PersistenceFilename = "ethtxmanager.json" - ReadPendingL1Txs = false - SafeStatusL1NumberOfBlocks = 0 - FinalizedStatusL1NumberOfBlocks = 0 - [SequenceSender.EthTxManager.Etherman] - URL = "http://127.0.0.1:${l1_rpc_port}" - MultiGasProvider = false - L1ChainID = ${l1_chain_id} -[Aggregator] -Host = "0.0.0.0" -Port = 50081 -RetryTime = "5s" -VerifyProofInterval = "10s" -TxProfitabilityCheckerType = "acceptall" -TxProfitabilityMinReward = "1.1" -ProofStatePollingInterval = "5s" -SenderAddress = "" -CleanupLockedProofsInterval = "2m" -GeneratingProofCleanupThreshold = "10m" -BatchProofSanityCheckEnabled = true -ForkId = 9 -GasOffset = 0 -WitnessURL = "localhost:8123" -UseL1BatchData = true -UseFullWitness = false -SettlementBackend = "l1" -AggLayerTxTimeout = "5m" -AggLayerURL = "" -MaxWitnessRetrievalWorkers = 2 -SyncModeOnlyEnabled = false -SequencerPrivateKey = {} - [Aggregator.DB] - Name = "aggregator_db" - User = "aggregator_user" - Password = "aggregator_password" - Host = "cdk-aggregator-db" - Port = "5432" - EnableLog = false - MaxConns = 200 - [Aggregator.Log] - Environment = "development" # "production" or "development" - Level = "info" - Outputs = ["stderr"] - [Aggregator.StreamClient] - Server = "localhost:6900" - [Aggregator.EthTxManager] - FrequencyToMonitorTxs = "1s" - WaitTxToBeMined = "2m" - GetReceiptMaxTime = "250ms" - GetReceiptWaitInterval = "1s" - PrivateKeys = [ - {Path = "/pk/aggregator.keystore", Password = "testonly"}, - ] - ForcedGas = 0 - GasPriceMarginFactor = 1 - MaxGasPriceLimit = 0 - PersistenceFilename = "" - ReadPendingL1Txs = false - SafeStatusL1NumberOfBlocks = 0 - FinalizedStatusL1NumberOfBlocks = 0 - [Aggregator.EthTxManager.Etherman] - URL = "" - L1ChainID = ${l1_chain_id} - HTTPHeaders = [] - [Aggregator.Synchronizer] - [Aggregator.Synchronizer.DB] - Name = "sync_db" - User = "sync_user" - Password = "sync_password" - Host = "cdk-l1-sync-db" - Port = "5432" - EnableLog = false - MaxConns = 10 - [Aggregator.Synchronizer.Synchronizer] - SyncInterval = "10s" - SyncChunkSize = 1000 - GenesisBlockNumber = 5511080 - SyncUpToBlock = "finalized" - BlockFinality = "finalized" - OverrideStorageCheck = false - [Aggregator.Synchronizer.Etherman] - [Aggregator.Synchronizer.Etherman.Validium] - Enabled = ${zkevm_is_validium} - - -[L1InfoTreeSync] -DBPath = "/tmp/L1InfoTreeSync.sqlite" -GlobalExitRootAddr="${zkevm_global_exit_root_address}" -RollupManagerAddr="${zkevm_rollup_manager_address}" -SyncBlockChunkSize=100 -BlockFinality="LatestBlock" -# http://el-1-geth-lighthouse:8545 -URLRPCL1="${l1_rpc_addr}" -WaitForNewBlocksPeriod="100ms" -InitialBlock=0 - - -[NetworkConfig.L1] -L1ChainID = ${l1_chain_id} -PolAddr = "${pol_token_address}" -ZkEVMAddr = "${zkevm_rollup_address}" -RollupManagerAddr = "${zkevm_rollup_manager_address}" -GlobalExitRootManagerAddr = "${zkevm_global_exit_root_address}" diff --git a/test/run-e2e.sh b/test/run-e2e.sh index 6a29e416..809f06e6 100755 --- a/test/run-e2e.sh +++ b/test/run-e2e.sh @@ -22,4 +22,6 @@ $BASE_FOLDER/scripts/kurtosis_prepare_params_yml.sh "$KURTOSIS_FOLDER" $DATA_AVA [ $? -ne 0 ] && echo "Error preparing params.yml" && exit 1 kurtosis clean --all +echo "Override cdk config file" +cp $BASE_FOLDER/config/kurtosis-cdk-node-config.toml.template $KURTOSIS_FOLDER/templates/trusted-node/cdk-node-config.toml kurtosis run --enclave cdk-v1 --args-file $DEST_KURTOSIS_PARAMS_YML --image-download always $KURTOSIS_FOLDER From 4ade60a25e672a643128e0b01e4c431208f73551 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:30:00 +0200 Subject: [PATCH 37/40] fix: test-e2e.yml --- .github/workflows/test-e2e.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index c89275c7..721cbf09 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -65,7 +65,6 @@ jobs: uses: actions/checkout@v4 with: repository: 0xPolygon/kurtosis-cdk - ref: fix/missing_cdk_config_rollupmanager path: "kurtosis-cdk" ref: "v0.2.11" From 3fd67bd0cc6f10704c3effd3c688c11050605344 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:55:41 +0200 Subject: [PATCH 38/40] fix: config file --- test/config/kurtosis-cdk-node-config.toml.template | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/config/kurtosis-cdk-node-config.toml.template b/test/config/kurtosis-cdk-node-config.toml.template index e774ca72..91ddb819 100644 --- a/test/config/kurtosis-cdk-node-config.toml.template +++ b/test/config/kurtosis-cdk-node-config.toml.template @@ -151,7 +151,7 @@ GetBatchWaitInterval = "10s" [Aggregator.Synchronizer.Etherman.Validium] Enabled = {{.is_cdk_validium}} -{{if eq .zkevm_rollup_fork_id "12"}} + [L1InfoTreeSync] DBPath = "/tmp/L1InfoTreeSync" # TODO: put a more realisitic path here GlobalExitRootAddr = "{{.zkevm_global_exit_root_address}}" @@ -161,7 +161,6 @@ BlockFinality = "LatestBlock" URLRPCL1 = "{{.l1_rpc_url}}" WaitForNewBlocksPeriod = "1s" InitialBlock = "{{.zkevm_rollup_manager_block_number}}" -{{end}} [NetworkConfig.L1] {{if eq .zkevm_rollup_fork_id "12"}} From 57f0ae21d68ad25ec73e347bb83d953ebecf75fd Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:40:58 +0200 Subject: [PATCH 39/40] fix: conflicts --- test/config/test.kurtosis_template.toml | 150 ------------------------ 1 file changed, 150 deletions(-) delete mode 100644 test/config/test.kurtosis_template.toml diff --git a/test/config/test.kurtosis_template.toml b/test/config/test.kurtosis_template.toml deleted file mode 100644 index aec3a3b6..00000000 --- a/test/config/test.kurtosis_template.toml +++ /dev/null @@ -1,150 +0,0 @@ -ForkUpgradeBatchNumber = 0 -ForkUpgradeNewForkId = 0 - -[Etherman] - URL = "http://127.0.0.1:${l1_rpc_port}" - -[Common] -IsValidiumMode = ${zkevm_is_validium} -ContractVersions = "${zkevm_contract_versions}" -[Common.Translator] - FullMatchRules = [ - {Old="http://zkevm-dac-001:8484", New="http://127.0.0.1:${dac_port}"}, - ] - -[Log] -Environment = "development" # "production" or "development" -Level = "debug" -Outputs = ["stderr"] - -[SequenceSender] -WaitPeriodSendSequence = "15s" -LastBatchVirtualizationTimeMaxWaitPeriod = "10s" -L1BlockTimestampMargin = "30s" -MaxTxSizeForL1 = 131072 -MaxBatchesForL1 = 2 -L2Coinbase = "${zkevm_l2_sequencer_address}" -PrivateKey = {Path = "${sequencer_keystore_file}", Password = "${zkevm_l2_keystore_password}"} - -SequencesTxFileName = "sequencesender.json" -GasOffset = 80000 -WaitPeriodPurgeTxFile = "15m" -MaxPendingTx = 1 -RPCURL = "${l2_rpc_addr}" -GetBatchWaitInterval = "10s" - [SequenceSender.StreamClient] - Server = "127.0.0.1:${zkevm_data_streamer_port}" - [SequenceSender.EthTxManager] - FrequencyToMonitorTxs = "1s" - WaitTxToBeMined = "2m" - GetReceiptMaxTime = "250ms" - GetReceiptWaitInterval = "1s" - PrivateKeys = [ - {Path = "${sequencer_keystore_file}", Password = "${zkevm_l2_keystore_password}"}, - ] - ForcedGas = 0 - GasPriceMarginFactor = 1 - MaxGasPriceLimit = 0 - PersistenceFilename = "ethtxmanager.json" - ReadPendingL1Txs = false - SafeStatusL1NumberOfBlocks = 0 - FinalizedStatusL1NumberOfBlocks = 0 - [SequenceSender.EthTxManager.Etherman] - URL = "http://127.0.0.1:${l1_rpc_port}" - MultiGasProvider = false - L1ChainID = ${l1_chain_id} -[Aggregator] -Host = "0.0.0.0" -Port = 50081 -RetryTime = "5s" -VerifyProofInterval = "10s" -TxProfitabilityCheckerType = "acceptall" -TxProfitabilityMinReward = "1.1" -ProofStatePollingInterval = "5s" -SenderAddress = "" -CleanupLockedProofsInterval = "2m" -GeneratingProofCleanupThreshold = "10m" -BatchProofSanityCheckEnabled = true -ForkId = 9 -GasOffset = 0 -WitnessURL = "localhost:8123" -UseL1BatchData = true -UseFullWitness = false -SettlementBackend = "l1" -AggLayerTxTimeout = "5m" -AggLayerURL = "" -MaxWitnessRetrievalWorkers = 2 -SyncModeOnlyEnabled = false -SequencerPrivateKey = {} - [Aggregator.DB] - Name = "aggregator_db" - User = "aggregator_user" - Password = "aggregator_password" - Host = "cdk-aggregator-db" - Port = "5432" - EnableLog = false - MaxConns = 200 - [Aggregator.Log] - Environment = "development" # "production" or "development" - Level = "info" - Outputs = ["stderr"] - [Aggregator.StreamClient] - Server = "localhost:6900" - [Aggregator.EthTxManager] - FrequencyToMonitorTxs = "1s" - WaitTxToBeMined = "2m" - GetReceiptMaxTime = "250ms" - GetReceiptWaitInterval = "1s" - PrivateKeys = [ - {Path = "/pk/aggregator.keystore", Password = "testonly"}, - ] - ForcedGas = 0 - GasPriceMarginFactor = 1 - MaxGasPriceLimit = 0 - PersistenceFilename = "" - ReadPendingL1Txs = false - SafeStatusL1NumberOfBlocks = 0 - FinalizedStatusL1NumberOfBlocks = 0 - [Aggregator.EthTxManager.Etherman] - URL = "" - L1ChainID = ${l1_chain_id} - HTTPHeaders = [] - [Aggregator.Synchronizer] - [Aggregator.Synchronizer.DB] - Name = "sync_db" - User = "sync_user" - Password = "sync_password" - Host = "cdk-l1-sync-db" - Port = "5432" - EnableLog = false - MaxConns = 10 - [Aggregator.Synchronizer.Synchronizer] - SyncInterval = "10s" - SyncChunkSize = 1000 - GenesisBlockNumber = 5511080 - SyncUpToBlock = "finalized" - BlockFinality = "finalized" - OverrideStorageCheck = false - [Aggregator.Synchronizer.Etherman] - [Aggregator.Synchronizer.Etherman.Validium] - Enabled = ${zkevm_is_validium} - - -[L1InfoTreeSync] -DBPath = "/tmp/L1InfoTreeSync.sqlite" -GlobalExitRootAddr="${zkevm_global_exit_root_address}" -RollupManagerAddr="${zkevm_rollup_manager_address}" -SyncBlockChunkSize=100 -BlockFinality="LatestBlock" -# http://el-1-geth-lighthouse:8545 -URLRPCL1="${l1_rpc_addr}" -WaitForNewBlocksPeriod="100ms" -InitialBlock=0 - - -[NetworkConfig.L1] -L1ChainID = ${l1_chain_id} -PolAddr = "${pol_token_address}" -ZkEVMAddr = "${zkevm_rollup_address}" -RollupManagerAddr = "${zkevm_rollup_manager_address}" -GlobalExitRootManagerAddr = "${zkevm_global_exit_root_address}" From ac713d8c91b26707c32fbdf1a0cdc113ee6e3c4c Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:54:49 +0200 Subject: [PATCH 40/40] fix: exclude script from sonarcloud --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index b8f78410..815d53a8 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,7 +7,7 @@ sonar.projectName=cdk sonar.organization=0xpolygon sonar.sources=. -sonar.exclusions=**/test/**,**/vendor/**,**/mocks/**,**/build/**,**/target/**,**/proto/include/**,**/*.pb.go,**/docs/**,**/*.sql,**/mocks_*/* +sonar.exclusions=**/test/**,**/vendor/**,**/mocks/**,**/build/**,**/target/**,**/proto/include/**,**/*.pb.go,**/docs/**,**/*.sql,**/mocks_*/*, scripts/** sonar.tests=. sonar.test.inclusions=**/*_test.go