From ac0b971f91ac03ca658b42a038bc1f3f8c51f454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Moraczy=C5=84ski?= Date: Wed, 1 Jun 2022 13:12:57 +0200 Subject: [PATCH] Fixes in post merge sync + change sepolia configs (#4086) * NLog * uncomment fcu Code * fastSyncTransition fix for sync? * ignore pivot comment * Make PeerRefresher more sophisticated with batching (cherry picked from commit a553d9c8d1b29bf9384fdc3694fbc784c5c347d6) # Conflicts: # src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs * Move to mainnet-shadowfork-5 (cherry picked from commit c62619c7c10850353f9dfedf7611ee3abd9c9662) * all peers? * fix build * cleanup in beacon pivot * NLog change * more logging - block tree * more logs * hive plugin fix && sepolia fast sync * fix sepolia.cfg & edit sepolia bootnodes * fix eth tests * cleanup * revert NLog changes * Engine api handlers refactorings and cleanups * fix test * change run-run-merge-hive-tests on-push * fix build * refactoring to StateReader * add logs, fix PoSSwitcher decoding * one more fix? * refactoring BlockchainProcessor * fix ignore parent not on main chain Co-authored-by: lukasz.rozmej --- .github/workflows/run-merge-hive-tests.yml | 5 +- src/Nethermind/Chains/mainnet_shadowfork.json | 46 +--- .../Ethereum.Test.Base/BlockchainTestBase.cs | 1 + .../BlockchainProcessorTests.cs | 7 +- .../Producers/DevBlockproducerTests.cs | 2 + .../Nethermind.Blockchain.Test/ReorgTests.cs | 4 +- .../Visitors/StartupTreeFixerTests.cs | 6 +- .../Nethermind.Blockchain/BlockTree.cs | 7 +- .../CliqueBlockProducerTests.cs | 4 +- .../StartBlockProducerAuRa.cs | 1 + .../CliquePlugin.cs | 1 + .../NethDevPlugin.cs | 1 + .../Nethermind.Consensus/IPoSSwitcher.cs | 20 +- .../Processing/BlockchainProcessor.cs | 40 ++-- .../Processing/ProcessingOptions.cs | 2 +- .../Processing/ReadOnlyChainProcessingEnv.cs | 2 +- .../Producers/BlockProducerEnvFactory.cs | 1 + .../Validators/BlockValidator.cs | 5 - .../Validators/HeaderValidator.cs | 16 +- .../Validators/IHeaderValidator.cs | 1 - .../Blockchain/TestBlockchain.cs | 2 +- .../Extensions/EnumerableExtensions.cs | 1 + .../BlockHeaderExtensions.cs | 9 +- src/Nethermind/Nethermind.Hive/HivePlugin.cs | 8 +- .../Steps/InitializeBlockchain.cs | 1 + .../EthModuleBenchmarks.cs | 1 + .../Modules/Trace/ParityStyleTracerTests.cs | 3 +- .../EngineModuleTests.HelperFunctions.cs | 24 +- .../EngineModuleTests.Setup.cs | 2 +- .../EngineModuleTests.Synchronization.cs | 24 +- .../EngineModuleTests.V1.cs | 208 +++++++++--------- .../Synchronization/BeaconHeadersSyncTests.cs | 4 +- .../Synchronization/BeaconPivotTests.cs | 2 +- .../BlockTreeExtensions.cs | 30 +++ .../ExecutionPayloadV1.cs} | 22 +- .../Data/V1/ForkchoiceStateV1.cs | 18 ++ .../Data/V1/ForkchoiceUpdatedV1Result.cs | 52 ++--- .../Data/V1/NewPayloadV1Result.cs | 3 + .../Data/V1/PayloadStatusV1.cs | 22 +- .../Data/V1/Statuses.cs | 17 +- .../Data/V1/TransitionConfigurationV1.cs | 14 ++ .../EngineRpcModule.cs | 29 +-- .../Handlers/IPayloadPreparationService.cs | 2 +- .../Handlers/PayloadPreparationService.cs | 44 ++-- .../Handlers/V1/ForkchoiceUpdatedV1Handler.cs | 166 ++++++-------- .../Handlers/V1/GetPayloadV1Handler.cs | 49 +++-- .../Handlers/V1/NewPayloadV1Handler.cs | 196 ++++++----------- .../IEngineRpcModule.cs | 22 +- .../MergeErrorCodes.cs | 2 +- .../Nethermind.Merge.Plugin/MergePlugin.cs | 6 +- .../MergeProcessingRecoveryStep.cs | 9 +- .../Nethermind.Merge.Plugin/PoSSwitcher.cs | 49 +++-- .../Synchronization/BeaconPivot.cs | 12 +- .../Synchronization/BeaconSync.cs | 2 +- .../Synchronization/ChainLevelHelper.cs | 2 +- .../Synchronization/PeerRefresher.cs | 51 ++++- src/Nethermind/Nethermind.Runner/NLog.config | 16 +- .../Properties/launchSettings.json | 4 + .../configs/mainnet_shadowfork.cfg | 6 +- .../Nethermind.Runner/configs/sepolia.cfg | 8 + .../configs/sepolia_archive.cfg | 16 ++ .../Nethermind.State/StateReaderExtensions.cs | 10 + .../BlockDownloaderTests.Merge.cs | 6 +- .../SyncThreadTests.cs | 4 +- .../SynchronizerTests.cs | 4 +- .../Blocks/BlockDownloader.cs | 1 + .../ParallelSync/MultiSyncModeSelector.cs | 6 +- .../Peers/SyncPeerPool.cs | 9 + 68 files changed, 731 insertions(+), 639 deletions(-) create mode 100644 src/Nethermind/Nethermind.Merge.Plugin/BlockTreeExtensions.cs rename src/Nethermind/Nethermind.Merge.Plugin/Data/{BlockRequestResult.cs => V1/ExecutionPayloadV1.cs} (86%) create mode 100644 src/Nethermind/Nethermind.Runner/configs/sepolia_archive.cfg diff --git a/.github/workflows/run-merge-hive-tests.yml b/.github/workflows/run-merge-hive-tests.yml index dac52c9a452..d78f38b396d 100644 --- a/.github/workflows/run-merge-hive-tests.yml +++ b/.github/workflows/run-merge-hive-tests.yml @@ -1,8 +1,11 @@ name: '[RUN] Merge Hive Tests' + on: push: - branches: [ kiln ] + tags: + - '*' workflow_dispatch: + jobs: build-dockers: runs-on: ubuntu-latest diff --git a/src/Nethermind/Chains/mainnet_shadowfork.json b/src/Nethermind/Chains/mainnet_shadowfork.json index 43b93eea022..b141e57a3be 100644 --- a/src/Nethermind/Chains/mainnet_shadowfork.json +++ b/src/Nethermind/Chains/mainnet_shadowfork.json @@ -180,7 +180,7 @@ "eip3198Transition": "0xC5D488", "eip3529Transition": "0xC5D488", "eip3541Transition": "0xC5D488", - "MergeForkIdTransition": "0xeef7a3" + "MergeForkIdTransition": "0xef2e92" }, "genesis": { "seal": { @@ -3847,47 +3847,9 @@ ] }, "nodes": [ - "enode://3121479bdb80ad8addab60694083ee83706e47c05523cdda4cbdaf5683794d67b3dbcad848a085dd823d9fb60df3483b50459950d5d9ec23e3373e7bd58e5819@165.227.100.193:30303", - "enode://06899e1abf67b53dd0c6e10dafa238c7b71e361583353c928fed2aa7642d05e3d7755cb3f934bfdcf4fe563996720fb8c74de356d5dda0329b65d1d23a389c90@143.110.188.48:30303", - "enode://36ad5c6e0a10e58234cf9e17bd07107f1ed69659d27d3f0510bc9d8c109d6898d4bb7e20a64e69ee13fc8cc67e0a7291a09f6efd5a6ee26b26ad99d8f8458717@157.230.27.43:30303", - "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", - "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", - "enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303", - "enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303", - "enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303", - "enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303", - "enode://81863f47e9bd652585d3f78b4b2ee07b93dad603fd9bc3c293e1244250725998adc88da0cef48f1de89b15ab92b15db8f43dc2b6fb8fbd86a6f217a1dd886701@193.70.55.37:30303", - "enode://4afb3a9137a88267c02651052cf6fb217931b8c78ee058bb86643542a4e2e0a8d24d47d871654e1b78a276c363f3c1bc89254a973b00adc359c9e9a48f140686@144.217.139.5:30303", - "enode://c16d390b32e6eb1c312849fe12601412313165df1a705757d671296f1ac8783c5cff09eab0118ac1f981d7148c85072f0f26407e5c68598f3ad49209fade404d@139.99.51.203:30303", - "enode://4faf867a2e5e740f9b874e7c7355afee58a2d1ace79f7b692f1d553a1134eddbeb5f9210dd14dc1b774a46fd5f063a8bc1fa90579e13d9d18d1f59bac4a4b16b@139.99.160.213:30303", - "enode://6a868ced2dec399c53f730261173638a93a40214cf299ccf4d42a76e3fa54701db410669e8006347a4b3a74fa090bb35af0320e4bc8d04cf5b7f582b1db285f5@163.172.131.191:30303", - "enode://66a483383882a518fcc59db6c017f9cd13c71261f13c8d7e67ed43adbbc82a932d88d2291f59be577e9425181fc08828dc916fdd053af935a9491edf9d6006ba@212.47.247.103:30303", - "enode://cd6611461840543d5b9c56fbf088736154c699c43973b3a1a32390cf27106f87e58a818a606ccb05f3866de95a4fe860786fea71bf891ea95f234480d3022aa3@163.172.157.114:30303", - "enode://1d1f7bcb159d308eb2f3d5e32dc5f8786d714ec696bb2f7e3d982f9bcd04c938c139432f13aadcaf5128304a8005e8606aebf5eebd9ec192a1471c13b5e31d49@138.201.223.35:30303", - "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", - "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", - "enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303", - "enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303", - "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", - "enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303", - "enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30305", - "enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308", - "enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309", - "enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303", - "enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303", - "enode://01f76fa0561eca2b9a7e224378dd854278735f1449793c46ad0c4e79e8775d080c21dcc455be391e90a98153c3b05dcc8935c8440de7b56fe6d67251e33f4e3c@51.15.42.252:30303", - "enode://2c9059f05c352b29d559192fe6bca272d965c9f2290632a2cfda7f83da7d2634f3ec45ae3a72c54dd4204926fb8082dcf9686e0d7504257541c86fc8569bcf4b@163.172.171.38:30303", - "enode://efe4f2493f4aff2d641b1db8366b96ddacfe13e7a6e9c8f8f8cf49f9cdba0fdf3258d8c8f8d0c5db529f8123c8f1d95f36d54d590ca1bb366a5818b9a4ba521c@163.172.187.252:30303", - "enode://bcc7240543fe2cf86f5e9093d05753dd83343f8fda7bf0e833f65985c73afccf8f981301e13ef49c4804491eab043647374df1c4adf85766af88a624ecc3330e@136.243.154.244:30303", - "enode://ed4227681ca8c70beb2277b9e870353a9693f12e7c548c35df6bca6a956934d6f659999c2decb31f75ce217822eefca149ace914f1cbe461ed5a2ebaf9501455@88.212.206.70:30303", - "enode://cadc6e573b6bc2a9128f2f635ac0db3353e360b56deef239e9be7e7fce039502e0ec670b595f6288c0d2116812516ad6b6ff8d5728ff45eba176989e40dead1e@37.128.191.230:30303", - "enode://595a9a06f8b9bc9835c8723b6a82105aea5d55c66b029b6d44f229d6d135ac3ecdd3e9309360a961ea39d7bee7bac5d03564077a4e08823acc723370aace65ec@46.20.235.22:30303", - "enode://029178d6d6f9f8026fc0bc17d5d1401aac76ec9d86633bba2320b5eed7b312980c0a210b74b20c4f9a8b0b2bf884b111fa9ea5c5f916bb9bbc0e0c8640a0f56c@216.158.85.185:30303", - "enode://fdd1b9bb613cfbc200bba17ce199a9490edc752a833f88d4134bf52bb0d858aa5524cb3ec9366c7a4ef4637754b8b15b5dc913e4ed9fdb6022f7512d7b63f181@212.47.247.103:30303", - "enode://cc26c9671dffd3ee8388a7c8c5b601ae9fe75fc0a85cedb72d2dd733d5916fad1d4f0dcbebad5f9518b39cc1f96ba214ab36a7fa5103aaf17294af92a89f227b@52.79.241.155:30303", - "enode://140872ce4eee37177fbb7a3c3aa4aaebe3f30bdbf814dd112f6c364fc2e325ba2b6a942f7296677adcdf753c33170cb4999d2573b5ff7197b4c1868f25727e45@52.78.149.82:30303", - "enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", - "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303" + "enode://ca855d0f6058d39596226031dccca3177a3aff85bec21fcba07fef475494070b9e8625aa3304aca00e9d81604c5d514cece14a9f2e00acced648dc00a4ca0d85@161.35.156.235:30303", + "enode://3dce2b885ad1980507d1df9fe04ec3d499c8b91e845503a33396a6a5e01b24e0196edc8f16d57e2513783678e624206c399caf1d06c6df97f7dab22723db672d@161.35.157.54:30303", + "enode://b23ca7fbd0425b0a4cb4bb131c9bfb71fa7bedc4510a1afc893ccd3862512ecb11ea8f3b6e31884858656baf37c94baef5f8f5087bce3080324630a5a3362985@104.248.15.135:30303" ], "accounts": { "0x0000000000000000000000000000000000000001": { diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index 76a517dbaef..8e12dd956eb 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -169,6 +169,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? blockTree, blockProcessor, new RecoverSignatures(ecdsa, NullTxPool.Instance, specProvider, _logManager), + stateReader, _logManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs index 058507214f8..14da0341521 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs @@ -32,6 +32,8 @@ using Nethermind.Logging; using Nethermind.State.Repositories; using Nethermind.Db.Blooms; +using Nethermind.State; +using Nethermind.Trie.Pruning; using Nethermind.TxPool; using NUnit.Framework; @@ -193,12 +195,15 @@ public ProcessingTestContext(bool startProcessor) MemDb blockDb = new(); MemDb blockInfoDb = new(); MemDb headersDb = new(); + + MemDb stateDb = new(); Block genesis = Build.A.Block.Genesis.TestObject; + _blockTree = new BlockTree(blockDb, headersDb, blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance); _blockProcessor = new BlockProcessorMock(_logManager); _recoveryStep = new RecoveryStepMock(_logManager); - _processor = new BlockchainProcessor(_blockTree, _blockProcessor, _recoveryStep, LimboLogs.Instance, BlockchainProcessor.Options.Default); + _processor = new BlockchainProcessor(_blockTree, _blockProcessor, _recoveryStep, new StateReader(new TrieStore(stateDb, LimboLogs.Instance), new MemDb(), LimboLogs.Instance), LimboLogs.Instance, BlockchainProcessor.Options.Default); _resetEvent = new AutoResetEvent(false); _blockTree.NewHeadBlock += (sender, args) => diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs index fd0fe7ff787..0a56537095c 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs @@ -70,6 +70,7 @@ public void Test() trieStore, dbProvider.RegisteredDbs[DbNames.Code], LimboLogs.Instance); + StateReader stateReader = new(trieStore, dbProvider.GetDb(DbNames.State), LimboLogs.Instance); StorageProvider storageProvider = new(trieStore, stateProvider, LimboLogs.Instance); BlockhashProvider blockhashProvider = new(blockTree, LimboLogs.Instance); VirtualMachine virtualMachine = new( @@ -96,6 +97,7 @@ public void Test() blockTree, blockProcessor, NullRecoveryStep.Instance, + stateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); BuildBlocksWhenRequested trigger = new(); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs index cba14758bc9..7d05f0461a5 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs @@ -57,7 +57,8 @@ public void Setup() { IDbProvider memDbProvider = TestMemDbProvider.Init(); TrieStore trieStore = new (new MemDb(), LimboLogs.Instance); - StateProvider stateProvider = new (trieStore, memDbProvider.CodeDb, LimboLogs.Instance); + StateProvider stateProvider = new(trieStore, memDbProvider.CodeDb, LimboLogs.Instance); + StateReader stateReader = new(trieStore, memDbProvider.CodeDb, LimboLogs.Instance); StorageProvider storageProvider = new (trieStore, stateProvider, LimboLogs.Instance); ChainLevelInfoRepository chainLevelInfoRepository = new (memDbProvider); ISpecProvider specProvider = MainnetSpecProvider.Instance; @@ -109,6 +110,7 @@ public void Setup() txPool, specProvider, LimboLogs.Instance), + stateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs index 4daa02bce8b..c9a3f421505 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs @@ -118,7 +118,7 @@ public async Task Suggesting_blocks_works_correctly_after_processor_restart(int // simulating restarts - we stopped the old blockchain processor and create the new one BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, - testRpc.BlockPreprocessorStep, LimboLogs.Instance, BlockchainProcessor.Options.Default); + testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); newBlockchainProcessor.Start(); testRpc.BlockchainProcessor = newBlockchainProcessor; @@ -151,7 +151,7 @@ public async Task Fixer_should_not_suggest_block_without_state(int suggestedBloc // simulating restarts - we stopped the old blockchain processor and create the new one BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, - testRpc.BlockPreprocessorStep, LimboLogs.Instance, BlockchainProcessor.Options.Default); + testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); newBlockchainProcessor.Start(); testRpc.BlockchainProcessor = newBlockchainProcessor; @@ -174,7 +174,7 @@ public async Task Fixer_should_not_suggest_block_with_null_block() // simulating restarts - we stopped the old blockchain processor and create the new one BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, - testRpc.BlockPreprocessorStep, LimboLogs.Instance, BlockchainProcessor.Options.Default); + testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); newBlockchainProcessor.Start(); testRpc.BlockchainProcessor = newBlockchainProcessor; diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs index 3c9a95cb33c..79e645d3b61 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs @@ -719,9 +719,12 @@ private AddBlockResult Suggest(Block? block, BlockHeader header, if (_logger.IsTrace) _logger.Trace( $"Suggesting a new block. BestSuggestedBlock {BestSuggestedBody}, BestSuggestedBlock TD {BestSuggestedBody?.TotalDifficulty}, Block TD {block?.TotalDifficulty}, Head: {Head}, Head TD: {Head?.TotalDifficulty}, Block {block?.ToString(Block.Format.FullHashAndNumber)}. ShouldProcess: {shouldProcess}, TryProcessKnownBlock: {fillBeaconBlock}"); + + if (_logger.IsTrace && shouldProcess == true && fillBeaconBlock == false) + _logger.Trace($"StackTrace: {new System.Diagnostics.StackTrace()}"); #if DEBUG - /* this is just to make sure that we do not fall into this trap when creating tests */ - if (header.StateRoot is null && !header.IsGenesis) + /* this is just to make sure that we do not fall into this trap when creating tests */ + if (header.StateRoot is null && !header.IsGenesis) { throw new InvalidDataException($"State root is null in {header.ToString(BlockHeader.Format.Short)}"); } diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs index 2c1e5ba240b..c05008f2f0b 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs @@ -147,7 +147,7 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f NullWitnessCollector.Instance, nodeLogManager); - BlockchainProcessor processor = new(blockTree, blockProcessor, new AuthorRecoveryStep(snapshotManager), nodeLogManager, BlockchainProcessor.Options.NoReceipts); + BlockchainProcessor processor = new(blockTree, blockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); processor.Start(); IReadOnlyTrieStore minerTrieStore = trieStore.AsReadOnly(); @@ -168,7 +168,7 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f NullWitnessCollector.Instance, nodeLogManager); - BlockchainProcessor minerProcessor = new(blockTree, minerBlockProcessor, new AuthorRecoveryStep(snapshotManager), nodeLogManager, BlockchainProcessor.Options.NoReceipts); + BlockchainProcessor minerProcessor = new(blockTree, minerBlockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); if (withGenesisAlreadyProcessed) { diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs index 9c998a305e0..497c404ba5a 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs @@ -257,6 +257,7 @@ BlockProducerEnv Create() readOnlyBlockTree, blockProcessor, _api.BlockPreprocessor, + txProcessingEnv.StateReader, _api.LogManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs index 7d7b281fe4f..75c67c073cd 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs @@ -126,6 +126,7 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd readOnlyBlockTree, producerProcessor, getFromApi.BlockPreprocessor, + getFromApi.StateReader, getFromApi.LogManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs index b7474acc0fa..0c4f1087e10 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs @@ -99,6 +99,7 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd readOnlyBlockTree, producerProcessor, getFromApi.BlockPreprocessor, + getFromApi.StateReader, getFromApi.LogManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Consensus/IPoSSwitcher.cs b/src/Nethermind/Nethermind.Consensus/IPoSSwitcher.cs index 57e061daf70..759fbc52bfe 100644 --- a/src/Nethermind/Nethermind.Consensus/IPoSSwitcher.cs +++ b/src/Nethermind/Nethermind.Consensus/IPoSSwitcher.cs @@ -32,10 +32,15 @@ public interface IPoSSwitcher UInt256? TerminalTotalDifficulty { get; } - // Final total difficulty is total difficulty of the last PoW block. FinalTotalDifficulty >= TerminalTotalDifficulty. - // TerminalTotalDifficulty is trigger for transition process. However, the last PoW block will be bigger than TTD. - // Thanks to this variable, we can simplify many things in our code. For example, we can insert newPayload with FinalTotalDifficulty - // This value will be known after the merge transition, and we can configure it in the first release after the merge. + /// + /// Total difficulty is total difficulty of the last PoW block. + /// + /// + /// FinalTotalDifficulty >= TerminalTotalDifficulty. + /// TerminalTotalDifficulty is trigger for transition process. However, the last PoW block will be bigger than TTD. + /// Thanks to this variable, we can simplify many things in our code. For example, we can insert newPayload with FinalTotalDifficulty + /// This value will be known after the merge transition, and we can configure it in the first release after the merge. + /// UInt256? FinalTotalDifficulty { get; } bool TransitionFinished { get; } @@ -55,4 +60,11 @@ public interface IPoSSwitcher bool IsPostMerge(BlockHeader header); } + + public static class PoSSwitcherExtensions + { + public static bool MisconfiguredTerminalTotalDifficulty(this IPoSSwitcher poSSwitcher) => poSSwitcher.TerminalTotalDifficulty is null; + + public static bool BlockBeforeTerminalTotalDifficulty(this IPoSSwitcher poSSwitcher, BlockHeader blockHeader) => blockHeader.TotalDifficulty < poSSwitcher.TerminalTotalDifficulty; + } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs index b593eaf3412..f3044cdd77e 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs @@ -25,11 +25,14 @@ using Nethermind.Core; using Nethermind.Core.Attributes; using Nethermind.Core.Crypto; +using Nethermind.Db; using Nethermind.Evm.Tracing; using Nethermind.Evm.Tracing.GethStyle; using Nethermind.Evm.Tracing.ParityStyle; using Nethermind.Int256; using Nethermind.Logging; +using Nethermind.State; +using Metrics = Nethermind.Blockchain.Metrics; namespace Nethermind.Consensus.Processing { @@ -42,6 +45,7 @@ public class BlockchainProcessor : IBlockchainProcessor, IBlockProcessingQueue private readonly IBlockProcessor _blockProcessor; private readonly IBlockPreprocessorStep _recoveryStep; + private readonly IStateReader _stateReader; private readonly Options _options; private readonly IBlockTree _blockTree; private readonly ILogger _logger; @@ -68,12 +72,14 @@ public class BlockchainProcessor : IBlockchainProcessor, IBlockProcessingQueue /// /// /// + /// /// /// public BlockchainProcessor( IBlockTree? blockTree, IBlockProcessor? blockProcessor, IBlockPreprocessorStep? recoveryStep, + IStateReader stateReader, ILogManager? logManager, Options options) { @@ -81,6 +87,7 @@ public BlockchainProcessor( _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); _blockProcessor = blockProcessor ?? throw new ArgumentNullException(nameof(blockProcessor)); _recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep)); + _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); _options = options; _blockTree.NewBestSuggestedBlock += OnNewBestBlock; @@ -538,27 +545,32 @@ private ProcessingBranch PrepareProcessingBranch(Block suggestedBlock, Processin bool headIsGenesis = _blockTree.Head?.IsGenesis ?? false; bool toBeProcessedIsNotBlockOne = toBeProcessed.Number > 1; + if (_logger.IsTrace) + _logger.Trace($"Finding parent of {toBeProcessed.ToString(Block.Format.Short)}"); + toBeProcessed = _blockTree.FindParent(toBeProcessed.Header, BlockTreeLookupOptions.None); + if (_logger.IsTrace) _logger.Trace($"Found parent {toBeProcessed?.ToString(Block.Format.Short)}"); bool isFastSyncTransition = headIsGenesis && toBeProcessedIsNotBlockOne; - if (!isFastSyncTransition) + if (toBeProcessed == null) { - if (_logger.IsTrace) - _logger.Trace($"Finding parent of {toBeProcessed.ToString(Block.Format.Short)}"); - toBeProcessed = _blockTree.FindParent(toBeProcessed.Header, BlockTreeLookupOptions.None); - if (_logger.IsTrace) _logger.Trace($"Found parent {toBeProcessed?.ToString(Block.Format.Short)}"); + if (_logger.IsDebug) + _logger.Debug( + $"Treating this as fast sync transition for {suggestedBlock.ToString(Block.Format.Short)}"); + break; + } - if (toBeProcessed == null) + if (isFastSyncTransition) + { + // if we have parent state it means that we don't need to go deeper + if (toBeProcessed?.StateRoot == null || _stateReader.HasStateForBlock(toBeProcessed.Header)) { - if (_logger.IsDebug) - _logger.Debug( - $"Treating this as fast sync transition for {suggestedBlock.ToString(Block.Format.Short)}"); + if (_logger.IsInfo) _logger.Info($"Found state for parent: {toBeProcessed}, StateRoot: {toBeProcessed?.StateRoot}"); break; } + else + { + if (_logger.IsInfo) _logger.Info($"A new block {toBeProcessed} in fast sync transition branch - state not found"); + } } - else - { - break; - } - // TODO: there is no test for the second condition // generally if we finish fast sync at block, e.g. 8 and then have 6 blocks processed and close Neth diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs index f28021bc48c..38cb45a9005 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs @@ -76,7 +76,7 @@ public enum ProcessingOptions /// Trace = ForceProcessing | ReadOnlyChain | DoNotVerifyNonce | NoValidation, - EthereumMerge = MarkAsProcessed | DoNotUpdateHead + EthereumMerge = MarkAsProcessed | DoNotUpdateHead | IgnoreParentNotOnMainChain } public static class ProcessingOptionsExtensions diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs index 3851fffa8ed..0e1f9ec480b 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs @@ -66,7 +66,7 @@ public ReadOnlyChainProcessingEnv( NullWitnessCollector.Instance, logManager); - _blockProcessingQueue = new BlockchainProcessor(_txEnv.BlockTree, BlockProcessor, recoveryStep, logManager, BlockchainProcessor.Options.NoReceipts); + _blockProcessingQueue = new BlockchainProcessor(_txEnv.BlockTree, BlockProcessor, recoveryStep, _txEnv.StateReader, logManager, BlockchainProcessor.Options.NoReceipts); BlockProcessingQueue = _blockProcessingQueue; ChainProcessor = new OneTimeChainProcessor(dbProvider, _blockProcessingQueue); } diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs index 1d1e9af9895..f860ec01f24 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs @@ -100,6 +100,7 @@ public virtual BlockProducerEnv Create(ITxSource? additionalTxSource = null) readOnlyBlockTree, blockProcessor, _blockPreprocessorStep, + txProcessingEnv.StateReader, _logManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs index 039f6d26a54..43d600ff44a 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs @@ -47,11 +47,6 @@ public BlockValidator( _headerValidator = headerValidator ?? throw new ArgumentNullException(nameof(headerValidator)); } - public bool ValidateHash(BlockHeader header) - { - return _headerValidator.ValidateHash(header); - } - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle) { return _headerValidator.Validate(header, parent, isUncle); diff --git a/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs index 31e88b04227..78f27dc2669 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs @@ -52,16 +52,7 @@ public HeaderValidator( _daoBlockNumber = specProvider.DaoBlockNumber; } - public virtual bool ValidateHash(BlockHeader header) - { - bool hashAsExpected = header.Hash == header.CalculateHash(); - if (!hashAsExpected) - { - if (_logger.IsWarn) _logger.Warn($"Invalid block header ({header.Hash}) - invalid block hash"); - } - - return hashAsExpected; - } + public static bool ValidateHash(BlockHeader header) => header.Hash == header.CalculateHash(); /// /// Note that this does not validate seal which is the responsibility of > @@ -73,6 +64,11 @@ public virtual bool ValidateHash(BlockHeader header) public virtual bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle = false) { bool hashAsExpected = ValidateHash(header); + + if (!hashAsExpected) + { + if (_logger.IsWarn) _logger.Warn($"Invalid block header ({header.Hash}) - invalid block hash"); + } IReleaseSpec spec = _specProvider.GetSpec(header.Number); bool extraDataValid = ValidateExtraData(header, parent, spec, isUncle); diff --git a/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs index 53baf96a9e9..074193f7161 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs @@ -20,7 +20,6 @@ namespace Nethermind.Consensus.Validators { public interface IHeaderValidator { - bool ValidateHash(BlockHeader header); bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle = false); bool Validate(BlockHeader header, bool isUncle = false); } diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index 372f95c1842..069c892e991 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -179,7 +179,7 @@ protected virtual async Task Build(ISpecProvider? specProvider = SealEngine = new SealEngine(sealer, Always.Valid); BlockProcessor = CreateBlockProcessor(); - BlockchainProcessor chainProcessor = new(BlockTree, BlockProcessor, BlockPreprocessorStep, LogManager, Consensus.Processing.BlockchainProcessor.Options.Default); + BlockchainProcessor chainProcessor = new(BlockTree, BlockProcessor, BlockPreprocessorStep, StateReader, LogManager, Consensus.Processing.BlockchainProcessor.Options.Default); BlockchainProcessor = chainProcessor; BlockProcessingQueue = chainProcessor; chainProcessor.Start(); diff --git a/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs index ba44eee4e70..b7ed3aefe0e 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs @@ -15,6 +15,7 @@ // along with the Nethermind. If not, see . // +using System; using System.Collections.Generic; using System.Linq; diff --git a/src/Nethermind/Nethermind.Crypto/BlockHeaderExtensions.cs b/src/Nethermind/Nethermind.Crypto/BlockHeaderExtensions.cs index 222384818d9..6b3d093b9c1 100644 --- a/src/Nethermind/Nethermind.Crypto/BlockHeaderExtensions.cs +++ b/src/Nethermind/Nethermind.Crypto/BlockHeaderExtensions.cs @@ -32,9 +32,10 @@ public static Keccak CalculateHash(this BlockHeader header, RlpBehaviors behavio return stream.GetHash(); } - public static Keccak CalculateHash(this Block block, RlpBehaviors behaviors = RlpBehaviors.None) - { - return CalculateHash(block.Header, behaviors); - } + public static Keccak CalculateHash(this Block block, RlpBehaviors behaviors = RlpBehaviors.None) => CalculateHash(block.Header, behaviors); + + public static Keccak GetOrCalculateHash(this BlockHeader header) => header.Hash ?? header.CalculateHash(); + + public static Keccak GetOrCalculateHash(this Block block) => block.Hash ?? block.CalculateHash(); } } diff --git a/src/Nethermind/Nethermind.Hive/HivePlugin.cs b/src/Nethermind/Nethermind.Hive/HivePlugin.cs index f37894e3291..7f7019ba86d 100644 --- a/src/Nethermind/Nethermind.Hive/HivePlugin.cs +++ b/src/Nethermind/Nethermind.Hive/HivePlugin.cs @@ -48,9 +48,13 @@ public Task Init(INethermindApi api) public Task InitNetworkProtocol() { - if (_api.SyncPeerPool == null) throw new ArgumentNullException(nameof(_api.SyncPeerPool)); + if (Enabled) + { + if (_api.SyncPeerPool == null) throw new ArgumentNullException(nameof(_api.SyncPeerPool)); + + _api.SyncPeerPool.PeerRefreshed += OnPeerRefreshed; + } - _api.SyncPeerPool.PeerRefreshed += OnPeerRefreshed; return Task.CompletedTask; } diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs index c5ee86ed9f8..b858acb5fae 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs @@ -256,6 +256,7 @@ private Task InitBlockchain() getApi.BlockTree, mainBlockProcessor, _api.BlockPreprocessor, + stateReader, getApi.LogManager, new BlockchainProcessor.Options { diff --git a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs index c05debef10a..eb6b29b0fdb 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs @@ -101,6 +101,7 @@ TransactionProcessor transactionProcessor NullTxPool.Instance, specProvider, LimboLogs.Instance), + stateReader, LimboLogs.Instance, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs index de60b04fb9d..c77ef1c8bd1 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs @@ -67,6 +67,7 @@ public void Setup() ITrieStore trieStore = new TrieStore(stateDb, LimboLogs.Instance).AsReadOnly(); StateProvider stateProvider = new(trieStore, codeDb, LimboLogs.Instance); StorageProvider storageProvider = new(trieStore, stateProvider, LimboLogs.Instance); + StateReader stateReader = new StateReader(trieStore, codeDb, LimboLogs.Instance); BlockhashProvider blockhashProvider = new(_blockTree, LimboLogs.Instance); VirtualMachine virtualMachine = new(blockhashProvider, specProvider, LimboLogs.Instance); @@ -84,7 +85,7 @@ public void Setup() LimboLogs.Instance); RecoverSignatures txRecovery = new(new EthereumEcdsa(ChainId.Mainnet, LimboLogs.Instance), NullTxPool.Instance, specProvider, LimboLogs.Instance); - _processor = new BlockchainProcessor(_blockTree, blockProcessor, txRecovery, LimboLogs.Instance, BlockchainProcessor.Options.NoReceipts); + _processor = new BlockchainProcessor(_blockTree, blockProcessor, txRecovery, stateReader, LimboLogs.Instance, BlockchainProcessor.Options.NoReceipts); Block genesis = Build.A.Block.Genesis.TestObject; _blockTree.SuggestBlock(genesis); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs index b5d8e3a6672..0f7c4cc7f0b 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs @@ -56,7 +56,7 @@ private void AssertExecutionStatusChanged(IEngineRpcModule rpc, Keccak headBlock Assert.AreEqual(safeBlockHash, result.SafeBlockHash); } - private (UInt256, UInt256) AddTransactions(MergeTestBlockchain chain, BlockRequestResult executePayloadRequest, + private (UInt256, UInt256) AddTransactions(MergeTestBlockchain chain, ExecutionPayloadV1 executePayloadRequest, PrivateKey from, Address to, uint count, int value, out BlockHeader parentHeader) { Transaction[] transactions = BuildTransactions(chain, executePayloadRequest.ParentHash, from, to, count, value, @@ -89,19 +89,19 @@ Transaction BuildTransaction(uint index, Account senderAccount) => .Select(i => BuildTransaction((uint)i, account)).ToArray(); } - private BlockRequestResult CreateParentBlockRequestOnHead(IBlockTree blockTree) + private ExecutionPayloadV1 CreateParentBlockRequestOnHead(IBlockTree blockTree) { Block? head = blockTree.Head; if (head == null) throw new NotSupportedException(); - return new BlockRequestResult() + return new ExecutionPayloadV1() { BlockNumber = head.Number, BlockHash = head.Hash!, StateRoot = head.StateRoot!, ReceiptsRoot = head.ReceiptsRoot!, GasLimit = head.GasLimit, Timestamp = (ulong)head.Timestamp }; } - private static BlockRequestResult CreateBlockRequest(BlockRequestResult parent, Address miner) + private static ExecutionPayloadV1 CreateBlockRequest(ExecutionPayloadV1 parent, Address miner) { - BlockRequestResult blockRequest = new() + ExecutionPayloadV1 blockRequest = new() { ParentHash = parent.BlockHash, FeeRecipient = miner, @@ -120,10 +120,10 @@ private static BlockRequestResult CreateBlockRequest(BlockRequestResult parent, return blockRequest; } - private static BlockRequestResult[] CreateBlockRequestBranch(BlockRequestResult parent, Address miner, int count) + private static ExecutionPayloadV1[] CreateBlockRequestBranch(ExecutionPayloadV1 parent, Address miner, int count) { - BlockRequestResult currentBlock = parent; - BlockRequestResult[] blockRequests = new BlockRequestResult[count]; + ExecutionPayloadV1 currentBlock = parent; + ExecutionPayloadV1[] blockRequests = new ExecutionPayloadV1[count]; for (int i = 0; i < count; i++) { currentBlock = CreateBlockRequest(currentBlock, miner); @@ -148,11 +148,11 @@ private static BlockRequestResult[] CreateBlockRequestBranch(BlockRequestResult } private static TestCaseData GetNewBlockRequestBadDataTestCase( - Expression> propertyAccess, T wrongValue) + Expression> propertyAccess, T wrongValue) { - Action setter = propertyAccess.GetSetter(); + Action setter = propertyAccess.GetSetter(); // ReSharper disable once ConvertToLocalFunction - Action wrongValueSetter = r => setter(r, wrongValue); + Action wrongValueSetter = r => setter(r, wrongValue); return new TestCaseData(wrongValueSetter) { TestName = @@ -160,7 +160,7 @@ private static TestCaseData GetNewBlockRequestBadDataTestCase( }; } - private static bool TryCalculateHash(BlockRequestResult request, out Keccak hash) + private static bool TryCalculateHash(ExecutionPayloadV1 request, out Keccak hash) { if (request.TryGetBlock(out Block? block) && block != null) { diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index eadc34110d7..19741df0ac4 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -61,7 +61,7 @@ private IEngineRpcModule CreateEngineModule(MergeTestBlockchain chain, ISyncConf { IPeerRefresher peerRefresher = Substitute.For(); - chain.BeaconPivot = new BeaconPivot(syncConfig ?? new SyncConfig(), chain.MergeConfig, new MemDb(), chain.BlockTree, peerRefresher, chain.LogManager); + chain.BeaconPivot = new BeaconPivot(syncConfig ?? new SyncConfig(), new MemDb(), chain.BlockTree, chain.LogManager); BlockCacheService blockCacheService = new(); chain.BeaconSync = new BeaconSync(chain.BeaconPivot, chain.BlockTree, syncConfig ?? new SyncConfig(), blockCacheService, chain.LogManager); return new EngineRpcModule( diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs index ad3649fe04c..6a0ada3c6bd 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Synchronization.cs @@ -54,7 +54,7 @@ public async Task forkChoiceUpdatedV1_unknown_block_initiates_syncing() .WithAuthor(Address.Zero) .WithPostMergeFlag(true) .TestObject; - await rpc.engine_newPayloadV1(new BlockRequestResult(block)); + await rpc.engine_newPayloadV1(new ExecutionPayloadV1(block)); // sync has not started yet chain.BeaconSync.IsBeaconSyncHeadersFinished().Should().BeTrue(); chain.BeaconSync.IsBeaconSyncFinished(block.Header).Should().BeTrue(); @@ -93,10 +93,10 @@ public async Task newPayloadV1_can_insert_blocks_from_cache_when_syncing() IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; - BlockRequestResult parentBlockRequest = new (Build.A.Block.WithNumber(2).TestObject); - BlockRequestResult[] requests = CreateBlockRequestBranch(parentBlockRequest, Address.Zero, 7); + ExecutionPayloadV1 parentBlockRequest = new (Build.A.Block.WithNumber(2).TestObject); + ExecutionPayloadV1[] requests = CreateBlockRequestBranch(parentBlockRequest, Address.Zero, 7); ResultWrapper payloadStatus; - foreach (BlockRequestResult r in requests) + foreach (ExecutionPayloadV1 r in requests) { payloadStatus = await rpc.engine_newPayloadV1(r); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Accepted).ToUpper()); @@ -136,7 +136,7 @@ public async Task Blocks_from_cache_inserted_when_fast_headers_sync_finish_befor using MergeTestBlockchain chain = await CreateBlockChain(); Keccak startingHead = chain.BlockTree.HeadHash; IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult[] requests = CreateBlockRequestBranch(new(chain.BlockTree.Head!), Address.Zero, 7); + ExecutionPayloadV1[] requests = CreateBlockRequestBranch(new(chain.BlockTree.Head!), Address.Zero, 7); ResultWrapper payloadStatus; for (int i = 4; i < requests.Length - 1; i++) @@ -183,7 +183,7 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_archive_sync() Keccak startingHead = chain.BlockTree.HeadHash; // create 7 block gap int gap = 7; - BlockRequestResult headBlockRequest = new(chain.BlockTree.Head!); + ExecutionPayloadV1 headBlockRequest = new(chain.BlockTree.Head!); Block[] missingBlocks = new Block[gap]; for (int i = 0; i < gap; i++) { @@ -192,7 +192,7 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_archive_sync() missingBlocks[i] = block!; } // setting up beacon pivot - BlockRequestResult pivotRequest = CreateBlockRequest(headBlockRequest, Address.Zero); + ExecutionPayloadV1 pivotRequest = CreateBlockRequest(headBlockRequest, Address.Zero); ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(pivotRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Accepted).ToUpper()); pivotRequest.TryGetBlock(out Block? pivotBlock); @@ -214,7 +214,7 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_archive_sync() forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // trigger insertion of blocks in cache into block tree by adding new block - BlockRequestResult bestBeaconBlockRequest = CreateBlockRequest(pivotRequest, Address.Zero); + ExecutionPayloadV1 bestBeaconBlockRequest = CreateBlockRequest(pivotRequest, Address.Zero); payloadStatus = await rpc.engine_newPayloadV1(bestBeaconBlockRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // simulate headers sync by inserting 3 headers from pivot backwards @@ -290,10 +290,10 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_fast_sync() IEngineRpcModule rpc = CreateEngineModule(chain, syncConfig); // create block gap from fast sync pivot int gap = 7; - BlockRequestResult[] requests = - CreateBlockRequestBranch(new BlockRequestResult(syncedBlockTree.Head!), Address.Zero, gap); + ExecutionPayloadV1[] requests = + CreateBlockRequestBranch(new ExecutionPayloadV1(syncedBlockTree.Head!), Address.Zero, gap); // setting up beacon pivot - BlockRequestResult pivotRequest = CreateBlockRequest(requests[^1], Address.Zero); + ExecutionPayloadV1 pivotRequest = CreateBlockRequest(requests[^1], Address.Zero); ResultWrapper payloadStatus = await rpc.engine_newPayloadV1(pivotRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Accepted).ToUpper()); pivotRequest.TryGetBlock(out Block? pivotBlock); @@ -316,7 +316,7 @@ public async Task Maintain_correct_pointers_for_beacon_sync_in_fast_sync() forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // trigger insertion of blocks in cache into block tree by adding new block - BlockRequestResult bestBeaconBlockRequest = CreateBlockRequest(pivotRequest, Address.Zero); + ExecutionPayloadV1 bestBeaconBlockRequest = CreateBlockRequest(pivotRequest, Address.Zero); payloadStatus = await rpc.engine_newPayloadV1(bestBeaconBlockRequest); payloadStatus.Data.Status.Should().Be(nameof(PayloadStatusV1.Syncing).ToUpper()); // fill in beacon headers until fast headers pivot diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs index 97af6e532e5..52aa22856a0 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs @@ -66,7 +66,7 @@ public async Task getPayload_correctlyEncodeTransactions() Build.A.Transaction.WithTo(TestItem.AddressD).WithType(TxType.EIP1559).WithMaxFeePerGas(20) .SignedAndResolved(TestItem.PrivateKeyA).TestObject }).TestObject; - payloadPreparationService.GetPayload(Arg.Any()).Returns(block); + payloadPreparationService.GetPayload(Arg.Any()).Returns(block); using MergeTestBlockchain chain = await CreateBlockChain(null, payloadPreparationService); IEngineRpcModule rpc = CreateEngineModule(chain); @@ -185,7 +185,7 @@ public async Task getPayload_should_serialize_unknown_payload_response_properly( string parameters = payloadId.ToHexString(true); string result = RpcTest.TestSerializedRequest(rpc, "engine_getPayloadV1", parameters); result.Should() - .Be("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32001,\"message\":\"unknown payload\"},\"id\":67}"); + .Be("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-38001,\"message\":\"unknown payload\"},\"id\":67}"); } [Test] @@ -199,10 +199,10 @@ public async Task Keccak random = Keccak.Zero; Address feeRecipient = TestItem.AddressD; - BlockRequestResult? blockRequestResult = await BuildAndGetPayloadResult(rpc, chain, startingHead, + ExecutionPayloadV1? blockRequestResult = await BuildAndGetPayloadResult(rpc, chain, startingHead, Keccak.Zero, startingHead, timestamp, random, feeRecipient); - BlockRequestResult expected = CreateParentBlockRequestOnHead(chain.BlockTree); + ExecutionPayloadV1 expected = CreateParentBlockRequestOnHead(chain.BlockTree); expected.GasLimit = 4000000L; expected.BlockHash = new Keccak("0x3ee80ba456bac700bfaf5b2827270406134e2392eb03ec50f6c23de28dd08811"); expected.LogsBloom = Bloom.Empty; @@ -235,9 +235,9 @@ public async Task getPayloadV1_should_return_error_if_there_was_no_corresponding .PayloadId!; byte[] requestedPayloadId = Bytes.FromHexString("0x45bd36a8143d860d"); - ResultWrapper response = await rpc.engine_getPayloadV1(requestedPayloadId); + ResultWrapper response = await rpc.engine_getPayloadV1(requestedPayloadId); - response.ErrorCode.Should().Be(MergeErrorCodes.UnavailablePayloadV1); + response.ErrorCode.Should().Be(MergeErrorCodes.UnknownPayload); } [Test] @@ -262,9 +262,9 @@ public async Task getPayloadV1_should_return_error_if_called_after_timeout() Thread.Sleep(timeout); - ResultWrapper response = await rpc.engine_getPayloadV1(Bytes.FromHexString(payloadId)); + ResultWrapper response = await rpc.engine_getPayloadV1(Bytes.FromHexString(payloadId)); - response.ErrorCode.Should().Be(MergeErrorCodes.UnavailablePayloadV1); + response.ErrorCode.Should().Be(MergeErrorCodes.UnknownPayload); } [Test] @@ -274,13 +274,13 @@ public async Task using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult blockRequestResult1 = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 blockRequestResult1 = await SendNewBlockV1(rpc, chain); PrivateKey from = TestItem.PrivateKeyA; Address to = TestItem.AddressB; Transaction[] txs = BuildTransactions(chain, blockRequestResult1.BlockHash, from, to, 3, 0, out _, out _); chain.AddTransactions(txs); - BlockRequestResult? blockRequestResult2 = await BuildAndSendNewBlockV1(rpc, chain, true); + ExecutionPayloadV1? blockRequestResult2 = await BuildAndSendNewBlockV1(rpc, chain, true); Keccak[] blockHashes = new[] { blockRequestResult1.BlockHash, TestItem.KeccakA, blockRequestResult2.BlockHash }; ExecutionPayloadBodyV1Result[] payloadBodies = rpc.engine_getPayloadBodiesV1(blockHashes).Result.Data; @@ -309,9 +309,9 @@ public async Task forkchoiceUpdatedV1_should_not_create_block_or_change_head_wit forkchoiceUpdatedV1Response.Data.PayloadStatus.Status.Should() .Be(PayloadStatus.Syncing); // ToDo wait for final PostMerge sync byte[] payloadId = Bytes.FromHexString("0x5d071947bfcc3e65"); - ResultWrapper getResponse = await rpc.engine_getPayloadV1(payloadId); + ResultWrapper getResponse = await rpc.engine_getPayloadV1(payloadId); - getResponse.ErrorCode.Should().Be(MergeErrorCodes.UnavailablePayloadV1); + getResponse.ErrorCode.Should().Be(MergeErrorCodes.UnknownPayload); Keccak actualHead = chain.BlockTree.HeadHash; actualHead.Should().NotBe(notExistingHash); actualHead.Should().Be(startingHead); @@ -324,7 +324,7 @@ public async Task executePayloadV1_accepts_previously_assembled_block_multiple_t IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; BlockHeader startingBestSuggestedHeader = chain.BlockTree.BestSuggestedHeader!; - BlockRequestResult getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); + ExecutionPayloadV1 getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); getPayloadResult.ParentHash.Should().Be(startingHead); @@ -347,7 +347,7 @@ public async Task executePayloadV1_accepts_previously_prepared_block_multiple_ti IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; BlockHeader startingBestSuggestedHeader = chain.BlockTree.BestSuggestedHeader!; - BlockRequestResult getPayloadResult = await PrepareAndGetPayloadResultV1(chain, rpc); + ExecutionPayloadV1 getPayloadResult = await PrepareAndGetPayloadResultV1(chain, rpc); getPayloadResult.ParentHash.Should().Be(startingHead); @@ -364,7 +364,7 @@ public async Task executePayloadV1_accepts_previously_prepared_block_multiple_ti } - private async Task PrepareAndGetPayloadResultV1(MergeTestBlockchain chain, + private async Task PrepareAndGetPayloadResultV1(MergeTestBlockchain chain, IEngineRpcModule rpc) { Keccak startingHead = chain.BlockTree.HeadHash; @@ -374,7 +374,7 @@ private async Task PrepareAndGetPayloadResultV1(MergeTestBlo return await PrepareAndGetPayloadResultV1(rpc, startingHead, timestamp, random, feeRecipient); } - private async Task PrepareAndGetPayloadResultV1( + private async Task PrepareAndGetPayloadResultV1( IEngineRpcModule rpc, Keccak currentHead, UInt256 timestamp, Keccak random, Address feeRecipient) { PayloadAttributes? payloadAttributes = new() @@ -385,7 +385,7 @@ private async Task PrepareAndGetPayloadResultV1( ResultWrapper? forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, payloadAttributes); byte[] payloadId = Bytes.FromHexString(forkchoiceUpdatedResult.Data.PayloadId); - ResultWrapper getPayloadResult = await rpc.engine_getPayloadV1(payloadId); + ResultWrapper getPayloadResult = await rpc.engine_getPayloadV1(payloadId); return getPayloadResult.Data!; } @@ -412,7 +412,7 @@ public async Task executePayloadV1_unknown_parentHash_return_accepted() { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); + ExecutionPayloadV1 getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); Keccak blockHash = getPayloadResult.BlockHash; getPayloadResult.ParentHash = TestItem.KeccakF; if (blockHash == getPayloadResult.BlockHash && TryCalculateHash(getPayloadResult, out Keccak? hash)) @@ -426,11 +426,11 @@ public async Task executePayloadV1_unknown_parentHash_return_accepted() } [TestCaseSource(nameof(WrongInputTestsV1))] - public async Task executePayloadV1_rejects_incorrect_input(Action breakerAction) + public async Task executePayloadV1_rejects_incorrect_input(Action breakerAction) { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); + ExecutionPayloadV1 getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); breakerAction(getPayloadResult); if (TryCalculateHash(getPayloadResult, out Keccak? hash)) { @@ -447,7 +447,7 @@ public async Task executePayloadV1_rejects_invalid_blockHash() { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); + ExecutionPayloadV1 getPayloadResult = await BuildAndGetPayloadResult(chain, rpc); getPayloadResult.BlockHash = TestItem.KeccakC; ResultWrapper @@ -467,7 +467,7 @@ public async Task executePayloadV1_accepts_already_known_block() block.Header.IsPostMerge = true; block.Header.Hash = block.CalculateHash(); await chain.BlockTree.SuggestBlockAsync(block!); - BlockRequestResult blockRequest = new(block); + ExecutionPayloadV1 blockRequest = new(block); ResultWrapper executePayloadResult = await rpc.engine_newPayloadV1(blockRequest); executePayloadResult.Data.Status.Should().Be(PayloadStatus.Valid); @@ -479,9 +479,9 @@ public async Task forkchoiceUpdatedV1_should_work_with_zero_keccak_for_finalizat using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); - Keccak newHeadHash = blockRequestResult.BlockHash; + Keccak newHeadHash = executionPayload.BlockHash; ForkchoiceStateV1 forkchoiceStateV1 = new(newHeadHash!, Keccak.Zero, startingHead); ResultWrapper forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, null); @@ -501,9 +501,9 @@ public async Task forkchoiceUpdatedV1_should_update_finalized_block_hash() TestRpcBlockchain testRpc = await CreateTestRpc(chain); IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); - Keccak newHeadHash = blockRequestResult.BlockHash; + Keccak newHeadHash = executionPayload.BlockHash; ForkchoiceStateV1 forkchoiceStateV1 = new(newHeadHash!, startingHead, startingHead!); ResultWrapper forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, null); @@ -531,9 +531,9 @@ public async Task forkchoiceUpdatedV1_should_update_safe_block_hash() TestRpcBlockchain testRpc = await CreateTestRpc(chain); IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); - Keccak newHeadHash = blockRequestResult.BlockHash; + Keccak newHeadHash = executionPayload.BlockHash; ForkchoiceStateV1 forkchoiceStateV1 = new(newHeadHash!, startingHead, startingHead!); ResultWrapper forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, null); @@ -560,9 +560,9 @@ public async Task forkchoiceUpdatedV1_should_work_with_zero_keccak_as_safe_block using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); - Keccak newHeadHash = blockRequestResult.BlockHash; + Keccak newHeadHash = executionPayload.BlockHash; ForkchoiceStateV1 forkchoiceStateV1 = new(newHeadHash!, newHeadHash!, Keccak.Zero); ResultWrapper forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, null); @@ -581,9 +581,9 @@ public async Task forkchoiceUpdatedV1_with_no_payload_attributes_should_change_h using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); - Keccak newHeadHash = blockRequestResult.BlockHash; + Keccak newHeadHash = executionPayload.BlockHash; ForkchoiceStateV1 forkchoiceStateV1 = new(newHeadHash!, startingHead, startingHead!); ResultWrapper forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, null); @@ -616,9 +616,9 @@ public async Task forkChoiceUpdatedV1_to_unknown_safeBlock_hash_should_fail() using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); Keccak startingHead = chain.BlockTree.HeadHash; - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); - Keccak newHeadHash = blockRequestResult.BlockHash; + Keccak newHeadHash = executionPayload.BlockHash; ForkchoiceStateV1 forkchoiceStateV1 = new(newHeadHash!, startingHead, TestItem.KeccakF); ResultWrapper forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, null); @@ -638,7 +638,7 @@ public async Task forkChoiceUpdatedV1_no_common_branch_failsk() Block parent = Build.A.Block.WithNumber(2).WithParentHash(TestItem.KeccakA).WithNonce(0).WithDifficulty(0).TestObject; Block block = Build.A.Block.WithNumber(3).WithParent(parent).WithNonce(0).WithDifficulty(0).TestObject; - await rpc.engine_newPayloadV1(new BlockRequestResult(parent)); + await rpc.engine_newPayloadV1(new ExecutionPayloadV1(parent)); ForkchoiceStateV1 forkchoiceStateV1 = new(parent.Hash!, startingHead, startingHead); ResultWrapper forkchoiceUpdatedResult = @@ -646,7 +646,7 @@ public async Task forkChoiceUpdatedV1_no_common_branch_failsk() forkchoiceUpdatedResult.Data.PayloadStatus.Status.Should() .Be("SYNCING"); - await rpc.engine_newPayloadV1(new BlockRequestResult(block)); + await rpc.engine_newPayloadV1(new ExecutionPayloadV1(block)); ForkchoiceStateV1 forkchoiceStateV1_1 = new(parent.Hash!, startingHead, startingHead); ResultWrapper forkchoiceUpdatedResult_1 = @@ -663,9 +663,9 @@ public async Task forkchoiceUpdatedV1_should_change_head_when_all_parameters_are { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); - Keccak newHeadHash = blockRequestResult.BlockHash; + Keccak newHeadHash = executionPayload.BlockHash; ForkchoiceStateV1 forkchoiceStateV1 = new(newHeadHash, newHeadHash, newHeadHash); ResultWrapper forkchoiceUpdatedResult = await rpc.engine_forkchoiceUpdatedV1(forkchoiceStateV1, null); @@ -686,10 +686,10 @@ public async Task Can_transition_from_PoW_chain() // creating PoS block Block? head = chain.BlockTree.Head; - BlockRequestResult blockRequestResult = await SendNewBlockV1(rpc, chain); + ExecutionPayloadV1 executionPayload = await SendNewBlockV1(rpc, chain); await rpc.engine_forkchoiceUpdatedV1( - new ForkchoiceStateV1(blockRequestResult.BlockHash, blockRequestResult.BlockHash, - blockRequestResult.BlockHash), null); + new ForkchoiceStateV1(executionPayload.BlockHash, executionPayload.BlockHash, + executionPayload.BlockHash), null); Assert.AreEqual(2, chain.BlockTree.Head!.Number); } @@ -703,10 +703,10 @@ public async Task executePayloadV1_should_not_accept_blocks_with_incorrect_ttd(l Enabled = true, TerminalTotalDifficulty = $"{terminalTotalDifficulty}" }); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult blockRequestResult = CreateBlockRequest( + ExecutionPayloadV1 executionPayload = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); - ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(blockRequestResult); + ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Invalid); resultWrapper.Data.LatestValidHash.Should().Be(Keccak.Zero); } @@ -733,13 +733,13 @@ public async Task executePayloadV1_accepts_first_block() { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult blockRequestResult = CreateBlockRequest( + ExecutionPayloadV1 executionPayload = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); - ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(blockRequestResult); + ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Valid); - new BlockRequestResult(chain.BlockTree.BestSuggestedBody).Should() - .BeEquivalentTo(blockRequestResult); + new ExecutionPayloadV1(chain.BlockTree.BestSuggestedBody).Should() + .BeEquivalentTo(executionPayload); } [Test] @@ -747,17 +747,17 @@ public async Task executePayloadV1_calculate_hash_for_cached_blocks() { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult blockRequestResult = CreateBlockRequest( + ExecutionPayloadV1 executionPayload = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); - ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(blockRequestResult); + ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Valid); ResultWrapper - resultWrapper2 = await rpc.engine_newPayloadV1(blockRequestResult); + resultWrapper2 = await rpc.engine_newPayloadV1(executionPayload); resultWrapper2.Data.Status.Should().Be(PayloadStatus.Valid); - blockRequestResult.ParentHash = blockRequestResult.BlockHash; + executionPayload.ParentHash = executionPayload.BlockHash; ResultWrapper invalidBlockRequest = - await rpc.engine_newPayloadV1(blockRequestResult); + await rpc.engine_newPayloadV1(executionPayload); invalidBlockRequest.Data.Status.Should().Be(PayloadStatus.InvalidBlockHash); } @@ -782,7 +782,7 @@ public async Task forkchoiceUpdatedV1_can_reorganize_to_last_block() using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - async Task CanReorganizeToBlock(BlockRequestResult block, MergeTestBlockchain testChain) + async Task CanReorganizeToBlock(ExecutionPayloadV1 block, MergeTestBlockchain testChain) { ForkchoiceStateV1 forkchoiceStateV1 = new(block.BlockHash, block.BlockHash, block.BlockHash); @@ -796,17 +796,17 @@ async Task CanReorganizeToBlock(BlockRequestResult block, MergeTestBlockchain te } async Task CanReorganizeToLastBlock(MergeTestBlockchain testChain, - params IReadOnlyList[] branches) + params IReadOnlyList[] branches) { - foreach (IReadOnlyList? branch in branches) + foreach (IReadOnlyList? branch in branches) { await CanReorganizeToBlock(branch.Last(), testChain); } } - IReadOnlyList branch1 = + IReadOnlyList branch1 = await ProduceBranchV1(rpc, chain, 10, CreateParentBlockRequestOnHead(chain.BlockTree), true); - IReadOnlyList branch2 = + IReadOnlyList branch2 = await ProduceBranchV1(rpc, chain, 6, branch1[3], true, TestItem.KeccakC); await CanReorganizeToLastBlock(chain, branch1, branch2); @@ -818,7 +818,7 @@ public async Task forkchoiceUpdatedV1_head_block_after_reorg() using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - async Task CanReorganizeToBlock(BlockRequestResult block, MergeTestBlockchain testChain) + async Task CanReorganizeToBlock(ExecutionPayloadV1 block, MergeTestBlockchain testChain) { ForkchoiceStateV1 forkchoiceStateV1 = new(block.BlockHash, block.BlockHash, block.BlockHash); @@ -831,9 +831,9 @@ async Task CanReorganizeToBlock(BlockRequestResult block, MergeTestBlockchain te testChain.State.StateRoot.Should().Be(testChain.BlockTree.Head!.StateRoot!); } - IReadOnlyList branch1 = + IReadOnlyList branch1 = await ProduceBranchV1(rpc, chain, 10, CreateParentBlockRequestOnHead(chain.BlockTree), true); - IReadOnlyList branch2 = + IReadOnlyList branch2 = await ProduceBranchV1(rpc, chain, 6, branch1[3], true, TestItem.KeccakC); await CanReorganizeToBlock(branch2.Last(), chain); @@ -844,19 +844,19 @@ public async Task newPayloadV1_should_return_accepted_for_side_branch() { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - BlockRequestResult blockRequestResult = CreateBlockRequest( + ExecutionPayloadV1 executionPayload = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); - ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(blockRequestResult); + ResultWrapper resultWrapper = await rpc.engine_newPayloadV1(executionPayload); resultWrapper.Data.Status.Should().Be(PayloadStatus.Valid); - ForkchoiceStateV1 forkChoiceUpdatedRequest = new(blockRequestResult.BlockHash, - blockRequestResult.BlockHash, blockRequestResult.BlockHash); + ForkchoiceStateV1 forkChoiceUpdatedRequest = new(executionPayload.BlockHash, + executionPayload.BlockHash, executionPayload.BlockHash); ResultWrapper fcu1 = (await rpc.engine_forkchoiceUpdatedV1(forkChoiceUpdatedRequest, new PayloadAttributes() { PrevRandao = TestItem.KeccakA, SuggestedFeeRecipient = Address.Zero, - Timestamp = blockRequestResult.Timestamp + 1 + Timestamp = executionPayload.Timestamp + 1 })); await rpc.engine_getPayloadV1(Bytes.FromHexString(fcu1.Data.PayloadId!)); } @@ -867,14 +867,14 @@ public async Task executePayloadV1_processes_passed_transactions(bool moveHead) { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - IReadOnlyList branch = + IReadOnlyList branch = await ProduceBranchV1(rpc, chain, 8, CreateParentBlockRequestOnHead(chain.BlockTree), moveHead); - foreach (BlockRequestResult block in branch) + foreach (ExecutionPayloadV1 block in branch) { uint count = 10; - BlockRequestResult executePayloadRequest = CreateBlockRequest(block, TestItem.AddressA); + ExecutionPayloadV1 executePayloadRequest = CreateBlockRequest(block, TestItem.AddressA); PrivateKey from = TestItem.PrivateKeyB; Address to = TestItem.AddressD; (_, UInt256 toBalanceAfter) = AddTransactions(chain, executePayloadRequest, from, to, count, 1, @@ -910,13 +910,13 @@ public async Task executePayloadV1_transactions_produce_receipts() { using MergeTestBlockchain chain = await CreateBlockChain(); IEngineRpcModule rpc = CreateEngineModule(chain); - IReadOnlyList branch = + IReadOnlyList branch = await ProduceBranchV1(rpc, chain, 1, CreateParentBlockRequestOnHead(chain.BlockTree), false); - foreach (BlockRequestResult block in branch) + foreach (ExecutionPayloadV1 block in branch) { uint count = 10; - BlockRequestResult executionPayload = CreateBlockRequest(block, TestItem.AddressA); + ExecutionPayloadV1 executionPayload = CreateBlockRequest(block, TestItem.AddressA); PrivateKey from = TestItem.PrivateKeyB; Address to = TestItem.AddressD; (_, UInt256 toBalanceAfter) = @@ -971,7 +971,7 @@ public async Task getPayloadV1_picks_transactions_from_pool_v1() Timestamp = 100, PrevRandao = TestItem.KeccakA, SuggestedFeeRecipient = Address.Zero }).Result.Data.PayloadId!; await blockImprovementLock.WaitAsync(10000); - BlockRequestResult getPayloadResult = + ExecutionPayloadV1 getPayloadResult = (await rpc.engine_getPayloadV1(Bytes.FromHexString(payloadId!))).Data!; getPayloadResult.StateRoot.Should().NotBe(chain.BlockTree.Genesis!.StateRoot!); @@ -1005,7 +1005,7 @@ public async Task getPayloadV1_return_correct_block_values_for_empty_block() { PrevRandao = random, Timestamp = timestamp, SuggestedFeeRecipient = suggestedFeeRecipient }; - BlockRequestResult getPayloadResult = await BuildAndGetPayloadResult(chain, rpc, payloadAttributes); + ExecutionPayloadV1 getPayloadResult = await BuildAndGetPayloadResult(chain, rpc, payloadAttributes); getPayloadResult.ParentHash.Should().Be(startingHead); @@ -1023,12 +1023,12 @@ public async Task getPayloadV1_return_correct_block_values_for_empty_block() } - private async Task> ProduceBranchV1(IEngineRpcModule rpc, + private async Task> ProduceBranchV1(IEngineRpcModule rpc, MergeTestBlockchain chain, - int count, BlockRequestResult startingParentBlock, bool setHead, Keccak? random = null) + int count, ExecutionPayloadV1 startingParentBlock, bool setHead, Keccak? random = null) { - List blocks = new(); - BlockRequestResult parentBlock = startingParentBlock; + List blocks = new(); + ExecutionPayloadV1 parentBlock = startingParentBlock; parentBlock.TryGetBlock(out Block? block); UInt256? startingTotalDifficulty = block!.IsGenesis ? block.Difficulty : chain.BlockFinder.FindHeader(block!.Header!.ParentHash!)!.TotalDifficulty; @@ -1037,7 +1037,7 @@ private async Task> ProduceBranchV1(IEngineRpc parentHeader.Difficulty; for (int i = 0; i < count; i++) { - BlockRequestResult? getPayloadResult = await BuildAndGetPayloadOnBranch(rpc, chain, parentHeader, + ExecutionPayloadV1? getPayloadResult = await BuildAndGetPayloadOnBranch(rpc, chain, parentHeader, parentBlock.Timestamp + 12, random ?? TestItem.KeccakA, Address.Zero); PayloadStatusV1 payloadStatusResponse = @@ -1076,10 +1076,10 @@ public async Task blockRequestResult_set_and_get_transactions_roundtrip() Transaction[] txsSource = BuildTransactions(chain, startingHead, sender, recipient, count, value, out _, out _); - BlockRequestResult blockRequestResult = new(); - blockRequestResult.SetTransactions(txsSource); + ExecutionPayloadV1 executionPayload = new(); + executionPayload.SetTransactions(txsSource); - Transaction[] txsReceived = blockRequestResult.GetTransactions(); + Transaction[] txsReceived = executionPayload.GetTransactions(); txsReceived.Should().BeEquivalentTo(txsSource, options => options .Excluding(t => t.ChainId) @@ -1165,32 +1165,32 @@ public async Task exchangeTransitionConfiguration_return_with_empty_Nethermind_c Assert.AreEqual("0x0000000000000000000000000000000000000000000000000000000000000000", result.TerminalBlockHash.ToString()); } - private async Task SendNewBlockV1(IEngineRpcModule rpc, MergeTestBlockchain chain) + private async Task SendNewBlockV1(IEngineRpcModule rpc, MergeTestBlockchain chain) { - BlockRequestResult blockRequestResult = CreateBlockRequest( + ExecutionPayloadV1 executionPayload = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressD); ResultWrapper executePayloadResult = - await rpc.engine_newPayloadV1(blockRequestResult); + await rpc.engine_newPayloadV1(executionPayload); executePayloadResult.Data.Status.Should().Be(PayloadStatus.Valid); - return blockRequestResult; + return executionPayload; } - private async Task BuildAndSendNewBlockV1(IEngineRpcModule rpc, MergeTestBlockchain chain, bool waitForBlockImprovement) + private async Task BuildAndSendNewBlockV1(IEngineRpcModule rpc, MergeTestBlockchain chain, bool waitForBlockImprovement) { Keccak head = chain.BlockTree.HeadHash; UInt256 timestamp = Timestamper.UnixTime.Seconds; Keccak random = Keccak.Zero; Address feeRecipient = Address.Zero; - BlockRequestResult blockRequestResult = await BuildAndGetPayloadResult(rpc, chain, head, + ExecutionPayloadV1 executionPayload = await BuildAndGetPayloadResult(rpc, chain, head, Keccak.Zero, head, timestamp, random, feeRecipient, waitForBlockImprovement); ResultWrapper executePayloadResult = - await rpc.engine_newPayloadV1(blockRequestResult); + await rpc.engine_newPayloadV1(executionPayload); executePayloadResult.Data.Status.Should().Be(PayloadStatus.Valid); - return blockRequestResult; + return executionPayload; } - private async Task BuildAndGetPayloadOnBranch( + private async Task BuildAndGetPayloadOnBranch( IEngineRpcModule rpc, MergeTestBlockchain chain, BlockHeader parentHeader, UInt256 timestamp, Keccak random, Address feeRecipient) { @@ -1200,7 +1200,7 @@ private async Task BuildAndGetPayloadOnBranch( // we're using payloadService directly, because we can't use fcU for branch string payloadId = chain.PayloadPreparationService!.StartPreparingPayload(parentHeader, payloadAttributes)!; - ResultWrapper getPayloadResult = + ResultWrapper getPayloadResult = await rpc.engine_getPayloadV1(Bytes.FromHexString(payloadId)); return getPayloadResult.Data!; } @@ -1214,7 +1214,7 @@ public async Task repeat_the_same_payload_after_fcu_should_return_valid_and_be_i IEngineRpcModule rpc = CreateEngineModule(chain); // Correct new payload - BlockRequestResult blockRequestResult1 = CreateBlockRequest( + ExecutionPayloadV1 blockRequestResult1 = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); ResultWrapper newPayloadResult1 = await rpc.engine_newPayloadV1(blockRequestResult1); @@ -1241,7 +1241,7 @@ public async Task payloadV1_invalid_parent_hash() IEngineRpcModule rpc = CreateEngineModule(chain); // Correct new payload - BlockRequestResult blockRequestResult1 = CreateBlockRequest( + ExecutionPayloadV1 blockRequestResult1 = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); ResultWrapper newPayloadResult1 = await rpc.engine_newPayloadV1(blockRequestResult1); @@ -1254,7 +1254,7 @@ public async Task payloadV1_invalid_parent_hash() forkchoiceUpdatedResult1.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); // New payload unknown parent hash - BlockRequestResult blockRequestResult2A = CreateBlockRequest(blockRequestResult1, TestItem.AddressA); + ExecutionPayloadV1 blockRequestResult2A = CreateBlockRequest(blockRequestResult1, TestItem.AddressA); blockRequestResult2A.ParentHash = TestItem.KeccakB; TryCalculateHash(blockRequestResult2A, out Keccak? hash); blockRequestResult2A.BlockHash = hash; @@ -1269,7 +1269,7 @@ public async Task payloadV1_invalid_parent_hash() forkchoiceUpdatedResult2A.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Syncing); // New payload with correct parent hash - BlockRequestResult blockRequestResult2B = CreateBlockRequest(blockRequestResult1, TestItem.AddressA); + ExecutionPayloadV1 blockRequestResult2B = CreateBlockRequest(blockRequestResult1, TestItem.AddressA); ResultWrapper newPayloadResult2B = await rpc.engine_newPayloadV1(blockRequestResult2B); newPayloadResult2B.Data.Status.Should().Be(PayloadStatus.Valid); @@ -1280,7 +1280,7 @@ public async Task payloadV1_invalid_parent_hash() forkchoiceUpdatedResult2B.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Valid); // New payload unknown parent hash - BlockRequestResult blockRequestResult3A = CreateBlockRequest(blockRequestResult2A, TestItem.AddressA); + ExecutionPayloadV1 blockRequestResult3A = CreateBlockRequest(blockRequestResult2A, TestItem.AddressA); ResultWrapper newPayloadResult3A = await rpc.engine_newPayloadV1(blockRequestResult3A); newPayloadResult3A.Data.Status.Should().Be(PayloadStatus.Accepted); @@ -1291,7 +1291,7 @@ public async Task payloadV1_invalid_parent_hash() ResultWrapper forkchoiceUpdatedResult3A = await rpc.engine_forkchoiceUpdatedV1(forkChoiceState3A); forkchoiceUpdatedResult3A.Data.PayloadStatus.Status.Should().Be(PayloadStatus.Syncing); - BlockRequestResult blockRequestResult3B = CreateBlockRequest(blockRequestResult2B, TestItem.AddressA); + ExecutionPayloadV1 blockRequestResult3B = CreateBlockRequest(blockRequestResult2B, TestItem.AddressA); ResultWrapper newPayloadResult3B = await rpc.engine_newPayloadV1(blockRequestResult3B); newPayloadResult3B.Data.Status.Should().Be(PayloadStatus.Valid); @@ -1328,7 +1328,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceStateGen, } // Add one block - BlockRequestResult blockRequestResult1 = CreateBlockRequest( + ExecutionPayloadV1 blockRequestResult1 = CreateBlockRequest( CreateParentBlockRequestOnHead(chain.BlockTree), TestItem.AddressA); blockRequestResult1.PrevRandao = prevRandao1; @@ -1353,7 +1353,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1, { - BlockRequestResult blockRequestResult2 = CreateBlockRequest( + ExecutionPayloadV1 blockRequestResult2 = CreateBlockRequest( blockRequestResult1, TestItem.AddressA); @@ -1377,7 +1377,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1, // re-org { - BlockRequestResult blockRequestResult3 = CreateBlockRequest( + ExecutionPayloadV1 blockRequestResult3 = CreateBlockRequest( blockRequestResult1, TestItem.AddressA); @@ -1402,7 +1402,7 @@ await rpc.engine_forkchoiceUpdatedV1(forkChoiceState1, } } - private async Task BuildAndGetPayloadResult( + private async Task BuildAndGetPayloadResult( IEngineRpcModule rpc, MergeTestBlockchain chain, Keccak headBlockHash, Keccak finalizedBlockHash, Keccak safeBlockHash, UInt256 timestamp, Keccak random, Address feeRecipient, bool waitForBlockImprovement = true) @@ -1422,12 +1422,12 @@ private async Task BuildAndGetPayloadResult( string payloadId = rpc.engine_forkchoiceUpdatedV1(forkchoiceState, payloadAttributes).Result.Data.PayloadId; if (waitForBlockImprovement) await blockImprovementLock.WaitAsync(10000); - ResultWrapper getPayloadResult = + ResultWrapper getPayloadResult = await rpc.engine_getPayloadV1(Bytes.FromHexString(payloadId)); return getPayloadResult.Data!; } - private async Task BuildAndGetPayloadResult(MergeTestBlockchain chain, + private async Task BuildAndGetPayloadResult(MergeTestBlockchain chain, IEngineRpcModule rpc, PayloadAttributes payloadAttributes) { Keccak startingHead = chain.BlockTree.HeadHash; @@ -1437,7 +1437,7 @@ private async Task BuildAndGetPayloadResult(MergeTestBlockch payloadAttributes.Timestamp, payloadAttributes.PrevRandao!, payloadAttributes.SuggestedFeeRecipient); } - private async Task BuildAndGetPayloadResult(MergeTestBlockchain chain, + private async Task BuildAndGetPayloadResult(MergeTestBlockchain chain, IEngineRpcModule rpc) { Keccak startingHead = chain.BlockTree.HeadHash; diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs index b73ef8db82d..36ec918112d 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs @@ -100,7 +100,7 @@ public Context( _syncConfig, LimboLogs.Instance); TotalDifficultyBasedBetterPeerStrategy bestPeerStrategy = new (syncProgressResolver, LimboLogs.Instance); - BeaconPivot = beaconPivot ?? new BeaconPivot(_syncConfig, _mergeConfig, _metadataDb, BlockTree, new PeerRefresher(peerPool), LimboLogs.Instance); + BeaconPivot = beaconPivot ?? new BeaconPivot(_syncConfig, _metadataDb, BlockTree, LimboLogs.Instance); BeaconSync = new(BeaconPivot, BlockTree, _syncConfig, new BlockCacheService(), LimboLogs.Instance); ISyncModeSelector selector = new MultiSyncModeSelector(syncProgressResolver, peerPool, _syncConfig, BeaconSync, bestPeerStrategy, LimboLogs.Instance); Feed = new BeaconHeadersSyncFeed(poSSwitcher, selector, blockTree, peerPool, _syncConfig, report, BeaconPivot, _mergeConfig, LimboLogs.Instance); @@ -255,7 +255,7 @@ private void BuildHeadersSyncBatchResponse(HeadersSyncBatch batch, IBlockTree bl private IBeaconPivot PreparePivot(long blockNumber, ISyncConfig syncConfig, IBlockTree blockTree, BlockHeader? pivotHeader = null) { IPeerRefresher peerRefresher = Substitute.For(); - IBeaconPivot pivot = new BeaconPivot(syncConfig, new MergeConfig() { Enabled = true }, new MemDb(), blockTree, peerRefresher, LimboLogs.Instance); + IBeaconPivot pivot = new BeaconPivot(syncConfig, new MemDb(), blockTree, LimboLogs.Instance); pivot.EnsurePivot(pivotHeader ?? Build.A.BlockHeader.WithNumber(blockNumber).TestObject); return pivot; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconPivotTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconPivotTests.cs index 722563efff9..bf8a7749b15 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconPivotTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconPivotTests.cs @@ -49,7 +49,7 @@ public void Setup() public void Beacon_pivot_defaults_to_sync_config_values_when_there_is_no_pivot() { IPeerRefresher peerRefresher = Substitute.For(); - IBeaconPivot pivot = new BeaconPivot(_syncConfig, new MergeConfig() { Enabled = true }, new MemDb(), Substitute.For(), peerRefresher, LimboLogs.Instance); + IBeaconPivot pivot = new BeaconPivot(_syncConfig, new MemDb(), Substitute.For(), LimboLogs.Instance); pivot.PivotHash.Should().Be(_syncConfig.PivotHashParsed); pivot.PivotNumber.Should().Be(_syncConfig.PivotNumberParsed); pivot.PivotDestinationNumber.Should().Be(0); diff --git a/src/Nethermind/Nethermind.Merge.Plugin/BlockTreeExtensions.cs b/src/Nethermind/Nethermind.Merge.Plugin/BlockTreeExtensions.cs new file mode 100644 index 00000000000..de2cb5840ad --- /dev/null +++ b/src/Nethermind/Nethermind.Merge.Plugin/BlockTreeExtensions.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2021 Demerzel Solutions Limited +// This file is part of the Nethermind library. +// +// The Nethermind library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The Nethermind library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the Nethermind. If not, see . +// + +using Nethermind.Blockchain; +using Nethermind.Core; + +namespace Nethermind.Merge.Plugin; + +public static class BlockTreeExtensions +{ + public static bool IsOnMainChainBehindOrEqualHead(this IBlockTree blockTree, Block block) => + block.Number <= (blockTree.Head?.Number ?? 0) && blockTree.IsMainChain(block.Header); + + public static bool IsOnMainChainBehindHead(this IBlockTree blockTree, Block block) => + block.Number < (blockTree.Head?.Number ?? 0) && blockTree.IsMainChain(block.Header); +} diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/BlockRequestResult.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ExecutionPayloadV1.cs similarity index 86% rename from src/Nethermind/Nethermind.Merge.Plugin/Data/BlockRequestResult.cs rename to src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ExecutionPayloadV1.cs index 41c8d901c35..bd42e7affdc 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/BlockRequestResult.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ExecutionPayloadV1.cs @@ -16,9 +16,6 @@ // using System; -using System.Collections.Generic; -using System.Linq; -using Nethermind.Blockchain; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -26,18 +23,20 @@ using Nethermind.State.Proofs; using Newtonsoft.Json; -namespace Nethermind.Merge.Plugin.Data +namespace Nethermind.Merge.Plugin.Data.V1 { /// /// A data object representing a block as being sent from the execution layer to the consensus layer. + /// + /// /// - public class BlockRequestResult + public class ExecutionPayloadV1 { - public BlockRequestResult() + public ExecutionPayloadV1() { } - public BlockRequestResult(Block block) + public ExecutionPayloadV1(Block block) { BlockHash = block.Hash!; ParentHash = block.ParentHash!; @@ -55,7 +54,7 @@ public BlockRequestResult(Block block) BaseFeePerGas = block.BaseFeePerGas; } - public bool TryGetBlock(out Block? block) + public bool TryGetBlock(out Block? block, UInt256? totalDifficulty = null) { try { @@ -74,6 +73,7 @@ public bool TryGetBlock(out Block? block) Transaction[] transactions = GetTransactions(); header.TxRoot = new TxTrie(transactions).RootHash; header.IsPostMerge = true; + header.TotalDifficulty = totalDifficulty; block = new Block(header, transactions, Array.Empty()); return true; } @@ -102,7 +102,11 @@ public bool TryGetBlock(out Block? block) public UInt256 BaseFeePerGas { get; set; } [JsonProperty(NullValueHandling = NullValueHandling.Include)] - public Keccak BlockHash { get; set; } = null!; + public Keccak? BlockHash { get; set; } = null!; + + /// + /// Array of transaction objects, each object is a byte list (DATA) representing TransactionType || TransactionPayload or LegacyTransaction as defined in EIP-2718 + /// public byte[][] Transactions { get; set; } = Array.Empty(); public override string ToString() => BlockHash == null ? $"{BlockNumber} null" : $"{BlockNumber} ({BlockHash})"; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceStateV1.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceStateV1.cs index e7508862c62..7a09ba5c928 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceStateV1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceStateV1.cs @@ -19,6 +19,11 @@ namespace Nethermind.Merge.Plugin.Data.V1 { + /// + /// Arguments to engine_ForkChoiceUpdate + /// + /// + /// public class ForkchoiceStateV1 { public ForkchoiceStateV1(Keccak headBlockHash, Keccak finalizedBlockHash, Keccak safeBlockHash) @@ -27,9 +32,22 @@ public ForkchoiceStateV1(Keccak headBlockHash, Keccak finalizedBlockHash, Keccak FinalizedBlockHash = finalizedBlockHash; SafeBlockHash = safeBlockHash; } + + /// + /// Hash of the head of the canonical chain. + /// public Keccak HeadBlockHash { get; set; } + /// + /// Safe block hash of the canonical chain under certain synchrony and honesty assumptions. This value MUST be either equal to or an ancestor of headBlockHash. + /// + /// Can be when transition block is not finalized yet. public Keccak SafeBlockHash { get; set; } + + /// + /// Hash of the most recent finalized block + /// + /// Can be when transition block is not finalized yet. public Keccak FinalizedBlockHash { get; set; } public override string ToString() diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceUpdatedV1Result.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceUpdatedV1Result.cs index b23017c6399..0a96ec0f390 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceUpdatedV1Result.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/ForkchoiceUpdatedV1Result.cs @@ -21,46 +21,34 @@ namespace Nethermind.Merge.Plugin.Data.V1 { + /// + /// Result of engine_forkChoiceUpdate call. + /// + /// + /// public class ForkchoiceUpdatedV1Result { - private static readonly ForkchoiceUpdatedV1Result _syncing = new() - { - PayloadId = null, PayloadStatus = PayloadStatusV1.Syncing - }; + public static readonly ResultWrapper Syncing = ResultWrapper.Success(new ForkchoiceUpdatedV1Result { PayloadId = null, PayloadStatus = PayloadStatusV1.Syncing }); - public static readonly ResultWrapper Syncing = - ResultWrapper.Success(_syncing); + public static ResultWrapper Valid(string? payloadId, Keccak? latestValidHash) => + ResultWrapper.Success(new ForkchoiceUpdatedV1Result { PayloadId = payloadId, PayloadStatus = new PayloadStatusV1() { Status = Data.V1.PayloadStatus.Valid, LatestValidHash = latestValidHash } }); - public static ResultWrapper Valid(string? payloadId, Keccak? latestValidHash) - { - return ResultWrapper.Success(new ForkchoiceUpdatedV1Result() + public static ResultWrapper Invalid(Keccak? latestValidHash, string? validationError = null) => + ResultWrapper.Success(new ForkchoiceUpdatedV1Result { - PayloadId = payloadId, - PayloadStatus = new PayloadStatusV1() - { - Status = Data.V1.PayloadStatus.Valid, LatestValidHash = latestValidHash - } + PayloadStatus = new PayloadStatusV1 { Status = Data.V1.PayloadStatus.Invalid, LatestValidHash = latestValidHash, ValidationError = validationError } }); - } - - public static ResultWrapper Invalid(Keccak? latestValidHash, string? validationError = null) - { - return ResultWrapper.Success(new ForkchoiceUpdatedV1Result() - { - PayloadStatus = new PayloadStatusV1() - { - Status = Data.V1.PayloadStatus.Invalid, LatestValidHash = latestValidHash, ValidationError = validationError - } - }); - } - - public static ResultWrapper Error(string message, int errorCode) - { - return ResultWrapper.Fail(message, errorCode); - } - public PayloadStatusV1 PayloadStatus { get; set; } + public static ResultWrapper Error(string message, int errorCode) => ResultWrapper.Fail(message, errorCode); + + /// + /// Status + /// + public PayloadStatusV1 PayloadStatus { get; set; } = PayloadStatusV1.Syncing; + /// + /// Identifier of the payload build process or null if there is none. + /// [JsonProperty(NullValueHandling = NullValueHandling.Include)] public string? PayloadId { get; set; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/NewPayloadV1Result.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/NewPayloadV1Result.cs index f8694ae9030..879b2e0916d 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/NewPayloadV1Result.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/NewPayloadV1Result.cs @@ -20,6 +20,9 @@ namespace Nethermind.Merge.Plugin.Data.V1; +/// +/// Wraps in for JSON RPC. +/// public static class NewPayloadV1Result { public static ResultWrapper Syncing = ResultWrapper.Success(PayloadStatusV1.Syncing); diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/PayloadStatusV1.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/PayloadStatusV1.cs index 0e945638be9..e3517e305f1 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/PayloadStatusV1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/PayloadStatusV1.cs @@ -20,19 +20,33 @@ namespace Nethermind.Merge.Plugin.Data.V1 { + /// + /// Result of engine_newPayloadV1 call. + /// + /// + /// public class PayloadStatusV1 { - public static PayloadStatusV1 InvalidBlockHash = new() { Status = PayloadStatus.InvalidBlockHash }; + public static readonly PayloadStatusV1 InvalidBlockHash = new() { Status = PayloadStatus.InvalidBlockHash }; - public static PayloadStatusV1 Syncing = new() { Status = PayloadStatus.Syncing }; + public static readonly PayloadStatusV1 Syncing = new() { Status = PayloadStatus.Syncing }; - public static PayloadStatusV1 Accepted = new() { Status = PayloadStatus.Accepted }; + public static readonly PayloadStatusV1 Accepted = new() { Status = PayloadStatus.Accepted }; + /// + /// One of . + /// public string Status { get; set; } + /// + /// Hash of the most recent valid block in the branch defined by payload and its ancestors. + /// [JsonProperty(NullValueHandling = NullValueHandling.Include)] public Keccak? LatestValidHash { get; set; } - + + /// + /// Message providing additional details on the validation error if the payload is classified as or . + /// [JsonProperty(NullValueHandling = NullValueHandling.Include)] public string? ValidationError { get; set; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/Statuses.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/Statuses.cs index 2afda0868a5..3c1a21c1c74 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/Statuses.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/Statuses.cs @@ -19,16 +19,29 @@ namespace Nethermind.Merge.Plugin.Data.V1 { public static class PayloadStatus { + /// + /// Payload is valid. + /// public const string Valid = "VALID"; + /// + /// Payload is invalid. + /// public const string Invalid = "INVALID"; + /// + /// Payload started a sync. + /// public const string Syncing = "SYNCING"; + /// + /// Payload was accepted but not executed yet. It can be executed in call. + /// public const string Accepted = "ACCEPTED"; + /// + /// Payload has invalid block hash. + /// public const string InvalidBlockHash = "INVALID_BLOCK_HASH"; - - public const string InvalidTerminalBlock = "INVALID_TERMINAL_BLOCK"; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/TransitionConfigurationV1.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/TransitionConfigurationV1.cs index 0564d4f7864..9f3e3e9887a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/TransitionConfigurationV1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/V1/TransitionConfigurationV1.cs @@ -20,11 +20,25 @@ namespace Nethermind.Merge.Plugin.Data.V1; +/// +/// Result of call. +/// +/// +/// public class TransitionConfigurationV1 { + /// + /// Maps on the TERMINAL_TOTAL_DIFFICULTY parameter of EIP-3675 + /// public UInt256? TerminalTotalDifficulty { get; set; } + /// + /// Maps on TERMINAL_BLOCK_HASH parameter of EIP-3675 + /// public Keccak TerminalBlockHash { get; set; } = Keccak.Zero; + /// + /// Maps on TERMINAL_BLOCK_NUMBER parameter of EIP-3675 + /// public long TerminalBlockNumber { get; set; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.cs b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.cs index 3b8dadd972b..cfdc4d1b494 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/EngineRpcModule.cs @@ -30,19 +30,19 @@ namespace Nethermind.Merge.Plugin { public class EngineRpcModule : IEngineRpcModule { - private readonly IAsyncHandler _getPayloadHandlerV1; - private readonly IAsyncHandler _newPayloadV1Handler; + private readonly IAsyncHandler _getPayloadHandlerV1; + private readonly IAsyncHandler _newPayloadV1Handler; private readonly IForkchoiceUpdatedV1Handler _forkchoiceUpdatedV1Handler; private readonly IHandler _executionStatusHandler; private readonly IAsyncHandler _executionPayloadBodiesHandler; private readonly IHandler _transitionConfigurationHandler; private readonly SemaphoreSlim _locker = new(1, 1); - private readonly TimeSpan Timeout = TimeSpan.FromSeconds(8); + private readonly TimeSpan _timeout = TimeSpan.FromSeconds(8); private readonly ILogger _logger; public EngineRpcModule( - IAsyncHandler getPayloadHandlerV1, - IAsyncHandler newPayloadV1Handler, + IAsyncHandler getPayloadHandlerV1, + IAsyncHandler newPayloadV1Handler, IForkchoiceUpdatedV1Handler forkchoiceUpdatedV1Handler, IHandler executionStatusHandler, IAsyncHandler executionPayloadBodiesHandler, @@ -63,16 +63,14 @@ public ResultWrapper engine_executionStatus() return _executionStatusHandler.Handle(); } - public async Task> engine_getPayloadV1(byte[] payloadId) + public async Task> engine_getPayloadV1(byte[] payloadId) { return await (_getPayloadHandlerV1.HandleAsync(payloadId)); } - - public async Task> engine_newPayloadV1( - BlockRequestResult executionPayload) + public async Task> engine_newPayloadV1(ExecutionPayloadV1 executionPayload) { - if (await _locker.WaitAsync(Timeout)) + if (await _locker.WaitAsync(_timeout)) { try { @@ -86,16 +84,14 @@ public async Task> engine_newPayloadV1( else { if (_logger.IsWarn) _logger.Warn($"{nameof(engine_newPayloadV1)} timeout."); - return ResultWrapper.Fail($"{nameof(engine_newPayloadV1)} timeout.", - ErrorCodes.Timeout); + return ResultWrapper.Fail($"{nameof(engine_newPayloadV1)} timeout.", ErrorCodes.Timeout); } } - public async Task> engine_forkchoiceUpdatedV1( - ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes = null) + public async Task> engine_forkchoiceUpdatedV1(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes = null) { - if (await _locker.WaitAsync(Timeout)) + if (await _locker.WaitAsync(_timeout)) { try { @@ -109,8 +105,7 @@ public async Task> engine_forkchoiceUpd else { if (_logger.IsWarn) _logger.Warn($"{nameof(engine_forkchoiceUpdatedV1)} timeout."); - return ResultWrapper.Fail($"{nameof(engine_forkchoiceUpdatedV1)} timeout.", - ErrorCodes.Timeout); + return ResultWrapper.Fail($"{nameof(engine_forkchoiceUpdatedV1)} timeout.", ErrorCodes.Timeout); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IPayloadPreparationService.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IPayloadPreparationService.cs index 8cf3001ae4d..dd445969086 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IPayloadPreparationService.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IPayloadPreparationService.cs @@ -26,7 +26,7 @@ public interface IPayloadPreparationService { string? StartPreparingPayload(BlockHeader parentHeader, PayloadAttributes payloadAttributes); - Block? GetPayload(byte[] payloadId); + Block? GetPayload(string payloadId); event EventHandler? BlockImproved; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/PayloadPreparationService.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/PayloadPreparationService.cs index f62812a7410..a09583bf43f 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/PayloadPreparationService.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/PayloadPreparationService.cs @@ -28,14 +28,15 @@ using Nethermind.Core.Timers; using Nethermind.Logging; using Nethermind.Merge.Plugin.Data; +using Nethermind.Merge.Plugin.Handlers.V1; namespace Nethermind.Merge.Plugin.Handlers { /// - /// A cache of pending payloads. A payload is created whenever a consensus client requests a payload creation. - /// Each payload is assigned a payload ID which can be used by the consensus client to retrieve payload later - /// by calling a GetPayload method. - /// https://hackmd.io/@n0ble/kiln-spec + /// A cache of pending payloads. A payload is created whenever a consensus client requests a payload creation in . + /// + /// Each payload is assigned a payloadId which can be used by the consensus client to retrieve payload later by calling a . + /// /// public class PayloadPreparationService : IPayloadPreparationService { @@ -52,7 +53,7 @@ public class PayloadPreparationService : IPayloadPreparationService // first BlockRequestResult is empty (without txs), second one is the ideal one private readonly ConcurrentDictionary _payloadStorage = new(); - private TaskQueue _taskQueue = new(); + private readonly TaskQueue _taskQueue = new(); public PayloadPreparationService( PostMergeBlockProducer blockProducer, @@ -68,7 +69,7 @@ public PayloadPreparationService( _sealer = sealer; _timeout = TimeSpan.FromSeconds(mergeConfig.SecondsPerSlot); - _cleanupOldPayloadDelay = 2 * mergeConfig.SecondsPerSlot * 1000; // 2 * slots time * 1000 (converting seconds to miliseconds) + _cleanupOldPayloadDelay = 2 * mergeConfig.SecondsPerSlot * 1000; // 2 * slots time * 1000 (converting seconds to milliseconds) ITimer timer = timerFactory.CreateTimer(slotsPerOldPayloadCleanup * _timeout); timer.Elapsed += CleanupOldPayloads; timer.AutoReset = false; @@ -77,9 +78,9 @@ public PayloadPreparationService( _logger = logManager.GetClassLogger(); } - public string? StartPreparingPayload(BlockHeader parentHeader, PayloadAttributes payloadAttributes) + public string StartPreparingPayload(BlockHeader parentHeader, PayloadAttributes payloadAttributes) { - string payloadId = ComputeNextPayloadId(parentHeader, payloadAttributes).ToHexString(true); + string payloadId = ComputeNextPayloadId(parentHeader, payloadAttributes); if (!_payloadStorage.ContainsKey(payloadId)) { payloadAttributes.SuggestedFeeRecipient = _sealer.Address != Address.Zero @@ -89,8 +90,7 @@ public PayloadPreparationService( Task blockImprovementTask = ImproveBlock(payloadId, parentHeader, payloadAttributes, emptyBlock); _taskQueue.Enqueue(() => blockImprovementTask); } - else - if (_logger.IsInfo) _logger.Info($"Payload with the same parameters has already started. PayloadId: {payloadId}"); + else if (_logger.IsInfo) _logger.Info($"Payload with the same parameters has already started. PayloadId: {payloadId}"); return payloadId; } @@ -104,8 +104,7 @@ private Block ProduceEmptyBlock(string payloadId, BlockHeader parentHeader, Payl return emptyBlock; } - private Task ImproveBlock(string payloadId, BlockHeader parentHeader, PayloadAttributes payloadAttributes, - Block emptyBlock) + private Task ImproveBlock(string payloadId, BlockHeader parentHeader, PayloadAttributes payloadAttributes, Block emptyBlock) { if (_logger.IsTrace) _logger.Trace($"Start improving block from payload {payloadId} with parent {parentHeader}"); @@ -176,14 +175,14 @@ private void CleanupOldPayloads(object? sender, EventArgs e) return t.Result; } - public Block? GetPayload(byte[] payloadId) + public Block? GetPayload(string payloadId) { - var payloadStr = payloadId.ToHexString(true); - if (_payloadStorage.ContainsKey(payloadStr)) + if (_payloadStorage.TryRemove(payloadId, out BlockImprovementContext? blockContext)) { - _payloadStorage.TryRemove(payloadStr, out BlockImprovementContext? blockContext); - blockContext?.Cancel(); - return blockContext?.CurrentBestBlock; + // TODO: We can wait here a bit ~500ms for the block production to complete. + // Client software MAY stop the corresponding build process after serving this call. + blockContext.Cancel(); + return blockContext.CurrentBestBlock; } return null; @@ -191,16 +190,15 @@ private void CleanupOldPayloads(object? sender, EventArgs e) public event EventHandler? BlockImproved; - private byte[] ComputeNextPayloadId(BlockHeader parentHeader, PayloadAttributes payloadAttributes) + private string ComputeNextPayloadId(BlockHeader parentHeader, PayloadAttributes payloadAttributes) { - byte[] input = new byte[32 + 32 + 32 + 20]; - Span inputSpan = input.AsSpan(); + Span inputSpan = stackalloc byte[32 + 32 + 32 + 20]; parentHeader.Hash!.Bytes.CopyTo(inputSpan.Slice(0, 32)); payloadAttributes.Timestamp.ToBigEndian(inputSpan.Slice(32, 32)); payloadAttributes.PrevRandao.Bytes.CopyTo(inputSpan.Slice(64, 32)); payloadAttributes.SuggestedFeeRecipient.Bytes.CopyTo(inputSpan.Slice(96, 20)); - Keccak inputHash = Keccak.Compute(input); - return inputHash.Bytes.Slice(0, 8); + ValueKeccak inputHash = ValueKeccak.Compute(inputSpan); + return inputHash.BytesAsSpan.Slice(0, 8).ToHexString(true); } class TaskQueue diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/ForkchoiceUpdatedV1Handler.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/ForkchoiceUpdatedV1Handler.cs index d373f71a8e0..e8017abb3ce 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/ForkchoiceUpdatedV1Handler.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/ForkchoiceUpdatedV1Handler.cs @@ -36,8 +36,8 @@ namespace Nethermind.Merge.Plugin.Handlers.V1 { /// - /// https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md - /// Propagates the change in the fork choice to the execution client + /// Propagates the change in the fork choice to the execution client. May initiate creating new payload. + /// . /// public class ForkchoiceUpdatedV1Handler : IForkchoiceUpdatedV1Handler { @@ -64,11 +64,9 @@ public ForkchoiceUpdatedV1Handler( ILogManager logManager) { _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); - _manualBlockFinalizationManager = manualBlockFinalizationManager ?? - throw new ArgumentNullException(nameof(manualBlockFinalizationManager)); + _manualBlockFinalizationManager = manualBlockFinalizationManager ?? throw new ArgumentNullException(nameof(manualBlockFinalizationManager)); _poSSwitcher = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher)); - _blockConfirmationManager = blockConfirmationManager ?? - throw new ArgumentNullException(nameof(blockConfirmationManager)); + _blockConfirmationManager = blockConfirmationManager ?? throw new ArgumentNullException(nameof(blockConfirmationManager)); _payloadPreparationService = payloadPreparationService; _blockCacheService = blockCacheService; _mergeSyncController = mergeSyncController; @@ -76,111 +74,87 @@ public ForkchoiceUpdatedV1Handler( _logger = logManager.GetClassLogger(); } - public async Task> Handle(ForkchoiceStateV1 forkchoiceState, - PayloadAttributes? payloadAttributes) + public async Task> Handle(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes) { string requestStr = $"{forkchoiceState} {payloadAttributes}"; - if (_logger.IsInfo) { _logger.Info($"Received: {requestStr}"); } + if (_logger.IsInfo) _logger.Info($"Received: {requestStr}."); - Block? newHeadBlock = EnsureHeadBlockHash(forkchoiceState.HeadBlockHash); - if (newHeadBlock == null) + Block? newHeadBlock = GetBlock(forkchoiceState.HeadBlockHash); + if (newHeadBlock is null) // if a head is unknown we are syncing { if (_blockCacheService.BlockCache.TryGetValue(forkchoiceState.HeadBlockHash, out Block? block)) { _mergeSyncController.InitSyncing(block.Header); + _peerRefresher.RefreshPeers(block.ParentHash); _blockCacheService.SyncingHead = forkchoiceState.HeadBlockHash; _blockCacheService.FinalizedHash = forkchoiceState.FinalizedBlockHash; - if (_logger.IsInfo) { _logger.Info($"Start a new sync process... Request: {requestStr}"); } + if (_logger.IsInfo) _logger.Info($"Start a new sync process... Request: {requestStr}."); return ForkchoiceUpdatedV1Result.Syncing; } if (_logger.IsInfo) { - _logger.Info($"Syncing... Unknown forkchoiceState head hash... Request: {requestStr}"); + _logger.Info($"Syncing... Unknown forkchoiceState head hash... Request: {requestStr}."); } return ForkchoiceUpdatedV1Result.Syncing; } - if (!_blockTree.WasProcessed(newHeadBlock.Number, newHeadBlock.Hash ?? newHeadBlock.CalculateHash())) + if (!_blockTree.WasProcessed(newHeadBlock.Number, newHeadBlock.GetOrCalculateHash())) { - // ToDO of course we shouldn't refresh the peers in this way. This need to be optimized and we need to rethink refreshing - if (i % 10 == 0) - _peerRefresher.RefreshPeers(newHeadBlock.Hash!); - ++i; + _peerRefresher.RefreshPeers(newHeadBlock.ParentHash); _blockCacheService.SyncingHead = forkchoiceState.HeadBlockHash; _blockCacheService.FinalizedHash = forkchoiceState.FinalizedBlockHash; - if (_logger.IsInfo) { _logger.Info($"Syncing beacon headers... Request: {requestStr}"); } + if (_logger.IsInfo) { _logger.Info($"Syncing beacon headers... Request: {requestStr}."); } return ForkchoiceUpdatedV1Result.Syncing; } - if (_logger.IsInfo) _logger.Info($"FCU - block {newHeadBlock} was processed"); + if (_logger.IsInfo) _logger.Info($"FCU - block {newHeadBlock} was processed."); - (BlockHeader? finalizedHeader, string? finalizationErrorMsg) = - ValidateBlockHash(forkchoiceState.FinalizedBlockHash); - if (finalizationErrorMsg != null) + BlockHeader? finalizedHeader = ValidateBlockHash(forkchoiceState.FinalizedBlockHash, out string? finalizationErrorMsg); + if (finalizationErrorMsg is not null) { - if (_logger.IsWarn) - _logger.Warn($"Invalid finalized block hash {finalizationErrorMsg}. Request: {requestStr}"); - + if (_logger.IsWarn) _logger.Warn($"Invalid finalized block hash {finalizationErrorMsg}. Request: {requestStr}."); return ForkchoiceUpdatedV1Result.Error(finalizationErrorMsg, MergeErrorCodes.InvalidForkchoiceState); } - (BlockHeader? safeBlockHashHeader, string? safeBlockErrorMsg) = - ValidateBlockHash(forkchoiceState.SafeBlockHash); - if (safeBlockErrorMsg != null) + BlockHeader? safeBlockHashHeader = ValidateBlockHash(forkchoiceState.SafeBlockHash, out string? safeBlockErrorMsg); + if (safeBlockErrorMsg is not null) { - if (_logger.IsWarn) - _logger.Warn($"Invalid safe block hash {finalizationErrorMsg}. Request: {requestStr}"); - + if (_logger.IsWarn) _logger.Warn($"Invalid safe block hash {finalizationErrorMsg}. Request: {requestStr}."); return ForkchoiceUpdatedV1Result.Error(safeBlockErrorMsg, MergeErrorCodes.InvalidForkchoiceState); } - (Block[]? blocks, string? setHeadErrorMsg) = - EnsureNewHead(newHeadBlock); - if (setHeadErrorMsg != null) + Block[]? blocks = EnsureNewHead(newHeadBlock, out string? setHeadErrorMsg); + if (setHeadErrorMsg is not null) { - if (_logger.IsWarn) - _logger.Warn($"Invalid new head block {setHeadErrorMsg}. Request: {requestStr}"); - + if (_logger.IsWarn) _logger.Warn($"Invalid new head block {setHeadErrorMsg}. Request: {requestStr}."); return ForkchoiceUpdatedV1Result.Error(setHeadErrorMsg, ErrorCodes.InvalidParams); } - - if (_poSSwitcher.TerminalTotalDifficulty == null || - newHeadBlock!.Header.TotalDifficulty < _poSSwitcher.TerminalTotalDifficulty) + + if (_poSSwitcher.MisconfiguredTerminalTotalDifficulty() || _poSSwitcher.BlockBeforeTerminalTotalDifficulty(newHeadBlock.Header)) { - if (_logger.IsWarn) - _logger.Warn( - $"Invalid terminal block. Nethermind TTD {_poSSwitcher.TerminalTotalDifficulty}, NewHeadBlock TD: {newHeadBlock!.Header.TotalDifficulty}. Request: {requestStr}"); + if (_logger.IsWarn) _logger.Warn($"Invalid terminal block. Nethermind TTD {_poSSwitcher.TerminalTotalDifficulty}, NewHeadBlock TD: {newHeadBlock!.Header.TotalDifficulty}. Request: {requestStr}."); // https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#specification // {status: INVALID, latestValidHash: 0x0000000000000000000000000000000000000000000000000000000000000000, validationError: errorMessage | null} if terminal block conditions are not satisfied return ForkchoiceUpdatedV1Result.Invalid(Keccak.Zero); } - - if (_blockTree.IsMainChain(forkchoiceState.HeadBlockHash) && - newHeadBlock.Number < (_blockTree.Head?.Number ?? 0)) + if (_blockTree.IsOnMainChainBehindHead(newHeadBlock)) { - if (_logger.IsInfo) - { - _logger.Info( - $"Valid. ForkchoiceUpdated ignored - already in canonical chain. Request: {requestStr}"); - } - + if (_logger.IsInfo) _logger.Info($"Valid. ForkchoiceUpdated ignored - already in canonical chain. Request: {requestStr}."); return ForkchoiceUpdatedV1Result.Valid(null, forkchoiceState.HeadBlockHash); } EnsureTerminalBlock(forkchoiceState, blocks); - string? payloadId = null; - bool newHeadTheSameAsCurrentHead = _blockTree.Head!.Hash == newHeadBlock.Hash; - bool shouldUpdateHead = blocks != null && !newHeadTheSameAsCurrentHead; + bool shouldUpdateHead = !newHeadTheSameAsCurrentHead && blocks is not null; if (shouldUpdateHead) { _blockTree.UpdateMainChain(blocks!, true, true); @@ -209,43 +183,44 @@ public async Task> Handle(ForkchoiceSta // // return ForkchoiceUpdatedV1Result.Error(errorMsg, MergeErrorCodes.InvalidForkchoiceState); // } - // - + if (nonZeroFinalizedBlockHash) { - _manualBlockFinalizationManager.MarkFinalized(newHeadBlock!.Header, finalizedHeader!); + _manualBlockFinalizationManager.MarkFinalized(newHeadBlock.Header, finalizedHeader!); } // In future safeBlockHash will be added to JSON-RPC if (nonZeroSafeBlockHash) - _blockConfirmationManager.Confirm(safeBlockHashHeader!.Hash!); - - if (shouldUpdateHead) { - _poSSwitcher.ForkchoiceUpdated(newHeadBlock!.Header, forkchoiceState.FinalizedBlockHash); - if (_logger.IsInfo) _logger.Info($"Block {forkchoiceState.HeadBlockHash} was set as head"); + _blockConfirmationManager.Confirm(safeBlockHashHeader!.Hash!); } - if (payloadAttributes != null && newHeadBlock!.Timestamp >= payloadAttributes.Timestamp) + if (shouldUpdateHead) { - if (_logger.IsWarn) - _logger.Warn( - $"Invalid payload attributes timestamp {payloadAttributes.Timestamp}, block timestamp {newHeadBlock!.Timestamp}. Request: {requestStr}"); - - return ForkchoiceUpdatedV1Result.Error( - $"Invalid payload attributes timestamp {payloadAttributes.Timestamp}, block timestamp {newHeadBlock!.Timestamp}. Request: {requestStr}", - MergeErrorCodes.InvalidPayloadAttributes); + _poSSwitcher.ForkchoiceUpdated(newHeadBlock.Header, forkchoiceState.FinalizedBlockHash); + if (_logger.IsInfo) _logger.Info($"Block {forkchoiceState.HeadBlockHash} was set as head."); } - if (payloadAttributes != null) + string? payloadId = null; + if (payloadAttributes is not null) { - payloadId = _payloadPreparationService.StartPreparingPayload(newHeadBlock!.Header, payloadAttributes); + if (newHeadBlock.Timestamp >= payloadAttributes.Timestamp) + { + if (_logger.IsWarn) _logger.Warn($"Invalid payload attributes timestamp {payloadAttributes.Timestamp}, block timestamp {newHeadBlock!.Timestamp}. Request: {requestStr}."); + + return ForkchoiceUpdatedV1Result.Error( + $"Invalid payload attributes timestamp {payloadAttributes.Timestamp}, block timestamp {newHeadBlock.Timestamp}. Request: {requestStr}", + MergeErrorCodes.InvalidPayloadAttributes); + } + else + { + payloadId = _payloadPreparationService.StartPreparingPayload(newHeadBlock.Header, payloadAttributes); + } } - if (_logger.IsInfo) { _logger.Info($"Valid. Request: {requestStr}"); } - - _blockTree.ForkChoiceUpdated(forkchoiceState.FinalizedBlockHash,forkchoiceState.SafeBlockHash); + if (_logger.IsInfo) _logger.Info($"Valid. Request: {requestStr}."); + _blockTree.ForkChoiceUpdated(forkchoiceState.FinalizedBlockHash, forkchoiceState.SafeBlockHash); return ForkchoiceUpdatedV1Result.Valid(payloadId, forkchoiceState.HeadBlockHash); } @@ -264,8 +239,7 @@ private void EnsureTerminalBlock(ForkchoiceStateV1 forkchoiceState, Block[]? blo { if (_poSSwitcher.TryUpdateTerminalBlock(blocks[i].Header)) { - if (_logger.IsInfo) - _logger.Info($"Terminal block {blocks[i].Header} updated during the forkchoice"); + if (_logger.IsInfo) _logger.Info($"Terminal block {blocks[i].Header} updated during the forkchoice"); } break; @@ -274,7 +248,7 @@ private void EnsureTerminalBlock(ForkchoiceStateV1 forkchoiceState, Block[]? blo } } - private Block? EnsureHeadBlockHash(Keccak headBlockHash) + private Block? GetBlock(Keccak headBlockHash) { Block? block = _blockTree.FindBlock(headBlockHash, BlockTreeLookupOptions.None); if (block is null) @@ -285,40 +259,38 @@ private void EnsureTerminalBlock(ForkchoiceStateV1 forkchoiceState, Block[]? blo return block; } - private (Block[]? Blocks, string? ErrorMsg) EnsureNewHead(Block newHeadBlock) + private Block[]? EnsureNewHead(Block newHeadBlock, out string? errorMessage) { - string? errorMsg = null; - if (_blockTree.Head!.Hash == newHeadBlock!.Hash) + errorMessage = null; + if (_blockTree.Head!.Hash == newHeadBlock.Hash) { - return (null, errorMsg); + return null; } if (!TryGetBranch(newHeadBlock, out Block[] branchOfBlocks)) { - errorMsg = - $"Block's {newHeadBlock} main chain predecessor cannot be found and it will not be set as head."; - if (_logger.IsWarn) _logger.Warn(errorMsg); + errorMessage = $"Block's {newHeadBlock} main chain predecessor cannot be found and it will not be set as head."; + if (_logger.IsWarn) _logger.Warn(errorMessage); } - return (branchOfBlocks, errorMsg); + return branchOfBlocks; } - private (BlockHeader? BlockHeader, string? ErrorMsg) ValidateBlockHash(Keccak blockHash, - bool skipZeroHash = true) + private BlockHeader? ValidateBlockHash(Keccak blockHash, out string? errorMessage, bool skipZeroHash = true) { - string? errorMsg = null; + errorMessage = null; if (skipZeroHash && blockHash == Keccak.Zero) - return (null, null); + { + return null; + } BlockHeader? blockHeader = _blockTree.FindHeader(blockHash, BlockTreeLookupOptions.None); if (blockHeader is null) { - errorMsg = $"Block {blockHash} not found."; - if (_logger.IsWarn) _logger.Warn(errorMsg); + errorMessage = $"Block {blockHash} not found."; + if (_logger.IsWarn) _logger.Warn(errorMessage); } - - - return (blockHeader, errorMsg); + return blockHeader; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/GetPayloadV1Handler.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/GetPayloadV1Handler.cs index 71bdc22bc31..0c97a1b0580 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/GetPayloadV1Handler.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/GetPayloadV1Handler.cs @@ -21,21 +21,24 @@ using Nethermind.JsonRpc; using Nethermind.Logging; using Nethermind.Merge.Plugin.Data; +using Nethermind.Merge.Plugin.Data.V1; namespace Nethermind.Merge.Plugin.Handlers.V1 { /// - /// https://hackmd.io/@n0ble/kintsugi-spec - /// engine_getPayloadV1. Given a 8 byte payload_id, it returns the most recent version of an execution payload - /// that is available by the time of the call or responds with an error. - /// This call must be responded immediately. An exception would be the case when no version of the payload - /// is ready yet and in this case there might be a slight delay before the response is done. + /// engine_getPayloadV1 + /// + /// Given a 8 byte payload_id, it returns the most recent version of an execution payload that is available by the time of the call or responds with an error. + /// + /// + /// + /// + /// This call must be responded immediately. An exception would be the case when no version of the payload is ready yet and in this case there might be a slight delay before the response is done. /// Execution client should create a payload with empty transaction set to be able to respond as soon as possible. - /// If there were no prior engine_preparePayload call with the corresponding payload_id or the process of building - /// a payload has been cancelled due to the timeout then execution client must respond with error message. + /// If there were no prior engine_preparePayload call with the corresponding payload_id or the process of building a payload has been cancelled due to the timeout then execution client must respond with error message. /// Execution client may stop the building process with the corresponding payload_id value after serving this call. - /// - public class GetPayloadV1Handler: IAsyncHandler + /// + public class GetPayloadV1Handler : IAsyncHandler { private readonly IPayloadPreparationService _payloadPreparationService; private readonly ILogger _logger; @@ -46,25 +49,23 @@ public GetPayloadV1Handler(IPayloadPreparationService payloadPreparationService, _logger = logManager.GetClassLogger(); } - public async Task> HandleAsync(byte[] payloadId) + public async Task> HandleAsync(byte[] payloadId) { - Block? block = _payloadPreparationService.GetPayload(payloadId); - - if (block == null) - { - if (_logger.IsWarn) _logger.Warn($"Block production for payload with id={payloadId.ToHexString()} failed"); - return ResultWrapper.Fail( - "unknown payload", - MergeErrorCodes.UnavailablePayloadV1); - } - - if (_logger.IsInfo) + string payloadStr = payloadId.ToHexString(true); + + // Given the payloadId client software MUST return the most recent version of the payload that is available in the corresponding build process at the time of receiving the call. + Block? block = _payloadPreparationService.GetPayload(payloadStr); + + if (block is null) { - _logger.Info($"GetPayloadV1 result: {block.Header.ToString(BlockHeader.Format.Full)}"); + // The call MUST return -38001: Unknown payload error if the build process identified by the payloadId does not exist. + if (_logger.IsWarn) _logger.Warn($"Block production for payload with id={payloadId.ToHexString()} failed."); + return ResultWrapper.Fail("unknown payload", MergeErrorCodes.UnknownPayload); } - BlockRequestResult result = new(block); - return ResultWrapper.Success(result); + if (_logger.IsInfo) _logger.Info($"GetPayloadV1 result: {block.Header.ToString(BlockHeader.Format.Full)}."); + + return ResultWrapper.Success(new ExecutionPayloadV1(block)); } } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/NewPayloadV1Handler.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/NewPayloadV1Handler.cs index 9b03c88408c..702a04d3881 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/NewPayloadV1Handler.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/V1/NewPayloadV1Handler.cs @@ -42,16 +42,15 @@ namespace Nethermind.Merge.Plugin.Handlers.V1 { /// - /// https://hackmd.io/@n0ble/kintsugi-spec - /// Verifies the payload according to the execution environment rule set (EIP-3675) - /// and returns the status of the verification and the hash of the last valid block + /// Verifies the payload according to the execution environment rule set (EIP-3675) and returns the of the verification and the hash of the last valid block. + /// + /// /// - public class NewPayloadV1Handler : IAsyncHandler + public class NewPayloadV1Handler : IAsyncHandler { private readonly IBlockValidator _blockValidator; private readonly IBlockTree _blockTree; private readonly IBlockchainProcessor _processor; - private readonly IInitConfig _initConfig; private readonly IPoSSwitcher _poSSwitcher; private readonly IBeaconSyncStrategy _beaconSyncStrategy; private readonly IBeaconPivot _beaconPivot; @@ -61,6 +60,7 @@ public class NewPayloadV1Handler : IAsyncHandler _latestBlocks = new(50, "LatestBlocks"); private readonly ConcurrentDictionary _lastValidHashes = new(); + private readonly ProcessingOptions _processingOptions; public NewPayloadV1Handler( IBlockValidator blockValidator, @@ -78,7 +78,6 @@ public NewPayloadV1Handler( _blockValidator = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator)); _blockTree = blockTree; _processor = processor; - _initConfig = initConfig; _poSSwitcher = poSSwitcher; _beaconSyncStrategy = beaconSyncStrategy; _beaconPivot = beaconPivot; @@ -86,52 +85,37 @@ public NewPayloadV1Handler( _processingQueue = processingQueue; _mergeSyncController = mergeSyncController; _logger = logManager.GetClassLogger(); + _processingOptions = initConfig.StoreReceipts ? ProcessingOptions.EthereumMerge | ProcessingOptions.StoreReceipts : ProcessingOptions.EthereumMerge; } - public async Task> HandleAsync(BlockRequestResult request) + public async Task> HandleAsync(ExecutionPayloadV1 request) { string requestStr = $"a new payload: {request}"; if (_logger.IsInfo) { _logger.Info($"Received {requestStr}"); } - request.TryGetBlock(out Block? block); - if (block == null) + if (!request.TryGetBlock(out Block? block, _poSSwitcher.FinalTotalDifficulty)) { - if (_logger.IsWarn) - _logger.Warn($"Invalid block. Result of {requestStr}"); - + if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {requestStr}."); return NewPayloadV1Result.Invalid(null, $"Block {request} could not be parsed as a block"); } - if (_blockValidator.ValidateHash(block.Header) == false) + if (!HeaderValidator.ValidateHash(block.Header)) { - if (_logger.IsWarn) - _logger.Warn($"InvalidBlockHash. Result of {requestStr}"); - + if (_logger.IsWarn) _logger.Warn($"InvalidBlockHash. Result of {requestStr}."); return NewPayloadV1Result.InvalidBlockHash; } - block.Header.TotalDifficulty = _poSSwitcher.FinalTotalDifficulty; + // ToDo if block is below syncPivot, we can return SYNCING and ignore block + BlockHeader? parentHeader = _blockTree.FindHeader(request.ParentHash, BlockTreeLookupOptions.None); - bool parentExists = parentHeader != null; - bool parentProcessed = parentExists && _blockTree.WasProcessed(parentHeader!.Number, - parentHeader!.Hash ?? parentHeader.CalculateHash()); - if (!parentExists) + if (parentHeader is null) { // possible that headers sync finished before this was called, so blocks in cache weren't inserted if (!_beaconSyncStrategy.IsBeaconSyncFinished(parentHeader)) { bool inserted = TryInsertDanglingBlock(block); - if (_logger.IsInfo) - { - if (inserted) - _logger.Info( - $"BeaconSync not finished - block {block} inserted"); - else - _logger.Info( - $"BeaconSync not finished - block {block} accepted"); - } - + if (_logger.IsInfo) _logger.Info(inserted ? $"BeaconSync not finished - block {block} inserted" : $"BeaconSync not finished - block {block} accepted."); return inserted ? NewPayloadV1Result.Syncing : NewPayloadV1Result.Accepted; } @@ -139,18 +123,15 @@ public async Task> HandleAsync(BlockRequestResult _blockCacheService.BlockCache.TryAdd(request.BlockHash, block); return NewPayloadV1Result.Accepted; } - + // we need to check if the head is greater than block.Number. In fast sync we could return Valid to CL without this if - if (block.Number <= (_blockTree.Head?.Number ?? 0)) + if (_blockTree.IsOnMainChainBehindOrEqualHead(block)) { - bool canIgnoreNewPayload = _blockTree.IsMainChain(block.Header); - if (canIgnoreNewPayload) - { - if (_logger.IsInfo) _logger.Info($"Valid... A new payload ignored. Block {block.ToString(Block.Format.FullHashAndNumber)} found in main chain."); - return NewPayloadV1Result.Valid(block.Hash); - } + if (_logger.IsInfo) _logger.Info($"Valid... A new payload ignored. Block {block.ToString(Block.Format.FullHashAndNumber)} found in main chain."); + return NewPayloadV1Result.Valid(block.Hash); } + bool parentProcessed = _blockTree.WasProcessed(parentHeader.Number, parentHeader.GetOrCalculateHash()); if (!parentProcessed) { BlockTreeInsertOptions insertOptions = BlockTreeInsertOptions.BeaconBlockInsert; @@ -159,139 +140,106 @@ public async Task> HandleAsync(BlockRequestResult return NewPayloadV1Result.Syncing; } - if (_poSSwitcher.TerminalTotalDifficulty == null || - parentHeader!.TotalDifficulty < _poSSwitcher.TerminalTotalDifficulty) + if (_poSSwitcher.MisconfiguredTerminalTotalDifficulty() || _poSSwitcher.BlockBeforeTerminalTotalDifficulty(parentHeader)) { - if (_logger.IsWarn) - _logger.Warn( - $"Invalid terminal block. Nethermind TTD {_poSSwitcher.TerminalTotalDifficulty}, Parent TD: {parentHeader!.TotalDifficulty}. Request: {requestStr}"); - - // https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#specification + if (_logger.IsWarn) _logger.Warn($"Invalid terminal block. Nethermind TTD {_poSSwitcher.TerminalTotalDifficulty}, Parent TD: {parentHeader!.TotalDifficulty}. Request: {requestStr}."); + // {status: INVALID, latestValidHash: 0x0000000000000000000000000000000000000000000000000000000000000000, validationError: errorMessage | null} if terminal block conditions are not satisfied return NewPayloadV1Result.Invalid(Keccak.Zero); } + // Otherwise, we can just process this block and we don't need to do BeaconSync anymore. _mergeSyncController.StopSyncing(); - (ValidationResult ValidationResult, string? Message) result = - ValidateBlockAndProcess(block, out Block? processedBlock, parentHeader); - if ((result.ValidationResult & ValidationResult.AlreadyKnown) != 0 || - result.ValidationResult == ValidationResult.Invalid) + + // Try to execute block + ValidationResult result = ValidateBlockAndProcess(block, parentHeader, out Block? processedBlock, out string? message); + + if ((result & ValidationResult.AlreadyKnown) == ValidationResult.AlreadyKnown || result == ValidationResult.Invalid) { - bool isValid = (result.ValidationResult & ValidationResult.Valid) != 0; + bool isValid = (result & ValidationResult.Valid) == ValidationResult.Valid; if (_logger.IsInfo) { string resultStr = isValid ? "Valid" : "Invalid"; - if (_logger.IsInfo) _logger.Info($"{resultStr}. Result of {requestStr}"); + if (_logger.IsInfo) _logger.Info($"{resultStr}. Result of {requestStr}."); } - return ResultWrapper.Success(BuildExecutePayloadResult(request, isValid, parentHeader, - result.Message)); + return ResultWrapper.Success(BuildExecutePayloadResult(request, isValid, parentHeader, message)); } - if (result.ValidationResult == ValidationResult.Syncing) + if (result == ValidationResult.Syncing) { - if (_logger.IsInfo) _logger.Info($"Processing queue wasn't empty added to queue {requestStr}"); + if (_logger.IsInfo) _logger.Info($"Processing queue wasn't empty added to queue {requestStr}."); return NewPayloadV1Result.Syncing; } - if (processedBlock == null) + if (processedBlock is null) { - if (_logger.IsInfo) { _logger.Info($"Invalid block processed. Result of {requestStr}"); } - - return ResultWrapper.Success(BuildExecutePayloadResult(request, false, parentHeader, - $"Processed block is null, request {request}")); + if (_logger.IsInfo) _logger.Info($"Invalid block processed. Result of {requestStr}."); + return ResultWrapper.Success(BuildExecutePayloadResult(request, false, parentHeader, $"Processed block is null, request {request}")); } - if (_logger.IsInfo) - _logger.Info($"Valid. Result of {requestStr}"); - + if (_logger.IsInfo) _logger.Info($"Valid. Result of {requestStr}."); return NewPayloadV1Result.Valid(request.BlockHash); } - private (ValidationResult ValidationResult, string? Message) ValidateBlockAndProcess(Block block, - out Block? processedBlock, BlockHeader parent) + private ValidationResult ValidateBlockAndProcess(Block block, BlockHeader parent, out Block? processedBlock, out string? validationMessage) { - string? validationMessage = null; + ValidationResult ToValid(bool valid) => valid ? ValidationResult.Valid : ValidationResult.Invalid; + + validationMessage = null; processedBlock = null; + // If duplicate, reuse results bool isRecentBlock = _latestBlocks.TryGet(block.Hash!, out bool isValid); if (isRecentBlock) { - if (isValid == false && _logger.IsWarn) + if (!isValid && _logger.IsWarn) { validationMessage = $"Invalid block {block} sent from latestBlock cache"; if (_logger.IsWarn) _logger.Warn(validationMessage); } - return (ValidationResult.AlreadyKnown | - (isValid ? ValidationResult.Valid : ValidationResult.Invalid), validationMessage); + return ValidationResult.AlreadyKnown | ToValid(isValid); } - else + + // Validate + bool validAndProcessed = ValidateWithBlockValidator(block, parent); + if (validAndProcessed) { - bool validAndProcessed = ValidateWithBlockValidator(block, parent, out processedBlock); - if (validAndProcessed) + if (_processingQueue.IsEmpty) { - if (_processingQueue.IsEmpty) - { - // processingQueue is empty so we can process the block in synchronous way - _blockTree.SuggestBlock(block, BlockTreeSuggestOptions.None, false); - processedBlock = _processor.Process(block, GetProcessingOptions(), NullBlockTracer.Instance); - } - else - { - // this is needed for restarts. We have blocks in queue so we should add it to queue and return SYNCING - _blockTree.SuggestBlock(block, BlockTreeSuggestOptions.ShouldProcess); - return (ValidationResult.Syncing, null); - } - - if (processedBlock == null) - { - if (_logger.IsWarn) - { - _logger.Warn( - $"Block {block.ToString(Block.Format.FullHashAndNumber)} cannot be processed and wont be accepted to the tree."); - } - - validAndProcessed = false; - } + // processingQueue is empty so we can process the block in synchronous way + _blockTree.SuggestBlock(block, BlockTreeSuggestOptions.None, false); + processedBlock = _processor.Process(block, _processingOptions, NullBlockTracer.Instance); } - - _latestBlocks.Set(block.Hash!, validAndProcessed); - return (validAndProcessed ? ValidationResult.Valid : ValidationResult.Invalid, validationMessage); - } - } - - private bool ValidateWithBlockValidator(Block block, BlockHeader parent, out Block? processedBlock) - { - block.Header.TotalDifficulty = parent.TotalDifficulty + block.Difficulty; - processedBlock = null; - block.Header.IsPostMerge = true; - bool isValid = _blockValidator.ValidateSuggestedBlock(block); - if (!isValid) - { - if (_logger.IsWarn) + else + { + // this is needed for restarts. We have blocks in queue so we should add it to queue and return SYNCING + _blockTree.SuggestBlock(block); + return ValidationResult.Syncing; + } + + if (processedBlock is null) { - _logger.Warn( - $"Block validator rejected the block {block.ToString(Block.Format.FullHashAndNumber)}"); + if (_logger.IsWarn) _logger.Warn($"Block {block.ToString(Block.Format.FullHashAndNumber)} cannot be processed and wont be accepted to the tree."); + validAndProcessed = false; } } - return isValid; + _latestBlocks.Set(block.Hash!, validAndProcessed); + return ToValid(validAndProcessed); } - private ProcessingOptions GetProcessingOptions() + private bool ValidateWithBlockValidator(Block block, BlockHeader parent) { - ProcessingOptions options = ProcessingOptions.EthereumMerge; - if (_initConfig.StoreReceipts) - { - options |= ProcessingOptions.StoreReceipts; - } - - return options; + block.Header.TotalDifficulty ??= parent.TotalDifficulty + block.Difficulty; + block.Header.IsPostMerge = true; // I think we don't need to set it again here. + bool isValid = _blockValidator.ValidateSuggestedBlock(block); + if (!isValid && _logger.IsWarn) _logger.Warn($"Block validator rejected the block {block.ToString(Block.Format.FullHashAndNumber)}."); + return isValid; } - private PayloadStatusV1 BuildExecutePayloadResult(BlockRequestResult request, bool isValid, BlockHeader? parent, - string? validationMessage) + private PayloadStatusV1 BuildExecutePayloadResult(ExecutionPayloadV1 request, bool isValid, BlockHeader? parent, string? validationMessage) { PayloadStatusV1 payloadStatus = new(); if (isValid) diff --git a/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.cs b/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.cs index a8ffa7e7301..d8f2881fcad 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/IEngineRpcModule.cs @@ -38,39 +38,33 @@ public interface IEngineRpcModule : IRpcModule ResultWrapper engine_executionStatus(); [JsonRpcMethod( - Description = - "Returns the most recent version of an execution payload with respect to the transaction set contained by the mempool.", + Description = "Returns the most recent version of an execution payload with respect to the transaction set contained by the mempool.", IsSharable = true, IsImplemented = true)] - Task> engine_getPayloadV1(byte[] payloadId); + Task> engine_getPayloadV1(byte[] payloadId); [JsonRpcMethod( - Description = - "Verifies the payload according to the execution environment rules and returns the verification status and hash of the last valid block.", + Description = "Verifies the payload according to the execution environment rules and returns the verification status and hash of the last valid block.", IsSharable = true, IsImplemented = true)] - Task> engine_newPayloadV1(BlockRequestResult executionPayload); + Task> engine_newPayloadV1(ExecutionPayloadV1 executionPayload); [JsonRpcMethod( - Description = - "Verifies the payload according to the execution environment rules and returns the verification status and hash of the last valid block.", + Description = "Verifies the payload according to the execution environment rules and returns the verification status and hash of the last valid block.", IsSharable = true, IsImplemented = true)] Task> engine_forkchoiceUpdatedV1(ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes = null); [JsonRpcMethod( - Description = - "Returns an array of execution payload bodies for the list of provided block hashes.", + Description = "Returns an array of execution payload bodies for the list of provided block hashes.", IsSharable = true, IsImplemented = true)] Task> engine_getPayloadBodiesV1(Keccak[] blockHashes); [JsonRpcMethod( - Description = - "Returns PoS transition configuration.", + Description = "Returns PoS transition configuration.", IsSharable = true, IsImplemented = true)] - ResultWrapper engine_exchangeTransitionConfigurationV1( - TransitionConfigurationV1 beaconTransitionConfiguration); + ResultWrapper engine_exchangeTransitionConfigurationV1(TransitionConfigurationV1 beaconTransitionConfiguration); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeErrorCodes.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeErrorCodes.cs index b84c82066e6..34fd24ac893 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeErrorCodes.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeErrorCodes.cs @@ -22,7 +22,7 @@ public static class MergeErrorCodes { public const int None = 0; - public const int UnavailablePayloadV1 = -32001; + public const int UnknownPayload = -38001; public const int InvalidForkchoiceState = -38002; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs index 89966aeffa6..5d8578c13a2 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs @@ -209,8 +209,10 @@ public Task InitSynchronization() if (_api.NodeStatsManager is null) throw new ArgumentNullException(nameof(_api.NodeStatsManager)); // ToDo strange place for validators initialization - _peerRefresher = new PeerRefresher(_api.SyncPeerPool); - _beaconPivot = new BeaconPivot(_syncConfig, _mergeConfig, _api.DbProvider.MetadataDb, _api.BlockTree, new PeerRefresher(_api.SyncPeerPool), _api.LogManager); + PeerRefresher peerRefresher = new(_api.SyncPeerPool, _api.TimerFactory); + _peerRefresher = peerRefresher; + _api.DisposeStack.Push(peerRefresher); + _beaconPivot = new BeaconPivot(_syncConfig, _api.DbProvider.MetadataDb, _api.BlockTree, _api.LogManager); _api.HeaderValidator = new MergeHeaderValidator(_poSSwitcher, _api.BlockTree, _api.SpecProvider, _api.SealValidator, _api.LogManager); _api.UnclesValidator = new MergeUnclesValidator(_poSSwitcher, _api.UnclesValidator); _api.BlockValidator = new BlockValidator(_api.TxValidator, _api.HeaderValidator, _api.UnclesValidator, diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeProcessingRecoveryStep.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeProcessingRecoveryStep.cs index 6b56cd2c162..902d7ae65d6 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeProcessingRecoveryStep.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeProcessingRecoveryStep.cs @@ -33,9 +33,14 @@ public MergeProcessingRecoveryStep( public void RecoverData(Block block) { - if (block.TotalDifficulty != null) + if (block.TotalDifficulty is not null) + { block.Header.IsPostMerge = _poSSwitcher.IsPostMerge(block.Header); - if (block.Author == null && block.IsPostMerge) + } + + if (block.Author is null && block.IsPostMerge) + { block.Header.Author = block.Beneficiary; + } } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs b/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs index 9fc0ece7baa..10f0d2994b9 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs @@ -58,7 +58,7 @@ public class PoSSwitcher : IPoSSwitcher private readonly IBlockCacheService _blockCacheService; private readonly ILogger _logger; private Keccak? _terminalBlockHash; - + private long? _terminalBlockNumber; private long? _firstPoSBlockNumber; private bool _hasEverReachedTerminalDifficulty; @@ -100,8 +100,7 @@ private void Initialize() _blockTree.NewHeadBlock += CheckIfTerminalBlockReached; if (_logger.IsInfo) - _logger.Info( - $"Client started with TTD: {TerminalTotalDifficulty}, TTD reached: {_hasEverReachedTerminalDifficulty}, Terminal Block Number {_terminalBlockNumber}, FinalTotalDifficulty: {FinalTotalDifficulty}"); + _logger.Info($"Client started with TTD: {TerminalTotalDifficulty}, TTD reached: {_hasEverReachedTerminalDifficulty}, Terminal Block Number {_terminalBlockNumber}, FinalTotalDifficulty: {FinalTotalDifficulty}"); } private void LoadFinalTotalDifficulty() @@ -109,7 +108,7 @@ private void LoadFinalTotalDifficulty() _finalTotalDifficulty = _mergeConfig.FinalTotalDifficultyParsed; // pivot post TTD, so we know FinalTotalDifficulty - if (_syncConfig.PivotTotalDifficultyParsed != 0 && TerminalTotalDifficulty !=null && _syncConfig.PivotTotalDifficultyParsed >= TerminalTotalDifficulty) + if (_syncConfig.PivotTotalDifficultyParsed != 0 && TerminalTotalDifficulty != null && _syncConfig.PivotTotalDifficultyParsed >= TerminalTotalDifficulty) { _finalTotalDifficulty = _syncConfig.PivotTotalDifficultyParsed; } @@ -133,10 +132,10 @@ public bool IsTerminalBlock(BlockHeader header) bool ttdRequirement = header.TotalDifficulty >= TerminalTotalDifficulty; if (ttdRequirement && header.IsGenesis) return true; - + if (ttdRequirement && header.Difficulty != 0) { - UInt256? parentTotalDifficulty = header.TotalDifficulty >= header.Difficulty ? header.TotalDifficulty - header.Difficulty : 0; + UInt256? parentTotalDifficulty = header.TotalDifficulty >= header.Difficulty ? header.TotalDifficulty - header.Difficulty : 0; isTerminalBlock = parentTotalDifficulty < TerminalTotalDifficulty; } @@ -177,9 +176,7 @@ public void ForkchoiceUpdated(BlockHeader newHeadHash, Keccak finalizedHash) { if (_finalizedBlockHash == Keccak.Zero) { - if (_logger.IsInfo) - _logger.Info( - $"Reached the first finalized PoS block FinalizedHash: {finalizedHash}, NewHeadHash: {newHeadHash}"); + if (_logger.IsInfo) _logger.Info($"Reached the first finalized PoS block FinalizedHash: {finalizedHash}, NewHeadHash: {newHeadHash}"); _blockTree.NewHeadBlock -= CheckIfTerminalBlockReached; } @@ -194,7 +191,7 @@ public void ForkchoiceUpdated(BlockHeader newHeadHash, Keccak finalizedHash) if (_logger.IsTrace) _logger.Trace( $"GetBlockConsensusInfo {header.ToString(BlockHeader.Format.FullHashAndNumber)} header.IsPostMerge: {header.IsPostMerge} header.TotalDifficulty {header.TotalDifficulty} header.Difficulty {header.Difficulty} TTD: {_specProvider.TerminalTotalDifficulty} MergeBlockNumber {_specProvider.MergeBlockNumber}, TransitionFinished: {TransitionFinished}"); - + bool isTerminal = false, isPostMerge; if (header.IsPostMerge) // block from Engine API, there is no need to check more cases { @@ -255,7 +252,7 @@ public bool IsPostMerge(BlockHeader header) => private void LoadTerminalBlock() { _terminalBlockNumber = _mergeConfig.TerminalBlockNumber ?? - _specProvider.MergeBlockNumber - 1; + _specProvider.MergeBlockNumber - 1; _terminalBlockExplicitSpecified = _terminalBlockNumber != null; _terminalBlockNumber ??= LoadTerminalBlockNumberFromDb(); @@ -270,11 +267,18 @@ private void LoadTerminalBlock() private long? LoadTerminalBlockNumberFromDb() { - if (_metadataDb.KeyExists(MetadataDbKeys.TerminalPoWNumber)) + try { - byte[]? hashFromDb = _metadataDb.Get(MetadataDbKeys.TerminalPoWNumber); - RlpStream stream = new(hashFromDb!); - return stream.DecodeLong(); + if (_metadataDb.KeyExists(MetadataDbKeys.TerminalPoWNumber)) + { + byte[]? hashFromDb = _metadataDb.Get(MetadataDbKeys.TerminalPoWNumber); + RlpStream stream = new(hashFromDb!); + return stream.DecodeLong(); + } + } + catch (RlpException) + { + if (_logger.IsWarn) _logger.Warn($"Cannot decode terminal block number"); } return null; @@ -282,11 +286,18 @@ private void LoadTerminalBlock() private Keccak? LoadHashFromDb(int key) { - if (_metadataDb.KeyExists(key)) + try + { + if (_metadataDb.KeyExists(key)) + { + byte[]? hashFromDb = _metadataDb.Get(key); + RlpStream stream = new(hashFromDb!); + return stream.DecodeKeccak(); + } + } + catch (RlpException) { - byte[]? hashFromDb = _metadataDb.Get(key); - RlpStream stream = new(hashFromDb!); - return stream.DecodeKeccak(); + if (_logger.IsWarn) _logger.Warn($"Cannot decode hash with metadata key: {key}"); } return null; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.cs index b4a2c379407..8d88fbcdc86 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.cs @@ -31,14 +31,10 @@ namespace Nethermind.Merge.Plugin.Synchronization public class BeaconPivot : IBeaconPivot { private readonly ISyncConfig _syncConfig; - private readonly IMergeConfig _mergeConfig; private readonly IDb _metadataDb; private readonly IBlockTree _blockTree; - private readonly IPeerRefresher _peerRefresher; private readonly ILogger _logger; private BlockHeader? _currentBeaconPivot; - private BlockHeader? _pivotParent; - private bool _pivotParentProcessed; private BlockHeader? CurrentBeaconPivot { @@ -49,7 +45,7 @@ private BlockHeader? CurrentBeaconPivot if (value != null) { _metadataDb.Set(MetadataDbKeys.BeaconSyncPivotHash, - Rlp.Encode(value.Hash ?? value.CalculateHash()).Bytes); + Rlp.Encode(value.GetOrCalculateHash()).Bytes); _metadataDb.Set(MetadataDbKeys.BeaconSyncPivotNumber, Rlp.Encode(value.Number).Bytes); } else _metadataDb.Delete(MetadataDbKeys.BeaconSyncPivotHash); @@ -59,17 +55,13 @@ private BlockHeader? CurrentBeaconPivot public BeaconPivot( ISyncConfig syncConfig, - IMergeConfig mergeConfig, IDb metadataDb, IBlockTree blockTree, - IPeerRefresher peerRefresher, ILogManager logManager) { _syncConfig = syncConfig; - _mergeConfig = mergeConfig; _metadataDb = metadataDb; _blockTree = blockTree; - _peerRefresher = peerRefresher; _logger = logManager.GetClassLogger(); LoadBeaconPivot(); } @@ -90,8 +82,6 @@ public void EnsurePivot(BlockHeader? blockHeader) bool beaconPivotExists = BeaconPivotExists(); if (blockHeader != null) { - _peerRefresher.RefreshPeers(blockHeader.Hash!); - // ToDo Sarah in some cases this could be wrong if (beaconPivotExists && (PivotNumber > blockHeader.Number || blockHeader.Hash == PivotHash)) { diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs index 7f699501186..00966e41b03 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs @@ -100,7 +100,7 @@ public bool IsBeaconSyncHeadersFinished() public bool IsBeaconSyncFinished(BlockHeader? blockHeader) { return !_beaconPivot.BeaconPivotExists() - || (blockHeader != null && _blockTree.WasProcessed(blockHeader.Number, blockHeader.Hash ?? blockHeader.CalculateHash())); + || (blockHeader != null && _blockTree.WasProcessed(blockHeader.Number, blockHeader.GetOrCalculateHash())); } public bool FastSyncEnabled => _syncConfig.FastSync; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/ChainLevelHelper.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/ChainLevelHelper.cs index 2ed40491714..d86fc3a9ad9 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/ChainLevelHelper.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/ChainLevelHelper.cs @@ -155,7 +155,7 @@ public Block[] GetNextBlocks(int maxCount) return null; } - Block? block = _blockTree.FindBlock(header!.ParentHash ?? header.CalculateHash()); + Block? block = _blockTree.FindBlock(header.ParentHash ?? header.CalculateHash()); parentBlockExists = block != null; if (_logger.IsTrace) _logger.Trace( diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs index 23a4ab04d01..7132c34485e 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PeerRefresher.cs @@ -15,32 +15,71 @@ // along with the Nethermind. If not, see . // +using System; using System.Collections.Generic; +using System.Threading.Tasks; using Nethermind.Core.Crypto; +using Nethermind.Core.Timers; using Nethermind.Synchronization.Peers; namespace Nethermind.Merge.Plugin.Synchronization; -public class PeerRefresher : IPeerRefresher +public class PeerRefresher : IPeerRefresher, IAsyncDisposable { private readonly ISyncPeerPool _syncPeerPool; + private static readonly TimeSpan _minRefreshDelay = TimeSpan.FromSeconds(10); + private DateTime _lastRefresh = DateTime.MinValue; + private Keccak _lastHash = Keccak.Zero; + private readonly ITimer _refreshTimer; - public PeerRefresher(ISyncPeerPool syncPeerPool) + public PeerRefresher(ISyncPeerPool syncPeerPool, ITimerFactory timerFactory) { + _refreshTimer = timerFactory.CreateTimer(_minRefreshDelay); + _refreshTimer.Elapsed += TimerOnElapsed; + _refreshTimer.AutoReset = false; _syncPeerPool = syncPeerPool; } - public void RefreshPeers(Keccak blockHash) + public void RefreshPeers(Keccak? blockHash) { - IEnumerable peers = _syncPeerPool.InitializedPeers; - foreach (PeerInfo peer in peers) + if (blockHash is not null) + { + _lastHash = blockHash; + TimeSpan timePassed = DateTime.Now - _lastRefresh; + if (timePassed > _minRefreshDelay) + { + Refresh(blockHash); + } + else if (!_refreshTimer.Enabled) + { + _refreshTimer.Interval = _minRefreshDelay - timePassed; + _refreshTimer.Start(); + } + } + } + + private void TimerOnElapsed(object? sender, EventArgs e) + { + Refresh(_lastHash); + } + + private void Refresh(Keccak blockHash) + { + _lastRefresh = DateTime.Now; + foreach (PeerInfo peer in _syncPeerPool.AllPeers) { _syncPeerPool.RefreshTotalDifficulty(peer.SyncPeer, blockHash); } } + + public ValueTask DisposeAsync() + { + _refreshTimer.Dispose(); + return default; + } } public interface IPeerRefresher { - void RefreshPeers(Keccak blockHash); + void RefreshPeers(Keccak? blockHash); } diff --git a/src/Nethermind/Nethermind.Runner/NLog.config b/src/Nethermind/Nethermind.Runner/NLog.config index cb3d754f77b..e1ac02d6eb2 100644 --- a/src/Nethermind/Nethermind.Runner/NLog.config +++ b/src/Nethermind/Nethermind.Runner/NLog.config @@ -59,10 +59,10 @@ - - - - + + + + @@ -89,10 +89,14 @@ + + + + - - + + diff --git a/src/Nethermind/Nethermind.Runner/Properties/launchSettings.json b/src/Nethermind/Nethermind.Runner/Properties/launchSettings.json index d2d1771bf17..bf1b8ca9a15 100644 --- a/src/Nethermind/Nethermind.Runner/Properties/launchSettings.json +++ b/src/Nethermind/Nethermind.Runner/Properties/launchSettings.json @@ -154,6 +154,10 @@ "commandName": "Project", "commandLineArgs": "--config configs\\sepolia.cfg --Init.DiagnosticMode MemDb" }, + "Sepolia Archive": { + "commandName": "Project", + "commandLineArgs": "--config configs\\sepolia_archive.cfg --Init.DiagnosticMode MemDb" + }, "Kiln_devnet": { "commandName": "Project", "commandLineArgs": "--config kiln_devnet.cfg --Init.DiagnosticMode MemDb" diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet_shadowfork.cfg b/src/Nethermind/Nethermind.Runner/configs/mainnet_shadowfork.cfg index 3342cfd870f..2f2d8282801 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet_shadowfork.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet_shadowfork.cfg @@ -18,7 +18,7 @@ "AncientBodiesBarrier": 11052984, "AncientReceiptsBarrier": 11052984, "DownloadBodiesInFastSync": true, - "DownloadReceiptsInFastSync": false, + "DownloadReceiptsInFastSync": true, "WitnessProtocolEnabled": true }, "JsonRpc": { @@ -37,6 +37,6 @@ }, "Merge": { "Enabled": true, - "TerminalTotalDifficulty": 47101300000000000000000 - } + "TerminalTotalDifficulty": 49399410637657203539968 + } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg b/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg index 56d068fd7c8..da2e31fb101 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg @@ -12,5 +12,13 @@ }, "Metrics": { "NodeName": "Sepolia" + }, + "Sync": { + "FastSync": true, + "FastBlocks": true, + "UseGethLimitsInFastBlocks": true, + "PivotNumber": 1202422, + "PivotHash": "0x7e76e3e46e5a2b0915bd2ce93ff7ccb0fdf628468dbb6b619bdfdfe36c396960", + "PivotTotalDifficulty": "4083462173020124" } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia_archive.cfg b/src/Nethermind/Nethermind.Runner/configs/sepolia_archive.cfg new file mode 100644 index 00000000000..56d068fd7c8 --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia_archive.cfg @@ -0,0 +1,16 @@ +{ + "Init": { + "ChainSpecPath": "chainspec/sepolia.json", + "GenesisHash": "0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9", + "BaseDbPath": "nethermind_db/sepolia", + "LogFileName": "sepolia.logs.txt", + "StaticNodesPath": "Data/static-nodes-sepolia.json", + "MemoryHint": 1024000000 + }, + "TxPool": { + "Size": 1024 + }, + "Metrics": { + "NodeName": "Sepolia" + } +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.State/StateReaderExtensions.cs b/src/Nethermind/Nethermind.State/StateReaderExtensions.cs index ba96df2071e..729c000a66b 100644 --- a/src/Nethermind/Nethermind.State/StateReaderExtensions.cs +++ b/src/Nethermind/Nethermind.State/StateReaderExtensions.cs @@ -19,6 +19,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Int256; +using Nethermind.Trie; namespace Nethermind.State { @@ -48,5 +49,14 @@ public static Keccak GetCodeHash(this IStateReader stateReader, Keccak stateRoot { return stateReader.GetAccount(stateRoot, address)?.CodeHash ?? Keccak.OfAnEmptyString; } + + public static bool HasStateForBlock(this IStateReader stateReader, BlockHeader header) + { + RootCheckVisitor rootCheckVisitor = new(); + stateReader.RunTreeVisitor(rootCheckVisitor, header.StateRoot); + return rootCheckVisitor.HasRoot; + } + + } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs index 98c3686e34c..8db60d14221 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs @@ -66,8 +66,7 @@ public async Task Merge_Happy_path(long headNumber, int options, int threshold, IBlockCacheService blockCacheService = new BlockCacheService(); PoSSwitcher posSwitcher = new(new MergeConfig() { Enabled = true, TerminalTotalDifficulty = "0" }, new SyncConfig(), metadataDb, notSyncedTree, RopstenSpecProvider.Instance, blockCacheService, LimboLogs.Instance); - BeaconPivot beaconPivot = new(new SyncConfig(), mergeConfig, metadataDb, notSyncedTree, - new PeerRefresher(Substitute.For()), LimboLogs.Instance); + BeaconPivot beaconPivot = new(new SyncConfig(), metadataDb, notSyncedTree, LimboLogs.Instance); beaconPivot.EnsurePivot(blockTrees.SyncedTree.FindHeader(16, BlockTreeLookupOptions.None)); MergeBlockDownloader downloader = new(posSwitcher, beaconPivot, ctx.Feed, ctx.PeerPool, notSyncedTree, Always.Valid, Always.Valid, NullSyncReport.Instance, receiptStorage, RopstenSpecProvider.Instance, @@ -118,8 +117,7 @@ public async Task Can_reach_terminal_block(long headNumber, int options, int thr IBlockCacheService blockCacheService = new BlockCacheService(); PoSSwitcher posSwitcher = new(new MergeConfig() { Enabled = true, TerminalTotalDifficulty = "10000000" }, new SyncConfig(), metadataDb, notSyncedTree, RopstenSpecProvider.Instance, blockCacheService, LimboLogs.Instance); - BeaconPivot beaconPivot = new(new SyncConfig(), mergeConfig, metadataDb, notSyncedTree, - new PeerRefresher(Substitute.For()), LimboLogs.Instance); + BeaconPivot beaconPivot = new(new SyncConfig(), metadataDb, notSyncedTree, LimboLogs.Instance); if (withBeaconPivot) beaconPivot.EnsurePivot(blockTrees.SyncedTree.FindHeader(16, BlockTreeLookupOptions.None)); MergeBlockDownloader downloader = new(posSwitcher, beaconPivot, ctx.Feed, ctx.PeerPool, notSyncedTree, diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs index eb5e3f0ce5b..02f18420d18 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs @@ -317,7 +317,7 @@ private SyncTestContext CreateSyncManager(int index) logManager); RecoverSignatures step = new(ecdsa, txPool, specProvider, logManager); - BlockchainProcessor processor = new(tree, blockProcessor, step, logManager, + BlockchainProcessor processor = new(tree, blockProcessor, step, stateReader, logManager, BlockchainProcessor.Options.Default); ITimerFactory timerFactory = Substitute.For(); @@ -340,7 +340,7 @@ private SyncTestContext CreateSyncManager(int index) NullWitnessCollector.Instance, logManager); - BlockchainProcessor devChainProcessor = new(tree, devBlockProcessor, step, logManager, + BlockchainProcessor devChainProcessor = new(tree, devBlockProcessor, step, stateReader, logManager, BlockchainProcessor.Options.NoReceipts); ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(LimboLogs.Instance, specProvider); TxPoolTxSource transactionSelector = new(txPool, specProvider, transactionComparerProvider, logManager, txFilterPipeline); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index ccd2a50f464..cfe610a7be4 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -359,8 +359,8 @@ ISyncConfig GetSyncConfig() => IBlockDownloaderFactory blockDownloaderFactory; if (IsMerge(synchronizerType)) { - IBeaconPivot beaconPivot = new BeaconPivot(syncConfig, mergeConfig, dbProvider.MetadataDb, - BlockTree, new PeerRefresher(SyncPeerPool), _logManager); + IBeaconPivot beaconPivot = new BeaconPivot(syncConfig, dbProvider.MetadataDb, + BlockTree, _logManager); SyncReport syncReport = new(SyncPeerPool, stats, syncModeSelector, syncConfig, beaconPivot, _logManager); blockDownloaderFactory = new MergeBlockDownloaderFactory( poSSwitcher, diff --git a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs index 85981976b33..937ae054114 100644 --- a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs +++ b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs @@ -351,6 +351,7 @@ bool HasMoreToSync() } } + if (_logger.IsTrace) _logger.Trace($"BlockDownloader - SuggestBlock {currentBlock}, ShouldProcess: {true}"); if (HandleAddResult(bestPeer, currentBlock.Header, blockIndex == 0, _blockTree.SuggestBlock(currentBlock, shouldProcess ? BlockTreeSuggestOptions.ShouldProcess : BlockTreeSuggestOptions.None))) { TryUpdateTerminalBlock(currentBlock.Header, shouldProcess); diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs index ac9776c807d..920e21ee01d 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs @@ -529,11 +529,9 @@ private bool HasJustStartedFullSync(Snapshot best) => private bool AnyDesiredPeerKnown(Snapshot best) => _betterPeerStrategy.IsDesiredPeer((best.PeerDifficulty, best.PeerBlock), best.Header); - - - private bool AnyPostPivotPeerKnown(long bestPeerBlock) => bestPeerBlock > _syncConfig.PivotNumberParsed; - + private bool AnyPostPivotPeerKnown(long bestPeerBlock) => bestPeerBlock > _syncConfig.PivotNumberParsed; + private (UInt256? maxPeerDifficulty, long? number) ReloadDataFromPeers() { UInt256? maxPeerDifficulty = null; diff --git a/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs b/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs index 10d515f461d..7e3c44882ca 100644 --- a/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs +++ b/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs @@ -24,6 +24,7 @@ using Nethermind.Blockchain; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Synchronization; +using Nethermind.Consensus.Validators; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; @@ -623,6 +624,14 @@ await firstToComplete.ContinueWith( return; } + if (!HeaderValidator.ValidateHash(header)) + { + if (_logger.IsTrace) _logger.Trace($"InitPeerInfo failed for node: {syncPeer.Node:c}{Environment.NewLine}Invalid block hash."); + _stats.ReportSyncEvent(syncPeer.Node, syncPeer.IsInitialized ? NodeStatsEventType.SyncFailed : NodeStatsEventType.SyncInitFailed); + syncPeer.Disconnect(DisconnectReason.DisconnectRequested, "refresh peer info fault - invalid header hash"); + return; + } + if (_logger.IsTrace) _logger.Trace($"Received head block info from {syncPeer.Node:c} with head block {header.ToString(BlockHeader.Format.Short)}, total difficulty {header.TotalDifficulty}"); if (!syncPeer.IsInitialized) _stats.ReportSyncEvent(syncPeer.Node, NodeStatsEventType.SyncInitCompleted);