From 58d84a296c6dcce0410d63471c0d56031c890528 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Thu, 30 Oct 2025 12:18:18 +0400 Subject: [PATCH] test: add comparison mode to system tests --- Makefile | 10 ++++ system_tests/common_test.go | 70 +++++++++++++++++----- system_tests/execution_client_only_test.go | 16 +++-- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 887d16ae469..4d73e2a1339 100644 --- a/Makefile +++ b/Makefile @@ -252,6 +252,16 @@ test-go-gas-dimensions: test-go-deps .github/workflows/gotestsum.sh --timeout 120m --run "TestDim(Log|TxOp)" --tags gasdimensionstest --nolog @printf $(done) +.PHONY: test-comparison +test-comparison: test-go-deps + @echo "Running Nethermind comparison test..." + @./scripts/run-comparison-test.sh + +.PHONY: test-comparison-verbose +test-comparison-verbose: test-go-deps + @echo "Running Nethermind comparison test (verbose mode)..." + @./scripts/run-comparison-test.sh --verbose + .PHONY: test-gen-proofs test-gen-proofs: \ $(arbitrator_test_wasms) \ diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 796bd7ea790..ecb3461dbba 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -97,15 +97,23 @@ import ( type info = *BlockchainTestInfo +type ExecutionClientMode int + +const ( + ExecutionClientModeInternal ExecutionClientMode = iota + 1 // internal geth + ExecutionClientModeExternal // external Nethermind + ExecutionClientModeComparison // both, compare results +) + type SecondNodeParams struct { - nodeConfig *arbnode.Config - execConfig *gethexec.Config - stackConfig *node.Config - dasConfig *das.DataAvailabilityConfig - initData *statetransfer.ArbosInitializationInfo - addresses *chaininfo.RollupAddresses - useExecutionClientOnly bool - useExternalExecutionClient bool // Use external Nethermind execution client instead of internal geth + nodeConfig *arbnode.Config + execConfig *gethexec.Config + stackConfig *node.Config + dasConfig *das.DataAvailabilityConfig + initData *statetransfer.ArbosInitializationInfo + addresses *chaininfo.RollupAddresses + useExecutionClientOnly bool + executionClientMode ExecutionClientMode } type TestClient struct { @@ -944,7 +952,7 @@ func build2ndNode( testClient := NewTestClient(ctx) testClient.Client, testClient.ConsensusNode = - Create2ndNodeWithConfig(t, ctx, firstNodeTestClient.ConsensusNode, parentChainTestClient.Stack, parentChainInfo, params.initData, params.nodeConfig, params.execConfig, params.stackConfig, valnodeConfig, params.addresses, initMessage, params.useExecutionClientOnly, params.useExternalExecutionClient) + Create2ndNodeWithConfig(t, ctx, firstNodeTestClient.ConsensusNode, parentChainTestClient.Stack, parentChainInfo, params.initData, params.nodeConfig, params.execConfig, params.stackConfig, valnodeConfig, params.addresses, initMessage, params.useExecutionClientOnly, params.executionClientMode) testClient.cleanup = func() { testClient.ConsensusNode.StopAndWait() } return testClient, func() { testClient.cleanup() } } @@ -1721,7 +1729,7 @@ func Create2ndNodeWithConfig( addresses *chaininfo.RollupAddresses, initMessage *arbostypes.ParsedInitMessage, useExecutionClientOnly bool, - useExternalExecutionClient bool, + executionClientMode ExecutionClientMode, ) (*ethclient.Client, *arbnode.Node) { if nodeConfig == nil { nodeConfig = arbnode.ConfigDefaultL1NonSequencerTest() @@ -1777,7 +1785,13 @@ func Create2ndNodeWithConfig( Require(t, err) var currentExec nethexec.FullExecutionClient - if useExternalExecutionClient { + switch executionClientMode { + case ExecutionClientModeInternal: + // Create internal geth execution client + currentExec, err = gethexec.CreateExecutionNode(ctx, chainStack, chainDb, blockchain, parentChainClient, configFetcher, 0) + Require(t, err) + + case ExecutionClientModeExternal: // Create external Nethermind execution client nethermindExecClient, err := nethexec.NewNethermindExecutionClient() Require(t, err) @@ -1790,9 +1804,28 @@ func Create2ndNodeWithConfig( } } currentExec = nethermindExecClient - } else { - currentExec, err = gethexec.CreateExecutionNode(ctx, chainStack, chainDb, blockchain, parentChainClient, configFetcher, 0) + + case ExecutionClientModeComparison: + // Create both internal geth and external Nethermind execution clients + gethExecClient, err := gethexec.CreateExecutionNode(ctx, chainStack, chainDb, blockchain, parentChainClient, configFetcher, 0) + Require(t, err) + + nethermindExecClient, err := nethexec.NewNethermindExecutionClient() Require(t, err) + + // Call DigestInitMessage to initialize the external execution client with genesis block + if initMessage != nil { + result := nethermindExecClient.DigestInitMessage(ctx, initMessage.InitialL1BaseFee, initMessage.SerializedChainConfig) + if result == nil { + t.Fatal("DigestInitMessage returned nil for external execution client") + } + } + + // Wrap both in comparison client + currentExec = nethexec.NewCompareExecutionClient(gethExecClient, nethermindExecClient, feedErrChan) + + default: + t.Fatalf("unsupported execution client mode: %v", executionClientMode) } if useExecutionClientOnly { @@ -1806,9 +1839,11 @@ func Create2ndNodeWithConfig( err = currentNode.Start(ctx) Require(t, err) - // For external execution client, connect directly to Nethermind for RPC calls + // Connect RPC client based on execution mode var chainClient *ethclient.Client - if useExternalExecutionClient { + switch executionClientMode { + case ExecutionClientModeExternal: + // For external execution client, connect directly to Nethermind for RPC calls nethRpcUrl := os.Getenv("PR_NETH_RPC_CLIENT_URL") if nethRpcUrl == "" { nethRpcUrl = "http://localhost:20545" @@ -1816,8 +1851,11 @@ func Create2ndNodeWithConfig( externalRpcClient, err := rpc.Dial(nethRpcUrl) Require(t, err) chainClient = ethclient.NewClient(externalRpcClient) - } else { + case ExecutionClientModeInternal, ExecutionClientModeComparison: + // For internal and comparison modes, use internal geth client chainClient = ClientForStack(t, chainStack) + default: + t.Fatalf("unsupported execution client mode: %v", executionClientMode) } StartWatchChanErr(t, ctx, feedErrChan, currentNode) diff --git a/system_tests/execution_client_only_test.go b/system_tests/execution_client_only_test.go index 613b64c7e5f..b3fec70e8df 100644 --- a/system_tests/execution_client_only_test.go +++ b/system_tests/execution_client_only_test.go @@ -11,7 +11,7 @@ import ( "github.com/offchainlabs/nitro/arbnode" ) -func testExecutionClientOnly(t *testing.T, useExternalExecutionClient bool) { +func testExecutionClientOnly(t *testing.T, executionClientMode ExecutionClientMode) { ctx := t.Context() builder := NewNodeBuilder(ctx).DefaultConfig(t, true) @@ -21,9 +21,9 @@ func testExecutionClientOnly(t *testing.T, useExternalExecutionClient bool) { replicaConfig := arbnode.ConfigDefaultL1NonSequencerTest() replicaParams := &SecondNodeParams{ - nodeConfig: replicaConfig, - useExecutionClientOnly: true, - useExternalExecutionClient: useExternalExecutionClient, + nodeConfig: replicaConfig, + useExecutionClientOnly: true, + executionClientMode: executionClientMode, } replicaTestClient, replicaCleanup := builder.Build2ndNode(t, replicaParams) @@ -51,9 +51,13 @@ func testExecutionClientOnly(t *testing.T, useExternalExecutionClient bool) { } func TestExecutionClientOnlyInternal(t *testing.T) { - testExecutionClientOnly(t, false) + testExecutionClientOnly(t, ExecutionClientModeInternal) } func TestExecutionClientOnlyExternal(t *testing.T) { - testExecutionClientOnly(t, true) + testExecutionClientOnly(t, ExecutionClientModeExternal) +} + +func TestExecutionClientOnlyComparison(t *testing.T) { + testExecutionClientOnly(t, ExecutionClientModeComparison) }