diff --git a/README.md b/README.md index 5b34a6e61d39..494dea98c302 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ # Nethermind Ethereum client [![Tests](https://github.com/nethermindeth/nethermind/actions/workflows/nethermind-tests.yml/badge.svg)](https://github.com/nethermindeth/nethermind/actions/workflows/nethermind-tests.yml) -[![Follow us on X](https://img.shields.io/twitter/follow/nethermindeth?style=social&label=Follow%20us)](https://x.com/nethermindeth) +[![Follow us on X](https://img.shields.io/twitter/follow/nethermind?style=social&label=Follow%20us)](https://x.com/nethermind) [![Chat on Discord](https://img.shields.io/discord/629004402170134531?style=social&logo=discord)](https://discord.gg/GXJFaYk) [![GitHub Discussions](https://img.shields.io/github/discussions/nethermindeth/nethermind?style=social)](https://github.com/nethermindeth/nethermind/discussions) [![GitPOAPs](https://public-api.gitpoap.io/v1/repo/NethermindEth/nethermind/badge)](https://www.gitpoap.io/gh/NethermindEth/nethermind) diff --git a/src/Nethermind/Chains/arena-z-mainnet.json.zst b/src/Nethermind/Chains/arena-z-mainnet.json.zst index e9113e55b220..5792108e41ae 100644 Binary files a/src/Nethermind/Chains/arena-z-mainnet.json.zst and b/src/Nethermind/Chains/arena-z-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/arena-z-sepolia.json.zst b/src/Nethermind/Chains/arena-z-sepolia.json.zst index cdb5309b4711..7302ef3c16bf 100644 Binary files a/src/Nethermind/Chains/arena-z-sepolia.json.zst and b/src/Nethermind/Chains/arena-z-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/automata-mainnet.json.zst b/src/Nethermind/Chains/automata-mainnet.json.zst index 0e9e27a6116d..017f4c5f5a42 100644 Binary files a/src/Nethermind/Chains/automata-mainnet.json.zst and b/src/Nethermind/Chains/automata-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/base-mainnet.json.zst b/src/Nethermind/Chains/base-mainnet.json.zst index 6401d6a84d4d..fdec15ef83ae 100644 Binary files a/src/Nethermind/Chains/base-mainnet.json.zst and b/src/Nethermind/Chains/base-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/base-sepolia.json.zst b/src/Nethermind/Chains/base-sepolia.json.zst index 0ebb4d1fa34e..c129b089596d 100644 Binary files a/src/Nethermind/Chains/base-sepolia.json.zst and b/src/Nethermind/Chains/base-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/bob-mainnet.json.zst b/src/Nethermind/Chains/bob-mainnet.json.zst index d7bfae7bcff5..4e349a61aa72 100644 Binary files a/src/Nethermind/Chains/bob-mainnet.json.zst and b/src/Nethermind/Chains/bob-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/boba-mainnet.json.zst b/src/Nethermind/Chains/boba-mainnet.json.zst index 71fd1372d268..03838fb0dda2 100644 Binary files a/src/Nethermind/Chains/boba-mainnet.json.zst and b/src/Nethermind/Chains/boba-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/boba-sepolia.json.zst b/src/Nethermind/Chains/boba-sepolia.json.zst index fe40e08c362d..de5e36abae18 100644 Binary files a/src/Nethermind/Chains/boba-sepolia.json.zst and b/src/Nethermind/Chains/boba-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/camp-sepolia.json.zst b/src/Nethermind/Chains/camp-sepolia.json.zst index 2c3309f68c10..1b3511bd9fe1 100644 Binary files a/src/Nethermind/Chains/camp-sepolia.json.zst and b/src/Nethermind/Chains/camp-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/cyber-mainnet.json.zst b/src/Nethermind/Chains/cyber-mainnet.json.zst index c39e500211bb..c85da79d3826 100644 Binary files a/src/Nethermind/Chains/cyber-mainnet.json.zst and b/src/Nethermind/Chains/cyber-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/cyber-sepolia.json.zst b/src/Nethermind/Chains/cyber-sepolia.json.zst index 214f3c4ca664..b51bf216a013 100644 Binary files a/src/Nethermind/Chains/cyber-sepolia.json.zst and b/src/Nethermind/Chains/cyber-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/dictionary b/src/Nethermind/Chains/dictionary index 20e4d3d6b4c3..2b5819f0e4ae 100644 Binary files a/src/Nethermind/Chains/dictionary and b/src/Nethermind/Chains/dictionary differ diff --git a/src/Nethermind/Chains/ethernity-mainnet.json.zst b/src/Nethermind/Chains/ethernity-mainnet.json.zst index f23bd1dc90f7..46379fd2022b 100644 Binary files a/src/Nethermind/Chains/ethernity-mainnet.json.zst and b/src/Nethermind/Chains/ethernity-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/ethernity-sepolia.json.zst b/src/Nethermind/Chains/ethernity-sepolia.json.zst index 4bc6ebf7aa2f..dc55f0155710 100644 Binary files a/src/Nethermind/Chains/ethernity-sepolia.json.zst and b/src/Nethermind/Chains/ethernity-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/foundation.json b/src/Nethermind/Chains/foundation.json index 554155c6879a..30a9ec37e5e2 100644 --- a/src/Nethermind/Chains/foundation.json +++ b/src/Nethermind/Chains/foundation.json @@ -199,6 +199,14 @@ "eip7251TransitionTimestamp": "0x681b3057", "eip7702TransitionTimestamp": "0x681b3057", "eip7623TransitionTimestamp": "0x681b3057", + "eip7594TransitionTimestamp": "0x6930b057", + "eip7823TransitionTimestamp": "0x6930b057", + "eip7825TransitionTimestamp": "0x6930b057", + "eip7883TransitionTimestamp": "0x6930b057", + "eip7918TransitionTimestamp": "0x6930b057", + "eip7934TransitionTimestamp": "0x6930b057", + "eip7939TransitionTimestamp": "0x6930b057", + "eip7951TransitionTimestamp": "0x6930b057", "depositContractAddress": "0x00000000219ab540356cbb839cbe05303d7705fa", "terminalTotalDifficulty": "C70D808A128D7380000", "blobSchedule": [ @@ -208,6 +216,20 @@ "target": 6, "max": 9, "baseFeeUpdateFraction": "0x4c6964" + }, + { + "name": "bpo1", + "timestamp": "0x69383057", + "target": 10, + "max": 15, + "baseFeeUpdateFraction": "0x7f5a51" + }, + { + "name": "bpo2", + "timestamp": "0x695db057", + "target": 14, + "max": 21, + "baseFeeUpdateFraction": "0xb24b3f" } ] }, diff --git a/src/Nethermind/Chains/fraxtal-mainnet.json.zst b/src/Nethermind/Chains/fraxtal-mainnet.json.zst index ed91032e2d24..030bddb357fc 100644 Binary files a/src/Nethermind/Chains/fraxtal-mainnet.json.zst and b/src/Nethermind/Chains/fraxtal-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/funki-mainnet.json.zst b/src/Nethermind/Chains/funki-mainnet.json.zst index 09b2dcbc7b2c..4d8eff551449 100644 Binary files a/src/Nethermind/Chains/funki-mainnet.json.zst and b/src/Nethermind/Chains/funki-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/funki-sepolia.json.zst b/src/Nethermind/Chains/funki-sepolia.json.zst index 492b9ee72307..5db62f1204a0 100644 Binary files a/src/Nethermind/Chains/funki-sepolia.json.zst and b/src/Nethermind/Chains/funki-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/hashkeychain-mainnet.json.zst b/src/Nethermind/Chains/hashkeychain-mainnet.json.zst index 635c53a69d8d..52fd8ed8a5be 100644 Binary files a/src/Nethermind/Chains/hashkeychain-mainnet.json.zst and b/src/Nethermind/Chains/hashkeychain-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/ink-mainnet.json.zst b/src/Nethermind/Chains/ink-mainnet.json.zst index 4962aeaa8a9f..d2e225730e67 100644 Binary files a/src/Nethermind/Chains/ink-mainnet.json.zst and b/src/Nethermind/Chains/ink-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/ink-sepolia.json.zst b/src/Nethermind/Chains/ink-sepolia.json.zst index 355e98d01863..1e824187026c 100644 Binary files a/src/Nethermind/Chains/ink-sepolia.json.zst and b/src/Nethermind/Chains/ink-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/lisk-mainnet.json.zst b/src/Nethermind/Chains/lisk-mainnet.json.zst index b861f8eab4cf..d1731571e279 100644 Binary files a/src/Nethermind/Chains/lisk-mainnet.json.zst and b/src/Nethermind/Chains/lisk-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/lisk-sepolia.json.zst b/src/Nethermind/Chains/lisk-sepolia.json.zst index e5e0ef57af6d..72e73346df8a 100644 Binary files a/src/Nethermind/Chains/lisk-sepolia.json.zst and b/src/Nethermind/Chains/lisk-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/lyra-mainnet.json.zst b/src/Nethermind/Chains/lyra-mainnet.json.zst index 3efc8fb54798..f926cd06200d 100644 Binary files a/src/Nethermind/Chains/lyra-mainnet.json.zst and b/src/Nethermind/Chains/lyra-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/metal-mainnet.json.zst b/src/Nethermind/Chains/metal-mainnet.json.zst index a09d22cca6af..7b2e6eed203e 100644 Binary files a/src/Nethermind/Chains/metal-mainnet.json.zst and b/src/Nethermind/Chains/metal-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/metal-sepolia.json.zst b/src/Nethermind/Chains/metal-sepolia.json.zst index e06f84b5277d..b9589a1495f2 100644 Binary files a/src/Nethermind/Chains/metal-sepolia.json.zst and b/src/Nethermind/Chains/metal-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/mint-mainnet.json.zst b/src/Nethermind/Chains/mint-mainnet.json.zst index 767212c16dff..dd580a3ac1ad 100644 Binary files a/src/Nethermind/Chains/mint-mainnet.json.zst and b/src/Nethermind/Chains/mint-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/mode-mainnet.json.zst b/src/Nethermind/Chains/mode-mainnet.json.zst index ebbba73331d6..864b1880f6c6 100644 Binary files a/src/Nethermind/Chains/mode-mainnet.json.zst and b/src/Nethermind/Chains/mode-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/mode-sepolia.json.zst b/src/Nethermind/Chains/mode-sepolia.json.zst index 148ca283c3cc..ba15e7b41167 100644 Binary files a/src/Nethermind/Chains/mode-sepolia.json.zst and b/src/Nethermind/Chains/mode-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/op-mainnet.json.zst b/src/Nethermind/Chains/op-mainnet.json.zst index 82270fcad1ec..2ced8c31de3f 100644 Binary files a/src/Nethermind/Chains/op-mainnet.json.zst and b/src/Nethermind/Chains/op-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/op-sepolia.json.zst b/src/Nethermind/Chains/op-sepolia.json.zst index 505c7b220db6..273e9638055f 100644 Binary files a/src/Nethermind/Chains/op-sepolia.json.zst and b/src/Nethermind/Chains/op-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/orderly-mainnet.json.zst b/src/Nethermind/Chains/orderly-mainnet.json.zst index c9f4111f7f25..6ed46dcc1693 100644 Binary files a/src/Nethermind/Chains/orderly-mainnet.json.zst and b/src/Nethermind/Chains/orderly-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/ozean-sepolia.json.zst b/src/Nethermind/Chains/ozean-sepolia.json.zst index 13d9a20574fc..c0bd43fc8d76 100644 Binary files a/src/Nethermind/Chains/ozean-sepolia.json.zst and b/src/Nethermind/Chains/ozean-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/pivotal-sepolia.json.zst b/src/Nethermind/Chains/pivotal-sepolia.json.zst index 457eeee0f749..4652ced5cba8 100644 Binary files a/src/Nethermind/Chains/pivotal-sepolia.json.zst and b/src/Nethermind/Chains/pivotal-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/polynomial-mainnet.json.zst b/src/Nethermind/Chains/polynomial-mainnet.json.zst index 38de4e507a15..aa4b1cf3b1c6 100644 Binary files a/src/Nethermind/Chains/polynomial-mainnet.json.zst and b/src/Nethermind/Chains/polynomial-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/race-mainnet.json.zst b/src/Nethermind/Chains/race-mainnet.json.zst index ac9c1856ddfa..aa60436ed34b 100644 Binary files a/src/Nethermind/Chains/race-mainnet.json.zst and b/src/Nethermind/Chains/race-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/race-sepolia.json.zst b/src/Nethermind/Chains/race-sepolia.json.zst index 9b1cdf012dbb..a847cf4129bc 100644 Binary files a/src/Nethermind/Chains/race-sepolia.json.zst and b/src/Nethermind/Chains/race-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/redstone-mainnet.json.zst b/src/Nethermind/Chains/redstone-mainnet.json.zst index e7ca96a6cc01..8ff28af177af 100644 Binary files a/src/Nethermind/Chains/redstone-mainnet.json.zst and b/src/Nethermind/Chains/redstone-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/settlus-mainnet-mainnet.json.zst b/src/Nethermind/Chains/settlus-mainnet-mainnet.json.zst index e6433f92b1d9..8cd588d51007 100644 Binary files a/src/Nethermind/Chains/settlus-mainnet-mainnet.json.zst and b/src/Nethermind/Chains/settlus-mainnet-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/settlus-sepolia-sepolia.json.zst b/src/Nethermind/Chains/settlus-sepolia-sepolia.json.zst index 1a3e94b1c9d1..9a2c8654e736 100644 Binary files a/src/Nethermind/Chains/settlus-sepolia-sepolia.json.zst and b/src/Nethermind/Chains/settlus-sepolia-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/shape-mainnet.json.zst b/src/Nethermind/Chains/shape-mainnet.json.zst index a0d2fb851847..7a1e27d2b3ac 100644 Binary files a/src/Nethermind/Chains/shape-mainnet.json.zst and b/src/Nethermind/Chains/shape-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/shape-sepolia.json.zst b/src/Nethermind/Chains/shape-sepolia.json.zst index 83fc7ea3d943..ade6b5df2c52 100644 Binary files a/src/Nethermind/Chains/shape-sepolia.json.zst and b/src/Nethermind/Chains/shape-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/snax-mainnet.json.zst b/src/Nethermind/Chains/snax-mainnet.json.zst index e003e16b078f..8ad945e99415 100644 Binary files a/src/Nethermind/Chains/snax-mainnet.json.zst and b/src/Nethermind/Chains/snax-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/soneium-mainnet.json.zst b/src/Nethermind/Chains/soneium-mainnet.json.zst index 101045bd9729..294f367fe33d 100644 Binary files a/src/Nethermind/Chains/soneium-mainnet.json.zst and b/src/Nethermind/Chains/soneium-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/soneium-minato-sepolia.json.zst b/src/Nethermind/Chains/soneium-minato-sepolia.json.zst index b27bf8936d32..e99be38792e3 100644 Binary files a/src/Nethermind/Chains/soneium-minato-sepolia.json.zst and b/src/Nethermind/Chains/soneium-minato-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/sseed-mainnet.json.zst b/src/Nethermind/Chains/sseed-mainnet.json.zst index 1b4631ce23a0..c8bb0b15d621 100644 Binary files a/src/Nethermind/Chains/sseed-mainnet.json.zst and b/src/Nethermind/Chains/sseed-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/swan-mainnet.json.zst b/src/Nethermind/Chains/swan-mainnet.json.zst index 12fee6b15512..1d2a3f1f8c52 100644 Binary files a/src/Nethermind/Chains/swan-mainnet.json.zst and b/src/Nethermind/Chains/swan-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/swell-mainnet.json.zst b/src/Nethermind/Chains/swell-mainnet.json.zst index 0aecfd71be14..ad42e1d7202a 100644 Binary files a/src/Nethermind/Chains/swell-mainnet.json.zst and b/src/Nethermind/Chains/swell-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/tbn-mainnet.json.zst b/src/Nethermind/Chains/tbn-mainnet.json.zst index c5a68a72f169..cf339f6bdedf 100644 Binary files a/src/Nethermind/Chains/tbn-mainnet.json.zst and b/src/Nethermind/Chains/tbn-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/tbn-sepolia.json.zst b/src/Nethermind/Chains/tbn-sepolia.json.zst index 129f99607809..b54801437f46 100644 Binary files a/src/Nethermind/Chains/tbn-sepolia.json.zst and b/src/Nethermind/Chains/tbn-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/unichain-mainnet.json.zst b/src/Nethermind/Chains/unichain-mainnet.json.zst index 2095634e15a3..07604c8c2067 100644 Binary files a/src/Nethermind/Chains/unichain-mainnet.json.zst and b/src/Nethermind/Chains/unichain-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/unichain-sepolia.json.zst b/src/Nethermind/Chains/unichain-sepolia.json.zst index 301c407b8531..4a2291427ef5 100644 Binary files a/src/Nethermind/Chains/unichain-sepolia.json.zst and b/src/Nethermind/Chains/unichain-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/worldchain-mainnet.json.zst b/src/Nethermind/Chains/worldchain-mainnet.json.zst index c5d391b9f48c..a566e64111bb 100644 Binary files a/src/Nethermind/Chains/worldchain-mainnet.json.zst and b/src/Nethermind/Chains/worldchain-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/worldchain-sepolia.json.zst b/src/Nethermind/Chains/worldchain-sepolia.json.zst index cbf0f2d87b13..e7439f335f93 100644 Binary files a/src/Nethermind/Chains/worldchain-sepolia.json.zst and b/src/Nethermind/Chains/worldchain-sepolia.json.zst differ diff --git a/src/Nethermind/Chains/xterio-eth-mainnet.json.zst b/src/Nethermind/Chains/xterio-eth-mainnet.json.zst index 2b1015e90d27..b36aabbac8ab 100644 Binary files a/src/Nethermind/Chains/xterio-eth-mainnet.json.zst and b/src/Nethermind/Chains/xterio-eth-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/zora-mainnet.json.zst b/src/Nethermind/Chains/zora-mainnet.json.zst index da176a17eaac..32e1ce5d75f3 100644 Binary files a/src/Nethermind/Chains/zora-mainnet.json.zst and b/src/Nethermind/Chains/zora-mainnet.json.zst differ diff --git a/src/Nethermind/Chains/zora-sepolia.json.zst b/src/Nethermind/Chains/zora-sepolia.json.zst index f397523dd780..715fe88f32de 100644 Binary files a/src/Nethermind/Chains/zora-sepolia.json.zst and b/src/Nethermind/Chains/zora-sepolia.json.zst differ diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs index 264bc859ca77..5e202049eaf8 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs index cdc20c50d11a..cc32ed244b0f 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs index b6be913b4c5d..3583300d49c2 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs index a650f3c79666..7579dc2ed9fc 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs index 62695ccc71fd..da29277f3419 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using FluentAssertions; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs index f1f952b6adde..9a7d2402270d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs index fae15df4b213..0b3c9a4a6417 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs index 6011d779adf7..fbf265a22a8d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs index eba45011cbb3..fc6bc1c07b95 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs index 44ec8d4041f5..0fec88659d02 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs index af62090dd9e9..4ad81bb85f3a 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs index a4daf560f351..fe0f84a61d36 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs index 6e8cafbada58..99231fdd948d 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs index 28326dea3909..874f6a40f6bb 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs index 097c9c8f658c..d9c6248b9404 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs index 2d273d715659..2e85ba8918d9 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Ethereum.Test.Base; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs index 5c75a9b80c63..b8e304a15167 100644 --- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs @@ -1,5 +1,7 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Collections.Generic; -using System.Linq; using Ethereum.Test.Base; using FluentAssertions; using NUnit.Framework; diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs index 6329281f660f..6916dd59eb53 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs @@ -20,6 +20,7 @@ public class BlockchainTest : EthereumTest public TestBlockJson[]? Blocks { get; set; } public TestBlockHeaderJson? GenesisBlockHeader { get; set; } + public TestEngineNewPayloadsJson[]? EngineNewPayloads { get; set; } public Dictionary? Pre { get; set; } public Dictionary? PostState { get; set; } diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index a842f6883a99..374f738ab79d 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -31,8 +31,11 @@ using Nethermind.Specs.Test; using Nethermind.Evm.State; using Nethermind.Init.Modules; -using Nethermind.TxPool; using NUnit.Framework; +using Nethermind.Merge.Plugin.Data; +using Nethermind.Merge.Plugin; +using Nethermind.JsonRpc; +using System.Reflection; namespace Ethereum.Test.Base; @@ -40,14 +43,12 @@ public abstract class BlockchainTestBase { private static readonly ILogger _logger; private static readonly ILogManager _logManager = new TestLogManager(LogLevel.Warn); - private static ISealValidator Sealer { get; } private static DifficultyCalculatorWrapper DifficultyCalculator { get; } + private const int _genesisProcessingTimeoutMs = 5000; static BlockchainTestBase() { DifficultyCalculator = new DifficultyCalculatorWrapper(); - Sealer = new EthashSealValidator(_logManager, DifficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default); // temporarily keep reusing the same one as otherwise it would recreate cache for each test - _logManager ??= LimboLogs.Instance; _logger = _logManager.GetClassLogger(); } @@ -83,8 +84,13 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? test.Network = ChainUtils.ResolveSpec(test.Network, test.ChainId); test.NetworkAfterTransition = ChainUtils.ResolveSpec(test.NetworkAfterTransition, test.ChainId); + bool isEngineTest = test.Blocks is null && test.EngineNewPayloads is not null; + List<(ForkActivation Activation, IReleaseSpec Spec)> transitions = + isEngineTest ? + [((ForkActivation)0, test.Network)] : [((ForkActivation)0, test.GenesisSpec), ((ForkActivation)1, test.Network)]; // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier + if (test.NetworkAfterTransition is not null) { transitions.Add((test.TransitionForkActivation!.Value, test.NetworkAfterTransition)); @@ -92,7 +98,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, transitions.ToArray()); - Assert.That(test.ChainId == GnosisSpecProvider.Instance.ChainId || specProvider.GenesisSpec == Frontier.Instance, "Expected genesis spec to be Frontier for blockchain tests"); + Assert.That(isEngineTest || test.ChainId == GnosisSpecProvider.Instance.ChainId || specProvider.GenesisSpec == Frontier.Instance, "Expected genesis spec to be Frontier for blockchain tests"); if (test.Network is Cancun || test.NetworkAfterTransition is Cancun) { @@ -122,18 +128,23 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? IConfigProvider configProvider = new ConfigProvider(); // configProvider.GetConfig().PreWarmStateOnBlockProcessing = false; - await using IContainer container = new ContainerBuilder() + ContainerBuilder containerBuilder = new ContainerBuilder() .AddModule(new TestNethermindModule(configProvider)) .AddSingleton(specProvider) .AddSingleton(_logManager) .AddSingleton(rewardCalculator) - .AddSingleton(DifficultyCalculator) - .AddSingleton(NullTxPool.Instance) - .Build(); + .AddSingleton(DifficultyCalculator); + + if (isEngineTest) + { + containerBuilder.AddModule(new TestMergeModule(configProvider)); + } + + await using IContainer container = containerBuilder.Build(); IMainProcessingContext mainBlockProcessingContext = container.Resolve(); IWorldState stateProvider = mainBlockProcessingContext.WorldState; - IBlockchainProcessor blockchainProcessor = mainBlockProcessingContext.BlockchainProcessor; + BlockchainProcessor blockchainProcessor = (BlockchainProcessor)mainBlockProcessingContext.BlockchainProcessor; IBlockTree blockTree = container.Resolve(); IBlockValidator blockValidator = container.Resolve(); blockchainProcessor.Start(); @@ -165,102 +176,66 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? { if (args.Block.Number == 0) { - Assert.That(stateProvider.HasStateForBlock(genesisBlock.Header), Is.EqualTo(true)); + Assert.That(stateProvider.HasStateForBlock(genesisBlock.Header), Is.True); + genesisProcessed.Set(); + } + }; + + blockchainProcessor.BlockRemoved += (_, args) => + { + if (args.ProcessingResult != ProcessingResult.Success && args.BlockHash == genesisBlock.Header.Hash) + { + Assert.Fail($"Failed to process genesis block: {args.Exception}"); genesisProcessed.Set(); } }; blockTree.SuggestBlock(genesisBlock); - genesisProcessed.WaitOne(); + genesisProcessed.WaitOne(_genesisProcessingTimeoutMs); parentHeader = genesisBlock.Header; // Dispose genesis block's AccountChanges genesisBlock.DisposeAccountChanges(); } - List<(Block Block, string ExpectedException)> correctRlp = DecodeRlps(test, failOnInvalidRlp); - for (int i = 0; i < correctRlp.Count; i++) + if (test.Blocks is not null) { - // Mimic the actual behaviour where block goes through validating sync manager - correctRlp[i].Block.Header.IsPostMerge = correctRlp[i].Block.Difficulty == 0; - - // For tests with reorgs, find the actual parent header from block tree - parentHeader = blockTree.FindHeader(correctRlp[i].Block.ParentHash) ?? parentHeader; - - Assert.That(correctRlp[i].Block.Hash is not null, $"null hash in {test.Name} block {i}"); - - bool expectsException = correctRlp[i].ExpectedException is not null; - // Validate block structure first (mimics SyncServer validation) - if (blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, parentHeader, out string? validationError)) - { - Assert.That(!expectsException, $"Expected block {correctRlp[i].Block.Hash} to fail with '{correctRlp[i].ExpectedException}', but it passed validation"); - try - { - // All validations passed, suggest the block - blockTree.SuggestBlock(correctRlp[i].Block); - - } - catch (InvalidBlockException e) - { - // Exception thrown during block processing - Assert.That(expectsException, $"Unexpected invalid block {correctRlp[i].Block.Hash}: {validationError}, Exception: {e}"); - // else: Expected to fail and did fail via exception → this is correct behavior - } - catch (Exception e) - { - Assert.Fail($"Unexpected exception during processing: {e}"); - } - finally - { - // Dispose AccountChanges to prevent memory leaks in tests - correctRlp[i].Block.DisposeAccountChanges(); - } - } - - try - { - // Validate block structure first (mimics SyncServer validation) - if (blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, parentHeader, out var validationError)) - { - // All validations passed, suggest the block - blockTree.SuggestBlock(correctRlp[i].Block); - } - else - { - if (correctRlp[i].ExpectedException is not null) - { - Assert.Fail($"Unexpected invalid block {correctRlp[i].Block.Hash}: {validationError}"); - } - } - } - catch (InvalidBlockException e) - { - // Validation FAILED - Assert.That(expectsException, $"Unexpected invalid block {correctRlp[i].Block.Hash}: {validationError}"); - // else: Expected to fail and did fail → this is correct behavior - } - - parentHeader = correctRlp[i].Block.Header; + // blockchain test + parentHeader = SuggestBlocks(test, failOnInvalidRlp, blockValidator, blockTree, parentHeader); + } + else if (test.EngineNewPayloads is not null) + { + // engine test + IEngineRpcModule engineRpcModule = container.Resolve(); + await RunNewPayloads(test.EngineNewPayloads, engineRpcModule); + } + else + { + Assert.Fail("Invalid blockchain test, did not contain blocks or new payloads."); } // NOTE: Tracer removal must happen AFTER StopAsync to ensure all blocks are traced // Blocks are queued asynchronously, so we need to wait for processing to complete await blockchainProcessor.StopAsync(true); - stopwatch?.Stop(); IBlockCachePreWarmer? preWarmer = container.Resolve().LifetimeScope.ResolveOptional(); - if (preWarmer is not null) + + // Caches are cleared async, which is a problem as read for the MainWorldState with prewarmer is not correct if its not cleared. + preWarmer?.ClearCaches(); + + Block? headBlock = blockTree.RetrieveHeadBlock(); + + Assert.That(headBlock, Is.Not.Null); + if (headBlock is null) { - // Caches are cleared async, which is a problem as read for the MainWorldState with prewarmer is not correct if its not cleared. - preWarmer.ClearCaches(); + return new EthereumTestResult(test.Name, null, false); } - Block? headBlock = blockTree.RetrieveHeadBlock(); List differences; using (stateProvider.BeginScope(headBlock.Header)) { - differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), stateProvider); + differences = RunAssertions(test, headBlock, stateProvider); } bool testPassed = differences.Count == 0; @@ -273,14 +248,8 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? blockchainProcessor.Tracers.Remove(tracer); } - Assert.That(differences.Count, Is.Zero, "differences"); - - return new EthereumTestResult - ( - test.Name, - null, - testPassed - ); + Assert.That(differences, Is.Empty, "differences"); + return new EthereumTestResult(test.Name, null, testPassed); } catch (Exception) { @@ -289,9 +258,93 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? } } - private List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp) + private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalidRlp, IBlockValidator blockValidator, IBlockTree blockTree, BlockHeader parentHeader) + { + List<(Block Block, string ExpectedException)> correctRlp = DecodeRlps(test, failOnInvalidRlp); + for (int i = 0; i < correctRlp.Count; i++) + { + // Mimic the actual behaviour where block goes through validating sync manager + correctRlp[i].Block.Header.IsPostMerge = correctRlp[i].Block.Difficulty == 0; + + // For tests with reorgs, find the actual parent header from block tree + parentHeader = blockTree.FindHeader(correctRlp[i].Block.ParentHash) ?? parentHeader; + + Assert.That(correctRlp[i].Block.Hash, Is.Not.Null, $"null hash in {test.Name} block {i}"); + + bool expectsException = correctRlp[i].ExpectedException is not null; + // Validate block structure first (mimics SyncServer validation) + if (blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, parentHeader, out string? validationError)) + { + Assert.That(!expectsException, $"Expected block {correctRlp[i].Block.Hash} to fail with '{correctRlp[i].ExpectedException}', but it passed validation"); + try + { + // All validations passed, suggest the block + blockTree.SuggestBlock(correctRlp[i].Block); + + } + catch (InvalidBlockException e) + { + // Exception thrown during block processing + Assert.That(expectsException, $"Unexpected invalid block {correctRlp[i].Block.Hash}: {validationError}, Exception: {e}"); + // else: Expected to fail and did fail via exception → this is correct behavior + } + catch (Exception e) + { + Assert.Fail($"Unexpected exception during processing: {e}"); + } + finally + { + // Dispose AccountChanges to prevent memory leaks in tests + correctRlp[i].Block.DisposeAccountChanges(); + } + } + else + { + // Validation FAILED + Assert.That(expectsException, $"Unexpected invalid block {correctRlp[i].Block.Hash}: {validationError}"); + // else: Expected to fail and did fail → this is correct behavior + } + + parentHeader = correctRlp[i].Block.Header; + } + return parentHeader; + } + + private async static Task RunNewPayloads(TestEngineNewPayloadsJson[]? newPayloads, IEngineRpcModule engineRpcModule) { - List<(Block Block, string ExpectedException)> correctRlp = new(); + (ExecutionPayloadV3, string[]?, string[]?, int, int)[] payloads = [.. JsonToEthereumTest.Convert(newPayloads)]; + + // blockchain test engine + foreach ((ExecutionPayload executionPayload, string[]? blobVersionedHashes, string[]? validationError, int newPayloadVersion, int fcuVersion) in payloads) + { + ResultWrapper res; + byte[]?[] hashes = blobVersionedHashes is null ? [] : [.. blobVersionedHashes.Select(x => Bytes.FromHexString(x))]; + + MethodInfo newPayloadMethod = engineRpcModule.GetType().GetMethod($"engine_newPayloadV{newPayloadVersion}"); + List newPayloadParams = [executionPayload]; + if (newPayloadVersion >= 3) + { + newPayloadParams.AddRange([hashes, executionPayload.ParentBeaconBlockRoot]); + } + if (newPayloadVersion >= 4) + { + newPayloadParams.Add(executionPayload.ExecutionRequests); + } + + res = await (Task>)newPayloadMethod.Invoke(engineRpcModule, [.. newPayloadParams]); + + if (res.Result.ResultType == ResultType.Success) + { + ForkchoiceStateV1 fcuState = new(executionPayload.BlockHash, executionPayload.BlockHash, executionPayload.BlockHash); + MethodInfo fcuMethod = engineRpcModule.GetType().GetMethod($"engine_forkchoiceUpdatedV{fcuVersion}"); + await (Task>)fcuMethod.Invoke(engineRpcModule, [fcuState, null]); + } + } + } + + private static List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp) + { + List<(Block Block, string ExpectedException)> correctRlp = []; for (int i = 0; i < test.Blocks!.Length; i++) { TestBlockJson testBlockJson = test.Blocks[i]; @@ -299,6 +352,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? { RlpStream rlpContext = Bytes.FromHexString(testBlockJson.Rlp!).AsRlpStream(); Block suggestedBlock = Rlp.Decode(rlpContext); + if (testBlockJson.BlockHeader is not null) { Assert.That(suggestedBlock.Header.Hash, Is.EqualTo(new Hash256(testBlockJson.BlockHeader.Hash))); @@ -330,8 +384,11 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? if (correctRlp.Count == 0) { - Assert.That(test.GenesisBlockHeader, Is.Not.Null); - Assert.That(test.LastBlockHash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); + using (Assert.EnterMultipleScope()) + { + Assert.That(test.GenesisBlockHeader, Is.Not.Null); + Assert.That(test.LastBlockHash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); + } } return correctRlp; @@ -340,7 +397,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? private static void InitializeTestState(BlockchainTest test, IWorldState stateProvider, ISpecProvider specProvider) { foreach (KeyValuePair accountState in - ((IEnumerable>)test.Pre ?? Array.Empty>())) + (IEnumerable>)test.Pre ?? Array.Empty>()) { foreach (KeyValuePair storageItem in accountState.Value.Storage) { @@ -356,18 +413,14 @@ private static void InitializeTestState(BlockchainTest test, IWorldState statePr stateProvider.Reset(); } - private List RunAssertions(BlockchainTest test, Block headBlock, IWorldState stateProvider) + private static List RunAssertions(BlockchainTest test, Block headBlock, IWorldState stateProvider) { if (test.PostStateRoot is not null) { return test.PostStateRoot != stateProvider.StateRoot ? ["state root mismatch"] : Enumerable.Empty().ToList(); } - TestBlockHeaderJson testHeaderJson = (test.Blocks? - .Where(b => b.BlockHeader is not null) - .SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader) ?? test.GenesisBlockHeader; - BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson); - List differences = new(); + List differences = []; IEnumerable> deletedAccounts = test.Pre? .Where(pre => !(test.PostState?.ContainsKey(pre.Key) ?? false)) ?? Array.Empty>(); @@ -380,7 +433,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS } } - foreach ((Address acountAddress, AccountState accountState) in test.PostState!) + foreach ((Address accountAddress, AccountState accountState) in test.PostState!) { int differencesBefore = differences.Count; @@ -390,87 +443,96 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS break; } - bool accountExists = stateProvider.AccountExists(acountAddress); - UInt256? balance = accountExists ? stateProvider.GetBalance(acountAddress) : null; - UInt256? nonce = accountExists ? stateProvider.GetNonce(acountAddress) : null; + bool accountExists = stateProvider.AccountExists(accountAddress); + UInt256? balance = accountExists ? stateProvider.GetBalance(accountAddress) : null; + UInt256? nonce = accountExists ? stateProvider.GetNonce(accountAddress) : null; if (accountState.Balance != balance) { - differences.Add($"{acountAddress} balance exp: {accountState.Balance}, actual: {balance}, diff: {(balance > accountState.Balance ? balance - accountState.Balance : accountState.Balance - balance)}"); + differences.Add($"{accountAddress} balance exp: {accountState.Balance}, actual: {balance}, diff: {(balance > accountState.Balance ? balance - accountState.Balance : accountState.Balance - balance)}"); } if (accountState.Nonce != nonce) { - differences.Add($"{acountAddress} nonce exp: {accountState.Nonce}, actual: {nonce}"); + differences.Add($"{accountAddress} nonce exp: {accountState.Nonce}, actual: {nonce}"); } - byte[] code = accountExists ? stateProvider.GetCode(acountAddress) : []; + byte[] code = accountExists ? stateProvider.GetCode(accountAddress) : []; if (!Bytes.AreEqual(accountState.Code, code)) { - differences.Add($"{acountAddress} code exp: {accountState.Code?.Length}, actual: {code?.Length}"); + differences.Add($"{accountAddress} code exp: {accountState.Code?.Length}, actual: {code?.Length}"); } if (differences.Count != differencesBefore) { - _logger.Info($"ACCOUNT STATE ({acountAddress}) HAS DIFFERENCES"); + _logger.Info($"ACCOUNT STATE ({accountAddress}) HAS DIFFERENCES"); } differencesBefore = differences.Count; KeyValuePair[] clearedStorages = []; - if (test.Pre.TryGetValue(acountAddress, out AccountState? state)) + if (test.Pre.ContainsKey(accountAddress)) { - clearedStorages = state.Storage.Where(s => !accountState.Storage.ContainsKey(s.Key)).ToArray(); + clearedStorages = [.. test.Pre[accountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key))]; } foreach (KeyValuePair clearedStorage in clearedStorages) { - ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key)); + ReadOnlySpan value = !stateProvider.AccountExists(accountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(accountAddress, clearedStorage.Key)); if (!value.IsZero()) { - differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}"); + differences.Add($"{accountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}"); } } foreach (KeyValuePair storageItem in accountState.Storage) { - ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)); + ReadOnlySpan value = !stateProvider.AccountExists(accountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(accountAddress, storageItem.Key)); if (!Bytes.AreEqual(storageItem.Value, value)) { - differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}"); + differences.Add($"{accountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}"); } } if (differences.Count != differencesBefore) { - _logger.Info($"ACCOUNT STORAGE ({acountAddress}) HAS DIFFERENCES"); + _logger.Info($"ACCOUNT STORAGE ({accountAddress}) HAS DIFFERENCES"); } } - BigInteger gasUsed = headBlock.Header.GasUsed; - if ((testHeader?.GasUsed ?? 0) != gasUsed) - { - differences.Add($"GAS USED exp: {testHeader?.GasUsed ?? 0}, actual: {gasUsed}"); - } + TestBlockHeaderJson? testHeaderJson = test.Blocks? + .Where(b => b.BlockHeader is not null) + .SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader; - if (headBlock.Transactions.Any() && testHeader.Bloom.ToString() != headBlock.Header.Bloom.ToString()) + if (testHeaderJson is not null) { - differences.Add($"BLOOM exp: {testHeader.Bloom}, actual: {headBlock.Header.Bloom}"); - } + BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson); - if (testHeader.StateRoot != stateProvider.StateRoot) - { - differences.Add($"STATE ROOT exp: {testHeader.StateRoot}, actual: {stateProvider.StateRoot}"); - } + BigInteger gasUsed = headBlock.Header.GasUsed; + if ((testHeader?.GasUsed ?? 0) != gasUsed) + { + differences.Add($"GAS USED exp: {testHeader?.GasUsed ?? 0}, actual: {gasUsed}"); + } - if (testHeader.TxRoot != headBlock.Header.TxRoot) - { - differences.Add($"TRANSACTIONS ROOT exp: {testHeader.TxRoot}, actual: {headBlock.Header.TxRoot}"); - } + if (headBlock.Transactions.Length != 0 && testHeader.Bloom.ToString() != headBlock.Header.Bloom.ToString()) + { + differences.Add($"BLOOM exp: {testHeader.Bloom}, actual: {headBlock.Header.Bloom}"); + } - if (testHeader.ReceiptsRoot != headBlock.Header.ReceiptsRoot) - { - differences.Add($"RECEIPT ROOT exp: {testHeader.ReceiptsRoot}, actual: {headBlock.Header.ReceiptsRoot}"); + if (testHeader.StateRoot != stateProvider.StateRoot) + { + differences.Add($"STATE ROOT exp: {testHeader.StateRoot}, actual: {stateProvider.StateRoot}"); + } + + if (testHeader.TxRoot != headBlock.Header.TxRoot) + { + differences.Add($"TRANSACTIONS ROOT exp: {testHeader.TxRoot}, actual: {headBlock.Header.TxRoot}"); + } + + if (testHeader.ReceiptsRoot != headBlock.Header.ReceiptsRoot) + { + differences.Add($"RECEIPT ROOT exp: {testHeader.ReceiptsRoot}, actual: {headBlock.Header.ReceiptsRoot}"); + } } if (test.LastBlockHash != headBlock.Hash) diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs index fdd03858fd8c..c344cd773da7 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs @@ -24,6 +24,7 @@ public class BlockchainTestJson public TestBlockJson[]? Blocks { get; set; } public TestBlockHeaderJson? GenesisBlockHeader { get; set; } + public TestEngineNewPayloadsJson[]? EngineNewPayloads { get; set; } public Dictionary? Pre { get; set; } public Dictionary? PostState { get; set; } diff --git a/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs b/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs index 3e85b70087f4..67b713e570ed 100644 --- a/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs +++ b/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs @@ -9,16 +9,10 @@ namespace Ethereum.Test.Base { - public class FileTestsSource + public class FileTestsSource(string fileName, string? wildcard = null) { - private readonly string _fileName; - private readonly string? _wildcard; - - public FileTestsSource(string fileName, string? wildcard = null) - { - _fileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); - _wildcard = wildcard; - } + private readonly string _fileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); + private readonly string? _wildcard = wildcard; public IEnumerable LoadTests(TestType testType) { diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs index b9aa74da334a..39dbc1517905 100644 --- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using Autofac; -using Nethermind.Api; using Nethermind.Config; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Validators; @@ -100,17 +99,19 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer) test.CurrentNumber, test.CurrentGasLimit, test.CurrentTimestamp, - []); - header.BaseFeePerGas = test.Fork.IsEip1559Enabled ? test.CurrentBaseFee ?? _defaultBaseFeeForStateTest : UInt256.Zero; - header.StateRoot = test.PostHash; + []) + { + BaseFeePerGas = test.Fork.IsEip1559Enabled ? test.CurrentBaseFee ?? _defaultBaseFeeForStateTest : UInt256.Zero, + StateRoot = test.PostHash, + IsPostMerge = test.CurrentRandom is not null, + MixHash = test.CurrentRandom, + WithdrawalsRoot = test.CurrentWithdrawalsRoot, + ParentBeaconBlockRoot = test.CurrentBeaconRoot, + ExcessBlobGas = test.CurrentExcessBlobGas ?? (test.Fork is Cancun ? 0ul : null), + BlobGasUsed = BlobGasCalculator.CalculateBlobGas(test.Transaction), + RequestsHash = test.RequestsHash + }; header.Hash = header.CalculateHash(); - header.IsPostMerge = test.CurrentRandom is not null; - header.MixHash = test.CurrentRandom; - header.WithdrawalsRoot = test.CurrentWithdrawalsRoot; - header.ParentBeaconBlockRoot = test.CurrentBeaconRoot; - header.ExcessBlobGas = test.CurrentExcessBlobGas ?? (test.Fork is Cancun ? 0ul : null); - header.BlobGasUsed = BlobGasCalculator.CalculateBlobGas(test.Transaction); - header.RequestsHash = test.RequestsHash; Stopwatch stopwatch = Stopwatch.StartNew(); IReleaseSpec? spec = specProvider.GetSpec((ForkActivation)test.CurrentNumber); @@ -161,9 +162,11 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer) } List differences = RunAssertions(test, stateProvider); - EthereumTestResult testResult = new(test.Name, test.ForkName, differences.Count == 0); - testResult.TimeInMs = stopwatch.Elapsed.TotalMilliseconds; - testResult.StateRoot = stateProvider.StateRoot; + EthereumTestResult testResult = new(test.Name, test.ForkName, differences.Count == 0) + { + TimeInMs = stopwatch.Elapsed.TotalMilliseconds, + StateRoot = stateProvider.StateRoot + }; if (differences.Count > 0) { diff --git a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs index 9a09b17017c1..36b05b9fb0ea 100644 --- a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs +++ b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json; using Nethermind.Config; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -14,6 +15,7 @@ using Nethermind.Crypto; using Nethermind.Evm.EvmObjectFormat; using Nethermind.Int256; +using Nethermind.Merge.Plugin.Data; using Nethermind.Serialization.Json; using Nethermind.Serialization.Rlp; using Nethermind.Specs; @@ -56,36 +58,89 @@ public static BlockHeader Convert(TestBlockHeaderJson? headerJson) (long)Bytes.FromHexString(headerJson.Number).ToUInt256(), (long)Bytes.FromHexString(headerJson.GasLimit).ToUnsignedBigInteger(), (ulong)Bytes.FromHexString(headerJson.Timestamp).ToUnsignedBigInteger(), - Bytes.FromHexString(headerJson.ExtraData) - ); - - header.Bloom = new Bloom(Bytes.FromHexString(headerJson.Bloom)); - header.GasUsed = (long)Bytes.FromHexString(headerJson.GasUsed).ToUnsignedBigInteger(); - header.Hash = new Hash256(headerJson.Hash); - header.MixHash = new Hash256(headerJson.MixHash); - header.Nonce = (ulong)Bytes.FromHexString(headerJson.Nonce).ToUnsignedBigInteger(); - header.ReceiptsRoot = new Hash256(headerJson.ReceiptTrie); - header.StateRoot = new Hash256(headerJson.StateRoot); - header.TxRoot = new Hash256(headerJson.TransactionsTrie); + Bytes.FromHexString(headerJson.ExtraData), + headerJson.BlobGasUsed is null ? null : (ulong)Bytes.FromHexString(headerJson.BlobGasUsed).ToUnsignedBigInteger(), + headerJson.ExcessBlobGas is null ? null : (ulong)Bytes.FromHexString(headerJson.ExcessBlobGas).ToUnsignedBigInteger(), + headerJson.ParentBeaconBlockRoot is null ? null : new Hash256(headerJson.ParentBeaconBlockRoot), + headerJson.RequestsHash is null ? null : new Hash256(headerJson.RequestsHash) + ) + { + Bloom = new Bloom(Bytes.FromHexString(headerJson.Bloom)), + GasUsed = (long)Bytes.FromHexString(headerJson.GasUsed).ToUnsignedBigInteger(), + Hash = new Hash256(headerJson.Hash), + MixHash = new Hash256(headerJson.MixHash), + Nonce = (ulong)Bytes.FromHexString(headerJson.Nonce).ToUnsignedBigInteger(), + ReceiptsRoot = new Hash256(headerJson.ReceiptTrie), + StateRoot = new Hash256(headerJson.StateRoot), + TxRoot = new Hash256(headerJson.TransactionsTrie), + WithdrawalsRoot = headerJson.WithdrawalsRoot is null ? null : new Hash256(headerJson.WithdrawalsRoot), + // BlockAccessListHash = headerJson.BlockAccessListHash is null ? null : new Hash256(headerJson.BlockAccessListHash), + }; + + if (headerJson.BaseFeePerGas is not null) + { + header.BaseFeePerGas = (ulong)Bytes.FromHexString(headerJson.BaseFeePerGas).ToUnsignedBigInteger(); + } + return header; } + public static IEnumerable<(ExecutionPayloadV3, string[]?, string[]?, int, int)> Convert(TestEngineNewPayloadsJson[]? executionPayloadsJson) + { + if (executionPayloadsJson is null) + { + throw new InvalidDataException("Execution payloads JSON was null when constructing test."); + } + + foreach (TestEngineNewPayloadsJson engineNewPayload in executionPayloadsJson) + { + TestEngineNewPayloadsJson.ParamsExecutionPayload executionPayload = engineNewPayload.Params[0].Deserialize(EthereumJsonSerializer.JsonOptions); + string[]? blobVersionedHashes = engineNewPayload.Params.Length > 1 ? engineNewPayload.Params[1].Deserialize(EthereumJsonSerializer.JsonOptions) : null; + string? parentBeaconBlockRoot = engineNewPayload.Params.Length > 2 ? engineNewPayload.Params[2].Deserialize(EthereumJsonSerializer.JsonOptions) : null; + string[]? validationError = engineNewPayload.Params.Length > 3 ? engineNewPayload.Params[3].Deserialize(EthereumJsonSerializer.JsonOptions) : null; + yield return (new ExecutionPayloadV3() + { + BaseFeePerGas = (ulong)Bytes.FromHexString(executionPayload.BaseFeePerGas).ToUnsignedBigInteger(), + BlockHash = new(executionPayload.BlockHash), + BlockNumber = (long)Bytes.FromHexString(executionPayload.BlockNumber).ToUnsignedBigInteger(), + ExtraData = Bytes.FromHexString(executionPayload.ExtraData), + FeeRecipient = new(executionPayload.FeeRecipient), + GasLimit = (long)Bytes.FromHexString(executionPayload.GasLimit).ToUnsignedBigInteger(), + GasUsed = (long)Bytes.FromHexString(executionPayload.GasUsed).ToUnsignedBigInteger(), + LogsBloom = new(Bytes.FromHexString(executionPayload.LogsBloom)), + ParentHash = new(executionPayload.ParentHash), + PrevRandao = new(executionPayload.PrevRandao), + ReceiptsRoot = new(executionPayload.ReceiptsRoot), + StateRoot = new(executionPayload.StateRoot), + Timestamp = (ulong)Bytes.FromHexString(executionPayload.Timestamp).ToUnsignedBigInteger(), + // BlockAccessList = executionPayload.BlockAccessList is null ? null : Bytes.FromHexString(executionPayload.BlockAccessList), + BlobGasUsed = executionPayload.BlobGasUsed is null ? null : (ulong)Bytes.FromHexString(executionPayload.BlobGasUsed).ToUnsignedBigInteger(), + ExcessBlobGas = executionPayload.ExcessBlobGas is null ? null : (ulong)Bytes.FromHexString(executionPayload.ExcessBlobGas).ToUnsignedBigInteger(), + ParentBeaconBlockRoot = parentBeaconBlockRoot is null ? null : new(parentBeaconBlockRoot), + Withdrawals = executionPayload.Withdrawals is null ? null : [.. executionPayload.Withdrawals.Select(x => Rlp.Decode(Bytes.FromHexString(x)))], + Transactions = [.. executionPayload.Transactions.Select(x => Bytes.FromHexString(x))], + ExecutionRequests = [] + }, blobVersionedHashes, validationError, int.Parse(engineNewPayload.NewPayloadVersion ?? "4"), int.Parse(engineNewPayload.ForkChoiceUpdatedVersion ?? "3")); + } + } + public static Transaction Convert(PostStateJson postStateJson, TransactionJson transactionJson) { - Transaction transaction = new(); - - transaction.Type = transactionJson.Type; - transaction.Value = transactionJson.Value[postStateJson.Indexes.Value]; - transaction.GasLimit = transactionJson.GasLimit[postStateJson.Indexes.Gas]; - transaction.GasPrice = transactionJson.GasPrice ?? transactionJson.MaxPriorityFeePerGas ?? 0; - transaction.DecodedMaxFeePerGas = transactionJson.MaxFeePerGas ?? 0; - transaction.Nonce = transactionJson.Nonce; - transaction.To = transactionJson.To; - transaction.Data = transactionJson.Data[postStateJson.Indexes.Data]; - transaction.SenderAddress = new PrivateKey(transactionJson.SecretKey).Address; - transaction.Signature = new Signature(1, 1, 27); - transaction.BlobVersionedHashes = transactionJson.BlobVersionedHashes; - transaction.MaxFeePerBlobGas = transactionJson.MaxFeePerBlobGas; + Transaction transaction = new() + { + Type = transactionJson.Type, + Value = transactionJson.Value[postStateJson.Indexes.Value], + GasLimit = transactionJson.GasLimit[postStateJson.Indexes.Gas], + GasPrice = transactionJson.GasPrice ?? transactionJson.MaxPriorityFeePerGas ?? 0, + DecodedMaxFeePerGas = transactionJson.MaxFeePerGas ?? 0, + Nonce = transactionJson.Nonce, + To = transactionJson.To, + Data = transactionJson.Data[postStateJson.Indexes.Data], + SenderAddress = new PrivateKey(transactionJson.SecretKey).Address, + Signature = new Signature(1, 1, 27), + BlobVersionedHashes = transactionJson.BlobVersionedHashes, + MaxFeePerBlobGas = transactionJson.MaxFeePerBlobGas + }; transaction.Hash = transaction.CalculateHash(); AccessList.Builder builder = new(); @@ -108,7 +163,7 @@ public static Transaction Convert(PostStateJson postStateJson, TransactionJson t if (transactionJson.AuthorizationList is not null) { transaction.AuthorizationList = - transactionJson.AuthorizationList + [.. transactionJson.AuthorizationList .Select(i => { if (i.Nonce > ulong.MaxValue) @@ -148,7 +203,7 @@ public static Transaction Convert(PostStateJson postStateJson, TransactionJson t (byte)i.V, r, s); - }).ToArray(); + })]; if (transaction.AuthorizationList.Any()) { transaction.Type = TxType.SetCode; @@ -172,14 +227,16 @@ public static void ProcessAccessList(AccessListItemJson[]? accessList, AccessLis public static Transaction Convert(LegacyTransactionJson transactionJson) { - Transaction transaction = new(); - transaction.Value = transactionJson.Value; - transaction.GasLimit = transactionJson.GasLimit; - transaction.GasPrice = transactionJson.GasPrice; - transaction.Nonce = transactionJson.Nonce; - transaction.To = transactionJson.To; - transaction.Data = transactionJson.Data; - transaction.Signature = new Signature(transactionJson.R, transactionJson.S, transactionJson.V); + Transaction transaction = new() + { + Value = transactionJson.Value, + GasLimit = transactionJson.GasLimit, + GasPrice = transactionJson.GasPrice, + Nonce = transactionJson.Nonce, + To = transactionJson.To, + Data = transactionJson.Data, + Signature = new Signature(transactionJson.R, transactionJson.S, transactionJson.V) + }; transaction.Hash = transaction.CalculateHash(); return transaction; } @@ -191,41 +248,42 @@ public static IEnumerable Convert(string name, string category return Enumerable.Repeat(new GeneralStateTest { Name = name, Category = category, LoadFailure = testJson.LoadFailure }, 1); } - List blockchainTests = new(); + List blockchainTests = []; foreach (KeyValuePair postStateBySpec in testJson.Post) { int iterationNumber = 0; foreach (PostStateJson stateJson in postStateBySpec.Value) { - GeneralStateTest test = new(); - test.Name = Path.GetFileName(name) + - $"_d{stateJson.Indexes.Data}g{stateJson.Indexes.Gas}v{stateJson.Indexes.Value}_"; + GeneralStateTest test = new() + { + Name = Path.GetFileName(name) + + $"_d{stateJson.Indexes.Data}g{stateJson.Indexes.Gas}v{stateJson.Indexes.Value}_", + Category = category, + ForkName = postStateBySpec.Key, + Fork = SpecNameParser.Parse(postStateBySpec.Key), + PreviousHash = testJson.Env.PreviousHash, + CurrentCoinbase = testJson.Env.CurrentCoinbase, + CurrentDifficulty = testJson.Env.CurrentDifficulty, + CurrentGasLimit = testJson.Env.CurrentGasLimit, + CurrentNumber = testJson.Env.CurrentNumber, + CurrentTimestamp = testJson.Env.CurrentTimestamp, + CurrentBaseFee = testJson.Env.CurrentBaseFee, + CurrentRandom = testJson.Env.CurrentRandom, + CurrentBeaconRoot = testJson.Env.CurrentBeaconRoot, + CurrentWithdrawalsRoot = testJson.Env.CurrentWithdrawalsRoot, + CurrentExcessBlobGas = testJson.Env.CurrentExcessBlobGas, + ParentBlobGasUsed = testJson.Env.ParentBlobGasUsed, + ParentExcessBlobGas = testJson.Env.ParentExcessBlobGas, + PostReceiptsRoot = stateJson.Logs, + PostHash = stateJson.Hash, + Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value), + Transaction = Convert(stateJson, testJson.Transaction) + }; + if (testJson.Info?.Labels?.ContainsKey(iterationNumber.ToString()) ?? false) { test.Name += testJson.Info?.Labels?[iterationNumber.ToString()]?.Replace(":label ", string.Empty); } - test.Category = category; - - test.ForkName = postStateBySpec.Key; - test.Fork = SpecNameParser.Parse(postStateBySpec.Key); - test.PreviousHash = testJson.Env.PreviousHash; - test.CurrentCoinbase = testJson.Env.CurrentCoinbase; - test.CurrentDifficulty = testJson.Env.CurrentDifficulty; - test.CurrentGasLimit = testJson.Env.CurrentGasLimit; - test.CurrentNumber = testJson.Env.CurrentNumber; - test.CurrentTimestamp = testJson.Env.CurrentTimestamp; - test.CurrentBaseFee = testJson.Env.CurrentBaseFee; - test.CurrentRandom = testJson.Env.CurrentRandom; - test.CurrentBeaconRoot = testJson.Env.CurrentBeaconRoot; - test.CurrentWithdrawalsRoot = testJson.Env.CurrentWithdrawalsRoot; - test.CurrentExcessBlobGas = testJson.Env.CurrentExcessBlobGas; - test.ParentBlobGasUsed = testJson.Env.ParentBlobGasUsed; - test.ParentExcessBlobGas = testJson.Env.ParentExcessBlobGas; - test.PostReceiptsRoot = stateJson.Logs; - test.PostHash = stateJson.Hash; - test.Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value); - test.Transaction = Convert(stateJson, testJson.Transaction); - blockchainTests.Add(test); ++iterationNumber; } @@ -241,17 +299,20 @@ public static BlockchainTest Convert(string name, string category, BlockchainTes return new BlockchainTest { Name = name, Category = category, LoadFailure = testJson.LoadFailure }; } - BlockchainTest test = new(); - test.Name = name; - test.Category = category; - test.Network = testJson.EthereumNetwork; - test.NetworkAfterTransition = testJson.EthereumNetworkAfterTransition; - test.TransitionForkActivation = testJson.TransitionForkActivation; - test.LastBlockHash = new Hash256(testJson.LastBlockHash); - test.GenesisRlp = testJson.GenesisRlp is null ? null : new Rlp(Bytes.FromHexString(testJson.GenesisRlp)); - test.GenesisBlockHeader = testJson.GenesisBlockHeader; - test.Blocks = testJson.Blocks; - test.Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value); + BlockchainTest test = new() + { + Name = name, + Category = category, + Network = testJson.EthereumNetwork, + NetworkAfterTransition = testJson.EthereumNetworkAfterTransition, + TransitionForkActivation = testJson.TransitionForkActivation, + LastBlockHash = new Hash256(testJson.LastBlockHash), + GenesisRlp = testJson.GenesisRlp is null ? null : new Rlp(Bytes.FromHexString(testJson.GenesisRlp)), + GenesisBlockHeader = testJson.GenesisBlockHeader, + Blocks = testJson.Blocks, + EngineNewPayloads = testJson.EngineNewPayloads, + Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value) + }; HalfBlockchainTestJson half = testJson as HalfBlockchainTestJson; if (half is not null) @@ -272,7 +333,7 @@ public static BlockchainTest Convert(string name, string category, BlockchainTes public static IEnumerable ConvertToEofTests(string json) { Dictionary testsInFile = _serializer.Deserialize>(json); - List tests = new(); + List tests = []; foreach (KeyValuePair namedTest in testsInFile) { (string name, string category) = GetNameAndCategory(namedTest.Key); @@ -281,11 +342,13 @@ public static IEnumerable ConvertToEofTests(string json) foreach (KeyValuePair pair in namedTest.Value.Vectors) { VectorTestJson vectorJson = pair.Value; - VectorTest vector = new(); - vector.Code = Bytes.FromHexString(vectorJson.Code); - vector.ContainerKind = ParseContainerKind(vectorJson.ContainerKind); + VectorTest vector = new() + { + Code = Bytes.FromHexString(vectorJson.Code), + ContainerKind = ParseContainerKind(vectorJson.ContainerKind) + }; - foreach (var result in vectorJson.Results) + foreach (KeyValuePair result in vectorJson.Results) { EofTest test = new() { @@ -293,10 +356,10 @@ public static IEnumerable ConvertToEofTests(string json) Category = $"{category} [{result.Key}]", Url = url, Description = description, - Spec = spec + Spec = spec, + Vector = vector, + Result = result.ToTestResult() }; - test.Vector = vector; - test.Result = result.ToTestResult(); tests.Add(test); } } @@ -305,7 +368,7 @@ public static IEnumerable ConvertToEofTests(string json) return tests; static ValidationStrategy ParseContainerKind(string containerKind) - => ("INITCODE".Equals(containerKind) ? ValidationStrategy.ValidateInitCodeMode : ValidationStrategy.ValidateRuntimeMode); + => "INITCODE".Equals(containerKind) ? ValidationStrategy.ValidateInitCodeMode : ValidationStrategy.ValidateRuntimeMode; static void GetTestMetaData(KeyValuePair namedTest, out string? description, out string? url, out string? spec) { @@ -332,7 +395,7 @@ public static IEnumerable ConvertStateTest(string json) Dictionary testsInFile = _serializer.Deserialize>(json); - List tests = new(); + List tests = []; foreach (KeyValuePair namedTest in testsInFile) { (string name, string category) = GetNameAndCategory(namedTest.Key); @@ -351,15 +414,16 @@ public static IEnumerable ConvertToBlockchainTests(string json) } catch (Exception) { - var half = _serializer.Deserialize>(json); - testsInFile = new Dictionary(); + Dictionary half = + _serializer.Deserialize>(json); + testsInFile = []; foreach (KeyValuePair pair in half) { testsInFile[pair.Key] = pair.Value; } } - List testsByName = new(); + List testsByName = []; foreach ((string testName, BlockchainTestJson testSpec) in testsInFile) { string[] transitionInfo = testSpec.Network.Split("At"); diff --git a/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs b/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs index 6f7aad55a2c3..71c23519184d 100644 --- a/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs +++ b/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; using System.Collections.Generic; using Ethereum.Test.Base.Interfaces; diff --git a/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs b/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs index 3508dba38c66..c154f53e5743 100644 --- a/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs +++ b/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs @@ -21,5 +21,12 @@ public class TestBlockHeaderJson public string Timestamp { get; set; } public string TransactionsTrie { get; set; } public string UncleHash { get; set; } + public string? BaseFeePerGas { get; set; } + public string? WithdrawalsRoot { get; set; } + public string? ParentBeaconBlockRoot { get; set; } + public string? RequestsHash { get; set; } + public string? BlockAccessListHash { get; set; } + public string? BlobGasUsed { get; set; } + public string? ExcessBlobGas { get; set; } } } diff --git a/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs b/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs new file mode 100644 index 000000000000..b89dcd2869b2 --- /dev/null +++ b/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Text.Json; + +namespace Ethereum.Test.Base +{ + public class TestEngineNewPayloadsJson + { + public JsonElement[] Params { get; set; } + public string? NewPayloadVersion { get; set; } + public string? ForkChoiceUpdatedVersion { get; set; } + + public class ParamsExecutionPayload + { + public string ParentHash { get; set; } + public string FeeRecipient { get; set; } + public string StateRoot { get; set; } + public string ReceiptsRoot { get; set; } + public string LogsBloom { get; set; } + public string BlockNumber { get; set; } + public string GasLimit { get; set; } + public string GasUsed { get; set; } + public string Timestamp { get; set; } + public string ExtraData { get; set; } + public string PrevRandao { get; set; } + public string BaseFeePerGas { get; set; } + public string BlobGasUsed { get; set; } + public string ExcessBlobGas { get; set; } + public string BlockHash { get; set; } + public string[] Transactions { get; set; } + public string[]? Withdrawals { get; set; } + public string? BlockAccessList { get; set; } + } + } +} diff --git a/src/Nethermind/Nethermind.Api/IInitConfig.cs b/src/Nethermind/Nethermind.Api/IInitConfig.cs index 9716f609b914..63ad69d84108 100644 --- a/src/Nethermind/Nethermind.Api/IInitConfig.cs +++ b/src/Nethermind/Nethermind.Api/IInitConfig.cs @@ -39,6 +39,9 @@ public interface IInitConfig : IConfig [ConfigItem(Description = "The hash of the genesis block. If not specified, the genesis block validity is not checked which is useful in the case of ad hoc test/private networks.", DefaultValue = "null")] string? GenesisHash { get; set; } + [ConfigItem(Description = "The network id. If not specified, taken from the chain spec file.", DefaultValue = "null", HiddenFromDocs = true)] + ulong? NetworkId { get; set; } + [ConfigItem(Description = "The path to the static nodes file.", DefaultValue = "static-nodes.json")] string StaticNodesPath { get; set; } diff --git a/src/Nethermind/Nethermind.Api/InitConfig.cs b/src/Nethermind/Nethermind.Api/InitConfig.cs index db0dbfdd706f..4c7e4dc0d5e4 100644 --- a/src/Nethermind/Nethermind.Api/InitConfig.cs +++ b/src/Nethermind/Nethermind.Api/InitConfig.cs @@ -18,6 +18,7 @@ public class InitConfig : IInitConfig public string BaseDbPath { get; set; } = "db"; public string LogFileName { get; set; } = "log.txt"; public string? GenesisHash { get; set; } + public ulong? NetworkId { get; set; } public string StaticNodesPath { get; set; } = "static-nodes.json"; public string TrustedNodesPath { get; set; } = "trusted-nodes.json"; public string? KzgSetupPath { get; set; } = null; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs index a82668f7d741..7288c0d85ac1 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs @@ -5,10 +5,8 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Eip2930; -using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; -using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs index 5020c48f7ef4..bbf93f80b7c8 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockhashProviderTests.cs @@ -352,4 +352,71 @@ public void Eip2935_poc_trimmed_hashes() var result = store.GetBlockHashFromState(current.Header, current.Header.Number - 1); Assert.That(result, Is.EqualTo(current.Header.ParentHash)); } + + [Test, MaxTime(Timeout.MaxTestTime)] + public void BlockhashStore_uses_custom_ring_buffer_size() + { + const int customRingBufferSize = 100; + const int chainLength = 150; + + Block genesis = Build.A.Block.Genesis.TestObject; + BlockTree tree = Build.A.BlockTree(genesis).OfHeadersOnly.OfChainLength(chainLength).TestObject; + BlockHeader? head = tree.FindHeader(chainLength - 1, BlockTreeLookupOptions.None); + + (IWorldState worldState, Hash256 stateRoot) = CreateWorldState(); + Block current = Build.A.Block.WithParent(head!).WithStateRoot(stateRoot).TestObject; + tree.SuggestHeader(current.Header); + + // Custom spec with non-standard ring buffer size + ReleaseSpec customSpec = new() + { + IsEip2935Enabled = true, + IsEip7709Enabled = true, + Eip2935RingBufferSize = customRingBufferSize + }; + + var specProvider = new CustomSpecProvider( + (new ForkActivation(0, genesis.Timestamp), customSpec)); + BlockhashStore store = new(specProvider, worldState); + + using IDisposable _ = worldState.BeginScope(current.Header); + + // Insert code (account already created by CreateWorldState) + byte[] code = [1, 2, 3]; + worldState.InsertCode(Eip2935Constants.BlockHashHistoryAddress, ValueKeccak.Compute(code), code, customSpec); + + // Process current block (150) - stores block 149's hash + store.ApplyBlockhashStateChanges(current.Header); + + // Simulate processing blocks 51-149 to fill the ring buffer + // At block 150 with buffer size 100, we need hashes for blocks 50-149 + // Block 150 stores block 149's hash (already done above) + // Now process blocks 51-149 from the tree to store blocks 50-148 + for (long blockNum = chainLength - customRingBufferSize + 1; blockNum < chainLength; blockNum++) + { + BlockHeader? header = tree.FindHeader(blockNum, BlockTreeLookupOptions.None); + Assert.That(header, Is.Not.Null, $"Block {blockNum} should exist in tree"); + + store.ApplyBlockhashStateChanges(header!); + } + + // Now verify all blocks behave correctly with custom ring buffer size + // At block 150 with buffer size 100, only blocks [50, 149] should be retrievable + for (long blockNum = 1; blockNum < chainLength - customRingBufferSize; blockNum++) + { + Hash256? result = store.GetBlockHashFromState(current.Header, blockNum, customSpec); + + Assert.That(result, Is.Null, + $"Block {blockNum} should be outside custom ring buffer of size {customRingBufferSize} (proves custom size is used, not default 8191)"); + } + + for (long blockNum = chainLength - customRingBufferSize; blockNum < chainLength; blockNum++) + { + BlockHeader? expectedHeader = tree.FindHeader(blockNum, BlockTreeLookupOptions.None); + Hash256? result = store.GetBlockHashFromState(current.Header, blockNum, customSpec); + + Assert.That(result, Is.EqualTo(expectedHeader!.Hash), + $"Block {blockNum} should be retrievable within custom ring buffer of size {customRingBufferSize}"); + } + } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Utils/LastNStateRootTrackerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Utils/LastNStateRootTrackerTests.cs index 1af52fc05346..699ef5593bfa 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Utils/LastNStateRootTrackerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Utils/LastNStateRootTrackerTests.cs @@ -106,4 +106,31 @@ public void Test_OnReorg_RebuildSet() tracker.HasStateRoot(Keccak.Compute(100.ToBigEndianByteArray())).Should().BeTrue(); } + + [Test] + public void Test_TrackLastN_WithCustomDepth() + { + System.Collections.Generic.List blocks = new(); + Block currentBlock = Build.A.Block.Genesis.TestObject; + blocks.Add(currentBlock); + for (int i = 0; i < 300; i++) + { + currentBlock = Build.A.Block + .WithParent(currentBlock) + .WithStateRoot(Keccak.Compute(i.ToBigEndianByteArray())) + .TestObject; + blocks.Add(currentBlock); + } + + BlockTree tree = Build.A.BlockTree().WithBlocks(blocks.ToArray()).TestObject; + + // Test with a custom depth of 256 blocks (useful for networks with fast block times like Arbitrum) + LastNStateRootTracker tracker = new LastNStateRootTracker(tree, 256); + + for (int i = 0; i < 320; i++) + { + tracker.HasStateRoot(Keccak.Compute(i.ToBigEndianByteArray())) + .Should().Be(i is >= 44 and < 300); + } + } } diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs index 00d7a44cda82..68c338bda3ce 100644 --- a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs +++ b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs @@ -30,7 +30,7 @@ public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spe if (!worldState.IsContract(eip2935Account)) return; Hash256 parentBlockHash = blockHeader.ParentHash; - var parentBlockIndex = new UInt256((ulong)((blockHeader.Number - 1) % Eip2935Constants.RingBufferSize)); + UInt256 parentBlockIndex = new UInt256((ulong)((blockHeader.Number - 1) % spec.Eip2935RingBufferSize)); StorageCell blockHashStoreCell = new(eip2935Account, parentBlockIndex); worldState.Set(blockHashStoreCell, parentBlockHash!.Bytes.WithoutLeadingZeros().ToArray()); } @@ -38,14 +38,14 @@ public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spe public Hash256? GetBlockHashFromState(BlockHeader currentHeader, long requiredBlockNumber) => GetBlockHashFromState(currentHeader, requiredBlockNumber, specProvider.GetSpec(currentHeader)); - public Hash256? GetBlockHashFromState(BlockHeader currentHeader, long requiredBlockNumber, IReleaseSpec? spec) + public Hash256? GetBlockHashFromState(BlockHeader currentHeader, long requiredBlockNumber, IReleaseSpec spec) { if (requiredBlockNumber >= currentHeader.Number || - requiredBlockNumber + Eip2935Constants.RingBufferSize < currentHeader.Number) + requiredBlockNumber + spec.Eip2935RingBufferSize < currentHeader.Number) { return null; } - var blockIndex = new UInt256((ulong)(requiredBlockNumber % Eip2935Constants.RingBufferSize)); + UInt256 blockIndex = new UInt256((ulong)(requiredBlockNumber % spec.Eip2935RingBufferSize)); Address? eip2935Account = spec.Eip2935ContractAddress ?? Eip2935Constants.BlockHashHistoryAddress; StorageCell blockHashStoreCell = new(eip2935Account, blockIndex); ReadOnlySpan data = worldState.Get(blockHashStoreCell); diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs index 77cc6b214f5a..0c19c64986d0 100644 --- a/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs +++ b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs @@ -12,5 +12,5 @@ public interface IBlockhashStore public void ApplyBlockhashStateChanges(BlockHeader blockHeader); public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spec); public Hash256? GetBlockHashFromState(BlockHeader currentBlockHeader, long requiredBlockNumber); - public Hash256? GetBlockHashFromState(BlockHeader currentBlockHeader, long requiredBlockNumber, IReleaseSpec? spec); + public Hash256? GetBlockHashFromState(BlockHeader currentBlockHeader, long requiredBlockNumber, IReleaseSpec spec); } diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs index dca9b5979433..45871f73fa1d 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs @@ -138,6 +138,9 @@ public interface ISyncConfig : IConfig [ConfigItem(Description = "_Technical._ Whether to enable snap serving. WARNING: Very slow on hash db layout. Default is to enable on halfpath layout.", DefaultValue = "null", HiddenFromDocs = true)] bool? SnapServingEnabled { get; set; } + [ConfigItem(Description = "The maximum depth (in blocks) for serving snap sync requests. Higher values allow serving requests for older blocks, useful for networks with fast block times like Arbitrum.", DefaultValue = "128")] + int SnapServingMaxDepth { get; set; } + [ConfigItem(Description = "_Technical._ MultiSyncModeSelector sync mode timer loop interval. Used for testing.", DefaultValue = "1000", HiddenFromDocs = true)] int MultiSyncModeSelectorLoopTimerMs { get; set; } diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs index 096d8f57444c..22c592973191 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs @@ -65,6 +65,7 @@ public string? PivotHash public int ExitOnSyncedWaitTimeSec { get; set; } = 60; public int MallocTrimIntervalSec { get; set; } = 300; public bool? SnapServingEnabled { get; set; } = null; + public int SnapServingMaxDepth { get; set; } = 128; public int MultiSyncModeSelectorLoopTimerMs { get; set; } = 1000; public int SyncDispatcherEmptyRequestDelayMs { get; set; } = 10; public int SyncDispatcherAllocateTimeoutMs { get; set; } = 1000; diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofBlockTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofBlockTracer.cs index c01b2cf454ad..ab8a6a5a11cb 100644 --- a/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofBlockTracer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofBlockTracer.cs @@ -6,16 +6,10 @@ namespace Nethermind.Blockchain.Tracing.Proofs; -public class ProofBlockTracer : BlockTracerBase +public class ProofBlockTracer(Hash256? txHash, bool treatZeroAccountDifferently) + : BlockTracerBase(txHash) { - private readonly bool _treatSystemAccountDifferently; - - public ProofBlockTracer(Hash256? txHash, bool treatSystemAccountDifferently) : base(txHash) - { - _treatSystemAccountDifferently = treatSystemAccountDifferently; - } - - protected override ProofTxTracer OnStart(Transaction? tx) => new(_treatSystemAccountDifferently); + protected override ProofTxTracer OnStart(Transaction? tx) => new(treatZeroAccountDifferently); /// /// Here I decided to return tracer after experimenting with ProofTxTrace class. It encapsulates less but avoid additional type introduction which does not bring much value. diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofTxTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofTxTracer.cs index 1c30f8e6a527..90c79d71e357 100644 --- a/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofTxTracer.cs +++ b/src/Nethermind/Nethermind.Blockchain/Tracing/Proofs/ProofTxTracer.cs @@ -11,7 +11,7 @@ namespace Nethermind.Blockchain.Tracing.Proofs; -public class ProofTxTracer(bool treatSystemAccountDifferently) : TxTracer +public class ProofTxTracer(bool treatZeroAccountDifferently) : TxTracer { public HashSet
Accounts { get; } = new(); @@ -33,7 +33,7 @@ public override void ReportBlockHash(Hash256 blockHash) public override void ReportBalanceChange(Address address, UInt256? before, UInt256? after) { - if (treatSystemAccountDifferently && Address.SystemUser == address && before is null && after?.IsZero != false) + if (treatZeroAccountDifferently && Address.Zero == address && before is null && after?.IsZero != false) { return; } @@ -43,7 +43,7 @@ public override void ReportBalanceChange(Address address, UInt256? before, UInt2 public override void ReportCodeChange(Address address, byte[]? before, byte[]? after) { - if (treatSystemAccountDifferently && Address.SystemUser == address && before is null && + if (treatZeroAccountDifferently && Address.Zero == address && before is null && after == Array.Empty()) { return; @@ -54,7 +54,7 @@ public override void ReportCodeChange(Address address, byte[]? before, byte[]? a public override void ReportNonceChange(Address address, UInt256? before, UInt256? after) { - if (treatSystemAccountDifferently && Address.SystemUser == address && before is null && after?.IsZero != false) + if (treatZeroAccountDifferently && Address.Zero == address && before is null && after?.IsZero != false) { return; } diff --git a/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs b/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs index c1824d21eaaa..66c4727bfac7 100644 --- a/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs +++ b/src/Nethermind/Nethermind.Blockchain/Utils/LastNStateRootTracker.cs @@ -11,8 +11,8 @@ namespace Nethermind.Blockchain.Utils; -// TODO: Move responsibility to IWorldStateManager? Could be, but if IWorldStateManager store more than 128 blocks -// of state, that would be out of spec for snap and it would fail hive test. +// TODO: Move responsibility to IWorldStateManager? Could be, but if IWorldStateManager stores more blocks +// of state than configured, that would require updating the snap serving configuration (ISyncConfig.SnapServingMaxDepth). public class LastNStateRootTracker : ILastNStateRootTracker, IDisposable { private readonly IBlockTree _blockTree; diff --git a/src/Nethermind/Nethermind.Config/BlocksConfig.cs b/src/Nethermind/Nethermind.Config/BlocksConfig.cs index 4d8df415df72..38f26353c377 100644 --- a/src/Nethermind/Nethermind.Config/BlocksConfig.cs +++ b/src/Nethermind/Nethermind.Config/BlocksConfig.cs @@ -58,6 +58,9 @@ private static string GetDefaultVersionExtraData() public ulong SecondsPerSlot { get; set; } = 12; public bool PreWarmStateOnBlockProcessing { get; set; } = true; + + public bool CachePrecompilesOnBlockProcessing { get; set; } = true; + public int PreWarmStateConcurrency { get; set; } = 0; public int BlockProductionTimeoutMs { get; set; } = 4_000; diff --git a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs index 320bee4879c1..15aef8934537 100644 --- a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs +++ b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs @@ -40,6 +40,9 @@ public interface IBlocksConfig : IConfig [ConfigItem(Description = "Whether to pre-warm the state when processing blocks. This can lead to an up to 2x speed-up in the main loop block processing.", DefaultValue = "True")] bool PreWarmStateOnBlockProcessing { get; set; } + [ConfigItem(Description = "Whether to cache precompile results when processing blocks.", DefaultValue = "True", HiddenFromDocs = true)] + bool CachePrecompilesOnBlockProcessing { get; set; } + [ConfigItem(Description = "Specify pre-warm state concurrency. Default is logical processor - 1.", DefaultValue = "0", HiddenFromDocs = true)] int PreWarmStateConcurrency { get; set; } @@ -49,7 +52,7 @@ public interface IBlocksConfig : IConfig [ConfigItem(Description = "The genesis block load timeout, in milliseconds.", DefaultValue = "40000")] int GenesisTimeoutMs { get; set; } - [ConfigItem(Description = "The max transaction bytes to add in block production, in kilobytes.", DefaultValue = "9728")] + [ConfigItem(Description = "The max transaction bytes to add in block production, in kilobytes.", DefaultValue = "7936")] long BlockProductionMaxTxKilobytes { get; set; } [ConfigItem(Description = "The ticker that gas rewards are denominated in for processing logs", DefaultValue = "ETH", HiddenFromDocs = true)] diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs b/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs index 1ab94f174a84..001413925e00 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs @@ -155,7 +155,7 @@ private bool IsLessOrEqualThanTarget(ReadOnlySpan result, in UInt256 diffi IEthashDataSet dataSet = _hintBasedCache.Get(epoch); if (dataSet is null) { - if (_logger.IsWarn) _logger.Warn($"Ethash cache miss for block {header.ToString(BlockHeader.Format.Short)}"); + if (_logger.IsTrace) _logger.Trace($"Ethash cache miss for block {header.ToString(BlockHeader.Format.Short)}"); dataSet = BuildCache(epoch); } @@ -167,8 +167,7 @@ private bool IsLessOrEqualThanTarget(ReadOnlySpan result, in UInt256 diffi byte[] mixHash; while (true) { - ValueHash256 result; - (mixHash, result, _) = Hashimoto(fullSize, dataSet, headerHashed, null, nonce); + (mixHash, ValueHash256 result, _) = Hashimoto(fullSize, dataSet, headerHashed, null, nonce); if (IsLessOrEqualThanTarget(result.Bytes, header.Difficulty)) { break; diff --git a/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs b/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs index 18347180f0fa..2a930771c265 100644 --- a/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs +++ b/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs @@ -11,7 +11,6 @@ using Nethermind.Consensus.Rewards; using Nethermind.Merge.Plugin; using Nethermind.Merge.Plugin.BlockProduction; -using Nethermind.Merge.Plugin.InvalidChainTracker; using Nethermind.TxPool; namespace Nethermind.Core.Test.Modules; @@ -43,6 +42,9 @@ protected override void Load(ContainerBuilder builder) .AddDecorator() .AddScoped() .AddDecorator() + + // Engine rpc + .AddSingleton() ; if (txPoolConfig.BlobsSupport.SupportsReorgs()) diff --git a/src/Nethermind/Nethermind.Core.Test/RipemdTests.cs b/src/Nethermind/Nethermind.Core.Test/RipemdTests.cs index 88403a11e132..b7c4e8115218 100644 --- a/src/Nethermind/Nethermind.Core.Test/RipemdTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/RipemdTests.cs @@ -9,7 +9,7 @@ namespace Nethermind.Core.Test [TestFixture] public class RipemdTests { - public const string RipemdOfEmptyString = "9c1185a5c5e9fc54612808977ee8f548b2258d31"; + public const string RipemdOfEmptyString = "0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31"; [Test] public void Empty_byte_array() diff --git a/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs b/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs index 504129823990..8b93eb277542 100644 --- a/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs +++ b/src/Nethermind/Nethermind.Core/Buffers/CappedArray.cs @@ -113,12 +113,10 @@ public readonly Span AsSpan(int start, int length) return AsSpan().ToArray(); } - public override string? ToString() - { - return typeof(T) == typeof(byte) ? - SpanExtensions.ToHexString(MemoryMarshal.AsBytes(AsSpan()), withZeroX: true) : + public override string? ToString() => + typeof(T) == typeof(byte) ? + MemoryMarshal.AsBytes(AsSpan()).ToHexString(withZeroX: true) : base.ToString(); - } public readonly ArraySegment AsArraySegment() { diff --git a/src/Nethermind/Nethermind.Core/InvalidBlockHelper.cs b/src/Nethermind/Nethermind.Core/InvalidBlockHelper.cs index f3d151850f29..171b3e125839 100644 --- a/src/Nethermind/Nethermind.Core/InvalidBlockHelper.cs +++ b/src/Nethermind/Nethermind.Core/InvalidBlockHelper.cs @@ -5,8 +5,6 @@ namespace Nethermind.Core; public static class InvalidBlockHelper { - public static string GetMessage(Block? block, string reason) - { - return $"Rejected invalid block {block?.ToString(Block.Format.FullHashNumberAndExtraData)}, reason: {reason}"; - } + public static string GetMessage(Block? block, string reason) => + $"Rejected invalid block {block?.ToString(Block.Format.FullHashNumberAndExtraData)}, reason: {reason}"; } diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs index d5377da9d6ad..f83a43c92eda 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs @@ -306,6 +306,12 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec bool IsEip7709Enabled { get; } Address Eip2935ContractAddress { get; } + /// + /// EIP-2935 ring buffer size for historical block hash storage. + /// Defaults to 8,191 blocks for Ethereum mainnet. + /// + long Eip2935RingBufferSize => Eip2935Constants.RingBufferSize; + /// /// SELFDESTRUCT only in same transaction /// diff --git a/src/Nethermind/Nethermind.Crypto/Ripemd.cs b/src/Nethermind/Nethermind.Crypto/Ripemd.cs index fc02c2e524ef..8fc68db757e3 100644 --- a/src/Nethermind/Nethermind.Crypto/Ripemd.cs +++ b/src/Nethermind/Nethermind.Crypto/Ripemd.cs @@ -1,25 +1,29 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core.Extensions; using Org.BouncyCastle.Crypto.Digests; -namespace Nethermind.Crypto +namespace Nethermind.Crypto; + +public static class Ripemd { - public static class Ripemd + const int HashOutputLength = 32; + + public static byte[] Compute(ReadOnlySpan input) { - public static byte[] Compute(byte[] input) - { - var digest = new RipeMD160Digest(); - digest.BlockUpdate(input, 0, input.Length); - var result = new byte[digest.GetDigestSize()]; - digest.DoFinal(result, 0); - return result; - } + RipeMD160Digest digest = new(); + digest.BlockUpdate(input); + byte[] result = new byte[HashOutputLength]; + int length = digest.GetDigestSize(); + Span span = result.AsSpan(HashOutputLength - length, length); + digest.DoFinal(span); + return result; + } - public static string ComputeString(byte[] input) - { - return Compute(input).ToHexString(false); - } + public static string ComputeString(ReadOnlySpan input) + { + return Compute(input).ToHexString(false); } } diff --git a/src/Nethermind/Nethermind.Evm.Precompiles/BN254.cs b/src/Nethermind/Nethermind.Evm.Precompiles/BN254.cs index fb4ced5f60f1..b2b6e2a74bee 100644 --- a/src/Nethermind/Nethermind.Evm.Precompiles/BN254.cs +++ b/src/Nethermind/Nethermind.Evm.Precompiles/BN254.cs @@ -2,8 +2,12 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Buffers.Binary; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; using Nethermind.MclBindings; namespace Nethermind.Evm.Precompiles; @@ -21,50 +25,59 @@ static BN254() throw new InvalidOperationException("MCL initialization failed"); } - internal static bool Add(Span input, Span output) + [MethodImpl(MethodImplOptions.NoInlining)] + internal static bool Add(byte[] output, ReadOnlySpan input) { - if (input.Length != 128) - return false; + const int chunkSize = 64; - if (!DeserializeG1(input[0..64], out mclBnG1 x)) - return false; + Debug.Assert(input.Length == 128); + Debug.Assert(output.Length == 64); - if (!DeserializeG1(input[64..128], out mclBnG1 y)) - return false; + fixed (byte* data = &MemoryMarshal.GetReference(input)) + { + if (!DeserializeG1(data, out mclBnG1 x)) + return false; + + if (!DeserializeG1(data + chunkSize, out mclBnG1 y)) + return false; - mclBnG1_add(ref x, x, y); // x += y - mclBnG1_normalize(ref x, x); + mclBnG1_add(ref x, x, y); // x += y + mclBnG1_normalize(ref x, x); - return SerializeG1(x, output); + return SerializeG1(x, output); + } } - internal static bool Mul(Span input, Span output) + [MethodImpl(MethodImplOptions.NoInlining)] + internal static bool Mul(byte[] output, ReadOnlySpan input) { - if (input.Length != 96) - return false; - - if (!DeserializeG1(input[0..64], out mclBnG1 x)) - return false; + const int chunkSize = 64; - Span yData = input[64..]; - yData.Reverse(); // To little-endian + Debug.Assert(input.Length == 96); + Debug.Assert(output.Length == 64); - mclBnFr y = default; - - fixed (byte* ptr = &MemoryMarshal.GetReference(yData)) + fixed (byte* data = &MemoryMarshal.GetReference(input)) { - if (mclBnFr_setLittleEndianMod(ref y, (nint)ptr, 32) == -1 || mclBnFr_isValid(y) == 0) + if (!DeserializeG1(data, out mclBnG1 x)) return false; - } - mclBnG1_mul(ref x, x, y); // x *= y - mclBnG1_normalize(ref x, x); + Unsafe.SkipInit(out mclBnFr y); + if (mclBnFr_setBigEndianMod(ref y, (nint)data + chunkSize, 32) == -1 || mclBnFr_isValid(y) == 0) + return false; - return SerializeG1(x, output); + mclBnG1_mul(ref x, x, y); // x *= y + mclBnG1_normalize(ref x, x); + return SerializeG1(x, output); + } } - internal static bool CheckPairing(Span input, Span output) + [MethodImpl(MethodImplOptions.NoInlining)] + internal static bool CheckPairing(byte[] output, ReadOnlySpan input) { + if ((uint)output.Length < 32) + return false; + + // Empty input means "true" by convention if (input.Length == 0) { output[31] = 1; @@ -74,138 +87,307 @@ internal static bool CheckPairing(Span input, Span output) if (input.Length % PairSize != 0) return false; - mclBnGT gt = default; - Unsafe.SkipInit(out mclBnGT previous); - var hasPrevious = false; - - for (int i = 0, count = input.Length; i < count; i += PairSize) + fixed (byte* data = &MemoryMarshal.GetReference(input)) { - var i64 = i + 64; - - if (!DeserializeG1(input[i..i64], out mclBnG1 g1)) - return false; - - if (!DeserializeG2(input[i64..(i64 + 128)], out mclBnG2 g2)) - return false; - - if (mclBnG1_isZero(g1) == 1 || mclBnG2_isZero(g2) == 1) - continue; + Unsafe.SkipInit(out mclBnGT ml); + Unsafe.SkipInit(out mclBnGT acc); + bool hasMl = false; + + for (int i = 0; i < input.Length; i += PairSize) + { + if (!DeserializeG1(data + i, out mclBnG1 g1)) + return false; + + if (!DeserializeG2(data + i + 64, out mclBnG2 g2)) + return false; + + // Skip if g1 or g2 are zero + if (IsZero(g1) || IsZero(g2)) + continue; + + mclBn_millerLoop(ref hasMl ? ref ml : ref acc, g1, g2); // Miller loop only + + if (hasMl) + { + mclBnGT_mul(ref acc, acc, ml); + } + else + { + hasMl = true; + } + } + + // All pairs had zero element -> valid + if (!hasMl) + { + output[31] = 1; + return true; + } + + // Single final exponentiation for the product + mclBn_finalExp(ref acc, acc); + + // True if the product of pairings equals 1 in GT + output[31] = Convert.ToByte(mclBnGT_isOne(acc) == 1); + } + return true; + } - mclBn_pairing(ref gt, g1, g2); + private static bool IsZero(in T data) + where T : unmanaged, allows ref struct + { + ref byte start = ref Unsafe.As(ref Unsafe.AsRef(in data)); + ReadOnlySpan span = MemoryMarshal.CreateReadOnlySpan(in start, sizeof(T)); + return span.IndexOfAnyExcept((byte)0) < 0; + } - // Skip multiplication for the first pairing as there's no previous result - if (hasPrevious) - mclBnGT_mul(ref gt, gt, previous); // gt *= previous + private static bool DeserializeG1(byte* data, out mclBnG1 point) + { + const int chunkSize = 32; - previous = gt; - hasPrevious = true; - } + point = default; - // If gt is zero, then no pairing was computed, and it's considered valid - if (mclBnGT_isOne(gt) == 1 || mclBnGT_isZero(gt) == 1) + // Treat all-zero as point at infinity for your calling convention + if (IsZero64(data)) { - output[31] = 1; return true; } - return mclBnGT_isValid(gt) == 1; + // Input is big-endian; MCL call below expects little-endian byte order for Fp + byte* tmp = stackalloc byte[chunkSize]; + + // x + CopyReverse32(data, tmp); + if (mclBnFp_deserialize(ref point.x, (nint)tmp, chunkSize) == nuint.Zero) + return false; + // y + CopyReverse32(data + chunkSize, tmp); + if (mclBnFp_deserialize(ref point.y, (nint)tmp, chunkSize) == nuint.Zero) + return false; + + mclBnFp_setInt32(ref point.z, 1); + return mclBnG1_isValid(point) == 1; } - private static bool DeserializeG1(Span data, out mclBnG1 point) + private static bool DeserializeG2(byte* data, out mclBnG2 point) { + const int chunkSize = 32; + point = default; - // Check for all-zero data - if (data.IndexOfAnyExcept((byte)0) == -1) + // Treat all-zero as point at infinity + if (IsZero128(data)) + { return true; + } - Span x = data[0..32]; - x.Reverse(); // To little-endian + // Input layout: x_im, x_re, y_im, y_re (each 32 bytes, big-endian) + // MCL Fp2 layout: d0 = re, d1 = im + byte* tmp = stackalloc byte[chunkSize]; - fixed (byte* ptr = &MemoryMarshal.GetReference(x)) - { - if (mclBnFp_deserialize(ref point.x, (nint)ptr, 32) == nuint.Zero) - return false; - } + // x.im + CopyReverse32(data, tmp); + if (mclBnFp_deserialize(ref point.x.d1, (nint)tmp, chunkSize) == nuint.Zero) + return false; - Span y = data[32..64]; - y.Reverse(); // To little-endian + // x.re + CopyReverse32(data + chunkSize, tmp); + if (mclBnFp_deserialize(ref point.x.d0, (nint)tmp, chunkSize) == nuint.Zero) + return false; - fixed (byte* ptr = &MemoryMarshal.GetReference(y)) - { - if (mclBnFp_deserialize(ref point.y, (nint)ptr, 32) == nuint.Zero) - return false; - } + // y.im + CopyReverse32(data + chunkSize * 2, tmp); + if (mclBnFp_deserialize(ref point.y.d1, (nint)tmp, chunkSize) == nuint.Zero) + return false; - mclBnFp_setInt32(ref point.z, 1); + // y.re + CopyReverse32(data + chunkSize * 3, tmp); + if (mclBnFp_deserialize(ref point.y.d0, (nint)tmp, chunkSize) == nuint.Zero) + return false; - return mclBnG1_isValid(point) == 1; + mclBnFp_setInt32(ref point.z.d0, 1); + + return mclBnG2_isValid(point) == 1 && mclBnG2_isValidOrder(point) == 1; } - private static bool DeserializeG2(Span data, out mclBnG2 point) + private static bool SerializeG1(in mclBnG1 point, byte[] output) { - point = default; - - // Check for all-zero data - if (data.IndexOfAnyExcept((byte)0) == -1) - return true; + const int chunkSize = 32; - Span x0 = data[32..64]; - Span x1 = data[0..32]; - x0.Reverse(); // To little-endian - x1.Reverse(); // To little-endian - - fixed (byte* ptr0 = &MemoryMarshal.GetReference(x0)) - fixed (byte* ptr1 = &MemoryMarshal.GetReference(x1)) + fixed (byte* ptr = &MemoryMarshal.GetArrayDataReference(output)) { - if (mclBnFp_deserialize(ref point.x.d0, (nint)ptr0, 32) == nuint.Zero) + if (mclBnFp_getLittleEndian((nint)ptr, chunkSize, point.x) == nuint.Zero) return false; - if (mclBnFp_deserialize(ref point.x.d1, (nint)ptr1, 32) == nuint.Zero) + if (mclBnFp_getLittleEndian((nint)ptr + chunkSize, chunkSize, point.y) == nuint.Zero) return false; + + CopyReverse32(ptr, ptr); // To big-endian + CopyReverse32(ptr + chunkSize, ptr + chunkSize); // To big-endian } - Span y0 = data[96..128]; - Span y1 = data[64..96]; - y0.Reverse(); // To little-endian - y1.Reverse(); // To little-endian + return true; + } + + private static unsafe bool IsZero64(byte* ptr) + { + const int Length = 64; - fixed (byte* ptr0 = &MemoryMarshal.GetReference(y0)) - fixed (byte* ptr1 = &MemoryMarshal.GetReference(y1)) + if (Vector512.IsHardwareAccelerated) { - if (mclBnFp_deserialize(ref point.y.d0, (nint)ptr0, 32) == nuint.Zero) - return false; - - if (mclBnFp_deserialize(ref point.y.d1, (nint)ptr1, 32) == nuint.Zero) - return false; + Vector512 a = Unsafe.ReadUnaligned>(ptr); + return a == default; + } + else if (Vector256.IsHardwareAccelerated) + { + Vector256 a = Unsafe.ReadUnaligned>(ptr); + Vector256 b = Unsafe.ReadUnaligned>(ptr + Vector256.Count); + Vector256 o = Vector256.BitwiseOr(a, b); + return o == default; + } + else if (Vector128.IsHardwareAccelerated) + { + // 4x16-byte blocks, coalesced in pairs + for (nuint offset = 0; offset < Length; offset += (nuint)Vector128.Count * 2) + { + Vector128 a = Unsafe.ReadUnaligned>(ptr + offset); + Vector128 b = Unsafe.ReadUnaligned>(ptr + offset + Vector128.Count); + Vector128 o = Vector128.BitwiseOr(a, b); + if (o != default) return false; + } + return true; + } + else + { + // scalar fallback + ulong* x = (ulong*)ptr; + for (int i = 0; i < 8; i++) + { + if (x[i] != 0) + return false; + } + return true; } + } - mclBnFp_setInt32(ref point.z.d0, 1); + private static unsafe bool IsZero128(byte* ptr) + { + const int Length = 128; - return mclBnG2_isValid(point) == 1 && mclBnG2_isValidOrder(point) == 1; + if (Vector512.IsHardwareAccelerated) + { + // 2x512 -> OR‑reduce -> EqualsAll + Vector512 a = Unsafe.ReadUnaligned>(ptr + 0); + Vector512 b = Unsafe.ReadUnaligned>(ptr + Vector512.Count); + Vector512 o = Vector512.BitwiseOr(a, b); + return o == default; + } + else if (Vector256.IsHardwareAccelerated) + { + // 4x32-byte blocks, coalesced in pairs (2 loads per iteration) + for (nuint offset = 0; offset < Length; offset += (nuint)Vector256.Count * 2) + { + Vector256 a = Unsafe.ReadUnaligned>(ptr + offset); + Vector256 b = Unsafe.ReadUnaligned>(ptr + offset + Vector256.Count); + Vector256 o = Vector256.BitwiseOr(a, b); + if (o != default) return false; + } + return true; + } + else if (Vector128.IsHardwareAccelerated) + { + // 8x16-byte blocks, coalesced in pairs + for (nuint offset = 0; offset < Length; offset += (nuint)Vector128.Count * 2) + { + Vector128 a = Unsafe.ReadUnaligned>(ptr + offset); + Vector128 b = Unsafe.ReadUnaligned>(ptr + offset + Vector128.Count); + Vector128 o = Vector128.BitwiseOr(a, b); + if (o != default) return false; + } + return true; + } + else + { + // scalar fallback + ulong* x = (ulong*)ptr; + for (int i = 0; i < 16; i++) + { + if (x[i] != 0) + return false; + } + return true; + } } - private static bool SerializeG1(in mclBnG1 point, Span output) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void CopyReverse32(byte* srcRef, byte* dstRef) { - Span x = output[0..32]; - - fixed (byte* ptr = &MemoryMarshal.GetReference(x)) + if (Avx2.IsSupported) { - if (mclBnFp_getLittleEndian((nint)ptr, 32, point.x) == nuint.Zero) - return false; + Reverse32BytesAvx2(srcRef, dstRef); + } + else if (Vector128.IsHardwareAccelerated) + { + Reverse32Bytes128(srcRef, dstRef); + } + else + { + // Fallback scalar path + Reverse32BytesScalar(srcRef, dstRef); } + } - Span y = output[32..64]; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Reverse32BytesAvx2(byte* srcRef, byte* dstRef) + { + // Load 32 bytes as one 256-bit vector + Vector256 vec = Unsafe.ReadUnaligned>(srcRef); + Vector256 fullRev; - fixed (byte* ptr = &MemoryMarshal.GetReference(y)) + Vector256 mask = Vector256.Create((byte)31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + if (Avx512Vbmi.VL.IsSupported) { - if (mclBnFp_getLittleEndian((nint)ptr, 32, point.y) == nuint.Zero) - return false; + fullRev = Avx512Vbmi.VL.PermuteVar32x8(vec, mask); + } + else + { + Vector256 revInLane = Avx2.Shuffle(vec, mask); + fullRev = Avx2.Permute2x128(revInLane, revInLane, 0x01); } - x.Reverse(); // To big-endian - y.Reverse(); // To big-endian + Unsafe.WriteUnaligned(dstRef, fullRev); + } - return true; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Reverse32Bytes128(byte* srcRef, byte* dstRef) + { + // Two 16-byte halves: reverse each then swap them + Vector128 lo = Unsafe.ReadUnaligned>(srcRef); + Vector128 hi = Unsafe.ReadUnaligned>(srcRef + Vector128.Count); + + Vector128 indices = Vector128.Create((byte)15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + lo = Vector128.Shuffle(lo, indices); + hi = Vector128.Shuffle(hi, indices); + + // Store swapped halves reversed + Unsafe.WriteUnaligned(dstRef, hi); + Unsafe.WriteUnaligned(dstRef + Vector128.Count, lo); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Reverse32BytesScalar(byte* srcRef, byte* dstRef) + { + ulong* src = (ulong*)srcRef; + ulong* dst = (ulong*)dstRef; + + ulong a = BinaryPrimitives.ReverseEndianness(src[0]); + ulong b = BinaryPrimitives.ReverseEndianness(src[1]); + ulong c = BinaryPrimitives.ReverseEndianness(src[2]); + ulong d = BinaryPrimitives.ReverseEndianness(src[3]); + + dst[0] = d; + dst[1] = c; + dst[2] = b; + dst[3] = a; } } diff --git a/src/Nethermind/Nethermind.Evm.Precompiles/BN254AddPrecompile.cs b/src/Nethermind/Nethermind.Evm.Precompiles/BN254AddPrecompile.cs index bc46669b04a8..a35d4e0d2e4e 100644 --- a/src/Nethermind/Nethermind.Evm.Precompiles/BN254AddPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm.Precompiles/BN254AddPrecompile.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Runtime.CompilerServices; using Nethermind.Core; using Nethermind.Core.Specs; @@ -10,6 +11,9 @@ namespace Nethermind.Evm.Precompiles; /// public class BN254AddPrecompile : IPrecompile { + private const int InputLength = 128; + private const int OutputLength = 64; + public static readonly BN254AddPrecompile Instance = new(); public static Address Address { get; } = Address.FromNumber(6); @@ -22,15 +26,33 @@ public class BN254AddPrecompile : IPrecompile public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; + [SkipLocalsInit] public (byte[], bool) Run(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) { Metrics.Bn254AddPrecompile++; - Span input = stackalloc byte[128]; - Span output = stackalloc byte[64]; + ReadOnlySpan input = inputData.Span; + if (InputLength < (uint)input.Length) + { + // Input is too long - trim to the expected length. + input = input[..InputLength]; + } + + byte[] output = new byte[OutputLength]; + bool result = (input.Length == InputLength) ? + BN254.Add(output, input) : + RunPaddedInput(output, input); - inputData.Span[0..Math.Min(inputData.Length, input.Length)].CopyTo(input); + return result ? (output, true) : IPrecompile.Failure; + } - return BN254.Add(input, output) ? (output.ToArray(), true) : IPrecompile.Failure; + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool RunPaddedInput(byte[] output, ReadOnlySpan input) + { + // Input is too short - pad with zeros up to the expected length. + Span padded = stackalloc byte[InputLength]; + // Copies input bytes; rest of the span is already zero-initialized. + input.CopyTo(padded); + return BN254.Add(output, padded); } } diff --git a/src/Nethermind/Nethermind.Evm.Precompiles/BN254MulPrecompile.cs b/src/Nethermind/Nethermind.Evm.Precompiles/BN254MulPrecompile.cs index e5b2796bc83a..c41258b6368f 100644 --- a/src/Nethermind/Nethermind.Evm.Precompiles/BN254MulPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm.Precompiles/BN254MulPrecompile.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Runtime.CompilerServices; using Nethermind.Core; using Nethermind.Core.Specs; @@ -10,6 +11,9 @@ namespace Nethermind.Evm.Precompiles; /// public class BN254MulPrecompile : IPrecompile { + private const int InputLength = 96; + private const int OutputLength = 64; + public static readonly BN254MulPrecompile Instance = new(); public static Address Address { get; } = Address.FromNumber(7); @@ -22,15 +26,34 @@ public class BN254MulPrecompile : IPrecompile public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; + [SkipLocalsInit] public (byte[], bool) Run(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) { Metrics.Bn254MulPrecompile++; - Span input = stackalloc byte[96]; - Span output = stackalloc byte[64]; + ReadOnlySpan input = inputData.Span; + if (InputLength < (uint)input.Length) + { + // Input is too long - trim to the expected length. + input = input[..InputLength]; + } + + byte[] output = new byte[OutputLength]; + bool result = (input.Length == InputLength) ? + BN254.Mul(output, input) : + RunPaddedInput(output, input); - inputData.Span[0..Math.Min(inputData.Length, input.Length)].CopyTo(input); + return result ? (output, true) : IPrecompile.Failure; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool RunPaddedInput(byte[] output, ReadOnlySpan input) + { + // Input is too short - pad with zeros up to the expected length. + Span padded = stackalloc byte[InputLength]; + // Copies input bytes; rest of the span is already zero-initialized. + input.CopyTo(padded); - return BN254.Mul(input, output) ? (output.ToArray(), true) : IPrecompile.Failure; + return BN254.Mul(output, padded); } } diff --git a/src/Nethermind/Nethermind.Evm.Precompiles/BN254PairingPrecompile.cs b/src/Nethermind/Nethermind.Evm.Precompiles/BN254PairingPrecompile.cs index ff0b8292062d..855e65126606 100644 --- a/src/Nethermind/Nethermind.Evm.Precompiles/BN254PairingPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm.Precompiles/BN254PairingPrecompile.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Buffers; using Nethermind.Core; using Nethermind.Core.Specs; @@ -36,15 +35,9 @@ public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec return IPrecompile.Failure; } - var input = ArrayPool.Shared.Rent(inputData.Length); - Span output = stackalloc byte[32]; + byte[] output = new byte[32]; + bool result = BN254.CheckPairing(output, inputData.Span); - inputData.CopyTo(input); - - var result = BN254.CheckPairing(input.AsSpan(0, inputData.Length), output); - - ArrayPool.Shared.Return(input); - - return result ? (output.ToArray(), true) : IPrecompile.Failure; + return result ? (output, true) : IPrecompile.Failure; } } diff --git a/src/Nethermind/Nethermind.Evm.Precompiles/Ripemd160Precompile.cs b/src/Nethermind/Nethermind.Evm.Precompiles/Ripemd160Precompile.cs index a4977a63c8c4..092a6689de57 100644 --- a/src/Nethermind/Nethermind.Evm.Precompiles/Ripemd160Precompile.cs +++ b/src/Nethermind/Nethermind.Evm.Precompiles/Ripemd160Precompile.cs @@ -38,6 +38,6 @@ public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec { Metrics.Ripemd160Precompile++; - return (Ripemd.Compute(inputData.ToArray()).PadLeft(32), true); + return (Ripemd.Compute(inputData.Span), true); } } diff --git a/src/Nethermind/Nethermind.Evm.Test/CallTests.cs b/src/Nethermind/Nethermind.Evm.Test/CallTests.cs new file mode 100644 index 000000000000..086752b11ad9 --- /dev/null +++ b/src/Nethermind/Nethermind.Evm.Test/CallTests.cs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Specs; +using NUnit.Framework; + +namespace Nethermind.Evm.Test +{ + public class CallTests : VirtualMachineTestsBase + { + protected override long BlockNumber => MainnetSpecProvider.ParisBlockNumber; + protected override ulong Timestamp => MainnetSpecProvider.OsakaBlockTimestamp; + + [Test] + [TestCase(Instruction.CALL)] + [TestCase(Instruction.CALLCODE)] + [TestCase(Instruction.DELEGATECALL)] + [TestCase(Instruction.STATICCALL)] + public void Stack_underflow_on_call(Instruction instruction) + { + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData("0x805e0d3cde3764a4d0a02f33cf624c8b7cfd911a") + .PushData("0x793d1e") + .Op(instruction) + .Done; + + TestAllTracerWithOutput result = Execute(Activation, 21020, code); + Assert.That(result.Error, Is.EqualTo("StackUnderflow")); + } + + [Test] + [TestCase(Instruction.CALL)] + [TestCase(Instruction.CALLCODE)] + [TestCase(Instruction.DELEGATECALL)] + [TestCase(Instruction.STATICCALL)] + public void Out_of_gas_on_call(Instruction instruction) + { + byte[] code = Prepare.EvmCode + .PushData(0) + .PushData(0) + .PushData("0x805e0d3cde3764a4d0a02f33cf624c8b7cfd911a") + .PushData("0x793d1e") + .PushData("0x793d1e") + .PushData("0x793d1e") + .PushData("0x793d1e") + .Op(instruction) + .Done; + + TestAllTracerWithOutput result = Execute(Activation, 21020, code); + Assert.That(result.Error, Is.EqualTo("OutOfGas")); + } + } +} diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs index 9287d74ec8bd..a686d51fdef5 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs @@ -118,14 +118,13 @@ protected GethLikeTxTrace ExecuteAndTraceToFile(Action dum /// /// deprecated. Please use activation instead of blockNumber. /// - protected TestAllTracerWithOutput Execute(long blockNumber, params byte[] code) - { - return Execute((blockNumber, Timestamp), code); - } + protected TestAllTracerWithOutput Execute(long blockNumber, params byte[] code) => Execute((blockNumber, Timestamp), code); - protected TestAllTracerWithOutput Execute(ForkActivation activation, params byte[] code) + protected TestAllTracerWithOutput Execute(ForkActivation activation, params byte[] code) => Execute(activation, 100000, code); + + protected TestAllTracerWithOutput Execute(ForkActivation activation, long gasLimit, params byte[] code) { - (Block block, Transaction transaction) = PrepareTx(activation, 100000, code); + (Block block, Transaction transaction) = PrepareTx(activation, gasLimit, code); TestAllTracerWithOutput tracer = CreateTracer(); _processor.Execute(transaction, new BlockExecutionContext(block.Header, SpecProvider.GetSpec(block.Header)), tracer); return tracer; @@ -139,14 +138,9 @@ protected TestAllTracerWithOutput Execute(ForkActivation activation, Transaction return tracer; } - protected TestAllTracerWithOutput Execute(params byte[] code) - { - return Execute(Activation, code); - } - protected TestAllTracerWithOutput Execute(Transaction tx) - { - return Execute(Activation, tx); - } + protected TestAllTracerWithOutput Execute(params byte[] code) => Execute(Activation, code); + + protected TestAllTracerWithOutput Execute(Transaction tx) => Execute(Activation, tx); protected virtual TestAllTracerWithOutput CreateTracer() => new(); diff --git a/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs b/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs index 24b15a7e66cb..a3db55e61c0b 100644 --- a/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs +++ b/src/Nethermind/Nethermind.Evm/Instructions/EvmInstructions.Call.cs @@ -109,9 +109,6 @@ public static EvmExceptionType InstructionCall( Address codeSource = stack.PopAddress(); if (codeSource is null) goto StackUnderflow; - // Charge gas for accessing the account's code (including delegation logic if applicable). - if (!EvmCalculations.ChargeAccountAccessGasWithDelegation(ref gasAvailable, vm, codeSource)) goto OutOfGas; - ref readonly ExecutionEnvironment env = ref vm.EvmState.Env; // Determine the call value based on the call type. UInt256 callValue; @@ -130,6 +127,16 @@ public static EvmExceptionType InstructionCall( goto StackUnderflow; } + // Pop additional parameters: data offset, data length, output offset, and output length. + if (!stack.PopUInt256(out UInt256 dataOffset) || + !stack.PopUInt256(out UInt256 dataLength) || + !stack.PopUInt256(out UInt256 outputOffset) || + !stack.PopUInt256(out UInt256 outputLength)) + goto StackUnderflow; + + // Charge gas for accessing the account's code (including delegation logic if applicable). + if (!EvmCalculations.ChargeAccountAccessGasWithDelegation(ref gasAvailable, vm, codeSource)) goto OutOfGas; + // For non-delegate calls, the transfer value is the call value. UInt256 transferValue = typeof(TOpCall) == typeof(OpDelegateCall) ? UInt256.Zero : callValue; // Enforce static call restrictions: no value transfer allowed unless it's a CALLCODE. @@ -162,13 +169,6 @@ public static EvmExceptionType InstructionCall( gasExtra += GasCostOf.NewAccount; } - // Pop additional parameters: data offset, data length, output offset, and output length. - if (!stack.PopUInt256(out UInt256 dataOffset) || - !stack.PopUInt256(out UInt256 dataLength) || - !stack.PopUInt256(out UInt256 outputOffset) || - !stack.PopUInt256(out UInt256 outputLength)) - goto StackUnderflow; - // Update gas: call cost, memory expansion for input and output, and extra gas. if (!EvmCalculations.UpdateGas(spec.GetCallCost(), ref gasAvailable) || !EvmCalculations.UpdateMemoryCost(vm.EvmState, ref gasAvailable, in dataOffset, dataLength) || diff --git a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs index f9f2d10556f1..7e96065b48c9 100644 --- a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs +++ b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs @@ -227,7 +227,7 @@ private TransactionResult CallAndRestore( ITxTracer tracer, BlockProcessingComponents components) { - transaction.SenderAddress ??= Address.SystemUser; + transaction.SenderAddress ??= Address.Zero; //Ignore nonce on all CallAndRestore calls transaction.Nonce = components.StateReader.GetNonce(blockHeader, transaction.SenderAddress); diff --git a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs index 058db11d0785..daba9ebcbe32 100644 --- a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs +++ b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs @@ -98,7 +98,7 @@ public override Transaction ToTransaction() tx.Data = Input; tx.GasPrice = GasPrice ?? 0; tx.ChainId = ChainId; - tx.SenderAddress = From ?? Address.SystemUser; + tx.SenderAddress = From ?? Address.Zero; if ((R != 0 || S != 0) && (R is not null || S is not null)) { ulong v; @@ -130,7 +130,7 @@ public override void EnsureDefaults(long? gasCap) ? gasCap : Math.Min(gasCap.Value, Gas.Value); - From ??= Address.SystemUser; + From ??= Address.Zero; } public override bool ShouldSetBaseFee() => GasPrice.IsPositive(); diff --git a/src/Nethermind/Nethermind.Init/Modules/MainProcessingContext.cs b/src/Nethermind/Nethermind.Init/Modules/MainProcessingContext.cs index 48a8e79fe3e8..9b4969d39625 100644 --- a/src/Nethermind/Nethermind.Init/Modules/MainProcessingContext.cs +++ b/src/Nethermind/Nethermind.Init/Modules/MainProcessingContext.cs @@ -75,7 +75,7 @@ public MainProcessingContext( { PreBlockCaches preBlockCaches = ctx.Resolve(); // Note: The use of FrozenDictionary means that this cannot be used for other processing env also due to risk of memory leak. - return new CachedCodeInfoRepository(precompileProvider, originalCodeInfoRepository, preBlockCaches?.PrecompileCache); + return new CachedCodeInfoRepository(precompileProvider, originalCodeInfoRepository, blocksConfig.CachePrecompilesOnBlockProcessing ? preBlockCaches?.PrecompileCache : null); }) ; } diff --git a/src/Nethermind/Nethermind.Init/PruningTrieStateFactory.cs b/src/Nethermind/Nethermind.Init/PruningTrieStateFactory.cs index 55707205ddb5..4153e411934b 100644 --- a/src/Nethermind/Nethermind.Init/PruningTrieStateFactory.cs +++ b/src/Nethermind/Nethermind.Init/PruningTrieStateFactory.cs @@ -87,7 +87,7 @@ ILogManager logManager trieStore, dbProvider, logManager, - new LastNStateRootTracker(blockTree, 128)); + new LastNStateRootTracker(blockTree, syncConfig.SnapServingMaxDepth)); // NOTE: Don't forget this! Very important! TrieStoreBoundaryWatcher trieStoreBoundaryWatcher = new(stateManager, blockTree!, logManager); @@ -190,10 +190,10 @@ ILogManager logManager AdviseConfig(pruningConfig, dbConfig, hardwareInfo); - if (syncConfig.SnapServingEnabled == true && pruningConfig.PruningBoundary < 128) + if (syncConfig.SnapServingEnabled == true && pruningConfig.PruningBoundary < syncConfig.SnapServingMaxDepth) { - if (_logger.IsInfo) _logger.Info($"Snap serving enabled, but {nameof(pruningConfig.PruningBoundary)} is less than 128. Setting to 128."); - pruningConfig.PruningBoundary = 128; + if (_logger.IsInfo) _logger.Info($"Snap serving enabled, but {nameof(pruningConfig.PruningBoundary)} is less than {syncConfig.SnapServingMaxDepth}. Setting to {syncConfig.SnapServingMaxDepth}."); + pruningConfig.PruningBoundary = syncConfig.SnapServingMaxDepth; } if (pruningConfig.PruningBoundary < 64) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs index 379c644d9e3c..0fe1eec136b7 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs @@ -125,7 +125,7 @@ public async Task Eth_estimate_gas_with_accessList(bool senderAccessList, long g AccessListTransactionForRpc transaction = test.JsonSerializer.Deserialize( - $"{{\"type\":\"0x1\", \"data\": \"{code.ToHexString(true)}\"}}"); + $"{{\"type\":\"0x1\", \"from\": \"{Address.SystemUser}\", \"data\": \"{code.ToHexString(true)}\"}}"); string serialized = await test.TestEthRpc("eth_estimateGas", transaction, "0x0"); Assert.That( serialized, Is.EqualTo($"{{\"jsonrpc\":\"2.0\",\"result\":\"{gasPriceWithoutAccessList.ToHexString(true)}\",\"id\":67}}")); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs index 409bf3d875b5..e880f58759db 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs @@ -297,6 +297,51 @@ public async Task Eth_call_with_base_fee_opcode_should_return_0() serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"id\":67}")); } + [Test] + public async Task Eth_call_with_base_fee_opcode_without_from_address_should_return_0() + { + using Context ctx = await Context.CreateWithLondonEnabled(); + + byte[] code = Prepare.EvmCode + .Op(Instruction.BASEFEE) + .PushData(0) + .Op(Instruction.MSTORE) + .PushData("0x20") + .PushData("0x0") + .Op(Instruction.RETURN) + .Done; + + string dataStr = code.ToHexString(); + TransactionForRpc transaction = ctx.Test.JsonSerializer.Deserialize( + $"{{\"type\": \"0x2\", \"data\": \"{dataStr}\"}}"); + string serialized = await ctx.Test.TestEthRpc("eth_call", transaction); + Assert.That( + serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"id\":67}")); + } + + [Test] + public async Task Eth_call_with_value_transfer_without_from_address_should_throw() + { + using Context ctx = await Context.CreateWithLondonEnabled(); + + byte[] code = Prepare.EvmCode + .Op(Instruction.BASEFEE) + .PushData(0) + .Op(Instruction.MSTORE) + .PushData("0x20") + .PushData("0x0") + .Op(Instruction.RETURN) + .Done; + + string dataStr = code.ToHexString(); + TransactionForRpc transaction = ctx.Test.JsonSerializer.Deserialize( + $"{{\"type\": \"0x2\", \"value\":\"{1.Ether()}\", \"data\": \"{dataStr}\"}}"); + string serialized = await ctx.Test.TestEthRpc("eth_call", transaction); + Console.WriteLine(serialized); + Assert.That( + serialized, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"insufficient sender balance\"},\"id\":67}")); + } + [Test] public async Task Eth_call_with_revert() { diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs index 8e2ecb1f265a..0e6b8f73d9ce 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs @@ -1226,21 +1226,21 @@ public enum AccessListProvided Full } - [TestCase(AccessListProvided.None, false, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] - [TestCase(AccessListProvided.Full, false, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] - [TestCase(AccessListProvided.Partial, false, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] + [TestCase(AccessListProvided.None, false, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] + [TestCase(AccessListProvided.Full, false, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]}],\"gasUsed\":\"0x10f53\"},\"id\":67}")] + [TestCase(AccessListProvided.Partial, false, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] - [TestCase(AccessListProvided.None, true, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] - [TestCase(AccessListProvided.Full, true, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] - [TestCase(AccessListProvided.Partial, true, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] + [TestCase(AccessListProvided.None, true, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] + [TestCase(AccessListProvided.Full, true, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]}],\"gasUsed\":\"0x10f53\"},\"id\":67}")] + [TestCase(AccessListProvided.Partial, true, 2, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]}],\"gasUsed\":\"0xf71b\"},\"id\":67}")] - [TestCase(AccessListProvided.None, true, 12, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0x14739\"},\"id\":67}")] - [TestCase(AccessListProvided.Full, true, 12, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0x14739\"},\"id\":67}")] - [TestCase(AccessListProvided.Partial, true, 12, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\"]}],\"gasUsed\":\"0x14739\"},\"id\":67}")] + [TestCase(AccessListProvided.None, true, 12, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0x14739\"},\"id\":67}")] + [TestCase(AccessListProvided.Full, true, 12, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\"]}],\"gasUsed\":\"0x15f71\"},\"id\":67}")] + [TestCase(AccessListProvided.Partial, true, 12, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\"]}],\"gasUsed\":\"0x14739\"},\"id\":67}")] - [TestCase(AccessListProvided.None, true, 17, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\",\"0x000000000000000000000000000000000000000000000000000000000000000d\",\"0x000000000000000000000000000000000000000000000000000000000000000e\",\"0x000000000000000000000000000000000000000000000000000000000000000f\",\"0x0000000000000000000000000000000000000000000000000000000000000010\",\"0x0000000000000000000000000000000000000000000000000000000000000011\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0x16f48\"},\"id\":67}")] - [TestCase(AccessListProvided.Full, true, 17, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\",\"0x000000000000000000000000000000000000000000000000000000000000000d\",\"0x000000000000000000000000000000000000000000000000000000000000000e\",\"0x000000000000000000000000000000000000000000000000000000000000000f\",\"0x0000000000000000000000000000000000000000000000000000000000000010\",\"0x0000000000000000000000000000000000000000000000000000000000000011\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0x16f48\"},\"id\":67}")] - [TestCase(AccessListProvided.Partial, true, 17, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\",\"0x000000000000000000000000000000000000000000000000000000000000000d\",\"0x000000000000000000000000000000000000000000000000000000000000000e\",\"0x000000000000000000000000000000000000000000000000000000000000000f\",\"0x0000000000000000000000000000000000000000000000000000000000000010\",\"0x0000000000000000000000000000000000000000000000000000000000000011\"]}],\"gasUsed\":\"0x16f48\"},\"id\":67}")] + [TestCase(AccessListProvided.None, true, 17, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\",\"0x000000000000000000000000000000000000000000000000000000000000000d\",\"0x000000000000000000000000000000000000000000000000000000000000000e\",\"0x000000000000000000000000000000000000000000000000000000000000000f\",\"0x0000000000000000000000000000000000000000000000000000000000000010\",\"0x0000000000000000000000000000000000000000000000000000000000000011\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]}],\"gasUsed\":\"0x16f48\"},\"id\":67}")] + [TestCase(AccessListProvided.Full, true, 17, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0xfffffffffffffffffffffffffffffffffffffffe\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\"]},{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\",\"0x000000000000000000000000000000000000000000000000000000000000000d\",\"0x000000000000000000000000000000000000000000000000000000000000000e\",\"0x000000000000000000000000000000000000000000000000000000000000000f\",\"0x0000000000000000000000000000000000000000000000000000000000000010\",\"0x0000000000000000000000000000000000000000000000000000000000000011\"]}],\"gasUsed\":\"0x18780\"},\"id\":67}")] + [TestCase(AccessListProvided.Partial, true, 17, "{\"jsonrpc\":\"2.0\",\"result\":{\"accessList\":[{\"address\":\"0x76e68a8696537e4141926f3e528733af9e237d69\",\"storageKeys\":[]},{\"address\":\"0xbd770416a3345f91e4b34576cb804a576fa48eb1\",\"storageKeys\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0000000000000000000000000000000000000000000000000000000000000002\",\"0x0000000000000000000000000000000000000000000000000000000000000003\",\"0x0000000000000000000000000000000000000000000000000000000000000004\",\"0x0000000000000000000000000000000000000000000000000000000000000005\",\"0x0000000000000000000000000000000000000000000000000000000000000006\",\"0x0000000000000000000000000000000000000000000000000000000000000007\",\"0x0000000000000000000000000000000000000000000000000000000000000008\",\"0x0000000000000000000000000000000000000000000000000000000000000009\",\"0x000000000000000000000000000000000000000000000000000000000000000a\",\"0x000000000000000000000000000000000000000000000000000000000000000b\",\"0x000000000000000000000000000000000000000000000000000000000000000c\",\"0x000000000000000000000000000000000000000000000000000000000000000d\",\"0x000000000000000000000000000000000000000000000000000000000000000e\",\"0x000000000000000000000000000000000000000000000000000000000000000f\",\"0x0000000000000000000000000000000000000000000000000000000000000010\",\"0x0000000000000000000000000000000000000000000000000000000000000011\"]}],\"gasUsed\":\"0x16f48\"},\"id\":67}")] public async Task Eth_create_access_list_sample(AccessListProvided accessListProvided, bool optimize, long loads, string expected) { @@ -1270,6 +1270,16 @@ public static void Should_handle_gasCap_as_max_if_null_or_zero(long? gasCap) Assert.That(rpcTx.Gas, Is.EqualTo(long.MaxValue), "Gas must be set to max if gasCap is null or 0"); } + [Test] + public static void Should_handle_fromAddress_as_zero_if_null() + { + LegacyTransactionForRpc rpcTx = new LegacyTransactionForRpc(); + + rpcTx.EnsureDefaults(0); + + Assert.That(rpcTx.From, Is.EqualTo(Address.Zero), "From address must be set to zero if tx.from is null"); + } + [Ignore(reason: "Shows disparity across 'default' methods")] [TestCase(null)] [TestCase(0)] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs index 6a258e603242..a069835132fb 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs @@ -46,7 +46,7 @@ namespace Nethermind.JsonRpc.Test.Modules.Proof; [TestFixture(false, false)] public class ProofRpcModuleTests { - private readonly bool _createSystemAccount; + private readonly bool _createZeroAccount; private readonly bool _useNonZeroGasPrice; private IProofRpcModule _proofRpcModule = null!; private IBlockTree _blockTree = null!; @@ -55,9 +55,9 @@ public class ProofRpcModuleTests private WorldStateManager _worldStateManager = null!; private IContainer _container; - public ProofRpcModuleTests(bool createSystemAccount, bool useNonZeroGasPrice) + public ProofRpcModuleTests(bool createZeroAccount, bool useNonZeroGasPrice) { - _createSystemAccount = createSystemAccount; + _createZeroAccount = createZeroAccount; _useNonZeroGasPrice = useNonZeroGasPrice; } @@ -376,7 +376,7 @@ public async Task Can_call_with_storage_load() .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); } [TestCase] @@ -389,7 +389,7 @@ public async Task Can_call_with_many_storage_loads() .Op(Instruction.SLOAD) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); } [TestCase] @@ -402,7 +402,7 @@ public async Task Can_call_with_storage_write() .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); } [TestCase] @@ -416,17 +416,17 @@ public async Task Can_call_with_extcodecopy() .Op(Instruction.EXTCODECOPY) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3)); } [TestCase] - public async Task Can_call_with_extcodecopy_to_system_account() + public async Task Can_call_with_extcodecopy_to_zero_account() { byte[] code = Prepare.EvmCode .PushData("0x20") .PushData("0x00") .PushData("0x00") - .PushData(Address.SystemUser) + .PushData(Address.Zero) .Op(Instruction.EXTCODECOPY) .Done; CallResultWithProof result = await TestCallWithCode(code); @@ -441,14 +441,14 @@ public async Task Can_call_with_extcodesize() .Op(Instruction.EXTCODESIZE) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3)); } [TestCase] - public async Task Can_call_with_extcodesize_to_system_account() + public async Task Can_call_with_extcodesize_to_zero_account() { byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) + .PushData(Address.Zero) .Op(Instruction.EXTCODESIZE) .Done; CallResultWithProof result = await TestCallWithCode(code); @@ -464,15 +464,15 @@ public async Task Can_call_with_extcodehash() .Op(Instruction.EXTCODEHASH) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3)); } [TestCase] - public async Task Can_call_with_extcodehash_to_system_account() + public async Task Can_call_with_extcodehash_to_zero_account() { _specProvider.NextForkSpec = MuirGlacier.Instance; byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) + .PushData(Address.Zero) .Op(Instruction.EXTCODEHASH) .Done; CallResultWithProof result = await TestCallWithCode(code); @@ -487,7 +487,7 @@ public async Task Can_call_with_just_basic_addresses() .Op(Instruction.STOP) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); } [TestCase] @@ -500,7 +500,7 @@ public async Task Can_call_with_balance() .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3 + (_useNonZeroGasPrice ? 1 : 0))); } [TestCase] @@ -512,15 +512,15 @@ public async Task Can_call_with_self_balance() .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); } [TestCase] - public async Task Can_call_with_balance_of_system_account() + public async Task Can_call_with_balance_of_zero_account() { _specProvider.NextForkSpec = MuirGlacier.Instance; byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) + .PushData(Address.Zero) .Op(Instruction.BALANCE) .Done; CallResultWithProof result = await TestCallWithCode(code); @@ -528,7 +528,7 @@ public async Task Can_call_with_balance_of_system_account() } [TestCase] - public async Task Can_call_with_call_to_system_account_with_zero_value() + public async Task Can_call_with_call_to_zero_account_with_zero_value() { _specProvider.NextForkSpec = MuirGlacier.Instance; byte[] code = Prepare.EvmCode @@ -537,7 +537,7 @@ public async Task Can_call_with_call_to_system_account_with_zero_value() .PushData(0) .PushData(0) .PushData(0) - .PushData(Address.SystemUser) + .PushData(Address.Zero) .PushData(1000000) .Op(Instruction.CALL) .Done; @@ -546,7 +546,7 @@ public async Task Can_call_with_call_to_system_account_with_zero_value() } [TestCase] - public async Task Can_call_with_static_call_to_system_account() + public async Task Can_call_with_static_call_to_zero_account() { _specProvider.NextForkSpec = MuirGlacier.Instance; byte[] code = Prepare.EvmCode @@ -554,7 +554,7 @@ public async Task Can_call_with_static_call_to_system_account() .PushData(0) .PushData(0) .PushData(0) - .PushData(Address.SystemUser) + .PushData(Address.Zero) .PushData(1000000) .Op(Instruction.STATICCALL) .Done; @@ -563,7 +563,7 @@ public async Task Can_call_with_static_call_to_system_account() } [TestCase] - public async Task Can_call_with_delegate_call_to_system_account() + public async Task Can_call_with_delegate_call_to_zero_account() { _specProvider.NextForkSpec = MuirGlacier.Instance; byte[] code = Prepare.EvmCode @@ -571,7 +571,7 @@ public async Task Can_call_with_delegate_call_to_system_account() .PushData(0) .PushData(0) .PushData(0) - .PushData(Address.SystemUser) + .PushData(Address.Zero) .PushData(1000000) .Op(Instruction.DELEGATECALL) .Done; @@ -580,7 +580,7 @@ public async Task Can_call_with_delegate_call_to_system_account() } [TestCase] - public async Task Can_call_with_call_to_system_account_with_non_zero_value() + public async Task Can_call_with_call_to_zero_account_with_non_zero_value() { _specProvider.NextForkSpec = MuirGlacier.Instance; byte[] code = Prepare.EvmCode @@ -589,7 +589,7 @@ public async Task Can_call_with_call_to_system_account_with_non_zero_value() .PushData(0) .PushData(0) .PushData(1) - .PushData(Address.SystemUser) + .PushData(Address.Zero) .PushData(1000000) .Op(Instruction.CALL) .Done; @@ -612,7 +612,7 @@ public async Task Can_call_with_call_with_zero_value() .Op(Instruction.CALL) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3)); } [TestCase] @@ -629,7 +629,7 @@ public async Task Can_call_with_static_call() .Op(Instruction.STATICCALL) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3)); } [TestCase] @@ -646,7 +646,7 @@ public async Task Can_call_with_delegate_call() .Op(Instruction.DELEGATECALL) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(_createSystemAccount && _useNonZeroGasPrice ? 3 : 2)); + Assert.That(result.Accounts.Length, Is.EqualTo(3)); } [TestCase] @@ -664,7 +664,7 @@ public async Task Can_call_with_call_with_non_zero_value() .Op(Instruction.CALL) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3 + (_useNonZeroGasPrice ? 1 : 0))); } [TestCase] @@ -677,15 +677,15 @@ public async Task Can_call_with_self_destruct() .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(2 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(3 + (_useNonZeroGasPrice ? 1 : 0))); } [TestCase] - public async Task Can_call_with_self_destruct_to_system_account() + public async Task Can_call_with_self_destruct_to_zero_account() { _specProvider.NextForkSpec = MuirGlacier.Instance; byte[] code = Prepare.EvmCode - .PushData(Address.SystemUser) + .PushData(Address.Zero) .Op(Instruction.SELFDESTRUCT) .Done; CallResultWithProof result = await TestCallWithCode(code); @@ -705,7 +705,7 @@ public async Task Can_call_with_many_storage_writes() .Op(Instruction.SSTORE) .Done; CallResultWithProof result = await TestCallWithCode(code); - Assert.That(result.Accounts.Length, Is.EqualTo(1 + (_useNonZeroGasPrice ? 1 : 0))); + Assert.That(result.Accounts.Length, Is.EqualTo(2)); } [TestCase] @@ -846,7 +846,7 @@ private async Task TestCallWithStorageAndCode(byte[] code, UInt256 gasPrice, Add TransactionForRpc tx = new LegacyTransactionForRpc { - // we are testing system transaction here when From is null + // we are testing transaction from zero address here when From is null From = from, To = TestItem.AddressB, GasPrice = gasPrice, @@ -908,9 +908,9 @@ private async Task TestCallWithStorageAndCode(byte[] code, UInt256 gasPrice, Add AddCode(stateProvider, TestItem.AddressB, code); } - if (_createSystemAccount) + if (_createZeroAccount) { - AddAccount(stateProvider, Address.SystemUser, 1.Ether()); + AddAccount(stateProvider, Address.Zero, 1.Ether()); } stateProvider.CommitTree(0); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs index 276a983e0fde..5e3cf3443b13 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs @@ -55,8 +55,6 @@ protected override SimulatePayload Prepare(Simulat Transaction tx = callTransactionModel.ToTransaction(); - // The RPC set SystemUser as default, but we want to set it to zero to follow hive test. - if (tx.SenderAddress == Address.SystemUser) tx.SenderAddress = Address.Zero; tx.ChainId = _blockchainBridge.GetChainId(); TransactionWithSourceDetails? result = new() diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofRpcModule.cs index 0e558150ce95..6a8167080165 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofRpcModule.cs @@ -61,14 +61,14 @@ public ResultWrapper proof_call(TransactionForRpc tx, Block { TxRoot = Keccak.EmptyTreeHash, ReceiptsRoot = Keccak.EmptyTreeHash, - Author = Address.SystemUser + Author = Address.Zero }; callHeader.TotalDifficulty = sourceHeader.TotalDifficulty + callHeader.Difficulty; callHeader.Hash = callHeader.CalculateHash(); Transaction transaction = tx.ToTransaction(); - transaction.SenderAddress ??= Address.SystemUser; + transaction.SenderAddress ??= Address.Zero; if (transaction.GasLimit == 0) { @@ -77,7 +77,7 @@ public ResultWrapper proof_call(TransactionForRpc tx, Block Block block = new(callHeader, new[] { transaction }, []); - ProofBlockTracer proofBlockTracer = new(null, transaction.SenderAddress == Address.SystemUser); + ProofBlockTracer proofBlockTracer = new(null, transaction.SenderAddress == Address.Zero); scope.Component.Trace(block, proofBlockTracer); CallResultWithProof callResultWithProof = new(); diff --git a/src/Nethermind/Nethermind.Logging.NLog/NLogManager.cs b/src/Nethermind/Nethermind.Logging.NLog/NLogManager.cs index 830e25fd2ab3..4497f7cf0487 100644 --- a/src/Nethermind/Nethermind.Logging.NLog/NLogManager.cs +++ b/src/Nethermind/Nethermind.Logging.NLog/NLogManager.cs @@ -31,6 +31,7 @@ public NLogManager(string logFileName, string logDirectory = null, string logRul // Required since 'NLog.config' could change during runtime, we need to re-apply the configuration _logManagerOnConfigurationChanged = (sender, args) => Setup(logFileName, logDirectory, logRules); LogManager.ConfigurationChanged += _logManagerOnConfigurationChanged; + Static.LogManager = this; } private static void Setup(string logFileName, string logDirectory = null, string logRules = null) diff --git a/src/Nethermind/Nethermind.Logging/StaticLoggerFactory.cs b/src/Nethermind/Nethermind.Logging/StaticLoggerFactory.cs new file mode 100644 index 000000000000..c38d81648b9b --- /dev/null +++ b/src/Nethermind/Nethermind.Logging/StaticLoggerFactory.cs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; + +namespace Nethermind.Logging; + +public static class Static +{ + public static ILogManager LogManager { get; set; } = LimboLogs.Instance; +} diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs index 8ee688de990a..fd73ea05442c 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V1.cs @@ -140,7 +140,7 @@ public async Task can_parse_forkchoiceUpdated_with_implicit_null_payloadAttribut public void ForkchoiceV1_ToString_returns_correct_results() { ForkchoiceStateV1 forkchoiceState = new(TestItem.KeccakA, TestItem.KeccakF, TestItem.KeccakC); - forkchoiceState.ToString().Should().Be("ForkChoice: 0x03783f...35b760, Safe: 0x017e66...b18f72, Finalized: 0xe61d9a...97c37a"); + forkchoiceState.ToString().Should().Be("ForkChoice: 0x03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760, Safe: 0x017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f72, Finalized: 0xe61d9a3d3848fb2cdd9a2ab61e2f21a10ea431275aed628a0557f9dee697c37a"); } [Test] @@ -1551,6 +1551,9 @@ public void Should_return_expected_capabilities_for_mainnet() nameof(IEngineRpcModule.engine_getPayloadV4), nameof(IEngineRpcModule.engine_newPayloadV4), + + nameof(IEngineRpcModule.engine_getPayloadV5), + nameof(IEngineRpcModule.engine_getBlobsV2) }; Assert.That(result, Is.EquivalentTo(expectedMethods)); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs index e1d8404c53da..8ad25a2ec4ef 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs @@ -8,7 +8,6 @@ using Nethermind.Core.ExecutionRequest; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; -using Nethermind.Evm; using Nethermind.Evm.State; namespace Nethermind.Merge.Plugin.Test; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/ForkchoiceStateV1.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/ForkchoiceStateV1.cs index 546e2fe4df9d..1eb47a3018ff 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/ForkchoiceStateV1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/ForkchoiceStateV1.cs @@ -10,33 +10,26 @@ namespace Nethermind.Merge.Plugin.Data; /// /// ///
-public class ForkchoiceStateV1 +public class ForkchoiceStateV1(Hash256 headBlockHash, Hash256 finalizedBlockHash, Hash256 safeBlockHash) { - public ForkchoiceStateV1(Hash256 headBlockHash, Hash256 finalizedBlockHash, Hash256 safeBlockHash) - { - HeadBlockHash = headBlockHash; - FinalizedBlockHash = finalizedBlockHash; - SafeBlockHash = safeBlockHash; - } - /// /// Hash of the head of the canonical chain. /// - public Hash256 HeadBlockHash { get; set; } + public Hash256 HeadBlockHash { get; set; } = headBlockHash; /// /// 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 Hash256 SafeBlockHash { get; set; } + public Hash256 SafeBlockHash { get; set; } = safeBlockHash; /// /// Hash of the most recent finalized block /// /// Can be when transition block is not finalized yet. - public Hash256 FinalizedBlockHash { get; set; } + public Hash256 FinalizedBlockHash { get; set; } = finalizedBlockHash; - public override string ToString() => $"ForkChoice: {HeadBlockHash.ToShortString()}, Safe: {SafeBlockHash.ToShortString()}, Finalized: {FinalizedBlockHash.ToShortString()}"; + public override string ToString() => $"ForkChoice: {HeadBlockHash}, Safe: {SafeBlockHash}, Finalized: {FinalizedBlockHash}"; public string ToString(long? headNumber, long? safeNumber, long? finalizedNumber) => headNumber is null || safeNumber is null || finalizedNumber is null ? ToString() diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs index 5c9cb6397c22..6b053535e37a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs @@ -162,7 +162,7 @@ public async Task> HandleAsync(ExecutionPayload r { if (!_blockValidator.ValidateOrphanedBlock(block!, out string? error)) { - if (_logger.IsWarn) _logger.Warn(InvalidBlockHelper.GetMessage(block, "orphaned block is invalid")); + if (_logger.IsWarn) _logger.Warn(InvalidBlockHelper.GetMessage(block, $"orphaned block is invalid: {error}")); return NewPayloadV1Result.Invalid(null, $"Invalid block without parent: {error}."); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs index 92d6a2961e0b..5a350188359c 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs @@ -22,7 +22,6 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Exceptions; -using Nethermind.Core.Timers; using Nethermind.Db; using Nethermind.Facade.Proxy; using Nethermind.HealthChecks; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs b/src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs new file mode 100644 index 000000000000..e0d1b606bd30 --- /dev/null +++ b/src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Threading.Tasks; +using Nethermind.Api; + +namespace Nethermind.Merge.Plugin; + +public class NoEngineRequestsTracker : IEngineRequestsTracker +{ + public void OnForkchoiceUpdatedCalled() { } + + public void OnNewPayloadCalled() { } + + public Task StartAsync() + => Task.CompletedTask; +} diff --git a/src/Nethermind/Nethermind.Network.Test/ForkInfoTests.cs b/src/Nethermind/Nethermind.Network.Test/ForkInfoTests.cs index b9086423ed75..a8f77e3b9e9e 100644 --- a/src/Nethermind/Nethermind.Network.Test/ForkInfoTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/ForkInfoTests.cs @@ -56,8 +56,14 @@ public class ForkInfoTests [TestCase(15_051_000, 1_710_338_134ul, "0xdce96c2d", 1_710_338_135ul, "Future Shanghai timestamp")] [TestCase(15_051_000, 1_710_338_135ul, "0x9f3d2254", 1_746_612_311ul, "First Cancun timestamp")] [TestCase(15_051_000, 1_746_612_310ul, "0x9f3d2254", 1_746_612_311ul, "Future Cancun timestamp")] - [TestCase(15_051_000, 1_746_612_311ul, "0xc376cf8b", 0ul, "First Prague timestamp")] - [TestCase(15_051_000, 1_846_612_311ul, "0xc376cf8b", 0ul, "Future Prague timestamp")] + [TestCase(15_051_000, 1_746_612_311ul, "0xc376cf8b", 1_764_798_551ul, "First Prague timestamp")] + [TestCase(15_051_000, 1_764_798_550ul, "0xc376cf8b", 1_764_798_551ul, "Future Prague timestamp")] + [TestCase(15_051_000, 1_764_798_551ul, "0x5167e2a6", 1_765_290_071ul, "First Osaka timestamp")] + [TestCase(15_051_000, 1_765_290_070ul, "0x5167e2a6", 1_765_290_071ul, "Future Osaka timestamp")] + [TestCase(15_051_000, 1_765_290_071ul, "0xcba2a1c0", 1_767_747_671ul, "First BPO1 timestamp")] + [TestCase(15_051_000, 1_767_747_670ul, "0xcba2a1c0", 1_767_747_671ul, "Future BPO1 timestamp")] + [TestCase(15_051_000, 1_767_747_671ul, "0x07c9462e", 0ul, "First BPO2 timestamp")] + [TestCase(15_051_000, 1_867_747_671ul, "0x07c9462e", 0ul, "Future BPO2 timestamp")] public void Fork_id_and_hash_as_expected(long head, ulong headTimestamp, string forkHashHex, ulong next, string description) { Test(head, headTimestamp, KnownHashes.MainnetGenesis, forkHashHex, next, description, MainnetSpecProvider.Instance, "foundation.json"); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs index c5e4047623c1..e59dceb9c214 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs @@ -14,7 +14,7 @@ namespace Nethermind.Network.P2P.Subprotocols.Eth.V63.Messages { public class ReceiptsMessageSerializer : IZeroInnerMessageSerializer { - private static readonly RlpLimit RlpLimit = RlpLimit.For(NethermindSyncLimits.MaxReceiptFetch, nameof(ReceiptsMessage.TxReceipts)); + private static readonly RlpLimit RlpLimit = RlpLimit.For(NethermindSyncLimits.MaxReceiptFetch * 4, nameof(ReceiptsMessage.TxReceipts)); private readonly ISpecProvider _specProvider; private readonly IRlpStreamDecoder _decoder; private readonly Func _decodeArrayFunc; diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs index 27190620f79d..ea9c54eb8c1f 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs @@ -21,12 +21,9 @@ public class AckMessageSerializer : IZeroMessageSerializer public void Serialize(IByteBuffer byteBuffer, AckMessage msg) { byteBuffer.EnsureWritable(TotalLength); - // TODO: find a way to now allocate this here - byte[] data = new byte[TotalLength]; - Buffer.BlockCopy(msg.EphemeralPublicKey.Bytes, 0, data, EphemeralPublicKeyOffset, EphemeralPublicKeyLength); - Buffer.BlockCopy(msg.Nonce, 0, data, NonceOffset, NonceLength); - data[IsTokenUsedOffset] = msg.IsTokenUsed ? (byte)0x01 : (byte)0x00; - byteBuffer.WriteBytes(data); + byteBuffer.WriteBytes(msg.EphemeralPublicKey.Bytes); + byteBuffer.WriteBytes(msg.Nonce); + byteBuffer.WriteByte(msg.IsTokenUsed ? (byte)0x01 : (byte)0x00); } public AckMessage Deserialize(IByteBuffer msgBytes) diff --git a/src/Nethermind/Nethermind.Precompiles.Benchmark/PrecompileBenchmarkBase.cs b/src/Nethermind/Nethermind.Precompiles.Benchmark/PrecompileBenchmarkBase.cs index 132d06e8228c..b3d99b3283aa 100644 --- a/src/Nethermind/Nethermind.Precompiles.Benchmark/PrecompileBenchmarkBase.cs +++ b/src/Nethermind/Nethermind.Precompiles.Benchmark/PrecompileBenchmarkBase.cs @@ -16,6 +16,8 @@ namespace Nethermind.Precompiles.Benchmark { public abstract class PrecompileBenchmarkBase { + private const int Operations = 25; + protected abstract IEnumerable Precompiles { get; } protected abstract string InputsDirectory { get; } @@ -50,14 +52,14 @@ public IEnumerable Inputs // take only first line from each file inputs.AddRange(File.ReadAllLines(file) .Select(LineToTestInput).Take(1).ToArray() - .Select(i => new Param(precompile, file, i, null))); + .Select(i => new Param(precompile, Path.GetFileName(file), i, null))); } foreach (string file in Directory.GetFiles(inputsDir, "*.json", SearchOption.TopDirectoryOnly)) { EthereumJsonSerializer jsonSerializer = new(); JsonInput[] jsonInputs = jsonSerializer.Deserialize(File.ReadAllText(file)); - IEnumerable parameters = jsonInputs.Select(i => new Param(precompile, i.Name!, i.Input!, i.Expected)); + IEnumerable parameters = jsonInputs.Select(i => new Param(precompile, Path.GetFileName(i.Name!), i.Input!, i.Expected)); inputs.AddRange(parameters); } @@ -75,8 +77,16 @@ public IEnumerable Inputs private static byte[] LineToTestInput(string line) => Bytes.FromHexString(line.Split(',')[0]); - [Benchmark(Baseline = true)] + [Benchmark(Baseline = true, OperationsPerInvoke = Operations)] public (ReadOnlyMemory, bool) Baseline() - => Input.Precompile.Run(Input.Bytes, Cancun.Instance); + { + bool overallResult = true; + for (var i = 0; i < Operations; i++) + { + (_, bool result) = Input.Precompile.Run(Input.Bytes, Cancun.Instance); + overallResult &= result; + } + return (default, overallResult); + } } } diff --git a/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs b/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs index 735fecf7a790..c5abbc08a8e2 100644 --- a/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs +++ b/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs @@ -72,6 +72,13 @@ private ChainSpec LoadChainSpec(IJsonSerializer ethereumJsonSerializer) var loader = new ChainSpecFileLoader(ethereumJsonSerializer, _logger); ChainSpec chainSpec = loader.LoadEmbeddedOrFromFile(_initConfig.ChainSpecPath); + + //overwriting NetworkId which is useful for some devnets (like bloatnet) + if (_initConfig.NetworkId is not null) + { + chainSpec.NetworkId = (ulong)_initConfig.NetworkId; + } + return chainSpec; } diff --git a/src/Nethermind/Nethermind.Runner/NLog.config b/src/Nethermind/Nethermind.Runner/NLog.config index 308420fbc7c8..1dd703dcb039 100644 --- a/src/Nethermind/Nethermind.Runner/NLog.config +++ b/src/Nethermind/Nethermind.Runner/NLog.config @@ -2,7 +2,9 @@ + autoReload="true" + throwExceptions="false" + flushAllBeforeShutdown="true"> diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json index fd8d2ac609ec..01203460445b 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 37310000, - "PivotHash": "0x6914684fefc777f69ee0ff75937ae5aeb0f8713ad9a3401ca65b5da2bc15d268" + "PivotNumber": 37720000, + "PivotHash": "0x97996ee4d7e4a5a482352f2e5b35e3dc480432ac6e7e822e5355c962dd556215" }, "Discovery": { "DiscoveryVersion": "V5" diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json index c21fd84419d4..99d1887983c3 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 32820000, - "PivotHash": "0xd9097a4f00e38b283e9af34f30c8dd7ff290332f63ec3a40a8f5000b8cab29ab" + "PivotNumber": 33230000, + "PivotHash": "0x2a4ba3dcdf6914f4831b98ac85f69aee5be588bc73d721d733f135b80f6eba87" }, "Discovery": { "DiscoveryVersion": "V5" diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.json b/src/Nethermind/Nethermind.Runner/configs/chiado.json index 8fcd38ba486e..49d5078ae002 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.json +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.json @@ -18,8 +18,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 18430000, - "PivotHash": "0x1502c72cda0ba5433ee8d5746b949dcab48660b3e1c28ca8dfbf6c7f4cb17a2c", + "PivotNumber": 18540000, + "PivotHash": "0x10d11866e0ccec8048793ed9e2802dfc5778b4de920429e68fd908ba5b870f75", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", "FastSyncCatchUpHeightDelta": 10000000000, "UseGethLimitsInFastBlocks": false diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.json b/src/Nethermind/Nethermind.Runner/configs/gnosis.json index c52465595601..d7f94465007d 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.json +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.json @@ -14,8 +14,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 42800000, - "PivotHash": "0xfe4205f86c14a6ac7183460eecbef5d78383019ff6257f7478fe83241e6b5070", + "PivotNumber": 42920000, + "PivotHash": "0x7251da26a4400cbca799c1484e56a51e823a8a8633d1906761f4d8e7b2657ff5", "PivotTotalDifficulty": "8626000110427538733349499292577475819600160930", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000, diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json index d061f18fc6d5..0e154c68305a 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json @@ -12,9 +12,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 20350000, - "PivotHash": "0x1322f952adf52f780a1f4042b50698ca2cbffe47a6c52c3ee8cfe45325939504", - "PivotTotalDifficulty": "37043030" + "PivotNumber": 20470000, + "PivotHash": "0xfc36a9482cf4f7d61db4ce5aa590ea3be9da33c7deed59b0d65b452793b8c87d", + "PivotTotalDifficulty": "37221457" }, "Metrics": { "NodeName": "JOC-Mainnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json index 5a26d1836576..d4c0dbc4898f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json @@ -12,9 +12,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 13960000, - "PivotHash": "0x49b78a4bc2c1c2b973d928e142cd005fc660af2082d877923aecf373264153fa", - "PivotTotalDifficulty": "23415163" + "PivotNumber": 14080000, + "PivotHash": "0xf6f4974b7c1bdfac2bb0fb4f29c227685c749cd9d5288f113340f50a91ecd4ea", + "PivotTotalDifficulty": "23603193" }, "Metrics": { "NodeName": "JOC-Testnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json index b6a1fe0ab7c3..0a90e7a4e690 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json @@ -17,8 +17,8 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 24900000, - "PivotHash": "0x41545430031ba1fb54677ac7edaaa09c5718232ec455da9c149f3d63f033c80c", + "PivotNumber": 25160000, + "PivotHash": "0x4e6664f4a677cb6a89c4f22fcea19069bd7869fe636cf81a41f5ad2fec6574af", "PivotTotalDifficulty": "0", "HeaderStateDistance": 6 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json index 3c7ccf4ada35..5239b5d253de 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json @@ -17,8 +17,8 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 19890000, - "PivotHash": "0x8ccc7427b89aca77749fcb3f1c5777201e8e5950e4bb0a095909ab7d92873d9e", + "PivotNumber": 20190000, + "PivotHash": "0x927b4789e8e6c32a9a50d0666fea16b68830559cc85953c11fc325b221865cc9", "PivotTotalDifficulty": "37331807", "HeaderStateDistance": 6 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.json b/src/Nethermind/Nethermind.Runner/configs/mainnet.json index e9eb06be4027..e2a09e8ecf4a 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.json @@ -10,8 +10,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 23657000, - "PivotHash": "0x9841197759955198a8726749a58082c579c08147f436d8f973c56fe82bb0b931", + "PivotNumber": 23707000, + "PivotHash": "0xc6b161ce092f229bae72d4354e2899aaa539e1b20711c61338071c0fc1a747c2", "PivotTotalDifficulty": "58750003716598352816469", "FastSyncCatchUpHeightDelta": "10000000000", "AncientReceiptsBarrier": 15537394, diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json index 1b9888229448..d8c370f73ee8 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json @@ -15,8 +15,8 @@ "FastSyncCatchUpHeightDelta": "10000000000", "AncientBodiesBarrier": 105235063, "AncientReceiptsBarrier": 105235063, - "PivotNumber": 142910000, - "PivotHash": "0x0bb18551efe5c041345ae90cd3e86f3f9a1ff8d1022b9faf617010867c84994b" + "PivotNumber": 143310000, + "PivotHash": "0x84ca47b442df85397ddf73c480bb34889e5a81fd1c0e11c2530d442e1148169e" }, "Discovery": { "DiscoveryVersion": "V5" diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json index ac81375ccf85..c1624363d86f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 34800000, - "PivotHash": "0xe1682ee31297d2d1c8431a3ba2e9fba56ad95e2b9533f8d327095fd3d080a926" + "PivotNumber": 35210000, + "PivotHash": "0x263b6c0f8e70c63b761d72f2ee1e73cba8f6bae0f26d70e6a2ffe44a8de36610" }, "Discovery": { "DiscoveryVersion": "V5" diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.json b/src/Nethermind/Nethermind.Runner/configs/sepolia.json index ba158eff855e..60dfc50382c6 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.json @@ -17,8 +17,8 @@ "FastSync": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 9489000, - "PivotHash": "0x0701715fe2509f8a91b39b64ec85eec8aeba14dce5dfca1a04a492962bc32198", + "PivotNumber": 9539000, + "PivotHash": "0xd3ec641ed35ac55726db6cf1a28a4ff57daf4cee21767505b48fc68204dfb5c1", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": 10000000000, "AncientReceiptsBarrier": 1450409, diff --git a/src/Nethermind/Nethermind.Runner/configs/worldchain-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/worldchain-mainnet.json index 6884eb77e242..8119a12f3284 100644 --- a/src/Nethermind/Nethermind.Runner/configs/worldchain-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/worldchain-mainnet.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 21040000, - "PivotHash": "0x14d35cdb573e4481eb718d15c1467d63118bfe9d30b83566a676d8c0247fc342" + "PivotNumber": 21440000, + "PivotHash": "0x14d923acf76133c35ae4861ddaf6004aad935541796b4d9608b9be23b55494fa" }, "Discovery": { "DiscoveryVersion": "V5" diff --git a/src/Nethermind/Nethermind.Runner/configs/worldchain-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/worldchain-sepolia.json index a938a000d049..03e912729fba 100644 --- a/src/Nethermind/Nethermind.Runner/configs/worldchain-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/worldchain-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 20430000, - "PivotHash": "0xf74c53163dd35e1332ad5f4ad92240d0284b5802846684043b2296e3a11b42b0" + "PivotNumber": 20840000, + "PivotHash": "0x44c699815804ec27223197de9f833aab4c9fb876c8738a7ead1bd0e511cb79e0" }, "Discovery": { "DiscoveryVersion": "V5" diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index bbcb2566b88b..5f796e5db26d 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -18,6 +18,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Int256; +using Nethermind.Logging; namespace Nethermind.Serialization.Rlp { @@ -1836,21 +1837,27 @@ public sealed class DecoderAttribute(string key = RlpDecoderKey.Default) : Attri public string Key { get; } = key; } + private static ILogger _logger = Static.LogManager.GetClassLogger(); + [StackTraceHidden] public static void GuardLimit(int count, int bytesLeft, RlpLimit? limit = null) { RlpLimit l = limit ?? RlpLimit.DefaultLimit; if (count > bytesLeft || count > l.Limit) + { ThrowCountOverLimit(count, bytesLeft, l); + } } [DoesNotReturn] [StackTraceHidden] private static void ThrowCountOverLimit(int count, int bytesLeft, RlpLimit limit) { - throw new RlpLimitException(string.IsNullOrEmpty(limit.CollectionExpression) + string message = string.IsNullOrEmpty(limit.CollectionExpression) ? $"Collection count of {count} is over limit {limit.Limit} or {bytesLeft} bytes left" - : $"Collection count {limit.CollectionExpression} of {count} is over limit {limit.Limit} or {bytesLeft} bytes left"); + : $"Collection count {limit.CollectionExpression} of {count} is over limit {limit.Limit} or {bytesLeft} bytes left"; + if (_logger.IsDebug) _logger.Error($"DEBUG/ERROR: {message}; {new StackTrace()}"); + throw new RlpLimitException(message); } } diff --git a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs index 36bdd07c53d1..a1f1d9606efd 100644 --- a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs +++ b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs @@ -548,7 +548,13 @@ public static IEnumerable MainnetActivations yield return new TestCaseData(MainnetSpecProvider.CancunActivation) { TestName = "Cancun" }; yield return new TestCaseData(new ForkActivation(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.PragueBlockTimestamp - 1)) { TestName = "Before Prague" }; yield return new TestCaseData(MainnetSpecProvider.PragueActivation) { TestName = "Prague" }; - yield return new TestCaseData(new ForkActivation(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.PragueBlockTimestamp + 100000000)) { TestName = "Future" }; + yield return new TestCaseData(new ForkActivation(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.OsakaBlockTimestamp - 1)) { TestName = "Before Osaka" }; + yield return new TestCaseData(MainnetSpecProvider.OsakaActivation) { TestName = "Osaka" }; + yield return new TestCaseData(new ForkActivation(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.BPO1BlockTimestamp - 1)) { TestName = "Before BPO1" }; + yield return new TestCaseData(MainnetSpecProvider.BPO1Activation) { TestName = "BPO1" }; + yield return new TestCaseData(new ForkActivation(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.BPO2BlockTimestamp - 1)) { TestName = "Before BPO2" }; + yield return new TestCaseData(MainnetSpecProvider.BPO2Activation) { TestName = "BPO2" }; + yield return new TestCaseData(new ForkActivation(MainnetSpecProvider.ParisBlockNumber, MainnetSpecProvider.BPO2BlockTimestamp + 100000000)) { TestName = "Future" }; } } @@ -595,9 +601,13 @@ public void Mainnet_loads_properly(ForkActivation forkActivation) IReleaseSpec postCancunSpec = provider.GetSpec(MainnetSpecProvider.CancunActivation); IReleaseSpec postPragueSpec = provider.GetSpec(MainnetSpecProvider.PragueActivation); + IReleaseSpec postOsakaSpec = provider.GetSpec(MainnetSpecProvider.OsakaActivation); + IReleaseSpec postBPO1Spec = provider.GetSpec(MainnetSpecProvider.BPO1Activation); + IReleaseSpec postBPO2Spec = provider.GetSpec(MainnetSpecProvider.BPO2Activation); VerifyCancunSpecificsForMainnetAndSepolia(postCancunSpec); VerifyPragueSpecificsForMainnetHoodiAndSepolia(provider.ChainId, postPragueSpec); + VerifyOsakaSpecificsForMainnetHoleskyHoodiAndSepolia(provider.ChainId, postOsakaSpec, postBPO1Spec, postBPO2Spec); } [Flags] diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs index ff14862f117f..a1a02a58ea9a 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs @@ -129,6 +129,7 @@ public class ChainParameters public Address Eip7251ContractAddress { get; set; } public ulong? Eip2935TransitionTimestamp { get; set; } public Address Eip2935ContractAddress { get; set; } + public long Eip2935RingBufferSize { get; set; } = Eip2935Constants.RingBufferSize; public ulong? Eip7951TransitionTimestamp { get; set; } public ulong? Rip7212TransitionTimestamp { get; set; } public ulong? Eip7692TransitionTimestamp { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index 0b4fdc3c8fa4..9ab4f76e4081 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -257,6 +257,7 @@ protected virtual ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releas releaseSpec.IsEip2935Enabled = (chainSpec.Parameters.Eip2935TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEofEnabled = (chainSpec.Parameters.Eip7692TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.Eip2935ContractAddress = chainSpec.Parameters.Eip2935ContractAddress; + releaseSpec.Eip2935RingBufferSize = chainSpec.Parameters.Eip2935RingBufferSize; releaseSpec.IsEip7702Enabled = (chainSpec.Parameters.Eip7702TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEip7823Enabled = (chainSpec.Parameters.Eip7823TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index 7374ae2341d4..13a2f5994e38 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -159,6 +159,7 @@ bool GetForInnerPathExistence(KeyValuePair o) => Eip4788ContractAddress = chainSpecJson.Params.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress, Eip2935TransitionTimestamp = chainSpecJson.Params.Eip2935TransitionTimestamp, Eip2935ContractAddress = chainSpecJson.Params.Eip2935ContractAddress ?? Eip2935Constants.BlockHashHistoryAddress, + Eip2935RingBufferSize = chainSpecJson.Params.Eip2935RingBufferSize ?? Eip2935Constants.RingBufferSize, TransactionPermissionContract = chainSpecJson.Params.TransactionPermissionContract, TransactionPermissionContractTransition = chainSpecJson.Params.TransactionPermissionContractTransition, ValidateChainIdTransition = chainSpecJson.Params.ValidateChainIdTransition, diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs index 6a80e4a902e1..4611a4f6f7eb 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs @@ -148,6 +148,7 @@ public class ChainSpecParamsJson public Address Eip4788ContractAddress { get; set; } public ulong? Eip2935TransitionTimestamp { get; set; } public Address Eip2935ContractAddress { get; set; } + public long? Eip2935RingBufferSize { get; set; } public UInt256? Eip4844BlobGasPriceUpdateFraction { get; set; } public UInt256? Eip4844MinBlobGasPrice { get; set; } public ulong? Eip4844FeeCollectorTransitionTimestamp { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs index 44b108cea33f..b790b15372cc 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs @@ -21,6 +21,7 @@ public Prague() IsEip7002Enabled = true; IsEip7251Enabled = true; IsEip7623Enabled = true; + IsEip7904Enabled = true; Eip2935ContractAddress = Eip2935Constants.BlockHashHistoryAddress; MaxBlobCount = 9; TargetBlobCount = 6; diff --git a/src/Nethermind/Nethermind.Specs/Forks/19_Osaka.cs b/src/Nethermind/Nethermind.Specs/Forks/19_Osaka.cs index cecd32a3d262..ef283c12974c 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/19_Osaka.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/19_Osaka.cs @@ -21,7 +21,6 @@ public Osaka() IsEip7934Enabled = true; IsEip7939Enabled = true; IsEip7951Enabled = true; - IsEip7904Enabled = true; } public new static IReleaseSpec Instance => LazyInitializer.EnsureInitialized(ref _instance, static () => new Osaka()); diff --git a/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs b/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs index 7352ae53fc09..1c3425fe3ba7 100644 --- a/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/MainnetSpecProvider.cs @@ -27,7 +27,9 @@ public class MainnetSpecProvider : ISpecProvider public const ulong ShanghaiBlockTimestamp = 0x64373057; public const ulong CancunBlockTimestamp = 0x65F1B057; public const ulong PragueBlockTimestamp = 0x681b3057; - public const ulong OsakaBlockTimestamp = ulong.MaxValue - 1; + public const ulong OsakaBlockTimestamp = 0x6930b057; + public const ulong BPO1BlockTimestamp = 0x69383057; + public const ulong BPO2BlockTimestamp = 0x695db057; IReleaseSpec ISpecProvider.GetSpecInternal(ForkActivation forkActivation) => forkActivation switch @@ -49,7 +51,9 @@ IReleaseSpec ISpecProvider.GetSpecInternal(ForkActivation forkActivation) => { Timestamp: < CancunBlockTimestamp } => Shanghai.Instance, { Timestamp: < PragueBlockTimestamp } => Cancun.Instance, { Timestamp: < OsakaBlockTimestamp } => Prague.Instance, - _ => Osaka.Instance + { Timestamp: < BPO1BlockTimestamp } => Osaka.Instance, + { Timestamp: < BPO2BlockTimestamp } => BPO1.Instance, + _ => BPO2.Instance }; public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalDifficulty = null) @@ -73,6 +77,8 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD public static ForkActivation CancunActivation { get; } = (ParisBlockNumber + 2, CancunBlockTimestamp); public static ForkActivation PragueActivation { get; } = (ParisBlockNumber + 3, PragueBlockTimestamp); public static ForkActivation OsakaActivation { get; } = (ParisBlockNumber + 4, OsakaBlockTimestamp); + public static ForkActivation BPO1Activation { get; } = (ParisBlockNumber + 5, BPO1BlockTimestamp); + public static ForkActivation BPO2Activation { get; } = (ParisBlockNumber + 6, BPO2BlockTimestamp); public ForkActivation[] TransitionActivations { get; } = { (ForkActivation)HomesteadBlockNumber, @@ -91,6 +97,8 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD CancunActivation, PragueActivation, OsakaActivation, + BPO1Activation, + BPO2Activation, }; public static MainnetSpecProvider Instance { get; } = new(); diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index 5bfeb5b51e56..fd03c060c01d 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -168,6 +168,7 @@ public Address Eip2935ContractAddress private FrozenSet? _precompiles; FrozenSet IReleaseSpec.Precompiles => _precompiles ??= BuildPrecompilesCache(); + public long Eip2935RingBufferSize { get; set; } = Eip2935Constants.RingBufferSize; public virtual FrozenSet BuildPrecompilesCache() { diff --git a/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs b/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs index 243bb99cd4c6..27f361829033 100644 --- a/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs +++ b/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs @@ -10,13 +10,11 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.Core.Test.Builders; -using Nethermind.Db; using Nethermind.Int256; using Nethermind.Blockchain.Tracing.ParityStyle; using Nethermind.Logging; using Nethermind.Evm.State; using Nethermind.State; -using Nethermind.Trie; using NUnit.Framework; namespace Nethermind.Store.Test; diff --git a/src/Nethermind/Nethermind.State.Test/WorldStateManagerTests.cs b/src/Nethermind/Nethermind.State.Test/WorldStateManagerTests.cs index 63ba31d6fedd..805bf20237ab 100644 --- a/src/Nethermind/Nethermind.State.Test/WorldStateManagerTests.cs +++ b/src/Nethermind/Nethermind.State.Test/WorldStateManagerTests.cs @@ -5,6 +5,7 @@ using Autofac; using FluentAssertions; using Nethermind.Blockchain; +using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -76,10 +77,10 @@ public void ShouldNotSupportHashLookupOnHalfpath(INodeStorage.KeyScheme keySchem public void ShouldAnnounceReorgOnDispose() { int lastBlock = 256; - int reorgDepth = 128; // Default reorg depth with snap serving IBlockTree blockTree = Substitute.For(); IConfigProvider configProvider = new ConfigProvider(); + int reorgDepth = configProvider.GetConfig().SnapServingMaxDepth; { using IContainer ctx = new ContainerBuilder() diff --git a/src/Nethermind/Nethermind.State/Snap/Constants.cs b/src/Nethermind/Nethermind.State/Snap/Constants.cs index 394923319b95..ef2ab6cf3850 100644 --- a/src/Nethermind/Nethermind.State/Snap/Constants.cs +++ b/src/Nethermind/Nethermind.State/Snap/Constants.cs @@ -5,6 +5,10 @@ namespace Nethermind.State.Snap { public class Constants { + /// + /// Maximum distance from head for pivot block validation in merge/beacon chain sync. + /// Note: For snap serving depth configuration, use ISyncConfig.SnapServingMaxDepth instead. + /// public const int MaxDistanceFromHead = 128; } } diff --git a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs index 1cd795a36f79..3b2ea7ca142e 100644 --- a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs +++ b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs @@ -216,7 +216,7 @@ private void BlockTreeOnNewHeadBlock(object? sender, BlockEventArgs e) if (!_blockValidator.ValidateSuggestedBlock(currentBlock, entry.ParentHeader, out string? errorMessage)) { PeerInfo peer = entry.PeerInfo; - if (_logger.IsWarn) _logger.Warn($"Invalid downloaded block from {peer}, {errorMessage}"); + if (_logger.IsDebug) _logger.Debug($"Invalid downloaded block from {peer}, {errorMessage}"); if (peer is not null) _syncPeerPool.ReportBreachOfProtocol(peer, DisconnectReason.ForwardSyncFailed, $"invalid block received: {errorMessage}. Block: {currentBlock.Header.ToString(BlockHeader.Format.Short)}"); entry.RetryBlockRequest(); @@ -410,7 +410,7 @@ public SyncResponseHandlingResult HandleResponse(BlocksRequest response, PeerInf if (!_blockValidator.ValidateBodyAgainstHeader(entry.Header, body, out string errorMessage)) { - if (_logger.IsWarn) _logger.Warn($"Invalid downloaded block from {peer}, {errorMessage}"); + if (_logger.IsDebug) _logger.Debug($"Invalid downloaded block from {peer}, {errorMessage}"); if (peer is not null) _syncPeerPool.ReportBreachOfProtocol(peer, DisconnectReason.ForwardSyncFailed, $"invalid block received: {errorMessage}. Block: {entry.Header.ToString(BlockHeader.Format.Short)}"); result = SyncResponseHandlingResult.LesserQuality; diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs index dd9a6d3ee210..71a99f54b449 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs @@ -201,6 +201,7 @@ public void Update() best.IsInFullSync = ShouldBeInFullSyncMode(best); best.IsInDisconnected = ShouldBeInDisconnectedMode(best); best.IsInWaitingForBlock = ShouldBeInWaitingForBlockMode(best); + if (_logger.IsTrace) _logger.Trace($"Snapshot: {BuildStateStringDebug(best)}"); newModes = SyncMode.None; CheckAddFlag(best.IsInUpdatingPivot, SyncMode.UpdatingPivot, ref newModes); @@ -392,7 +393,7 @@ private bool ShouldBeInFastSyncMode(Snapshot best) // We stop `FastSyncLag` block before the highest known block in case the highest known block is non-canon // and we need to sync away from it. - // Note: its ok if target block height is not accurate as long as long full sync downloader does not stop + // Note: its ok if target block height is not accurate as long as full sync downloader does not stop // earlier than this condition below which would cause a hang. bool notReachedFullSyncTransition = best.Header < best.TargetBlock - TotalSyncLag; @@ -420,7 +421,7 @@ private bool ShouldBeInFastSyncMode(Snapshot best) (nameof(postPivotPeerAvailable), postPivotPeerAvailable), (nameof(notReachedFullSyncTransition), notReachedFullSyncTransition), (nameof(notInAStickyFullSync), notInAStickyFullSync), - ($"{nameof(stateNotDownloadedYet)}||${longRangeCatchUp}", stateNotDownloadedYet || longRangeCatchUp), + ($"{nameof(stateNotDownloadedYet)} || ${longRangeCatchUp}", stateNotDownloadedYet || longRangeCatchUp), (nameof(notNeedToWaitForHeaders), notNeedToWaitForHeaders)); } @@ -606,8 +607,8 @@ private bool ShouldBeInStateSyncMode(Snapshot best) (nameof(notInUpdatingPivot), notInUpdatingPivot), (nameof(hasFastSyncBeenActive), hasFastSyncBeenActive), (nameof(hasAnyPostPivotPeer), hasAnyPostPivotPeer), - ($"{nameof(notInFastSync)}||{nameof(stickyStateNodes)}", notInFastSync || stickyStateNodes), - ($"{nameof(stateNotDownloadedYet)}||{nameof(longRangeCatchUp)}", stateNotDownloadedYet || longRangeCatchUp), + ($"{nameof(notInFastSync)} || {nameof(stickyStateNodes)}", notInFastSync || stickyStateNodes), + ($"{nameof(stateNotDownloadedYet)} || {nameof(longRangeCatchUp)}", stateNotDownloadedYet || longRangeCatchUp), (nameof(notInAStickyFullSync), notInAStickyFullSync), (nameof(notNeedToWaitForHeaders), notNeedToWaitForHeaders)); } @@ -627,7 +628,7 @@ private bool ShouldBeInStateNodesMode(Snapshot best) { LogDetailedSyncModeChecks("STATE_NODES", (nameof(isInStateSync), isInStateSync), - ($"{nameof(snapSyncDisabled)}||{nameof(snapRangesFinished)}", snapSyncDisabled || snapRangesFinished)); + ($"{nameof(snapSyncDisabled)} || {nameof(snapRangesFinished)}", snapSyncDisabled || snapRangesFinished)); } return result; @@ -760,15 +761,15 @@ private void LogDetailedSyncModeChecks(string syncType, params (string Name, boo List matched = new(); List failed = new(); - foreach ((string Name, bool IsSatisfied) in checks) + foreach ((string name, bool isSatisfied) in checks) { - if (IsSatisfied) + if (isSatisfied) { - matched.Add(Name); + matched.Add(name); } else { - failed.Add(Name); + failed.Add(name); } } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index e3f4715ced9d..5e681453fd2a 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -407,6 +407,7 @@ public void EnqueueNextSlot(StorageRange parentRequest, int accountIndex, ValueH public void RetryStorageRange(StorageRange storageRange) { + bool dispose = false; if (storageRange.Accounts.Count == 1) { EnqueueNextSlot(storageRange); @@ -417,9 +418,12 @@ public void RetryStorageRange(StorageRange storageRange) { EnqueueAccountStorage(account); } + + dispose = true; } Interlocked.Add(ref _activeStorageRequests, -(storageRange?.Accounts.Count ?? 0)); + if (dispose) storageRange.Dispose(); } public void ReportAccountRangePartitionFinished(in ValueHash256 hashLimit) diff --git a/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs b/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs index 51da785e1a6b..a596548ec393 100644 --- a/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs +++ b/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs @@ -7,8 +7,6 @@ using System.Threading.Tasks; using Ethereum.Test.Base; using Ethereum.Test.Base.Interfaces; -using Nethermind.Blockchain.Tracing.GethStyle; -using Nethermind.Evm.Tracing; namespace Nethermind.Test.Runner; @@ -21,21 +19,29 @@ public class BlockchainTestsRunner( bool traceNoStack = false) : BlockchainTestBase, IBlockchainTestRunner { - private readonly ConsoleColor _defaultColour = Console.ForegroundColor; + private readonly ConsoleColor _defaultColor = Console.ForegroundColor; private readonly ITestSourceLoader _testsSource = testsSource ?? throw new ArgumentNullException(nameof(testsSource)); public async Task> RunTestsAsync() { - List testResults = new(); - IEnumerable tests = _testsSource.LoadTests(); + List testResults = []; + IEnumerable tests = _testsSource.LoadTests(); + foreach (EthereumTest loadedTest in tests) + { + if (loadedTest as FailedToLoadTest is not null) + { + WriteRed(loadedTest.LoadFailure); + testResults.Add(new EthereumTestResult(loadedTest.Name, loadedTest.LoadFailure)); + continue; + } - // Create a streaming tracer once for all tests if tracing is enabled - using BlockchainTestStreamingTracer? tracer = trace - ? new BlockchainTestStreamingTracer(new() { EnableMemory = traceMemory, DisableStack = traceNoStack }) - : null; + // Create a streaming tracer once for all tests if tracing is enabled + using BlockchainTestStreamingTracer? tracer = trace + ? new BlockchainTestStreamingTracer(new() { EnableMemory = traceMemory, DisableStack = traceNoStack }) + : null; + + BlockchainTest test = loadedTest as BlockchainTest; - foreach (BlockchainTest test in tests) - { if (filter is not null && test.Name is not null && !Regex.Match(test.Name, $"^({filter})").Success) continue; Setup(); @@ -66,13 +72,13 @@ private void WriteRed(string text) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(text); - Console.ForegroundColor = _defaultColour; + Console.ForegroundColor = _defaultColor; } private void WriteGreen(string text) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(text); - Console.ForegroundColor = _defaultColour; + Console.ForegroundColor = _defaultColor; } }