From 8019b032e6bbc97a6b2434e8ae3f33234d162f9e Mon Sep 17 00:00:00 2001 From: bar-bera Date: Wed, 24 Jun 2026 10:44:32 +0200 Subject: [PATCH 1/6] remove geth --- scripts/build/testing.mk | 94 ---- testing/simulated/execution/geth.go | 58 --- .../simulated/execution/simulation_client.go | 2 +- testing/simulated/payload_cache_test.go | 476 ++++++------------ testing/simulated/pectra_fork_test.go | 130 +++-- testing/simulated/pectra_genesis_test.go | 4 +- testing/simulated/pectra_withdrawal_test.go | 4 +- testing/simulated/rpc_errors_test.go | 6 +- testing/simulated/simulated_test.go | 4 +- testing/simulated/utils.go | 2 +- 10 files changed, 231 insertions(+), 549 deletions(-) delete mode 100644 testing/simulated/execution/geth.go diff --git a/scripts/build/testing.mk b/scripts/build/testing.mk index 894c1fd80b..4e6b75afdc 100644 --- a/scripts/build/testing.mk +++ b/scripts/build/testing.mk @@ -73,34 +73,6 @@ start-reth: --engine.persistence-threshold 0 \ --engine.memory-block-buffer-target 0 -## Start an ephemeral `geth` node with docker -start-geth: - $(call ask_reset_dir_func, $(ETH_DATA_DIR)) - docker run \ - --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ - -v $(PWD)/.tmp:/.tmp \ - ghcr.io/berachain/bera-geth:latest init \ - --datadir ${ETH_DATA_DIR} \ - ${ETH_GENESIS_PATH} - - docker run \ - -p 30303:30303 \ - -p 8545:8545 \ - -p 8551:8551 \ - --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ - -v $(PWD)/.tmp:/.tmp \ - ghcr.io/berachain/bera-geth:latest \ - --syncmode=full \ - --http \ - --http.addr 0.0.0.0 \ - --http.api eth,net \ - --authrpc.addr 0.0.0.0 \ - --authrpc.jwtsecret $(JWT_PATH) \ - --authrpc.vhosts "*" \ - --datadir ${ETH_DATA_DIR} \ - --ipcpath ${IPC_PATH} - - ################# # Bepolia # ################# @@ -112,38 +84,6 @@ start-bepolia: @JWT_SECRET_PATH=$(JWT_PATH) \ ${TESTAPP_FILES_DIR}/entrypoint.sh testnet -start-geth-bepolia: - $(call ask_reset_dir_func, $(ETH_DATA_DIR)) - docker run \ - --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ - --rm -v $(PWD)/${BEPOLIA_NETWORK_FILES_DIR}:/${BEPOLIA_NETWORK_FILES_DIR} \ - -v $(PWD)/.tmp:/.tmp \ - ghcr.io/berachain/bera-geth:latest init \ - --datadir ${ETH_DATA_DIR} \ - ${BEPOLIA_ETH_GENESIS_PATH} - - @# Read bootnodes from the file; the file is mounted into the container. - @bootnodes=`cat $(PWD)/$(BEPOLIA_NETWORK_FILES_DIR)/el-bootnodes.txt`; \ - echo "Using bootnodes: $$bootnodes"; \ - docker run \ - -p 30303:30303 \ - -p 8545:8545 \ - -p 8551:8551 \ - --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ - --rm -v $(PWD)/${BEPOLIA_NETWORK_FILES_DIR}:/${BEPOLIA_NETWORK_FILES_DIR} \ - -v $(PWD)/.tmp:/.tmp \ - ghcr.io/berachain/bera-geth:latest \ - --http \ - --http.addr 0.0.0.0 \ - --http.api eth,net \ - --authrpc.addr 0.0.0.0 \ - --authrpc.jwtsecret $(JWT_PATH) \ - --authrpc.vhosts "*" \ - --datadir ${ETH_DATA_DIR} \ - --ipcpath ${IPC_PATH} \ - --syncmode=full \ - --bootnodes $$bootnodes - start-reth-bepolia: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) @trustedpeers=`cat $(PWD)/$(BEPOLIA_NETWORK_FILES_DIR)/el-peers.txt`; \ @@ -177,40 +117,6 @@ start-mainnet: @JWT_SECRET_PATH=$(JWT_PATH) \ ${TESTAPP_FILES_DIR}/entrypoint.sh mainnet -# NOTE: By default this will use the EL peers as your bootnodes. If you want specific -# discovery bootnodes by region, refer to testing/networks/80094/el-bootnodes.txt -start-geth-mainnet: - $(call ask_reset_dir_func, $(ETH_DATA_DIR)) - docker run \ - --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ - --rm -v $(PWD)/${MAINNET_NETWORK_FILES_DIR}:/${MAINNET_NETWORK_FILES_DIR} \ - -v $(PWD)/.tmp:/.tmp \ - ghcr.io/berachain/bera-geth:latest init \ - --datadir ${ETH_DATA_DIR} \ - ${MAINNET_ETH_GENESIS_PATH} - - @# Read bootnodes from the file; the file is mounted into the container. - @bootnodes=`cat $(PWD)/$(MAINNET_NETWORK_FILES_DIR)/el-peers.txt`; \ - echo "Using bootnodes: $$bootnodes"; \ - docker run \ - -p 30303:30303 \ - -p 8545:8545 \ - -p 8551:8551 \ - --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ - --rm -v $(PWD)/${MAINNET_NETWORK_FILES_DIR}:/${MAINNET_NETWORK_FILES_DIR} \ - -v $(PWD)/.tmp:/.tmp \ - ghcr.io/berachain/bera-geth:latest \ - --http \ - --http.addr 0.0.0.0 \ - --http.api eth,net \ - --authrpc.addr 0.0.0.0 \ - --authrpc.jwtsecret $(JWT_PATH) \ - --authrpc.vhosts "*" \ - --datadir ${ETH_DATA_DIR} \ - --ipcpath ${IPC_PATH} \ - --syncmode=full \ - --bootnodes $$bootnodes - start-reth-mainnet: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) @trustedpeers=`cat $(PWD)/$(MAINNET_NETWORK_FILES_DIR)/el-peers.txt`; \ diff --git a/testing/simulated/execution/geth.go b/testing/simulated/execution/geth.go deleted file mode 100644 index 2e9c10aa1a..0000000000 --- a/testing/simulated/execution/geth.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build simulated - -// SPDX-License-Identifier: BUSL-1.1 -// -// Copyright (C) 2025, Berachain Foundation. All rights reserved. -// Use of this software is governed by the Business Source License included -// in the LICENSE file of this repository and at www.mariadb.com/bsl11. -// -// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY -// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER -// VERSIONS OF THE LICENSED WORK. -// -// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF -// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF -// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). -// -// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -// TITLE. - -package execution - -import ( - "fmt" - - "github.com/ory/dockertest/docker" -) - -// NewGethNode creates a new execution node configured for Geth by using the default Geth command builder. -func NewGethNode(homeDir string, image docker.PullImageOptions) *ExecNode { - return NewExecNode(homeDir, image, defaultGethCmdStrBuilder) -} - -// ValidGethImage returns the default Docker image options for the Geth node. -func ValidGethImage() docker.PullImageOptions { - return docker.PullImageOptions{ - Repository: "ghcr.io/berachain/bera-geth", - Tag: "latest", - } -} - -// defaultGethCmdStrBuilder returns a command string tailored for running a Geth node. -func defaultGethCmdStrBuilder(genesisFile string) string { - return fmt.Sprintf(` - bera-geth init --datadir /tmp/gethdata /testdata/%s && - bera-geth --http --http.addr 0.0.0.0 --http.api eth,net,web3,debug \ - --authrpc.addr 0.0.0.0 \ - --authrpc.jwtsecret /testing/files/jwt.hex \ - --authrpc.vhosts '*' \ - --datadir /tmp/gethdata \ - --ipcpath /tmp/gethdata/bera-geth.ipc \ - --syncmode full \ - --verbosity 4 \ - --nodiscover - `, genesisFile) -} diff --git a/testing/simulated/execution/simulation_client.go b/testing/simulated/execution/simulation_client.go index bc1ebd2337..00ccfac927 100644 --- a/testing/simulated/execution/simulation_client.go +++ b/testing/simulated/execution/simulation_client.go @@ -35,7 +35,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/kzg4844" ) -// SimulationClient calls `eth_simulateV1` on a Geth node. +// SimulationClient calls `eth_simulateV1` on an execution client. type SimulationClient struct { engineClient *client.EngineClient } diff --git a/testing/simulated/payload_cache_test.go b/testing/simulated/payload_cache_test.go index c5f2edab6c..f06f2cb783 100644 --- a/testing/simulated/payload_cache_test.go +++ b/testing/simulated/payload_cache_test.go @@ -52,9 +52,9 @@ import ( // PayloadCacheSuite defines our test suite for Pectra related work using simulated Comet component. type PayloadCacheSuite struct { suite.Suite - Geth simulated.SharedAccessors Reth simulated.SharedAccessors Reth2 simulated.SharedAccessors + Reth3 simulated.SharedAccessors } // TestPayloadCacheSuite runs the test suite. @@ -71,22 +71,22 @@ func (s *PayloadCacheSuite) SetupTest() { ) // Create a cancellable context for the duration of the test. - s.Geth.CtxApp, s.Geth.CtxAppCancelFn = context.WithCancel(context.Background()) s.Reth.CtxApp, s.Reth.CtxAppCancelFn = context.WithCancel(context.Background()) + s.Reth2.CtxApp, s.Reth2.CtxAppCancelFn = context.WithCancel(context.Background()) if useThirdValidatorSetup { - s.Reth2.CtxApp, s.Reth2.CtxAppCancelFn = context.WithCancel(context.Background()) + s.Reth3.CtxApp, s.Reth3.CtxAppCancelFn = context.WithCancel(context.Background()) } // CometBFT uses context.TODO() for all ABCI calls, so we replicate that. - s.Geth.CtxComet = context.TODO() - s.Geth.HomeDir = s.T().TempDir() - s.Reth.CtxComet = context.TODO() s.Reth.HomeDir = s.T().TempDir() + s.Reth2.CtxComet = context.TODO() + s.Reth2.HomeDir = s.T().TempDir() + if useThirdValidatorSetup { - s.Reth2.CtxComet = context.TODO() - s.Reth2.HomeDir = s.T().TempDir() + s.Reth3.CtxComet = context.TODO() + s.Reth3.HomeDir = s.T().TempDir() } // Initialize the home directory, Comet configuration, and genesis info. @@ -96,72 +96,72 @@ func (s *PayloadCacheSuite) SetupTest() { chainSpec, err := chainSpecFunc() s.Require().NoError(err) var ( - gethCmtCfg *cmtcfg.Config rethCmtCfg *cmtcfg.Config reth2CmtCfg *cmtcfg.Config + reth3CmtCfg *cmtcfg.Config ) if useThirdValidatorSetup { configs, root := simulated.InitializeHomeDirs( - s.T(), chainSpec, elGenesisPath, s.Geth.HomeDir, s.Reth.HomeDir, s.Reth2.HomeDir, + s.T(), chainSpec, elGenesisPath, s.Reth.HomeDir, s.Reth2.HomeDir, s.Reth3.HomeDir, ) - gethCmtCfg, rethCmtCfg, reth2CmtCfg = configs[0], configs[1], configs[2] - s.Geth.GenesisValidatorsRoot = root + rethCmtCfg, reth2CmtCfg, reth3CmtCfg = configs[0], configs[1], configs[2] s.Reth.GenesisValidatorsRoot = root s.Reth2.GenesisValidatorsRoot = root + s.Reth3.GenesisValidatorsRoot = root } else { configs, root := simulated.InitializeHomeDirs( - s.T(), chainSpec, elGenesisPath, s.Geth.HomeDir, s.Reth.HomeDir, + s.T(), chainSpec, elGenesisPath, s.Reth.HomeDir, s.Reth2.HomeDir, ) - gethCmtCfg, rethCmtCfg = configs[0], configs[1] - s.Geth.GenesisValidatorsRoot = root + rethCmtCfg, reth2CmtCfg = configs[0], configs[1] s.Reth.GenesisValidatorsRoot = root + s.Reth2.GenesisValidatorsRoot = root } - // Start the EL (execution layer) Geth node. - gethNode := execution.NewGethNode(s.Geth.HomeDir, execution.ValidGethImage()) - elHandle, authRPC, elRPC := gethNode.Start(s.T(), path.Base(elGenesisPath)) - s.Geth.ElHandle = elHandle + // Start the EL (execution layer) Reth node. + rethNode := execution.NewRethNode(s.Reth.HomeDir, execution.ValidRethImage()) + elHandle, authRPC, elRPC := rethNode.Start(s.T(), path.Base(elGenesisPath)) + s.Reth.ElHandle = elHandle // Choose the reth node to run. 2 specific tests require the engine api override flag. var ( - rethNode *execution.ExecNode reth2Node *execution.ExecNode + reth3Node *execution.ExecNode ) if strings.Contains(testName, "TestReth_MustRebuildPostForkPayload_IsSuccessful") || strings.Contains(testName, "TestReth_MustRebuildPreForkPayload_IsSuccessful") { - rethNode = execution.NewRethNodeWithEngineOverride(s.Reth.HomeDir, execution.ValidRethImage()) + reth2Node = execution.NewRethNodeWithEngineOverride(s.Reth2.HomeDir, execution.ValidRethImage()) if useThirdValidatorSetup { - reth2Node = execution.NewRethNodeWithEngineOverride(s.Reth2.HomeDir, execution.ValidRethImage()) + reth3Node = execution.NewRethNodeWithEngineOverride(s.Reth3.HomeDir, execution.ValidRethImage()) } } else { - rethNode = execution.NewRethNode(s.Reth.HomeDir, execution.ValidRethImage()) + reth2Node = execution.NewRethNode(s.Reth2.HomeDir, execution.ValidRethImage()) if useThirdValidatorSetup { - reth2Node = execution.NewRethNode(s.Reth2.HomeDir, execution.ValidRethImage()) + reth3Node = execution.NewRethNode(s.Reth3.HomeDir, execution.ValidRethImage()) } } - rethHandle, rethAuthRPC, rethRPC := rethNode.Start(s.T(), path.Base(elGenesisPath)) - s.Reth.ElHandle = rethHandle + rethHandle, rethAuthRPC, rethRPC := reth2Node.Start(s.T(), path.Base(elGenesisPath)) + s.Reth2.ElHandle = rethHandle var ( reth2Handle *execution.Resource reth2AuthRPC *url.ConnectionURL reth2RPC *url.ConnectionURL ) if useThirdValidatorSetup { - reth2Handle, reth2AuthRPC, reth2RPC = reth2Node.Start(s.T(), path.Base(elGenesisPath)) - s.Reth2.ElHandle = reth2Handle + reth2Handle, reth2AuthRPC, reth2RPC = reth3Node.Start(s.T(), path.Base(elGenesisPath)) + s.Reth3.ElHandle = reth2Handle } // Prepare a logger backed by a buffer to capture logs for assertions. - s.Geth.LogBuffer = &simulated.SyncBuffer{} - logger := phuslu.NewLogger(s.Geth.LogBuffer, nil) - s.Reth.LogBuffer = &simulated.SyncBuffer{} - rethLogger := phuslu.NewLogger(s.Reth.LogBuffer, nil) + logger := phuslu.NewLogger(s.Reth.LogBuffer, nil) + + s.Reth2.LogBuffer = &simulated.SyncBuffer{} + rethLogger := phuslu.NewLogger(s.Reth2.LogBuffer, nil) var reth2Logger *phuslu.Logger if useThirdValidatorSetup { - s.Reth2.LogBuffer = &simulated.SyncBuffer{} - reth2Logger = phuslu.NewLogger(s.Reth2.LogBuffer, nil) + s.Reth3.LogBuffer = &simulated.SyncBuffer{} + reth2Logger = phuslu.NewLogger(s.Reth3.LogBuffer, nil) } // Build the Beacon node with the simulated Comet component and electra genesis chain spec @@ -169,83 +169,82 @@ func (s *PayloadCacheSuite) SetupTest() { components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) - s.Geth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ - TempHomeDir: s.Geth.HomeDir, - CometConfig: gethCmtCfg, + s.Reth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ + TempHomeDir: s.Reth.HomeDir, + CometConfig: rethCmtCfg, AuthRPC: authRPC, ClientRPC: elRPC, Logger: logger, AppOpts: viper.New(), Components: components, }) - s.Geth.SimComet = s.Geth.TestNode.SimComet - nodeAddress, err := s.Geth.SimComet.GetNodeAddress() + s.Reth.SimComet = s.Reth.TestNode.SimComet + nodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) + s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) - s.Reth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ - TempHomeDir: s.Reth.HomeDir, - CometConfig: rethCmtCfg, + s.Reth2.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ + TempHomeDir: s.Reth2.HomeDir, + CometConfig: reth2CmtCfg, AuthRPC: rethAuthRPC, ClientRPC: rethRPC, Logger: rethLogger, AppOpts: viper.New(), Components: components, }) - s.Reth.SimComet = s.Reth.TestNode.SimComet - nodeAddress, err = s.Reth.SimComet.GetNodeAddress() + s.Reth2.SimComet = s.Reth2.TestNode.SimComet + nodeAddress, err = s.Reth2.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) + s.Reth2.SimComet.Comet.SetNodeAddress(nodeAddress) if useThirdValidatorSetup { - s.Reth2.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ - TempHomeDir: s.Reth2.HomeDir, - CometConfig: reth2CmtCfg, + s.Reth3.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ + TempHomeDir: s.Reth3.HomeDir, + CometConfig: reth3CmtCfg, AuthRPC: reth2AuthRPC, ClientRPC: reth2RPC, Logger: reth2Logger, AppOpts: viper.New(), Components: components, }) - s.Reth2.SimComet = s.Reth2.TestNode.SimComet - nodeAddress, err = s.Reth2.SimComet.GetNodeAddress() + s.Reth3.SimComet = s.Reth3.TestNode.SimComet + nodeAddress, err = s.Reth3.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Reth2.SimComet.Comet.SetNodeAddress(nodeAddress) + s.Reth3.SimComet.Comet.SetNodeAddress(nodeAddress) } // Start the Beacon node in a separate goroutine. go func() { - _ = s.Geth.TestNode.Start(s.Geth.CtxApp) + _ = s.Reth.TestNode.Start(s.Reth.CtxApp) }() // Start the Beacon node in a separate goroutine. go func() { - _ = s.Reth.TestNode.Start(s.Reth.CtxApp) + _ = s.Reth2.TestNode.Start(s.Reth2.CtxApp) }() if useThirdValidatorSetup { go func() { - _ = s.Reth2.TestNode.Start(s.Reth2.CtxApp) + _ = s.Reth3.TestNode.Start(s.Reth3.CtxApp) }() } - s.Geth.SimulationClient = execution.NewSimulationClient(s.Geth.TestNode.EngineClient) - // Reth does not have a simulation API + s.Reth.SimulationClient = execution.NewSimulationClient(s.Reth.TestNode.EngineClient) timeOut := 10 * time.Second interval := 50 * time.Millisecond - err = simulated.WaitTillServicesStarted(s.Geth.LogBuffer, timeOut, interval) - s.Require().NoError(err) err = simulated.WaitTillServicesStarted(s.Reth.LogBuffer, timeOut, interval) s.Require().NoError(err) + err = simulated.WaitTillServicesStarted(s.Reth2.LogBuffer, timeOut, interval) + s.Require().NoError(err) if useThirdValidatorSetup { - err = simulated.WaitTillServicesStarted(s.Reth2.LogBuffer, timeOut, interval) + err = simulated.WaitTillServicesStarted(s.Reth3.LogBuffer, timeOut, interval) s.Require().NoError(err) } } // TearDownTest cleans up the test environment. func (s *PayloadCacheSuite) TearDownTest() { - s.Geth.CleanupTestWithLabel(s.T(), "GETH") s.Reth.CleanupTestWithLabel(s.T(), "RETH") s.Reth2.CleanupTestWithLabel(s.T(), "RETH2") + s.Reth3.CleanupTestWithLabel(s.T(), "RETH3") } // This tests a reth validator proposing a block. It then accepts the proposal in @@ -329,87 +328,6 @@ func (s *PayloadCacheSuite) TestReth_ReusePayload_IsSuccessful() { } } -// This tests a geth validator proposing a block. It then accepts the proposal in -// process proposal. But the block is not finalized by consensus. Then this -// validator is chosen to propose at a subsequent round. It should just get the old -// payload from its cache. -func (s *PayloadCacheSuite) TestGeth_ReusePayload_IsSuccessful() { - // Initialize the chain state. - s.Geth.InitializeChain(s.T(), 2) // 1 geth validator - nodeAddress, err := s.Geth.SimComet.GetNodeAddress() - s.Require().NoError(err) - s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) - - // Next block is height 1. - nextBlockHeight := int64(1) - consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) - - { - // Prepare the proposal. - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ - Height: nextBlockHeight, - Time: consensusTime, - ProposerAddress: nodeAddress, - }) - s.Require().NoError(prepareErr) - s.Require().Len(proposal.Txs, 2) - - // Process the proposal. - processRequest := &types.ProcessProposalRequest{ - Txs: proposal.Txs, - Height: nextBlockHeight, - ProposerAddress: nodeAddress, - Time: consensusTime, - NextProposerAddress: nodeAddress, - } - // This will trigger a optimistic payload build for block height 2. - processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) - s.Require().NoError(respErr) - s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) - } - - // For some reason, the supermajority does not finalize the block. - // Next round is height 1, but simulating consensus time is 1 second after previous round. - time.Sleep(200 * time.Millisecond) // This lets the optimistic build complete. - consensusTime = time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime())+1, 0) - { - // Prepare the proposal. Bkit cached the payload ID, so we just get the old one from geth. - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ - Height: nextBlockHeight, - Time: consensusTime, - ProposerAddress: nodeAddress, - }) - s.Require().NoError(prepareErr) - s.Require().Len(proposal.Txs, 2) - - // Process the proposal. - processRequest := &types.ProcessProposalRequest{ - Txs: proposal.Txs, - Height: nextBlockHeight, - ProposerAddress: nodeAddress, - Time: consensusTime, - NextProposerAddress: nodeAddress, - } - - // Process the proposal. - processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) - s.Require().NoError(processErr) - s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) - - // Now the block is finalized and committed. - finalizeRequest := &types.FinalizeBlockRequest{ - Txs: proposal.Txs, - Height: nextBlockHeight, - ProposerAddress: nodeAddress, - Time: consensusTime, - } - _, finalizeErr := s.Geth.SimComet.Comet.FinalizeBlock(s.Geth.CtxComet, finalizeRequest) - s.Require().NoError(finalizeErr) - _, commitErr := s.Geth.SimComet.Comet.Commit(s.Geth.CtxComet, &types.CommitRequest{}) - s.Require().NoError(commitErr) - } -} - // This tests a reth validator proposing a invalid block. The proposal is rejected. Then this // validator is chosen to propose at a subsequent round. It should now be forced to // rebuild a new payload (and not reuse the old one from its cache). @@ -492,88 +410,6 @@ func (s *PayloadCacheSuite) TestReth_RebuildPayload_IsSuccessful() { } } -// This tests a geth validator proposing a invalid block. The proposal is rejected. Then this -// validator is chosen to propose at a subsequent round. It should now be forced to -// rebuild a new payload (and not reuse the old one from its cache). -func (s *PayloadCacheSuite) TestGeth_RebuildPayload_IsSuccessful() { - // Initialize the chain state. - s.Geth.InitializeChain(s.T(), 2) // 1 geth validator - nodeAddress, err := s.Geth.SimComet.GetNodeAddress() - s.Require().NoError(err) - s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) - - // Next block is height 1. - nextBlockHeight := int64(1) - consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) - - { - // Prepare an invalid proposal. - faultyConsensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime())-1, 0) - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ - Height: nextBlockHeight, - Time: faultyConsensusTime, - ProposerAddress: nodeAddress, - }) - s.Require().NoError(prepareErr) - s.Require().Len(proposal.Txs, 2) - - // Process the proposal. - processRequest := &types.ProcessProposalRequest{ - Txs: proposal.Txs, - Height: nextBlockHeight, - ProposerAddress: nodeAddress, - Time: consensusTime, - NextProposerAddress: nodeAddress, - } - // As we reject our own built proposal, bkit should evict this payload from its cache. - processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) - s.Require().NoError(respErr) - s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) - s.Require().Contains( - s.Geth.LogBuffer.String(), - "failed decoding *types.SignedBeaconBlock: ssz: offset smaller than previous", - ) - } - - // Subsequent round where we are selected to propose again. - { - // Prepare the valid proposal. This should now request the EL for a new payload. - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ - Height: nextBlockHeight, - Time: consensusTime, - ProposerAddress: nodeAddress, - }) - s.Require().NoError(prepareErr) - s.Require().Len(proposal.Txs, 2) - - // Process the proposal. - processRequest := &types.ProcessProposalRequest{ - Txs: proposal.Txs, - Height: nextBlockHeight, - ProposerAddress: nodeAddress, - Time: consensusTime, - NextProposerAddress: nodeAddress, - } - - // Process the proposal. - processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) - s.Require().NoError(processErr) - s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) - - // Now the block is finalized and committed. - finalizeRequest := &types.FinalizeBlockRequest{ - Txs: proposal.Txs, - Height: nextBlockHeight, - ProposerAddress: nodeAddress, - Time: consensusTime, - } - _, finalizeErr := s.Geth.SimComet.Comet.FinalizeBlock(s.Geth.CtxComet, finalizeRequest) - s.Require().NoError(finalizeErr) - _, commitErr := s.Geth.SimComet.Comet.Commit(s.Geth.CtxComet, &types.CommitRequest{}) - s.Require().NoError(commitErr) - } -} - // Test a scenario where the first proposed block is pre-fork and accepted initially but never // finalized by the network (which triggeres optimistic builds). The subsequent rounds are now // post-fork. Only reth with the flag can force rebuild a payload. @@ -581,24 +417,24 @@ func (s *PayloadCacheSuite) TestGeth_RebuildPayload_IsSuccessful() { // NOTE: this test requires reth with the --engine.always-process-payload-attributes-on-canonical-head flag. func (s *PayloadCacheSuite) TestReth_MustRebuildPostForkPayload_IsSuccessful() { // Initialize the chain state. - s.Geth.InitializeChain(s.T(), 2) // 1 geth validator - gethNodeAddress, err := s.Geth.SimComet.GetNodeAddress() - s.Require().NoError(err) - s.Geth.SimComet.Comet.SetNodeAddress(gethNodeAddress) s.Reth.InitializeChain(s.T(), 2) // 1 reth validator rethNodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth.SimComet.Comet.SetNodeAddress(rethNodeAddress) + s.Reth2.InitializeChain(s.T(), 2) // 1 reth validator + reth2NodeAddress, err := s.Reth2.SimComet.GetNodeAddress() + s.Require().NoError(err) + s.Reth2.SimComet.Comet.SetNodeAddress(reth2NodeAddress) // Next block is height 1. nextBlockHeight := int64(1) - consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()-1), 0) + consensusTime := time.Unix(int64(s.Reth2.TestNode.ChainSpec.ElectraForkTime()-1), 0) { // Prepare the proposal. - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) @@ -607,20 +443,20 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPostForkPayload_IsSuccessful() { processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, Time: consensusTime, - NextProposerAddress: gethNodeAddress, + NextProposerAddress: rethNodeAddress, } // This will trigger a optimistic payload build for block height 2. - processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) + processResp, respErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Reth also prepares proposal. - proposal, prepareErr = s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ + proposal, prepareErr = s.Reth2.SimComet.Comet.PrepareProposal(s.Reth2.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) @@ -629,12 +465,12 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPostForkPayload_IsSuccessful() { processRequest = &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, Time: consensusTime, - NextProposerAddress: rethNodeAddress, + NextProposerAddress: reth2NodeAddress, } // This will trigger a optimistic payload build for block height 2. - processResp, respErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) + processResp, respErr = s.Reth2.SimComet.Comet.ProcessProposal(s.Reth2.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) } @@ -644,28 +480,28 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPostForkPayload_IsSuccessful() { // Next round is height 1, but simulating consensus time is 1 second after previous round. time.Sleep(10 * time.Millisecond) // Next round. { - // Try to build a new (pre-fork) payload from geth EL. - // NOTE: this will fail because geth does not allow re-building a payload for a height - // that has already been marked safe/finalized - consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + // Try to build a new (pre-fork) payload from reth EL. + // NOTE: this will fail because reth (without --engine.always-process-payload-attributes-on-canonical-head + // flag) does not allow re-building a payload for a height that has already been marked safe/finalized. + consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) + proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) - s.Require().Len(proposal.Txs, 0) // Geth returns an empty proposal. + s.Require().Len(proposal.Txs, 0) // Reth returns an empty proposal. } time.Sleep(10 * time.Millisecond) // Next round. { // Try to build a new post-fork payload from reth EL. This works because the reth flag // allows us to rebuild a payload that has already been marked safe/finalized. - consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) - proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ + consensusTime := time.Unix(int64(s.Reth2.TestNode.ChainSpec.ElectraForkTime()), 0) + proposal, prepareErr := s.Reth2.SimComet.Comet.PrepareProposal(s.Reth2.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) @@ -674,14 +510,14 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPostForkPayload_IsSuccessful() { processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, Time: consensusTime, - NextProposerAddress: rethNodeAddress, + NextProposerAddress: reth2NodeAddress, } - processResp, respErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) + processResp, respErr := s.Reth2.SimComet.Comet.ProcessProposal(s.Reth2.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) - processResp, respErr = s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) + processResp, respErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) } @@ -695,46 +531,46 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPostForkPayload_IsSuccessful() { // to propose the valid pre-fork block. func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { // Initialize the chain state. - s.Geth.InitializeChain(s.T(), 2) - gethNodeAddress, err := s.Geth.SimComet.GetNodeAddress() - s.Require().NoError(err) s.Reth.InitializeChain(s.T(), 2) rethNodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) + s.Reth2.InitializeChain(s.T(), 2) + reth2NodeAddress, err := s.Reth2.SimComet.GetNodeAddress() + s.Require().NoError(err) nextBlockHeight := int64(1) - // Both reth and geth prepare and propose a post-fork block without finalizing. + // Both nodes prepare and propose a post-fork block without finalizing. { - consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) + consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) - // Geth builds. - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + // Reth builds. + proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) - // Geth processes the proposal. No bkit payload eviction here. + // Reth processes the proposal. No bkit payload eviction here. // Optimistically build the next height's payload. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, Time: consensusTime, - NextProposerAddress: gethNodeAddress, + NextProposerAddress: rethNodeAddress, } - s.Geth.LogBuffer.Reset() - processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) + s.Reth.LogBuffer.Reset() + processResp, respErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // Reth also builds. - proposal, prepareErr = s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ + proposal, prepareErr = s.Reth2.SimComet.Comet.PrepareProposal(s.Reth2.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) @@ -744,12 +580,12 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { processRequest = &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, Time: consensusTime, - NextProposerAddress: rethNodeAddress, + NextProposerAddress: reth2NodeAddress, } - s.Reth.LogBuffer.Reset() - processResp, respErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) + s.Reth2.LogBuffer.Reset() + processResp, respErr = s.Reth2.SimComet.Comet.ProcessProposal(s.Reth2.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) } @@ -758,18 +594,18 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { // The previous payload in cache has been evicted. The optimistic builds for next height // should have completed by now. { - // Try to build a new (pre-fork) payload from geth EL. - // NOTE: this will fail because geth does not allow re-building a payload for a height + // Try to build a new (pre-fork) payload from reth EL. + // NOTE: this will fail because reth does not allow re-building a payload for a height // that has already been marked safe/finalized - consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime())-2, 0) + consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime())-2, 0) prepareReq := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, } - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, prepareReq) + proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, prepareReq) s.Require().NoError(prepareErr) - s.Require().Len(proposal.Txs, 0) // Geth returns an empty proposal. + s.Require().Len(proposal.Txs, 0) // Reth returns an empty proposal. } time.Sleep(10 * time.Millisecond) // Next round. @@ -778,11 +614,11 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { { // Force build a new (pre-fork) payload from reth EL. // NOTE: this requires --engine.always-process-payload-attributes-on-canonical-head. - consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime())-1, 0) - proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ + consensusTime := time.Unix(int64(s.Reth2.TestNode.ChainSpec.ElectraForkTime())-1, 0) + proposal, prepareErr := s.Reth2.SimComet.Comet.PrepareProposal(s.Reth2.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) @@ -790,21 +626,21 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, Time: consensusTime, - NextProposerAddress: gethNodeAddress, + NextProposerAddress: rethNodeAddress, } // Process the proposal. No bkit payload eviction here from cache. Also trigger an optimistic // build for next height. - s.Geth.LogBuffer.Reset() - processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) + s.Reth.LogBuffer.Reset() + processResp, processErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // Reth also process proposal and does not evict payload from bkit cache. - s.Reth.LogBuffer.Reset() - processResp, processErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) + s.Reth2.LogBuffer.Reset() + processResp, processErr = s.Reth2.SimComet.Comet.ProcessProposal(s.Reth2.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) @@ -812,33 +648,33 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: rethNodeAddress, + ProposerAddress: reth2NodeAddress, Time: consensusTime, } - _, finalizeErr := s.Geth.SimComet.Comet.FinalizeBlock(s.Geth.CtxComet, finalizeRequest) + _, finalizeErr := s.Reth.SimComet.Comet.FinalizeBlock(s.Reth.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) - _, finalizeErr = s.Reth.SimComet.Comet.FinalizeBlock(s.Reth.CtxComet, finalizeRequest) + _, finalizeErr = s.Reth2.SimComet.Comet.FinalizeBlock(s.Reth2.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) // Commit the block. - _, err := s.Geth.SimComet.Comet.Commit(s.Geth.CtxComet, &types.CommitRequest{}) - s.Require().NoError(err) - s.Geth.LogBuffer.Reset() - _, err = s.Reth.SimComet.Comet.Commit(s.Reth.CtxComet, &types.CommitRequest{}) + _, err := s.Reth.SimComet.Comet.Commit(s.Reth.CtxComet, &types.CommitRequest{}) s.Require().NoError(err) s.Reth.LogBuffer.Reset() + _, err = s.Reth2.SimComet.Comet.Commit(s.Reth2.CtxComet, &types.CommitRequest{}) + s.Require().NoError(err) + s.Reth2.LogBuffer.Reset() } - // Finally, we cross the fork and show no issues. Geth uses the optimistic build which has the + // Finally, we cross the fork and show no issues. Reth uses the optimistic build which has the // correct payload time and consequently is built correctly for post-fork. nextBlockHeight++ time.Sleep(100 * time.Millisecond) // The optimistic build for next height should have completed by now. { - consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) + proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) @@ -846,18 +682,18 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, - ProposerAddress: gethNodeAddress, + ProposerAddress: rethNodeAddress, Time: consensusTime, } // Process the proposal. - processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) + processResp, processErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) - s.Require().Contains(s.Geth.LogBuffer.String(), "Processing execution requests") - processResp, processErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) + s.Require().Contains(s.Reth.LogBuffer.String(), "Processing execution requests") + processResp, processErr = s.Reth2.SimComet.Comet.ProcessProposal(s.Reth2.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) - s.Require().Contains(s.Reth.LogBuffer.String(), "Processing execution requests") + s.Require().Contains(s.Reth2.LogBuffer.String(), "Processing execution requests") } } @@ -867,38 +703,38 @@ func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { // from cache and a third validator accepts that proposal. func (s *PayloadCacheSuite) TestReth_MisorderedBlobSidecarsCachedEnvelope_IsSuccessful() { // Initialize chain state with 3 validators. - s.Geth.InitializeChain(s.T(), 3) s.Reth.InitializeChain(s.T(), 3) s.Reth2.InitializeChain(s.T(), 3) + s.Reth3.InitializeChain(s.T(), 3) // validator A: malicious proposer. - maliciousProposerAddress, err := s.Geth.SimComet.GetNodeAddress() + maliciousProposerAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Geth.SimComet.Comet.SetNodeAddress(maliciousProposerAddress) + s.Reth.SimComet.Comet.SetNodeAddress(maliciousProposerAddress) // validator B: verifies malicious proposal and later proposes from cache. - cachingValidatorAddress, err := s.Reth.SimComet.GetNodeAddress() + cachingValidatorAddress, err := s.Reth2.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Reth.SimComet.Comet.SetNodeAddress(cachingValidatorAddress) + s.Reth2.SimComet.Comet.SetNodeAddress(cachingValidatorAddress) // validator C: verifies validator B's subsequent proposal. - verifyingValidatorAddress, err := s.Reth2.SimComet.GetNodeAddress() + verifyingValidatorAddress, err := s.Reth3.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Reth2.SimComet.Comet.SetNodeAddress(verifyingValidatorAddress) + s.Reth3.SimComet.Comet.SetNodeAddress(verifyingValidatorAddress) nextBlockHeight := int64(1) - consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) + consensusTime := time.Unix(int64(s.Reth2.TestNode.ChainSpec.ElectraForkTime()), 0) // Seed proposer A's EL with blob txs so the proposal has reorderable sidecars. - s.submitBlobTransactions(s.Geth, 2) + s.submitBlobTransactions(s.Reth, 2) var ( proposal *types.PrepareProposalResponse reorderedTx bool ) for i := 0; i < 10; i++ { - proposal, err = s.Geth.SimComet.Comet.PrepareProposal( - s.Geth.CtxComet, &types.PrepareProposalRequest{ + proposal, err = s.Reth.SimComet.Comet.PrepareProposal( + s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: maliciousProposerAddress, @@ -932,8 +768,8 @@ func (s *PayloadCacheSuite) TestReth_MisorderedBlobSidecarsCachedEnvelope_IsSucc // validator B verifies and accepts the maliciously-ordered proposal. This caches the // payload envelope, but the block never finalizes. - processResp, err := s.Reth.SimComet.Comet.ProcessProposal( - s.Reth.CtxComet, &types.ProcessProposalRequest{ + processResp, err := s.Reth2.SimComet.Comet.ProcessProposal( + s.Reth2.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: maliciousProposerAddress, @@ -947,8 +783,8 @@ func (s *PayloadCacheSuite) TestReth_MisorderedBlobSidecarsCachedEnvelope_IsSucc // Next round at same height; validator B now proposes from cached envelope. time.Sleep(200 * time.Millisecond) consensusTime = consensusTime.Add(time.Second) - cachedProposal, err := s.Reth.SimComet.Comet.PrepareProposal( - s.Reth.CtxComet, &types.PrepareProposalRequest{ + cachedProposal, err := s.Reth2.SimComet.Comet.PrepareProposal( + s.Reth2.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: cachingValidatorAddress, @@ -972,8 +808,8 @@ func (s *PayloadCacheSuite) TestReth_MisorderedBlobSidecarsCachedEnvelope_IsSucc } // validator C verifies the cached proposal and accepts it. - processResp, err = s.Reth2.SimComet.Comet.ProcessProposal( - s.Reth2.CtxComet, &types.ProcessProposalRequest{ + processResp, err = s.Reth3.SimComet.Comet.ProcessProposal( + s.Reth3.CtxComet, &types.ProcessProposalRequest{ Txs: cachedProposal.Txs, Height: nextBlockHeight, ProposerAddress: cachingValidatorAddress, diff --git a/testing/simulated/pectra_fork_test.go b/testing/simulated/pectra_fork_test.go index 8f8f67716b..58a655e89d 100644 --- a/testing/simulated/pectra_fork_test.go +++ b/testing/simulated/pectra_fork_test.go @@ -51,8 +51,8 @@ import ( // PectraForkSuite defines our test suite for Pectra related work using simulated Comet component. type PectraForkSuite struct { suite.Suite - Geth simulated.SharedAccessors - Reth simulated.SharedAccessors + Reth simulated.SharedAccessors + Reth2 simulated.SharedAccessors } // TestPectraForkSuite runs the test suite. @@ -63,53 +63,53 @@ func TestPectraForkSuite(t *testing.T) { // SetupTest initializes the test environment. func (s *PectraForkSuite) SetupTest() { // Create a cancellable context for the duration of the test. - s.Geth.CtxApp, s.Geth.CtxAppCancelFn = context.WithCancel(context.Background()) s.Reth.CtxApp, s.Reth.CtxAppCancelFn = context.WithCancel(context.Background()) + s.Reth2.CtxApp, s.Reth2.CtxAppCancelFn = context.WithCancel(context.Background()) // CometBFT uses context.TODO() for all ABCI calls, so we replicate that. - s.Geth.CtxComet = context.TODO() - s.Geth.HomeDir = s.T().TempDir() - s.Reth.CtxComet = context.TODO() s.Reth.HomeDir = s.T().TempDir() + s.Reth2.CtxComet = context.TODO() + s.Reth2.HomeDir = s.T().TempDir() + // Initialize the home directory, Comet configuration, and genesis info. const elGenesisPath = "./el-genesis-files/pectra-fork-genesis.json" chainSpecFunc := simulated.ProvidePectraForkTestChainSpec // Create the chainSpec. chainSpec, err := chainSpecFunc() s.Require().NoError(err) - configs, genesisValidatorsRoot := simulated.InitializeHomeDirs(s.T(), chainSpec, elGenesisPath, s.Geth.HomeDir) + configs, genesisValidatorsRoot := simulated.InitializeHomeDirs(s.T(), chainSpec, elGenesisPath, s.Reth.HomeDir) cometConfig := configs[0] - s.Geth.GenesisValidatorsRoot = genesisValidatorsRoot s.Reth.GenesisValidatorsRoot = genesisValidatorsRoot + s.Reth2.GenesisValidatorsRoot = genesisValidatorsRoot // Copy the home dir for the Reth Node - simulated.CopyHomeDir(s.T(), s.Geth.HomeDir, s.Reth.HomeDir) - - // Start the EL (execution layer) Geth node. - gethNode := execution.NewGethNode(s.Geth.HomeDir, execution.ValidGethImage()) - elHandle, authRPC, elRPC := gethNode.Start(s.T(), path.Base(elGenesisPath)) - s.Geth.ElHandle = elHandle + simulated.CopyHomeDir(s.T(), s.Reth.HomeDir, s.Reth2.HomeDir) + // Start the EL (execution layer) Reth node. rethNode := execution.NewRethNode(s.Reth.HomeDir, execution.ValidRethImage()) - rethHandle, rethAuthRPC, elRPC := rethNode.Start(s.T(), path.Base(elGenesisPath)) - s.Reth.ElHandle = rethHandle + elHandle, authRPC, elRPC := rethNode.Start(s.T(), path.Base(elGenesisPath)) + s.Reth.ElHandle = elHandle - // Prepare a logger backed by a buffer to capture logs for assertions. - s.Geth.LogBuffer = &simulated.SyncBuffer{} - logger := phuslu.NewLogger(s.Geth.LogBuffer, nil) + rethNode2 := execution.NewRethNode(s.Reth2.HomeDir, execution.ValidRethImage()) + rethHandle, rethAuthRPC, elRPC := rethNode2.Start(s.T(), path.Base(elGenesisPath)) + s.Reth2.ElHandle = rethHandle + // Prepare a logger backed by a buffer to capture logs for assertions. s.Reth.LogBuffer = &simulated.SyncBuffer{} - rethLogger := phuslu.NewLogger(s.Reth.LogBuffer, nil) + logger := phuslu.NewLogger(s.Reth.LogBuffer, nil) + + s.Reth2.LogBuffer = &simulated.SyncBuffer{} + rethLogger := phuslu.NewLogger(s.Reth2.LogBuffer, nil) // Build the Beacon node with the simulated Comet component and electra genesis chain spec components := simulated.FixedComponents(s.T()) components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) - s.Geth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ - TempHomeDir: s.Geth.HomeDir, + s.Reth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ + TempHomeDir: s.Reth.HomeDir, CometConfig: cometConfig, AuthRPC: authRPC, ClientRPC: elRPC, @@ -117,10 +117,10 @@ func (s *PectraForkSuite) SetupTest() { AppOpts: viper.New(), Components: components, }) - s.Geth.SimComet = s.Geth.TestNode.SimComet + s.Reth.SimComet = s.Reth.TestNode.SimComet - s.Reth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ - TempHomeDir: s.Reth.HomeDir, + s.Reth2.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ + TempHomeDir: s.Reth2.HomeDir, CometConfig: cometConfig, AuthRPC: rethAuthRPC, ClientRPC: elRPC, @@ -128,45 +128,43 @@ func (s *PectraForkSuite) SetupTest() { AppOpts: viper.New(), Components: components, }) - s.Reth.SimComet = s.Reth.TestNode.SimComet + s.Reth2.SimComet = s.Reth2.TestNode.SimComet // Start the Beacon node in a separate goroutine. go func() { - _ = s.Geth.TestNode.Start(s.Geth.CtxApp) + _ = s.Reth.TestNode.Start(s.Reth.CtxApp) }() // Start the Beacon node in a separate goroutine. go func() { - _ = s.Reth.TestNode.Start(s.Reth.CtxApp) + _ = s.Reth2.TestNode.Start(s.Reth2.CtxApp) }() - s.Geth.SimulationClient = execution.NewSimulationClient(s.Geth.TestNode.EngineClient) - // Reth does not have a simulation API + s.Reth.SimulationClient = execution.NewSimulationClient(s.Reth.TestNode.EngineClient) timeOut := 10 * time.Second interval := 50 * time.Millisecond - err = simulated.WaitTillServicesStarted(s.Geth.LogBuffer, timeOut, interval) - s.Require().NoError(err) err = simulated.WaitTillServicesStarted(s.Reth.LogBuffer, timeOut, interval) s.Require().NoError(err) + err = simulated.WaitTillServicesStarted(s.Reth2.LogBuffer, timeOut, interval) + s.Require().NoError(err) } // TearDownTest cleans up the test environment. func (s *PectraForkSuite) TearDownTest() { - s.Geth.CleanupTestWithLabel(s.T(), "GETH") s.Reth.CleanupTestWithLabel(s.T(), "RETH") + s.Reth2.CleanupTestWithLabel(s.T(), "RETH2") } // TestTimestampFork_ELAndCLInSync_IsSuccessful tests that we can fork successfully if EL and CL have synced timestamps // The forks timestamp at Unix 0, as the genesis at Unix 0, Cancun is at 10 and Prague is at 20. -// The Geth Node will be the block producer but the Reth node is treated as a full node, i.e. doesn't produce blocks. +// The Reth Node will be the block producer but the Reth2 node is treated as a full node, i.e. doesn't produce blocks. func (s *PectraForkSuite) TestTimestampFork_ELAndCLInSync_IsSuccessful() { - // Initialize the geth chain state. - s.Geth.InitializeChain(s.T(), 1) - // Initialize the reth chain state. + // Initialize the chain state. s.Reth.InitializeChain(s.T(), 1) + s.Reth2.InitializeChain(s.T(), 1) - nodeAddress, err := s.Geth.SimComet.GetNodeAddress() + nodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) + s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) expectedMessages := []string{ "Processing block with fork version service=blockchain\u001B[0m block=1\u001B[0m fork=0x04010000\u001B[0m", @@ -192,7 +190,7 @@ func (s *PectraForkSuite) TestTimestampFork_ELAndCLInSync_IsSuccessful() { for currentHeight := startHeight; currentHeight < startHeight+iterations; currentHeight++ { submitTxNonce = s.submitTransactions(submitTxNonce, 100) - proposal, err := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + proposal, err := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, @@ -215,14 +213,14 @@ func (s *PectraForkSuite) TestTimestampFork_ELAndCLInSync_IsSuccessful() { Time: consensusTime, } expectedMessage := expectedMessages[expectedMessagesIdx] - processFinalizeCommit(s.T(), s.Geth, processRequest, finalizeRequest, expectedMessage) processFinalizeCommit(s.T(), s.Reth, processRequest, finalizeRequest, expectedMessage) + processFinalizeCommit(s.T(), s.Reth2, processRequest, finalizeRequest, expectedMessage) expectedMessagesIdx++ // set consensus time for the next block to match // the timestamp of the payload built optimistically. - forkVersion := s.Geth.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())) //#nosec: G115 + forkVersion := s.Reth.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())) //#nosec: G115 blk, _, err := encoding.ExtractBlobsAndBlockFromRequest( processRequest, blockchain.BeaconBlockTxIndex, @@ -240,15 +238,15 @@ func (s *PectraForkSuite) TestTimestampFork_ELAndCLInSync_IsSuccessful() { // A user makes a consolidation request on our chain which isn't supported. func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored() { // Initialize the chain state. - s.Geth.InitializeChain(s.T(), 1) s.Reth.InitializeChain(s.T(), 1) + s.Reth2.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. - blsSigner := simulated.GetBlsSigner(s.Geth.HomeDir) + blsSigner := simulated.GetBlsSigner(s.Reth.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() - s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) + s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) nextBlockHeight := int64(1) // We must first move the chain to the fork height, then an extra block @@ -257,7 +255,7 @@ func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored( { for i := 0; i < 2; i++ { consensusTime := time.Now() - proposal, err := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + proposal, err := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, @@ -280,8 +278,8 @@ func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored( Time: consensusTime, } expectedMsg := "fork=0x05000000" - processFinalizeCommit(s.T(), s.Geth, processRequest, finalizeRequest, expectedMsg) processFinalizeCommit(s.T(), s.Reth, processRequest, finalizeRequest, expectedMsg) + processFinalizeCommit(s.T(), s.Reth2, processRequest, finalizeRequest, expectedMsg) nextBlockHeight++ } } @@ -291,10 +289,10 @@ func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored( senderKey, err := crypto.HexToECDSA("fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306") s.Require().NoError(err) - elChainID := big.NewInt(int64(s.Geth.TestNode.ChainSpec.DepositEth1ChainID())) + elChainID := big.NewInt(int64(s.Reth.TestNode.ChainSpec.DepositEth1ChainID())) signer := gethtypes.NewPragueSigner(elChainID) - fee, feeErr := eip7251.GetConsolidationFee(s.Geth.CtxApp, s.Geth.TestNode.EngineClient) + fee, feeErr := eip7251.GetConsolidationFee(s.Reth.CtxApp, s.Reth.TestNode.EngineClient) s.Require().NoError(feeErr) // The inputs to the request do not necessarily matter, as long as they pass EL validation @@ -314,7 +312,7 @@ func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored( txBytes, marshalErr := consolidationTx.MarshalBinary() s.Require().NoError(marshalErr) var result interface{} - err = s.Geth.TestNode.EngineClient.Call(s.Geth.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) + err = s.Reth.TestNode.EngineClient.Call(s.Reth.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) time.Sleep(time.Second) // give it time to allow the tx to be included in the next block } @@ -322,7 +320,7 @@ func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored( { for i := 0; i < 5; i++ { consensusTime := time.Now() - proposal, err := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + proposal, err := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, @@ -349,8 +347,8 @@ func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored( // The first block since tx submission will have the consolidation propagated to the CL. expectedMsg = "consolidations=1" } - processFinalizeCommit(s.T(), s.Geth, processRequest, finalizeRequest, expectedMsg) processFinalizeCommit(s.T(), s.Reth, processRequest, finalizeRequest, expectedMsg) + processFinalizeCommit(s.T(), s.Reth2, processRequest, finalizeRequest, expectedMsg) nextBlockHeight++ } } @@ -360,8 +358,8 @@ func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored( // The next round will propose a valid pre-fork block that gets finalized due to deviance in the consensus timestamp. // The proposer will then propose a valid post-fork block that is correctly finalized. func (s *PectraForkSuite) TestValidProposer_ProposesPostForkBlockIsNotFinalized_IsSuccessful() { - client := s.Geth - helper := s.Reth + client := s.Reth + helper := s.Reth2 // Initialize the chain state. client.InitializeChain(s.T(), 1) @@ -530,17 +528,17 @@ func (s *PectraForkSuite) TestValidProposer_ProposesPostForkBlockIsNotFinalized_ // This will be rejected and is expected to occur around the fork for 1 or 2 rounds. func (s *PectraForkSuite) TestValidProposer_ProposesPreForkBlockWithPostForkConsensusTimestamp_IsRejected() { // Initialize the chain state. - s.Geth.InitializeChain(s.T(), 1) - nodeAddress, err := s.Geth.SimComet.GetNodeAddress() + s.Reth.InitializeChain(s.T(), 1) + nodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) - s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) + s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) nextBlockHeight := int64(1) // The proposer prepares a proposal with a pre-fork timestamp, but a post-fork process proposal consensus time. { // a pre-fork time. consensusTime := time.Unix(2, 0) - proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ + proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, @@ -558,12 +556,12 @@ func (s *PectraForkSuite) TestValidProposer_ProposesPreForkBlockWithPostForkCons // Process the proposal, expect a reject { - s.Geth.LogBuffer.Reset() - processResp, err := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) + s.Reth.LogBuffer.Reset() + processResp, err := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains( - s.Geth.LogBuffer.String(), + s.Reth.LogBuffer.String(), "failed decoding *types.SignedBeaconBlock: ssz: offset smaller than previous: decoded 392, previous was 396", ) } @@ -574,7 +572,7 @@ func (s *PectraForkSuite) TestValidProposer_ProposesPreForkBlockWithPostForkCons // correctly invokes `ProcessFork` on the state processor. func (s *PectraForkSuite) Test_OptimisticBuildAtFork_IsSuccessful() { // Initialize the chain state. - client := s.Geth + client := s.Reth client.InitializeChain(s.T(), 1) // init the validator // Retrieve the BLS signer and proposer address. @@ -674,8 +672,8 @@ func (s *PectraForkSuite) Test_OptimisticBuildAtFork_IsSuccessful() { // Test a scenario where reth must rebuild a payload for a failed state transition. func (s *PectraForkSuite) TestReth_MustRebuildForFailedStateTransition_IsSuccessful() { // Initialize the chain state. - testEL := s.Reth - helpBuilder := s.Geth + testEL := s.Reth2 + helpBuilder := s.Reth testEL.InitializeChain(s.T(), 1) helpBuilder.InitializeChain(s.T(), 1) @@ -818,7 +816,7 @@ func (s *PectraForkSuite) submitTransactions(startNonce uint64, numTransactions // corresponds with funded address in genesis 0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4 senderKey, err := crypto.HexToECDSA("fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306") s.Require().NoError(err) - elChainID := big.NewInt(int64(s.Geth.TestNode.ChainSpec.DepositEth1ChainID())) + elChainID := big.NewInt(int64(s.Reth.TestNode.ChainSpec.DepositEth1ChainID())) signer := gethtypes.NewPragueSigner(elChainID) for i := startNonce; i < startNonce+numTransactions; i++ { @@ -837,7 +835,7 @@ func (s *PectraForkSuite) submitTransactions(startNonce uint64, numTransactions s.Require().NoError(marshalErr) var result interface{} - err = s.Geth.TestNode.EngineClient.Call(s.Geth.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) + err = s.Reth.TestNode.EngineClient.Call(s.Reth.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) } return startNonce + numTransactions diff --git a/testing/simulated/pectra_genesis_test.go b/testing/simulated/pectra_genesis_test.go index bc2b4d53df..a2bec41b33 100644 --- a/testing/simulated/pectra_genesis_test.go +++ b/testing/simulated/pectra_genesis_test.go @@ -80,8 +80,8 @@ func (s *PectraGenesisSuite) SetupTest() { cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot - // Start the EL (execution layer) Geth node. - elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) + // Start the EL (execution layer) Reth node. + elNode := execution.NewRethNode(s.HomeDir, execution.ValidRethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle diff --git a/testing/simulated/pectra_withdrawal_test.go b/testing/simulated/pectra_withdrawal_test.go index b3055f69d2..fe0b34e6e0 100644 --- a/testing/simulated/pectra_withdrawal_test.go +++ b/testing/simulated/pectra_withdrawal_test.go @@ -87,8 +87,8 @@ func (s *PectraWithdrawalSuite) SetupTest() { cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot - // Start the EL (execution layer) Geth node. - elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) + // Start the EL (execution layer) Reth node. + elNode := execution.NewRethNode(s.HomeDir, execution.ValidRethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle diff --git a/testing/simulated/rpc_errors_test.go b/testing/simulated/rpc_errors_test.go index 380426eadc..787a2da389 100644 --- a/testing/simulated/rpc_errors_test.go +++ b/testing/simulated/rpc_errors_test.go @@ -207,8 +207,8 @@ func (s *RPCErrorProxySuite) SetupTest() { cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot - // Start Geth. - elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) + // Start Reth. + elNode := execution.NewRethNode(s.HomeDir, execution.ValidRethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle @@ -216,7 +216,7 @@ func (s *RPCErrorProxySuite) SetupTest() { s.errProxy = newRPCErrorProxy(authRPC.String()) s.errProxyServer = httptest.NewServer(s.errProxy) - // Create a ConnectionURL pointing to the proxy instead of Geth. + // Create a ConnectionURL pointing to the proxy instead of execution client. proxyURL, err := url.NewFromRaw(s.errProxyServer.URL) s.Require().NoError(err) diff --git a/testing/simulated/simulated_test.go b/testing/simulated/simulated_test.go index c723772ab2..77eb0e28da 100644 --- a/testing/simulated/simulated_test.go +++ b/testing/simulated/simulated_test.go @@ -67,8 +67,8 @@ func (s *SimulatedSuite) SetupTest() { cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot - // Start the EL (execution layer) Geth node. - elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) + // Start the EL (execution layer) Reth node. + elNode := execution.NewRethNode(s.HomeDir, execution.ValidRethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle diff --git a/testing/simulated/utils.go b/testing/simulated/utils.go index dbe6d2f235..05d623a500 100644 --- a/testing/simulated/utils.go +++ b/testing/simulated/utils.go @@ -119,7 +119,7 @@ func (s *SharedAccessors) CleanupTest(t *testing.T) { } // CleanupTestWithLabel performs common cleanup operations with an optional label for logs. -// Use this when managing multiple execution clients (e.g., "GETH", "RETH"). +// Use this when managing multiple execution clients. func (s *SharedAccessors) CleanupTestWithLabel(t *testing.T, label string) { t.Helper() From 222579a44d83dc74c2959d902c8268a0353b14b5 Mon Sep 17 00:00:00 2001 From: bar-bera Date: Wed, 24 Jun 2026 15:00:59 +0200 Subject: [PATCH 2/6] fix some testing --- .../el-genesis-files/eth-genesis.json | 8 ++++- testing/simulated/execution/execnode.go | 12 ++++++-- testing/simulated/execution/reth.go | 6 ++++ .../simulated/execution/simulation_client.go | 11 +++---- testing/simulated/fulu_deposit_test.go | 2 +- testing/simulated/malicious_consensus_test.go | 2 +- testing/simulated/malicious_proposer_test.go | 2 +- testing/simulated/payload_cache_test.go | 2 +- testing/simulated/pectra_fork_test.go | 2 +- testing/simulated/pectra_genesis_test.go | 30 +++++++------------ testing/simulated/pectra_withdrawal_test.go | 7 ++--- testing/simulated/rpc_errors_test.go | 2 +- testing/simulated/simulated_test.go | 2 +- testing/simulated/utils.go | 10 +++++++ 14 files changed, 58 insertions(+), 40 deletions(-) diff --git a/testing/simulated/el-genesis-files/eth-genesis.json b/testing/simulated/el-genesis-files/eth-genesis.json index 8c2a6d4c41..12d140924e 100644 --- a/testing/simulated/el-genesis-files/eth-genesis.json +++ b/testing/simulated/el-genesis-files/eth-genesis.json @@ -19,6 +19,7 @@ "mergeNetsplitBlock": 0, "shanghaiTime": 0, "cancunTime": 0, + "pragueTime": 9999999999999999, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true, "ethash": {}, @@ -27,6 +28,11 @@ "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 } }, "berachain": { @@ -384,4 +390,4 @@ "balance": "0x0" } } -} \ No newline at end of file +} diff --git a/testing/simulated/execution/execnode.go b/testing/simulated/execution/execnode.go index ea77acfa50..1183aa5502 100644 --- a/testing/simulated/execution/execnode.go +++ b/testing/simulated/execution/execnode.go @@ -66,9 +66,15 @@ func (e *ExecNode) Start(t *testing.T, genesisFile string) (*Resource, *url.Conn err = pool.Client.Ping() require.NoErrorf(t, err, "could not connect to Docker: %s", err) - // Pull the image if it is not already present. - err = pool.Client.PullImage(e.image, docker.AuthConfiguration{}) - require.NoError(t, err, "failed to pull image") + // Refresh the image from the registry, but tolerate an unreachable registry when the + // image is already present locally. + if pullErr := pool.Client.PullImage(e.image, docker.AuthConfiguration{}); pullErr != nil { + _, inspectErr := pool.Client.InspectImage(e.image.Repository + ":" + e.image.Tag) + require.NoErrorf(t, inspectErr, + "failed to pull image %s:%s and it is not present locally (pull error: %v)", + e.image.Repository, e.image.Tag, pullErr, + ) + } // Resolve the absolute path to the local test files. absPath, err := filepath.Abs("../files") diff --git a/testing/simulated/execution/reth.go b/testing/simulated/execution/reth.go index 8e38dede41..69b30049b7 100644 --- a/testing/simulated/execution/reth.go +++ b/testing/simulated/execution/reth.go @@ -58,6 +58,9 @@ func defaultRethCmdStrBuilder(genesisFile string) string { --full \ --engine.persistence-threshold=0 \ --engine.memory-block-buffer-target=0 \ + --txpool.pending-max-count=4096 \ + --txpool.queued-max-count=4096 \ + --txpool.max-account-slots=256 \ -vvvv \ `, genesisFile) } @@ -75,6 +78,9 @@ func rethWithEngineOverrideFlagCmdStrBuilder(genesisFile string) string { --engine.persistence-threshold=0 \ --engine.memory-block-buffer-target=0 \ --engine.always-process-payload-attributes-on-canonical-head \ + --txpool.pending-max-count=4096 \ + --txpool.queued-max-count=4096 \ + --txpool.max-account-slots=256 \ -vvvv \ `, genesisFile) } diff --git a/testing/simulated/execution/simulation_client.go b/testing/simulated/execution/simulation_client.go index 00ccfac927..968bf81ecd 100644 --- a/testing/simulated/execution/simulation_client.go +++ b/testing/simulated/execution/simulation_client.go @@ -27,17 +27,18 @@ import ( "context" "math/big" - "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/ethclient" ) -// SimulationClient calls `eth_simulateV1` on an execution client. +// SimulationClient calls `eth_simulateV1` on an execution client's eth JSON-RPC +// endpoint. Reth only serves eth_simulateV1 on the eth namespace, not on the auth RPC. type SimulationClient struct { - engineClient *client.EngineClient + ethClient *ethclient.Client } // TransactionArgs represents the fields needed to construct a dynamic-fee transaction. @@ -129,7 +130,7 @@ type SimulatedBlock struct { } // NewSimulationClient returns a client for eth_simulateV1 calls. -func NewSimulationClient(cli *client.EngineClient) *SimulationClient { +func NewSimulationClient(cli *ethclient.Client) *SimulationClient { return &SimulationClient{cli} } @@ -143,7 +144,7 @@ func (c *SimulationClient) Simulate( var result []*SimulatedBlock blockNumberInput := hexutil.Uint64(blockNumber) - if err := c.engineClient.Call(ctx, &result, "eth_simulateV1", opts, blockNumberInput); err != nil { + if err := c.ethClient.Client().CallContext(ctx, &result, "eth_simulateV1", opts, blockNumberInput); err != nil { return nil, err } return result, nil diff --git a/testing/simulated/fulu_deposit_test.go b/testing/simulated/fulu_deposit_test.go index 56c22c816a..a821fdc756 100644 --- a/testing/simulated/fulu_deposit_test.go +++ b/testing/simulated/fulu_deposit_test.go @@ -99,7 +99,7 @@ func (s *FuluDepositSuite) SetupTest() { _ = s.TestNode.Start(s.CtxApp) }() - s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) + s.SimulationClient = execution.NewSimulationClient(s.TestNode.ContractBackend) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) diff --git a/testing/simulated/malicious_consensus_test.go b/testing/simulated/malicious_consensus_test.go index bce854703f..61a2251c80 100644 --- a/testing/simulated/malicious_consensus_test.go +++ b/testing/simulated/malicious_consensus_test.go @@ -133,5 +133,5 @@ func (s *SimulatedSuite) TestFinalizeBlock_BadBlock_Errors() { }) s.Require().ErrorIs(err, errors.ErrInvalidPayloadStatus) s.Require().Nil(finalizeResp) - s.Require().Contains(s.LogBuffer.String(), "max fee per gas less than block base fee: address 0x20f33CE90A13a4b5E7697E3544c3083B8F8A51D4, maxFeePerGas: 10000000, baseFee: 765625000") + s.Require().Contains(s.LogBuffer.String(), "gas price is less than basefee") } diff --git a/testing/simulated/malicious_proposer_test.go b/testing/simulated/malicious_proposer_test.go index fb6860578c..88811ed266 100644 --- a/testing/simulated/malicious_proposer_test.go +++ b/testing/simulated/malicious_proposer_test.go @@ -146,7 +146,7 @@ func (s *SimulatedSuite) TestProcessProposal_BadBlock_IsRejected() { // Verify that the log contains the expected error message. s.Require().Contains(s.LogBuffer.String(), errors.ErrInvalidPayloadStatus.Error()) // Note this error message may change across execution clients. Base fee changes with number of core loop iterations. - s.Require().Contains(s.LogBuffer.String(), "max fee per gas less than block base fee: address 0x20f33CE90A13a4b5E7697E3544c3083B8F8A51D4, maxFeePerGas: 10000000, baseFee: 765625000") + s.Require().Contains(s.LogBuffer.String(), "gas price is less than basefee") } // TestProcessProposal_InvalidTimestamps_Errors effectively serves as a test for how a valid node would react to diff --git a/testing/simulated/payload_cache_test.go b/testing/simulated/payload_cache_test.go index f06f2cb783..b68df5fb1f 100644 --- a/testing/simulated/payload_cache_test.go +++ b/testing/simulated/payload_cache_test.go @@ -227,7 +227,7 @@ func (s *PayloadCacheSuite) SetupTest() { }() } - s.Reth.SimulationClient = execution.NewSimulationClient(s.Reth.TestNode.EngineClient) + s.Reth.SimulationClient = execution.NewSimulationClient(s.Reth.TestNode.ContractBackend) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.Reth.LogBuffer, timeOut, interval) diff --git a/testing/simulated/pectra_fork_test.go b/testing/simulated/pectra_fork_test.go index 58a655e89d..5ac82b31e9 100644 --- a/testing/simulated/pectra_fork_test.go +++ b/testing/simulated/pectra_fork_test.go @@ -139,7 +139,7 @@ func (s *PectraForkSuite) SetupTest() { _ = s.Reth2.TestNode.Start(s.Reth2.CtxApp) }() - s.Reth.SimulationClient = execution.NewSimulationClient(s.Reth.TestNode.EngineClient) + s.Reth.SimulationClient = execution.NewSimulationClient(s.Reth.TestNode.ContractBackend) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.Reth.LogBuffer, timeOut, interval) diff --git a/testing/simulated/pectra_genesis_test.go b/testing/simulated/pectra_genesis_test.go index a2bec41b33..65bc4102f3 100644 --- a/testing/simulated/pectra_genesis_test.go +++ b/testing/simulated/pectra_genesis_test.go @@ -111,7 +111,7 @@ func (s *PectraGenesisSuite) SetupTest() { _ = s.TestNode.Start(s.CtxApp) }() - s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) + s.SimulationClient = execution.NewSimulationClient(s.TestNode.ContractBackend) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) @@ -191,8 +191,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithPartialWithdrawalRequests_IsS Data: withdrawalTxData, }) - var balance hexutil.Big - err = s.TestNode.EngineClient.Call(s.CtxApp, &balance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") + balance := s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance before withdrawal request sent: %s", balance.ToInt().String()) var txBytes []byte @@ -216,8 +215,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithPartialWithdrawalRequests_IsS s.Require().Contains(s.LogBuffer.String(), "Processing execution requests service=state-processor\u001B[0m deposits=0\u001B[0m withdrawals=2\u001B[0m consolidations=0\u001B[0m") s.LogBuffer.Reset() - err := s.TestNode.EngineClient.Call(s.CtxApp, &afterRequestBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") - s.Require().NoError(err) + afterRequestBalance = s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance after withdrawal request included in block: %s", afterRequestBalance.ToInt().String()) nextBlockHeight++ } @@ -235,8 +233,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithPartialWithdrawalRequests_IsS s.MoveChainToHeight(s.T(), nextBlockHeight, int64(iterationsToTurn), nodeAddress, time.Now()) s.LogBuffer.Reset() - err := s.TestNode.EngineClient.Call(s.CtxApp, &beforeWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") - s.Require().NoError(err) + beforeWithdrawalBalance = s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance before withdrawal processed: %s", beforeWithdrawalBalance.ToInt().String()) // Balance should not have changed yet @@ -248,9 +245,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithPartialWithdrawalRequests_IsS { s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) - var afterWithdrawalBalance hexutil.Big - err := s.TestNode.EngineClient.Call(s.CtxApp, &afterWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") - s.Require().NoError(err) + afterWithdrawalBalance := s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance after withdrawal processed: %s", afterWithdrawalBalance.ToInt().String()) withdrawalAmountWei := new(big.Int).Mul(big.NewInt(int64(totalWithdrawalAmount)), big.NewInt(params.GWei)) @@ -309,8 +304,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithFullWithdrawalRequest_IsSucce Data: withdrawalTxData, }) - var balance hexutil.Big - err = s.TestNode.EngineClient.Call(s.CtxApp, &balance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") + balance := s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance before withdrawal request sent: %s", balance.ToInt().String()) txBytes, err := withdrawalTx.MarshalBinary() @@ -333,8 +327,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithFullWithdrawalRequest_IsSucce // No validator updates yet s.Require().Len(finalizeBlockResponses[0].GetValidatorUpdates(), 0) - err := s.TestNode.EngineClient.Call(s.CtxApp, &afterRequestBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") - s.Require().NoError(err) + afterRequestBalance = s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance after withdrawal request included in block: %s", afterRequestBalance.ToInt().String()) nextBlockHeight++ } @@ -372,8 +365,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithFullWithdrawalRequest_IsSucce s.MoveChainToHeight(s.T(), nextBlockHeight, int64(iterationsToTurn), nodeAddress, time.Now()) s.LogBuffer.Reset() - err := s.TestNode.EngineClient.Call(s.CtxApp, &beforeWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") - s.Require().NoError(err) + beforeWithdrawalBalance = s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance before withdrawal processed: %s", beforeWithdrawalBalance.ToInt().String()) // Balance should not have changed yet @@ -384,9 +376,7 @@ func (s *PectraGenesisSuite) TestFullLifecycle_WithFullWithdrawalRequest_IsSucce // The next block will be the turn of the Epoch, and the balance will change { s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) - var afterWithdrawalBalance hexutil.Big - err := s.TestNode.EngineClient.Call(s.CtxApp, &afterWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") - s.Require().NoError(err) + afterWithdrawalBalance := s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance after withdrawal processed: %s", afterWithdrawalBalance.ToInt().String()) // Since this is a full withdrawal, the full balance will be withdrawn. @@ -502,6 +492,6 @@ func (s *PectraGenesisSuite) TestMaliciousProposer_AddInvalidExecutionRequests_I // Verify that the log contains the expected error message. s.Require().Contains(s.LogBuffer.String(), errors.ErrInvalidPayloadStatus.Error()) - s.Require().Contains(s.LogBuffer.String(), "invalid requests hash (remote: 33ba74e937423115e3abf4250db02588388b4b3a7918950ed44a28e4bf3428d2 local: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)") + s.Require().Contains(s.LogBuffer.String(), "mismatched block requests hash") } } diff --git a/testing/simulated/pectra_withdrawal_test.go b/testing/simulated/pectra_withdrawal_test.go index fe0b34e6e0..55c88a90b5 100644 --- a/testing/simulated/pectra_withdrawal_test.go +++ b/testing/simulated/pectra_withdrawal_test.go @@ -118,7 +118,7 @@ func (s *PectraWithdrawalSuite) SetupTest() { _ = s.TestNode.Start(s.CtxApp) }() - s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) + s.SimulationClient = execution.NewSimulationClient(s.TestNode.ContractBackend) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) @@ -403,8 +403,7 @@ func (s *PectraWithdrawalSuite) TestWithdrawalFromExcessStake_WithPartialWithdra Data: withdrawalTxData, }) - var balance hexutil.Big - err = s.TestNode.EngineClient.Call(s.CtxApp, &balance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") + balance := s.GetBalance(s.T(), simulated.WithdrawalExecutionAddress) s.T().Logf("Balance before withdrawal request sent: %s", balance.ToInt().String()) var txBytes []byte @@ -578,7 +577,7 @@ func (s *PectraWithdrawalSuite) TestWithdrawalFromExcessStake_HasCorrectWithdraw s.Require().NoError(convertErr) expectedStartBalanceGwei, convertErr := beaconmath.GweiFromWei(expectedStartBalance) s.Require().NoError(convertErr) - s.Require().InDelta(finalBalanceGwei.Unwrap(), expectedStartBalanceGwei.Unwrap(), 2_000_000) // maximum 2_000_000 Gwei delta + s.Require().InDelta(finalBalanceGwei.Unwrap(), expectedStartBalanceGwei.Unwrap(), 3_000_000) // maximum 3_000_000 Gwei delta (EL gas accounting varies slightly by client) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight-1, nil, nil) s.Require().NoError(err) diff --git a/testing/simulated/rpc_errors_test.go b/testing/simulated/rpc_errors_test.go index 787a2da389..fecdf16f73 100644 --- a/testing/simulated/rpc_errors_test.go +++ b/testing/simulated/rpc_errors_test.go @@ -244,7 +244,7 @@ func (s *RPCErrorProxySuite) SetupTest() { _ = s.TestNode.Start(s.CtxApp) }() - s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) + s.SimulationClient = execution.NewSimulationClient(s.TestNode.ContractBackend) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) diff --git a/testing/simulated/simulated_test.go b/testing/simulated/simulated_test.go index 77eb0e28da..03c87d54c3 100644 --- a/testing/simulated/simulated_test.go +++ b/testing/simulated/simulated_test.go @@ -97,7 +97,7 @@ func (s *SimulatedSuite) SetupTest() { _ = s.TestNode.Start(s.CtxApp) }() - s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) + s.SimulationClient = execution.NewSimulationClient(s.TestNode.ContractBackend) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) diff --git a/testing/simulated/utils.go b/testing/simulated/utils.go index 05d623a500..bad194b464 100644 --- a/testing/simulated/utils.go +++ b/testing/simulated/utils.go @@ -176,6 +176,16 @@ func (s *SharedAccessors) InitializeChain(t *testing.T, numValidators int) { require.Len(t, deposits, numValidators, fmt.Sprintf("Expected %d deposit(s)", numValidators)) } +// GetBalance returns the latest balance of the given hex execution address, queried via +// the execution-layer eth JSON-RPC (ContractBackend). Prefer this over an eth_getBalance +// call on the EngineClient: reth's auth/engine endpoint does not serve eth_getBalance. +func (s *SharedAccessors) GetBalance(t *testing.T, addr string) hexutil.Big { + t.Helper() + balance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, gethcommon.HexToAddress(addr), nil) + require.NoError(t, err) + return hexutil.Big(*balance) +} + // MoveChainToHeight will iterate through the core loop `iterations` times, i.e. Propose, Process, Finalize and Commit. // Returns the list of proposed comet blocks. func (s *SharedAccessors) MoveChainToHeight( From 6b3caa9fb5043a4dd509fbba6c80afa7fa626d4f Mon Sep 17 00:00:00 2001 From: bar-bera Date: Wed, 24 Jun 2026 20:18:32 +0200 Subject: [PATCH 3/6] fix missing tests --- .../simulated/execution/simulation_client.go | 11 +- testing/simulated/malicious_proposer_test.go | 15 +- testing/simulated/transformers.go | 10 +- testing/simulated/utils.go | 29 ++- testing/simulated/valid_chain_test.go | 227 +++++------------- 5 files changed, 101 insertions(+), 191 deletions(-) diff --git a/testing/simulated/execution/simulation_client.go b/testing/simulated/execution/simulation_client.go index 968bf81ecd..f3f5e4c643 100644 --- a/testing/simulated/execution/simulation_client.go +++ b/testing/simulated/execution/simulation_client.go @@ -184,14 +184,9 @@ func TxsToTransactionArgs(chainID uint64, txs []*types.Transaction) ([]Transacti ChainID: &chainIDHex, } - if sidecar := tx.BlobTxSidecar(); sidecar != nil { - blobCap := hexutil.Big(*tx.BlobGasFeeCap()) - call.BlobHashes = tx.BlobHashes() - call.BlobFeeCap = &blobCap - call.Blobs = sidecar.Blobs - call.Commitments = sidecar.Commitments - call.Proofs = sidecar.Proofs - } + // NOTE: blob fields are intentionally NOT set for simulation. + // reth's eth_simulateV1 cannot build an EIP-4844 transaction from + // blobVersionedHashes / maxFeePerBlobGas alone. args[i] = call } diff --git a/testing/simulated/malicious_proposer_test.go b/testing/simulated/malicious_proposer_test.go index 88811ed266..251423da8f 100644 --- a/testing/simulated/malicious_proposer_test.go +++ b/testing/simulated/malicious_proposer_test.go @@ -305,22 +305,17 @@ func (s *SimulatedSuite) TestProcessProposal_InvalidBlobCommitment_Errors() { blobTxs[i] = blobTx } - proposedBlockMessage := simulated.ComputeAndSetValidExecutionBlock( + // Build the block carrying the malformed blob tx directly via MakeEthBlock (no eth_simulateV1, + // which reth cannot use to build blob txs). + proposedBlockMessage := simulated.ComputeAndSetInvalidExecutionBlock( s.T(), proposedBlock.GetBeaconBlock(), - s.SimulationClient, s.TestNode.ChainSpec, blobTxs, + nil, ) proposedBlockMessage.GetBody().SetBlobKzgCommitments(commitments) - // Finalize the block by applying the state transition to update its state root. - queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) - s.Require().NoError(err) - - proposedBlockMessage, err = simulated.ComputeAndSetStateRoot(queryCtx, consensusTime, nodeAddress, s.TestNode.StateProcessor, s.TestNode.StorageBackend, proposedBlockMessage) - s.Require().NoError(err) - newSignedBlock, err := ctypes.NewSignedBeaconBlock( proposedBlockMessage, &ctypes.ForkData{ @@ -377,7 +372,7 @@ func (s *SimulatedSuite) TestProcessProposal_InvalidBlobCommitment_Errors() { }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) - s.Require().Contains(s.LogBuffer.String(), "could not apply tx 1 [0xdbbf691e9271a8bc3de5e64405337972fb4a5185cc3df160bac310c515f7d768]: blob transaction missing blob hashes") + s.Require().Contains(s.LogBuffer.String(), "unexpected list") } // TestProcessProposal_InvalidBlobInclusionProof_Errors effectively serves as a test for a malicious blobs. diff --git a/testing/simulated/transformers.go b/testing/simulated/transformers.go index fd8ec59cc5..8e9b60284c 100644 --- a/testing/simulated/transformers.go +++ b/testing/simulated/transformers.go @@ -47,14 +47,16 @@ func transformSimulatedBlockToGethBlock( simBlock *execution.SimulatedBlock, txs []*gethtypes.Transaction, parentBeaconRoot common.Root, + withdrawals gethtypes.Withdrawals, ) *gethtypes.Block { // Convert numeric fields. excessBlobGas := simBlock.ExcessBlobGas.ToInt().Uint64() blobGasUsed := simBlock.BlobGasUsed.ToInt().Uint64() baseFeePerGas := simBlock.BaseFeePerGas.ToInt() - // Compute the withdrawals hash from the simulated block's withdrawals. - withdrawalsHash := gethtypes.DeriveSha(simBlock.Withdrawals, gethtrie.NewStackTrie(nil)) + // reth's eth_simulateV1 ignores the withdrawals override and returns none, so the expected + // withdrawals are supplied by the caller. + withdrawalsHash := gethtypes.DeriveSha(withdrawals, gethtrie.NewStackTrie(nil)) // Create a new header using values from the simulated block. header := &gethtypes.Header{ @@ -81,11 +83,11 @@ func transformSimulatedBlockToGethBlock( ParentBeaconRoot: (*gethcommon.Hash)(&parentBeaconRoot), } - // Create the block body using the transactions and withdrawals from the simulation. + // Create the block body using the transactions from the simulation and withdrawals from the caller. body := gethtypes.Body{ Transactions: txs, Uncles: nil, - Withdrawals: simBlock.Withdrawals, + Withdrawals: withdrawals, } return gethtypes.NewBlockWithHeader(header).WithBody(body) diff --git a/testing/simulated/utils.go b/testing/simulated/utils.go index bad194b464..7543a122d6 100644 --- a/testing/simulated/utils.go +++ b/testing/simulated/utils.go @@ -257,6 +257,29 @@ func (s *SharedAccessors) MoveChainToHeight( return proposedCometBlocks, finalizedResponses, proposalTime } +// PrepareProposalUntil repeatedly calls PrepareProposal for req (up to 10 attempts, 200ms apart) +// until cond reports the built proposal is ready, then returns that proposal. +func (s *SharedAccessors) PrepareProposalUntil( + t *testing.T, + req *types.PrepareProposalRequest, + cond func(*types.PrepareProposalResponse) bool, +) *types.PrepareProposalResponse { + t.Helper() + const maxAttempts = 10 + const retryInterval = 200 * time.Millisecond + for attempt := 0; attempt < maxAttempts; attempt++ { + proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, req) + require.NoError(t, err) + require.NotEmpty(t, proposal) + if cond(proposal) { + return proposal + } + time.Sleep(retryInterval) + } + require.FailNow(t, "PrepareProposal did not satisfy the condition within the retry budget") + return nil +} + // WaitTillServicesStarted waits until the log buffer contains "All services started". // It checks periodically with a timeout to prevent indefinite waiting. // If there is a better way to determine the services have started, e.g. readiness probe, replace this. @@ -401,8 +424,12 @@ func ComputeAndSetValidExecutionBlock( txsNoSidecar, sidecars := splitTxs(txs) origParent := latestBlock.GetParentBlockRoot() + // reth's eth_simulateV1 ignores the withdrawals override and returns no withdrawals, so build the + // execution block with the original block's withdrawals (which the CL expects). + origWithdrawals := latestBlock.GetBody().GetExecutionPayload().GetWithdrawals() + gethWithdrawals := *(*coretypes.Withdrawals)(unsafe.Pointer(&origWithdrawals)) // Transform the simulated block into a Geth block. - execBlock := transformSimulatedBlockToGethBlock(simBlock, txsNoSidecar, origParent) + execBlock := transformSimulatedBlockToGethBlock(simBlock, txsNoSidecar, origParent, gethWithdrawals) // TODO: Add support for execution requests before allowing electra return updateBeaconBlockBody(t, latestBlock, forkVersion, execBlock, sidecars, nil) } diff --git a/testing/simulated/valid_chain_test.go b/testing/simulated/valid_chain_test.go index 057cb01637..c5367aab77 100644 --- a/testing/simulated/valid_chain_test.go +++ b/testing/simulated/valid_chain_test.go @@ -23,15 +23,12 @@ package simulated_test import ( + "bytes" "math/big" "time" "github.com/berachain/beacon-kit/beacon/blockchain" - ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" - dablob "github.com/berachain/beacon-kit/da/blob" - datypes "github.com/berachain/beacon-kit/da/types" - "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/simulated" @@ -106,34 +103,14 @@ func (s *SimulatedSuite) TestFullLifecycle_ValidBlockWithInjectedTransaction_IsS nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) - // Test happens on Deneb, pre Deneb1 fork. - startTime := time.Unix(0, 0) + // Build at the first block, on Deneb (pre Deneb1 fork at t=30). The proposer's EL build for the + // first block is fresh (no cached optimistic payload from a prior round), so the injected tx + // sitting in the txpool is included in the built block. + currentHeight := int64(blockHeight) + consensusTime := time.Unix(1, 0) - // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. - proposals, _, consensusTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) - s.Require().Len(proposals, coreLoopIterations) - - // We expected this test to happen during Pre-Deneb1 fork. - currentHeight := int64(blockHeight + coreLoopIterations) - - // Prepare a valid block proposal. - proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ - Height: currentHeight, - Time: consensusTime, - ProposerAddress: nodeAddress, - }) - s.Require().NoError(err) - s.Require().NotEmpty(proposal) - - // Unmarshal the proposal block. - proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( - proposal.Txs, - blockchain.BeaconBlockTxIndex, - s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())), - ) - s.Require().NoError(err) - - // Sign a valid transaction that is expected to pass + // Since reth cannot use eth_simulateV1-based construction to build a valid payload, + // submit a valid transaction to the EL txpool and let the proposer include it in the block. recipientAddress := gethcommon.HexToAddress("0x56898d1aFb10cad584961eb96AcD476C6826e41E") validTx, err := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), @@ -143,39 +120,35 @@ func (s *SimulatedSuite) TestFullLifecycle_ValidBlockWithInjectedTransaction_IsS To: &recipientAddress, Value: big.NewInt(0), Gas: 21016, - GasTipCap: big.NewInt(765625000), - GasFeeCap: big.NewInt(765625000), + GasTipCap: big.NewInt(10_000_000_000), + GasFeeCap: big.NewInt(10_000_000_000), Data: []byte{}, }, ) - - validTxs := []*gethtypes.Transaction{validTx} - // Create a new beacon block with the valid transaction. - // Note: The beacon block returned here has an incorrect beacon state root, which is fixed in `ComputeAndSetStateRoot`. - unsignedBlock := simulated.ComputeAndSetValidExecutionBlock(s.T(), proposedBlock.GetBeaconBlock(), s.SimulationClient, s.TestNode.ChainSpec, validTxs) - - // Finalize the block by applying the state transition to update its state root. - queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) - s.Require().NoError(err) - finalBlock, err := simulated.ComputeAndSetStateRoot(queryCtx, consensusTime, nodeAddress, s.TestNode.StateProcessor, s.TestNode.StorageBackend, unsignedBlock) - s.Require().NoError(err) - - newSignedBlock, err := ctypes.NewSignedBeaconBlock( - finalBlock, - &ctypes.ForkData{ - CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(unsignedBlock.GetTimestamp()), - GenesisValidatorsRoot: s.GenesisValidatorsRoot, - }, - s.TestNode.ChainSpec, - blsSigner, - ) s.Require().NoError(err) + s.Require().NoError(s.TestNode.ContractBackend.SendTransaction(s.CtxApp, validTx)) - newBlockBytes, err := newSignedBlock.MarshalSSZ() + validTxBytes, err := validTx.MarshalBinary() s.Require().NoError(err) + forkVersion := s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())) - // Replace the old block with the new block in the proposal. - proposal.Txs[0] = newBlockBytes + // Build the proposal, retrying until the proposer's EL build includes the injected tx. + proposal := s.PrepareProposalUntil(s.T(), &types.PrepareProposalRequest{ + Height: currentHeight, + Time: consensusTime, + ProposerAddress: nodeAddress, + }, func(p *types.PrepareProposalResponse) bool { + builtBlock, derr := encoding.UnmarshalBeaconBlockFromABCIRequest( + p.Txs, blockchain.BeaconBlockTxIndex, forkVersion, + ) + s.Require().NoError(derr) + for _, txBytes := range builtBlock.GetBody().GetExecutionPayload().GetTransactions() { + if bytes.Equal(txBytes, validTxBytes) { + return true + } + } + return false + }) // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() @@ -207,153 +180,71 @@ func (s *SimulatedSuite) TestFullLifecycle_ValidBlockWithInjectedTransaction_IsS // TestFullLifecycle_ValidBlockAndInjectedBlob_IsSuccessful tests that a valid block and blob and proposal is processed, finalized, and committed. func (s *SimulatedSuite) TestFullLifecycle_ValidBlockAndInjectedBlob_IsSuccessful() { const blockHeight = 1 - const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) - // Retrieve the BLS signer and proposer address. + // Retrieve the proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) - // Test happens on Deneb, pre Deneb1 fork. - startTime := time.Unix(0, 0) - - // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. - proposals, _, consensusTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) - s.Require().Len(proposals, coreLoopIterations) - - // We expected this test to happen during Pre-Deneb1 fork. - currentHeight := int64(blockHeight + coreLoopIterations) - - // Prepare a valid block proposal. - proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ - Height: currentHeight, - Time: consensusTime, - ProposerAddress: nodeAddress, - }) - s.Require().NoError(err) - s.Require().NotEmpty(proposal) - - // Unmarshal the proposal block. - proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( - proposal.Txs, - blockchain.BeaconBlockTxIndex, - s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())), - ) - s.Require().NoError(err) + // Since reth cannot use eth_simulateV1-based construction to build a valid payload, + // submit a valid transaction to the EL txpool and let the proposer include it in the block. + currentHeight := int64(blockHeight) + consensusTime := time.Unix(1, 0) - // Create the Blobs, with proofs and commitments - // Each blob will go into 1 transaction. + // Create the blobs with proofs and commitments. Each blob goes into its own blob transaction. blobs := []*eip4844.Blob{{1, 2, 3}, {4, 5, 6}} proofs, commitments := simulated.GetProofAndCommitmentsForBlobs(require.New(s.T()), blobs, s.TestNode.KZGVerifier) s.Require().Len(proofs, len(blobs)) s.Require().Len(commitments, len(blobs)) - // Sign blob transactions - blobTxs := make([]*gethtypes.Transaction, len(blobs)) + // Sign the blob transactions and submit them to the EL txpool. for i := range blobs { - blobCommitment := commitments[i] - blobHash := blobCommitment.ToVersionedHash() + blobHash := commitments[i].ToVersionedHash() txSidecar := &gethtypes.BlobTxSidecar{ Blobs: []kzg4844.Blob{kzg4844.Blob(blobs[i][:])}, - Commitments: []kzg4844.Commitment{kzg4844.Commitment(blobCommitment)}, + Commitments: []kzg4844.Commitment{kzg4844.Commitment(commitments[i])}, Proofs: []kzg4844.Proof{kzg4844.Proof(proofs[i])}, } - blobTx, err := gethtypes.SignNewTx( + blobTx, txErr := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), gethtypes.NewCancunSigner(big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID()))), &gethtypes.BlobTx{ - Nonce: uint64(i), - // Set to 875000000 as that is the tx base fee - GasTipCap: uint256.NewInt(875000000), - GasFeeCap: uint256.NewInt(875000000), - // Set to 21000 for minimum intrinsic gas + Nonce: uint64(i), + GasTipCap: uint256.NewInt(10_000_000_000), + GasFeeCap: uint256.NewInt(10_000_000_000), Gas: 210000, Value: uint256.NewInt(0), Data: []byte{}, AccessList: nil, - BlobFeeCap: uint256.NewInt(10), - // If we have 1 tx with multiple blobs, we must add the blob hashes here. + BlobFeeCap: uint256.NewInt(10_000_000_000), BlobHashes: []gethcommon.Hash{blobHash}, - // Sidecar must be set to nil here or Geth will error with "unexpected blob sidecar in transaction" - Sidecar: nil, + Sidecar: nil, }, ) - s.Require().NoError(err) - // Once we've signed the Tx, we tag the blob with the tx purely for association between tx and sidecars. - // In this case, each 1 tx has a sidecar with 1 blob, even though 1 tx could have more than 1 blob. + s.Require().NoError(txErr) blobTx = blobTx.WithBlobTxSidecar(txSidecar) - blobTxs[i] = blobTx - } - - proposedBlockMessage := simulated.ComputeAndSetValidExecutionBlock( - s.T(), - proposedBlock.GetBeaconBlock(), - s.SimulationClient, - s.TestNode.ChainSpec, - blobTxs, - ) - proposedBlockMessage.GetBody().SetBlobKzgCommitments(commitments) - - // Finalize the block by applying the state transition to update its state root. - queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) - s.Require().NoError(err) - - proposedBlockMessage, err = simulated.ComputeAndSetStateRoot(queryCtx, consensusTime, nodeAddress, s.TestNode.StateProcessor, s.TestNode.StorageBackend, proposedBlockMessage) - s.Require().NoError(err) - - newSignedBlock, err := ctypes.NewSignedBeaconBlock( - proposedBlockMessage, - &ctypes.ForkData{ - CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(proposedBlockMessage.GetTimestamp()), - GenesisValidatorsRoot: s.GenesisValidatorsRoot, - }, - s.TestNode.ChainSpec, - blsSigner, - ) - s.Require().NoError(err) - - // Inject the new block - newSignedBlockBytes, err := newSignedBlock.MarshalSSZ() - s.Require().NoError(err) - proposal.Txs[0] = newSignedBlockBytes - - // Create the beaconBlock Header for the sidecar - blockWithCommitmentsSignedHeader := ctypes.NewSignedBeaconBlockHeader( - newSignedBlock.GetHeader(), - newSignedBlock.GetSignature(), - ) - - sidecarsSlice := make([]*datypes.BlobSidecar, len(blobs)) - // Build Inclusion Proofs for Sidecars - sidecarFactory := dablob.NewSidecarFactory(metrics.NewNoOpTelemetrySink()) - for i := range blobs { - inclusionProof, err := sidecarFactory.BuildKZGInclusionProof(proposedBlockMessage.GetBody(), math.U64(i)) - s.Require().NoError(err) - sidecar := datypes.BuildBlobSidecar( - math.U64(i), - blockWithCommitmentsSignedHeader, - blobs[i], - commitments[i], - proofs[i], - inclusionProof, - ) - sidecarsSlice[i] = sidecar + s.Require().NoError(s.TestNode.ContractBackend.SendTransaction(s.CtxApp, blobTx)) } - sidecars := datypes.BlobSidecars(sidecarsSlice) - // Inject the valid sidecar - sidecarBytes, err := sidecars.MarshalSSZ() - s.Require().NoError(err) - proposal.Txs[1] = sidecarBytes + // Build the proposal, retrying until the proposer's EL build includes both blobs. + proposal := s.PrepareProposalUntil(s.T(), &types.PrepareProposalRequest{ + Height: currentHeight, + Time: consensusTime, + ProposerAddress: nodeAddress, + }, func(p *types.PrepareProposalResponse) bool { + sidecars, scErr := encoding.UnmarshalBlobSidecarsFromABCIRequest(p.Txs, blockchain.BlobSidecarsTxIndex) + s.Require().NoError(scErr) + return len(sidecars) == len(blobs) + }) - // Reset the log buffer to discard old logs we don't care about + // Reset the log buffer to discard old logs we don't care about. s.LogBuffer.Reset() - // Process the proposal containing the valid block. + // Process the proposal containing the valid block and blobs. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, From eaebabb60ea2ac0bdde5ceef6ec53b84290fe84e Mon Sep 17 00:00:00 2001 From: bar-bera Date: Fri, 26 Jun 2026 12:43:18 +0200 Subject: [PATCH 4/6] fix var shadowing --- testing/simulated/pectra_fork_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/simulated/pectra_fork_test.go b/testing/simulated/pectra_fork_test.go index 5ac82b31e9..5cea50c66a 100644 --- a/testing/simulated/pectra_fork_test.go +++ b/testing/simulated/pectra_fork_test.go @@ -93,7 +93,7 @@ func (s *PectraForkSuite) SetupTest() { s.Reth.ElHandle = elHandle rethNode2 := execution.NewRethNode(s.Reth2.HomeDir, execution.ValidRethImage()) - rethHandle, rethAuthRPC, elRPC := rethNode2.Start(s.T(), path.Base(elGenesisPath)) + rethHandle, rethAuthRPC, rethRPC := rethNode2.Start(s.T(), path.Base(elGenesisPath)) s.Reth2.ElHandle = rethHandle // Prepare a logger backed by a buffer to capture logs for assertions. @@ -123,7 +123,7 @@ func (s *PectraForkSuite) SetupTest() { TempHomeDir: s.Reth2.HomeDir, CometConfig: cometConfig, AuthRPC: rethAuthRPC, - ClientRPC: elRPC, + ClientRPC: rethRPC, Logger: rethLogger, AppOpts: viper.New(), Components: components, From 4d8db4ca3507fd5ab741e060c70712690bb6b8a4 Mon Sep 17 00:00:00 2001 From: bar-bera Date: Fri, 26 Jun 2026 12:45:55 +0200 Subject: [PATCH 5/6] remove dead var --- testing/simulated/valid_chain_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/simulated/valid_chain_test.go b/testing/simulated/valid_chain_test.go index c5367aab77..2136ff7b91 100644 --- a/testing/simulated/valid_chain_test.go +++ b/testing/simulated/valid_chain_test.go @@ -91,7 +91,6 @@ func (s *SimulatedSuite) TestFullLifecycle_ValidBlock_IsSuccessful() { // inject custom transactions and state transitions into the core loop. func (s *SimulatedSuite) TestFullLifecycle_ValidBlockWithInjectedTransaction_IsSuccessful() { const blockHeight = 1 - const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) From d70e54baf438d68c1a280d2bedfef025fbdedc46 Mon Sep 17 00:00:00 2001 From: bar-bera Date: Fri, 10 Jul 2026 12:31:06 +0200 Subject: [PATCH 6/6] remove useless retry loop on prepare proposal --- testing/simulated/utils.go | 23 -------------- testing/simulated/valid_chain_test.go | 44 +++++++++++++++------------ 2 files changed, 25 insertions(+), 42 deletions(-) diff --git a/testing/simulated/utils.go b/testing/simulated/utils.go index 7543a122d6..2075c3584d 100644 --- a/testing/simulated/utils.go +++ b/testing/simulated/utils.go @@ -257,29 +257,6 @@ func (s *SharedAccessors) MoveChainToHeight( return proposedCometBlocks, finalizedResponses, proposalTime } -// PrepareProposalUntil repeatedly calls PrepareProposal for req (up to 10 attempts, 200ms apart) -// until cond reports the built proposal is ready, then returns that proposal. -func (s *SharedAccessors) PrepareProposalUntil( - t *testing.T, - req *types.PrepareProposalRequest, - cond func(*types.PrepareProposalResponse) bool, -) *types.PrepareProposalResponse { - t.Helper() - const maxAttempts = 10 - const retryInterval = 200 * time.Millisecond - for attempt := 0; attempt < maxAttempts; attempt++ { - proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, req) - require.NoError(t, err) - require.NotEmpty(t, proposal) - if cond(proposal) { - return proposal - } - time.Sleep(retryInterval) - } - require.FailNow(t, "PrepareProposal did not satisfy the condition within the retry budget") - return nil -} - // WaitTillServicesStarted waits until the log buffer contains "All services started". // It checks periodically with a timeout to prevent indefinite waiting. // If there is a better way to determine the services have started, e.g. readiness probe, replace this. diff --git a/testing/simulated/valid_chain_test.go b/testing/simulated/valid_chain_test.go index 2136ff7b91..76f0416ae3 100644 --- a/testing/simulated/valid_chain_test.go +++ b/testing/simulated/valid_chain_test.go @@ -131,23 +131,27 @@ func (s *SimulatedSuite) TestFullLifecycle_ValidBlockWithInjectedTransaction_IsS s.Require().NoError(err) forkVersion := s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())) - // Build the proposal, retrying until the proposer's EL build includes the injected tx. - proposal := s.PrepareProposalUntil(s.T(), &types.PrepareProposalRequest{ + // Build the proposal and ensure the injected tx submitted to the EL pool is included. + proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, - }, func(p *types.PrepareProposalResponse) bool { - builtBlock, derr := encoding.UnmarshalBeaconBlockFromABCIRequest( - p.Txs, blockchain.BeaconBlockTxIndex, forkVersion, - ) - s.Require().NoError(derr) - for _, txBytes := range builtBlock.GetBody().GetExecutionPayload().GetTransactions() { - if bytes.Equal(txBytes, validTxBytes) { - return true - } - } - return false }) + s.Require().NoError(err) + s.Require().NotEmpty(proposal) + + builtBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( + proposal.Txs, blockchain.BeaconBlockTxIndex, forkVersion, + ) + s.Require().NoError(err) + txIncluded := false + for _, txBytes := range builtBlock.GetBody().GetExecutionPayload().GetTransactions() { + if bytes.Equal(txBytes, validTxBytes) { + txIncluded = true + break + } + } + s.Require().True(txIncluded, "injected transaction was not included in the built block") // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() @@ -230,16 +234,18 @@ func (s *SimulatedSuite) TestFullLifecycle_ValidBlockAndInjectedBlob_IsSuccessfu s.Require().NoError(s.TestNode.ContractBackend.SendTransaction(s.CtxApp, blobTx)) } - // Build the proposal, retrying until the proposer's EL build includes both blobs. - proposal := s.PrepareProposalUntil(s.T(), &types.PrepareProposalRequest{ + // Build the proposal and ensure the blob txs submitted to the EL pool are included. + proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, - }, func(p *types.PrepareProposalResponse) bool { - sidecars, scErr := encoding.UnmarshalBlobSidecarsFromABCIRequest(p.Txs, blockchain.BlobSidecarsTxIndex) - s.Require().NoError(scErr) - return len(sidecars) == len(blobs) }) + s.Require().NoError(err) + s.Require().NotEmpty(proposal) + + sidecars, err := encoding.UnmarshalBlobSidecarsFromABCIRequest(proposal.Txs, blockchain.BlobSidecarsTxIndex) + s.Require().NoError(err) + s.Require().Len(sidecars, len(blobs), "injected blobs were not included in the built block") // Reset the log buffer to discard old logs we don't care about. s.LogBuffer.Reset()