From c91e0b2801585e0392d9147f9e2dd2fe81df76f0 Mon Sep 17 00:00:00 2001 From: Nikita Mescheryakov Date: Mon, 4 Nov 2024 14:10:58 +0300 Subject: [PATCH] Make chainspec extendable by plugins (#7540) Co-authored-by: Lukasz Rozmej Co-authored-by: Lautaro Emanuel <31224949+emlautarom1@users.noreply.github.com> --- .../Nethermind.AuRa.Test/AuRaPluginTests.cs | 6 +- .../AuRaSealValidatorTests.cs | 9 +- .../ChainSpecLoaderTest.cs | 95 ++++++++ .../AuRaContractGasLimitOverrideTests.cs | 15 +- .../Reward/AuRaRewardCalculatorTests.cs | 7 +- .../Transactions/TxPermissionFilterTest.cs | 8 +- .../BlockProcessorTests.cs | 1 + .../BlockProducerBaseTests.BaseFee.cs | 1 + ...lockProducerBaseTests.IsProducingBlocks.cs | 1 + .../Services/HealthHintServiceTests.cs | 1 + .../Visitors/StartupTreeFixerTests.cs | 1 + .../CliqueHealthHintServiceTests.cs | 12 +- .../Nethermind.Config/ConfigSourceHelper.cs | 91 ++++++-- .../AuRaSealValidator.cs | 5 +- .../Config/AuRaChainSpecEngineParameters.cs | 185 +++++++++++++++ .../InitializeBlockchainAuRa.cs | 21 +- .../StartBlockProducerAuRa.cs | 27 +-- .../Rewards/AuRaRewardCalculator.cs | 7 +- .../Validators/AuRaParameters.cs | 70 ++++++ .../CliqueChainSpecEngineParameters.cs | 18 ++ .../CliqueHealthHintService.cs | 8 +- .../CliquePlugin.cs | 14 +- .../EthashChainSpecEngineParameters.cs | 101 ++++++++ .../EthashPlugin.cs | 4 +- .../NethDevChainSpecEngineParameters.cs | 14 ++ .../NethDevPlugin.cs | 10 +- .../InvalidConfigurationException.cs | 9 +- .../ChainSpecLoaderTests.cs | 118 ++++++++++ .../Nethermind.Ethash.Test/ChainSpecTest.cs | 215 +++++++++++++++++ .../Eth/EthRpcModuleTests.EstimateGas.cs | 1 + .../Modules/Eth/EthRpcModuleTests.EthCall.cs | 1 + .../Modules/Eth/EthRpcModuleTests.GasPrice.cs | 1 + .../Modules/Eth/EthRpcModuleTests.cs | 1 + .../Modules/TraceRpcModuleTests.cs | 2 + .../AuRaMergeEngineModuleTests.cs | 17 +- .../AuRaMergeBlockProducerEnvFactory.cs | 6 +- .../InitializeBlockchainAuRaMerge.cs | 9 +- .../Withdrawals/WithdrawalContractFactory.cs | 3 +- ...hainSpecBasedSpecProviderTests.TheMerge.cs | 7 +- .../EngineModuleTests.HelperFunctions.cs | 2 +- .../MergePluginTests.cs | 9 +- .../Nethermind.Merge.Plugin/MergePlugin.cs | 1 + .../IOptimismSpecHelper.cs | 2 +- .../InitializeBlockchainOptimism.cs | 7 +- .../Nethermind.Optimism/OPConfigHelper.cs | 8 +- .../OptimismChainSpecEngineParameters.cs | 64 +++++ .../Nethermind.Optimism/OptimismPlugin.cs | 7 +- .../OptimismSynchronizerModule.cs | 5 +- .../OptimismTransactionProcessor.cs | 2 +- .../EthereumRunnerTests.cs | 13 +- .../Nethermind.Runner.Test.csproj | 2 + .../Nethermind.Runner.Test/testspec.json | 4 +- .../EthereumJsonSerializer.cs | 5 + .../IJsonSerializer.cs | 2 + .../LongConverter.cs | 6 + .../ChainSpecBasedSpecProviderTests.cs | 220 ++---------------- .../ChainSpecStyle/ChainSpecLoaderTests.cs | 162 +------------ .../TestChainSpecParametersProvider.cs | 38 +++ .../Nethermind.Specs.Test.csproj | 2 + ...n_happens_before_blockActivation_test.json | 5 +- ...ation_equal_to_genesis_timestamp_test.json | 5 +- .../ChainSpecStyle/AuRaParameters.cs | 117 ---------- .../ChainSpecStyle/ChainSpec.cs | 10 +- .../ChainSpecBasedSpecProvider.cs | 64 ++--- .../ChainSpecStyle/ChainSpecLoader.cs | 151 ++---------- .../ChainSpecParametersProvider.cs | 70 ++++++ .../ChainSpecStyle/CliqueParameters.cs | 16 -- .../ChainSpecStyle/EthashParameters.cs | 41 ---- .../IChainSpecEngineParameters.cs | 15 ++ .../IChainSpecParametersProvider.cs | 13 ++ .../Json/BlockRewardConverter.cs | 68 ++++++ .../Json/BlockRewardJsonConverter.cs | 64 ----- .../ChainSpecStyle/Json/ChainSpecJson.cs | 187 --------------- .../Json/StepDurationJsonConverter.cs | 64 ----- .../ChainSpecStyle/OptimismParameters.cs | 32 --- .../ChainSpecStyle/ValidatorTypeExtensions.cs | 18 -- .../Nethermind.Specs/Nethermind.Specs.csproj | 4 + .../TaikoChainSpecEngineParameters.cs | 14 ++ .../Nethermind.Taiko/TaikoPlugin.cs | 6 +- 79 files changed, 1417 insertions(+), 1230 deletions(-) create mode 100644 src/Nethermind/Nethermind.AuRa.Test/ChainSpecLoaderTest.cs create mode 100644 src/Nethermind/Nethermind.Consensus.AuRa/Config/AuRaChainSpecEngineParameters.cs create mode 100644 src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaParameters.cs create mode 100644 src/Nethermind/Nethermind.Consensus.Clique/CliqueChainSpecEngineParameters.cs create mode 100644 src/Nethermind/Nethermind.Consensus.Ethash/EthashChainSpecEngineParameters.cs create mode 100644 src/Nethermind/Nethermind.Consensus.Ethash/NethDevChainSpecEngineParameters.cs create mode 100644 src/Nethermind/Nethermind.Ethash.Test/ChainSpecLoaderTests.cs create mode 100644 src/Nethermind/Nethermind.Ethash.Test/ChainSpecTest.cs create mode 100644 src/Nethermind/Nethermind.Optimism/OptimismChainSpecEngineParameters.cs create mode 100644 src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/TestChainSpecParametersProvider.cs delete mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/AuRaParameters.cs create mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecParametersProvider.cs delete mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/CliqueParameters.cs delete mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/EthashParameters.cs create mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecEngineParameters.cs create mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecParametersProvider.cs create mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardConverter.cs delete mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardJsonConverter.cs delete mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/StepDurationJsonConverter.cs delete mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs delete mode 100644 src/Nethermind/Nethermind.Specs/ChainSpecStyle/ValidatorTypeExtensions.cs create mode 100644 src/Nethermind/Nethermind.Taiko/TaikoChainSpecEngineParameters.cs diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs index d1309bb2d00..97218053fc9 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs @@ -5,10 +5,12 @@ using FluentAssertions; using Nethermind.Config; using Nethermind.Consensus.AuRa; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.InitializationSteps; using Nethermind.Logging; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.Test.ChainSpecStyle; using NUnit.Framework; namespace Nethermind.AuRa.Test @@ -19,7 +21,9 @@ public class AuRaPluginTests public void Init_when_not_AuRa_doesnt_trow() { AuRaPlugin auRaPlugin = new(); - Action init = () => auRaPlugin.Init(new AuRaNethermindApi(new ConfigProvider(), new EthereumJsonSerializer(), new TestLogManager(), new ChainSpec())); + ChainSpec chainSpec = new(); + chainSpec.EngineChainSpecParametersProvider = new TestChainSpecParametersProvider(new AuRaChainSpecEngineParameters()); + Action init = () => auRaPlugin.Init(new AuRaNethermindApi(new ConfigProvider(), new EthereumJsonSerializer(), new TestLogManager(), chainSpec)); init.Should().NotThrow(); } diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs index c4395f5c961..b9a71702903 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/AuRaSealValidatorTests.cs @@ -7,6 +7,7 @@ using System.Net; using Nethermind.Blockchain; using Nethermind.Consensus.AuRa; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.Validators; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -24,7 +25,7 @@ namespace Nethermind.AuRa.Test public class AuRaSealValidatorTests { private AuRaSealValidator _sealValidator; - private AuRaParameters _auRaParameters; + private AuRaChainSpecEngineParameters _auRaParameters; private IAuRaStepCalculator _auRaStepCalculator; private ILogManager _logManager; private IWallet _wallet; @@ -38,7 +39,7 @@ public class AuRaSealValidatorTests [SetUp] public void SetUp() { - _auRaParameters = new AuRaParameters(); + _auRaParameters = new AuRaChainSpecEngineParameters(); _auRaStepCalculator = Substitute.For(); _logManager = LimboLogs.Instance; _wallet = new DevWallet(new WalletConfig(), _logManager); @@ -89,7 +90,7 @@ BlockHeaderBuilder GetParentBlock() => Build.A.BlockHeader TestCaseData GetTestCaseData( BlockHeaderBuilder parent, BlockHeaderBuilder block, - Action paramAction = null, + Action paramAction = null, Repeat repeat = Repeat.No, bool parentIsHead = true, bool isValidSealer = true) => @@ -141,7 +142,7 @@ TestCaseData GetTestCaseData( } [TestCaseSource(nameof(ValidateParamsTests))] - public (bool, object) validate_params(BlockHeader parentBlock, BlockHeader block, Action modifyParameters, Repeat repeat, bool parentIsHead, bool isValidSealer) + public (bool, object) validate_params(BlockHeader parentBlock, BlockHeader block, Action modifyParameters, Repeat repeat, bool parentIsHead, bool isValidSealer) { _blockTree.Head.Returns(parentIsHead ? new Block(parentBlock) : new Block(Build.A.BlockHeader.WithNumber(parentBlock.Number - 1).TestObject)); _validSealerStrategy.IsValidSealer(Arg.Any>(), block.Beneficiary, block.AuRaStep.Value, out _).Returns(isValidSealer); diff --git a/src/Nethermind/Nethermind.AuRa.Test/ChainSpecLoaderTest.cs b/src/Nethermind/Nethermind.AuRa.Test/ChainSpecLoaderTest.cs new file mode 100644 index 00000000000..3364fa5c8a7 --- /dev/null +++ b/src/Nethermind/Nethermind.AuRa.Test/ChainSpecLoaderTest.cs @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Generic; +using System.IO; +using FluentAssertions; +using Nethermind.Consensus.AuRa.Config; +using Nethermind.Core; +using Nethermind.Core.Extensions; +using Nethermind.Serialization.Json; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; +using NUnit.Framework; + +namespace Nethermind.AuRa.Test; + +public class ChainSpecLoaderTest +{ + private static ChainSpec LoadChainSpec(string path) + { + ChainSpecLoader chainSpecLoader = new(new EthereumJsonSerializer()); + ChainSpec chainSpec = chainSpecLoader.LoadFromFile(path); + return chainSpec; + } + + [Test] + public void Can_load_gnosis() + { + string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../../../", "Chains/gnosis.json"); + ChainSpec chainSpec = LoadChainSpec(path); + + Assert.That(chainSpec.Parameters.Eip1559BaseFeeInitialValue, Is.EqualTo(1.GWei()), $"fork base fee"); + Assert.That(chainSpec.NetworkId, Is.EqualTo(100), $"{nameof(chainSpec.NetworkId)}"); + Assert.That(chainSpec.Name, Is.EqualTo("GnosisChain"), $"{nameof(chainSpec.Name)}"); + Assert.That(chainSpec.SealEngineType, Is.EqualTo(SealEngineType.AuRa), "engine"); + + int berlinGnosisBlockNumber = 16101500; + chainSpec.Parameters.Eip2565Transition.Should().Be(berlinGnosisBlockNumber); + chainSpec.Parameters.Eip2929Transition.Should().Be(berlinGnosisBlockNumber); + chainSpec.Parameters.Eip2930Transition.Should().Be(berlinGnosisBlockNumber); + + chainSpec.Parameters.TerminalTotalDifficulty.ToString() + .Should().Be("8626000000000000000000058750000000000000000000"); + + var auraParams = chainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); + + auraParams.WithdrawalContractAddress.ToString(true) + .Should().Be("0x0B98057eA310F4d31F2a452B414647007d1645d9"); + } + + [Test] + public void Can_load_chiado() + { + string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../../../", "Chains/chiado.json"); + ChainSpec chainSpec = LoadChainSpec(path); + + Assert.That(chainSpec.Parameters.Eip1559BaseFeeInitialValue, Is.EqualTo(1.GWei()), $"fork base fee"); + Assert.That(chainSpec.NetworkId, Is.EqualTo(10200), $"{nameof(chainSpec.NetworkId)}"); + Assert.That(chainSpec.Name, Is.EqualTo("chiado"), $"{nameof(chainSpec.Name)}"); + Assert.That(chainSpec.SealEngineType, Is.EqualTo(SealEngineType.AuRa), "engine"); + + chainSpec.Parameters.TerminalTotalDifficulty.ToString() + .Should().Be("231707791542740786049188744689299064356246512"); + + var auraParams = chainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); + + auraParams.WithdrawalContractAddress.ToString(true) + .Should().Be("0xb97036A26259B7147018913bD58a774cf91acf25"); + + chainSpec.ShanghaiTimestamp.Should().Be(ChiadoSpecProvider.ShanghaiTimestamp); + chainSpec.ShanghaiTimestamp.Should().Be(ChiadoSpecProvider.Instance.TimestampFork); + } + + [Test] + public void Can_load_posdao_with_rewriteBytecode() + { + // TODO: modexp 2565 + string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Specs/posdao.json"); + ChainSpec chainSpec = LoadChainSpec(path); + IDictionary> expected = new Dictionary> + { + { + 21300000, new Dictionary() + { + {new Address("0x1234000000000000000000000000000000000001"), Bytes.FromHexString("0x111")}, + {new Address("0x1234000000000000000000000000000000000002"), Bytes.FromHexString("0x222")}, + } + } + }; + + var auraParams = chainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); + + auraParams.RewriteBytecode.Should().BeEquivalentTo(expected); + } +} diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs index 6f2f7b13d6d..079f507fe05 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs @@ -10,6 +10,7 @@ using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Consensus; using Nethermind.Consensus.AuRa; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Rewards; @@ -17,6 +18,7 @@ using Nethermind.Consensus.Withdrawals; using Nethermind.Core; using Nethermind.Logging; +using Nethermind.Specs.ChainSpecStyle; using NUnit.Framework; namespace Nethermind.AuRa.Test.Contract; @@ -81,8 +83,11 @@ public class TestGasLimitContractBlockchain : TestContractBlockchain protected override BlockProcessor CreateBlockProcessor() { - KeyValuePair blockGasLimitContractTransition = ChainSpec.AuRa.BlockGasLimitContractTransitions.First(); - BlockGasLimitContract gasLimitContract = new(AbiEncoder.Instance, blockGasLimitContractTransition.Value, blockGasLimitContractTransition.Key, + KeyValuePair blockGasLimitContractTransition = ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters().BlockGasLimitContractTransitions + .First(); + BlockGasLimitContract gasLimitContract = new(AbiEncoder.Instance, blockGasLimitContractTransition.Value, + blockGasLimitContractTransition.Key, new ReadOnlyTxProcessingEnv( WorldStateManager, BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance)); @@ -114,8 +119,10 @@ public class TestGasLimitContractBlockchainLateBlockGasLimit : TestGasLimitContr { protected override BlockProcessor CreateBlockProcessor() { - KeyValuePair blockGasLimitContractTransition = ChainSpec.AuRa.BlockGasLimitContractTransitions.First(); - ChainSpec.AuRa.BlockGasLimitContractTransitions = new Dictionary() { { 10, blockGasLimitContractTransition.Value } }; + var parameters = ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(); + KeyValuePair blockGasLimitContractTransition = parameters.BlockGasLimitContractTransitions.First(); + parameters.BlockGasLimitContractTransitions = new Dictionary() { { 10, blockGasLimitContractTransition.Value } }; return base.CreateBlockProcessor(); } } diff --git a/src/Nethermind/Nethermind.AuRa.Test/Reward/AuRaRewardCalculatorTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Reward/AuRaRewardCalculatorTests.cs index 417955c1ffe..c83e8d09827 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Reward/AuRaRewardCalculatorTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Reward/AuRaRewardCalculatorTests.cs @@ -7,6 +7,7 @@ using System.Linq; using FluentAssertions; using Nethermind.Abi; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.Rewards; using Nethermind.Consensus.Rewards; using Nethermind.Core; @@ -25,7 +26,7 @@ namespace Nethermind.AuRa.Test.Reward { public class AuRaRewardCalculatorTests { - private AuRaParameters _auraParameters; + private AuRaChainSpecEngineParameters _auraParameters; private IAbiEncoder _abiEncoder; private ITransactionProcessor _transactionProcessor; private Block _block; @@ -40,11 +41,11 @@ public void SetUp() _address10 = TestItem.AddressA; _address50 = TestItem.AddressB; _address150 = TestItem.AddressC; - _auraParameters = new AuRaParameters + _auraParameters = new AuRaChainSpecEngineParameters() { BlockRewardContractAddress = _address10, BlockRewardContractTransition = 10, - BlockReward = new Dictionary() { { 0, 200 } }, + BlockReward = new SortedDictionary() { { 0, 200 } }, }; _abiEncoder = Substitute.For(); diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs index da04745095f..09c673e0126 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs @@ -13,6 +13,7 @@ using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.AuRa.Transactions; +using Nethermind.Consensus.AuRa.Validators; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; @@ -27,7 +28,6 @@ using Nethermind.Int256; using Nethermind.Evm.TransactionProcessing; using Nethermind.Logging; -using Nethermind.Specs.ChainSpecStyle; using Nethermind.Trie.Pruning; using Nethermind.TxPool; using NSubstitute; @@ -267,12 +267,6 @@ public class TestTxPermissionsBlockchain : TestContractBlockchain protected override BlockProcessor CreateBlockProcessor() { - AuRaParameters.Validator validator = new() - { - Addresses = TestItem.Addresses, - ValidatorType = AuRaParameters.ValidatorType.List - }; - TransactionPermissionContractVersions = new LruCache(PermissionBasedTxFilter.Cache.MaxCacheSize, nameof(TransactionPermissionContract)); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs index a9c11d23a2d..402d67b329d 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs @@ -29,6 +29,7 @@ using Nethermind.Consensus.Rewards; using Nethermind.Core.Test.Blockchain; using Nethermind.Evm.TransactionProcessing; +using Nethermind.Specs.Test.ChainSpecStyle; namespace Nethermind.Blockchain.Test; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs index 3df241870a2..e51b2f803f9 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs @@ -12,6 +12,7 @@ using Nethermind.Int256; using Nethermind.JsonRpc.Test.Modules; using Nethermind.Specs; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.TxPool; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs index 0bb6554aca4..d91d07d732a 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.IsProducingBlocks.cs @@ -24,6 +24,7 @@ using Nethermind.Logging; using Nethermind.Specs; using Nethermind.Specs.Forks; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.State; using NSubstitute; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs index aee9e3a4df5..30427856af5 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Services/HealthHintServiceTests.cs @@ -5,6 +5,7 @@ using Nethermind.Blockchain.Services; using Nethermind.Core; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.Test.ChainSpecStyle; using NUnit.Framework; namespace Nethermind.Blockchain.Test.Services; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs index 366cbec9617..ff88673cf63 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Visitors/StartupTreeFixerTests.cs @@ -12,6 +12,7 @@ using Nethermind.Db; using Nethermind.Logging; using Nethermind.JsonRpc.Test.Modules; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.State; using NSubstitute; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueHealthHintServiceTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueHealthHintServiceTests.cs index fb16d67607c..fea4631c3fc 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueHealthHintServiceTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueHealthHintServiceTests.cs @@ -4,8 +4,6 @@ using System.Collections.Generic; using Nethermind.Blockchain.Services; using Nethermind.Consensus.Clique; -using Nethermind.Core; -using Nethermind.Specs.ChainSpecStyle; using NSubstitute; using NUnit.Framework; @@ -29,7 +27,7 @@ public void GetBlockProcessorAndProducerIntervalHint_returns_expected_result( public class BlockProcessorIntervalHint { - public ChainSpec ChainSpec { get; set; } + public CliqueChainSpecEngineParameters ChainSpec { get; set; } public ulong ValidatorsCount { get; set; } @@ -47,27 +45,27 @@ public static IEnumerable BlockProcessorIntervalHint { yield return new BlockProcessorIntervalHint() { - ChainSpec = new ChainSpec() { SealEngineType = SealEngineType.Clique, Clique = new CliqueParameters() { Period = 15 } }, + ChainSpec = new CliqueChainSpecEngineParameters { Period = 15 }, ExpectedProcessingHint = 60, ExpectedProducingHint = 30 }; yield return new BlockProcessorIntervalHint() { - ChainSpec = new ChainSpec() { SealEngineType = SealEngineType.Clique, Clique = new CliqueParameters() { Period = 23 } }, + ChainSpec = new CliqueChainSpecEngineParameters { Period = 23 }, ExpectedProcessingHint = 92, ExpectedProducingHint = 46 }; yield return new BlockProcessorIntervalHint() { ValidatorsCount = 10, - ChainSpec = new ChainSpec() { SealEngineType = SealEngineType.Clique, Clique = new CliqueParameters() { Period = 23 } }, + ChainSpec = new CliqueChainSpecEngineParameters { Period = 23 }, ExpectedProcessingHint = 92, ExpectedProducingHint = 460 }; yield return new BlockProcessorIntervalHint() { ValidatorsCount = 2, - ChainSpec = new ChainSpec() { SealEngineType = SealEngineType.Clique, Clique = new CliqueParameters() { Period = 10 } }, + ChainSpec = new CliqueChainSpecEngineParameters { Period = 10 }, ExpectedProcessingHint = 40, ExpectedProducingHint = 40 }; diff --git a/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs b/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs index f30ec069974..462e5ca74fa 100644 --- a/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs +++ b/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs @@ -7,13 +7,26 @@ using System.Linq; using Nethermind.Int256; using System.Text.Json; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; namespace Nethermind.Config { - internal static class ConfigSourceHelper + public static class ConfigSourceHelper { public static object ParseValue(Type valueType, string valueString, string category, string name) { + if (Nullable.GetUnderlyingType(valueType) is { } nullableType) + { + return IsNullString(valueString) ? null : ParseValue(nullableType, valueString, category, name); + } + + if (!valueType.IsValueType && IsNullString(valueString)) + { + return null; + } + try { object value; @@ -22,8 +35,13 @@ public static object ParseValue(Type valueType, string valueString, string categ //supports Arrays, e.g int[] and generic IEnumerable, IList var itemType = valueType.IsGenericType ? valueType.GetGenericArguments()[0] : valueType.GetElementType(); + if (itemType == typeof(byte) && !valueString.AsSpan().TrimStart().StartsWith("[")) + { + // hex encoded byte array + value = Bytes.FromHexString(valueString.Trim()); + } //In case of collection of objects (more complex config models) we parse entire collection - if (itemType.IsClass && typeof(IConfigModel).IsAssignableFrom(itemType)) + else if (itemType.IsClass && typeof(IConfigModel).IsAssignableFrom(itemType)) { var objCollection = JsonSerializer.Deserialize(valueString, valueType); value = objCollection; @@ -32,12 +50,12 @@ public static object ParseValue(Type valueType, string valueString, string categ { valueString = valueString.Trim().RemoveStart('[').RemoveEnd(']'); var valueItems = valueString.Split(',').Select(s => s.Trim()).ToArray(); - var collection = valueType.IsGenericType + IList collection = (valueType.IsGenericType ? (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(itemType)) - : (IList)Activator.CreateInstance(valueType, valueItems.Length); + : (IList)Activator.CreateInstance(valueType, valueItems.Length))!; var i = 0; - foreach (var valueItem in valueItems) + foreach (string valueItem in valueItems) { string item = valueItem; if (valueItem.StartsWith('"') && valueItem.EndsWith('"')) @@ -80,35 +98,70 @@ public static object ParseValue(Type valueType, string valueString, string categ } } - public static object GetDefault(Type type) + private static bool IsNullString(string valueString) => + string.IsNullOrEmpty(valueString) || valueString.Equals("null", StringComparison.InvariantCultureIgnoreCase); + + public static object GetDefault(Type type) => type.IsValueType ? (false, Activator.CreateInstance(type)) : (false, null); + + private static bool TryFromHex(Type type, string itemValue, out object value) { - return type.IsValueType ? (false, Activator.CreateInstance(type)) : (false, null); + if (!itemValue.StartsWith("0x")) + { + value = null; + return false; + } + + if (typeof(IConvertible).IsAssignableFrom(type) && type != typeof(string)) + { + object baseValue = type == typeof(ulong) + ? Convert.ToUInt64(itemValue, 16) // Use UInt64 parsing for unsigned types to avoid overflow + : Convert.ToInt64(itemValue, 16); // Default to Int64 parsing for other integer types + + value = Convert.ChangeType(baseValue, type); + return true; + } + + value = null; + return false; } private static object GetValue(Type valueType, string itemValue) { + if (Nullable.GetUnderlyingType(valueType) is { } nullableType) + { + return IsNullString(itemValue) ? null : GetValue(nullableType, itemValue); + } + + if (!valueType.IsValueType && IsNullString(itemValue)) + { + return null; + } + if (valueType == typeof(UInt256)) { return UInt256.Parse(itemValue); } - if (valueType.IsEnum) + if (valueType == typeof(Address)) { - if (Enum.TryParse(valueType, itemValue, true, out var enumValue)) - { - return enumValue; - } + return Address.TryParse(itemValue, out Address address) + ? address + : throw new FormatException($"Could not parse {itemValue} to {typeof(Address)}"); + } - throw new FormatException($"Cannot parse enum value: {itemValue}, type: {valueType.Name}"); + if (valueType == typeof(Hash256)) + { + return new Hash256(itemValue); } - var nullableType = Nullable.GetUnderlyingType(valueType); + if (valueType.IsEnum) + { + return Enum.TryParse(valueType, itemValue, true, out object enumValue) + ? enumValue + : throw new FormatException($"Cannot parse enum value: {itemValue}, type: {valueType.Name}"); + } - return nullableType is null - ? Convert.ChangeType(itemValue, valueType) - : !string.IsNullOrEmpty(itemValue) && !itemValue.Equals("null", StringComparison.InvariantCultureIgnoreCase) - ? Convert.ChangeType(itemValue, nullableType) - : null; + return TryFromHex(valueType, itemValue, out object value) ? value : Convert.ChangeType(itemValue, valueType); } } } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs index 641b822b8be..46c40702741 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaSealValidator.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using Nethermind.Blockchain; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.Validators; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -16,7 +17,7 @@ namespace Nethermind.Consensus.AuRa { public class AuRaSealValidator : ISealValidator { - private readonly AuRaParameters _parameters; + private readonly AuRaChainSpecEngineParameters _parameters; private readonly IAuRaStepCalculator _stepCalculator; private readonly IBlockTree _blockTree; private readonly IValidatorStore _validatorStore; @@ -25,7 +26,7 @@ public class AuRaSealValidator : ISealValidator private readonly ILogger _logger; private readonly ReceivedSteps _receivedSteps = new ReceivedSteps(); - public AuRaSealValidator(AuRaParameters parameters, IAuRaStepCalculator stepCalculator, IBlockTree blockTree, IValidatorStore validatorStore, IValidSealerStrategy validSealerStrategy, IEthereumEcdsa ecdsa, ILogManager logManager) + public AuRaSealValidator(AuRaChainSpecEngineParameters parameters, IAuRaStepCalculator stepCalculator, IBlockTree blockTree, IValidatorStore validatorStore, IValidSealerStrategy validSealerStrategy, IEthereumEcdsa ecdsa, ILogManager logManager) { _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); _stepCalculator = stepCalculator ?? throw new ArgumentNullException(nameof(stepCalculator)); diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Config/AuRaChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Config/AuRaChainSpecEngineParameters.cs new file mode 100644 index 00000000000..8f185939b20 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus.AuRa/Config/AuRaChainSpecEngineParameters.cs @@ -0,0 +1,185 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using Nethermind.Consensus.AuRa.Validators; +using Nethermind.Core; +using Nethermind.Int256; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.ChainSpecStyle.Json; + +namespace Nethermind.Consensus.AuRa.Config; + +public class AuRaChainSpecEngineParameters : IChainSpecEngineParameters +{ + public const long TransitionDisabled = long.MaxValue; + public string? EngineName => "AuthorityRound"; + public string? SealEngineType => Core.SealEngineType.AuRa; + + [JsonConverter(typeof(StepDurationJsonConverter))] + public SortedDictionary StepDuration { get; set; } = new(); + + [JsonConverter(typeof(BlockRewardConverter))] + public SortedDictionary? BlockReward { get; set; } + + public long? MaximumUncleCountTransition { get; set; } + + public long? MaximumUncleCount { get; set; } + + public Address? BlockRewardContractAddress { get; set; } + + public long? BlockRewardContractTransition { get; set; } + + public IDictionary BlockRewardContractTransitions { get; set; } = new Dictionary(); + + public long ValidateScoreTransition { get; set; } + + public long ValidateStepTransition { get; set; } + + [JsonPropertyName("Validators")] + private AuRaValidatorJson ValidatorsJson { get; set; } + + public IDictionary RandomnessContractAddress { get; set; } = new Dictionary(); + + public IDictionary BlockGasLimitContractTransitions { get; set; } = new Dictionary(); + + public long TwoThirdsMajorityTransition { get; set; } = TransitionDisabled; + + public long PosdaoTransition { get; set; } = TransitionDisabled; + + public IDictionary> RewriteBytecode { get; set; } = new Dictionary>(); + + public Address WithdrawalContractAddress { get; set; } + + private AuRaParameters.Validator? _validators; + public AuRaParameters.Validator Validators + { + get => _validators ??= LoadValidator(ValidatorsJson); + } + + public void ApplyToReleaseSpec(ReleaseSpec spec, long startBlock, ulong? startTimestamp) + { + spec.MaximumUncleCount = (int)(startBlock >= (MaximumUncleCountTransition ?? long.MaxValue) ? MaximumUncleCount ?? 2 : 2); + } + + static AuRaParameters.Validator LoadValidator(AuRaValidatorJson validatorJson, int level = 0) + { + AuRaParameters.ValidatorType validatorType = validatorJson.GetValidatorType(); + AuRaParameters.Validator validator = new() { ValidatorType = validatorType }; + switch (validator.ValidatorType) + { + case AuRaParameters.ValidatorType.List: + validator.Addresses = validatorJson.List; + break; + case AuRaParameters.ValidatorType.Contract: + validator.Addresses = [validatorJson.SafeContract]; + break; + case AuRaParameters.ValidatorType.ReportingContract: + validator.Addresses = [validatorJson.Contract]; + break; + case AuRaParameters.ValidatorType.Multi: + if (level != 0) throw new ArgumentException("AuRa multi validator cannot be inner validator."); + validator.Validators = validatorJson.Multi + .ToDictionary(kvp => kvp.Key, kvp => LoadValidator(kvp.Value, level + 1)) + .ToImmutableSortedDictionary(); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return validator; + } + + private class StepDurationJsonConverter : JsonConverter> + { + public override void Write(Utf8JsonWriter writer, SortedDictionary value, JsonSerializerOptions options) + { + throw new NotSupportedException(); + } + + public override SortedDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var value = new SortedDictionary(); + if (reader.TokenType == JsonTokenType.String) + { + value.Add(0, JsonSerializer.Deserialize(ref reader, options)); + } + else if (reader.TokenType == JsonTokenType.Number) + { + value.Add(0, reader.GetInt64()); + } + else if (reader.TokenType == JsonTokenType.StartObject) + { + reader.Read(); + while (reader.TokenType != JsonTokenType.EndObject) + { + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new ArgumentException("Cannot deserialize BlockReward."); + } + var key = long.Parse(reader.GetString()); + reader.Read(); + if (reader.TokenType == JsonTokenType.String) + { + value.Add(key, long.Parse(reader.GetString())); + } + else if (reader.TokenType == JsonTokenType.Number) + { + value.Add(key, reader.GetInt64()); + } + else + { + throw new ArgumentException("Cannot deserialize BlockReward."); + } + + reader.Read(); + } + } + else + { + throw new ArgumentException("Cannot deserialize BlockReward."); + } + + return value; + } + } + + private class AuRaValidatorJson + { + public Address[]? List { get; set; } + public Address? Contract { get; set; } + public Address? SafeContract { get; set; } + public Dictionary Multi { get; set; } = new(); + + public AuRaParameters.ValidatorType GetValidatorType() + { + if (List is not null) + { + return AuRaParameters.ValidatorType.List; + } + + if (Contract is not null) + { + return AuRaParameters.ValidatorType.ReportingContract; + } + + if (SafeContract is not null) + { + return AuRaParameters.ValidatorType.Contract; + } + + if (Multi is not null) + { + return AuRaParameters.ValidatorType.Multi; + } + + throw new NotSupportedException("AuRa validator type not supported."); + } + } +} diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs index cf7ac81bbc7..cdf3c499336 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs @@ -27,6 +27,7 @@ using Nethermind.Evm; using Nethermind.Init.Steps; using Nethermind.Logging; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; using Nethermind.TxPool; using Nethermind.TxPool.Comparison; @@ -36,6 +37,7 @@ namespace Nethermind.Consensus.AuRa.InitializationSteps; public class InitializeBlockchainAuRa : InitializeBlockchain { private readonly AuRaNethermindApi _api; + private readonly AuRaChainSpecEngineParameters _parameters; private INethermindApi NethermindApi => _api; private AuRaSealValidator? _sealValidator; @@ -45,13 +47,15 @@ public class InitializeBlockchainAuRa : InitializeBlockchain public InitializeBlockchainAuRa(AuRaNethermindApi api) : base(api) { _api = api; + _parameters = _api.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(); _auraConfig = NethermindApi.Config(); } protected override async Task InitBlockchain() { - var chainSpecAuRa = _api.ChainSpec.AuRa; - _auRaStepCalculator = new AuRaStepCalculator(_api.ChainSpec.AuRa.StepDuration, _api.Timestamper, _api.LogManager); + var chainSpecAuRa = _api.ChainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); + _auRaStepCalculator = new AuRaStepCalculator(chainSpecAuRa.StepDuration, _api.Timestamper, _api.LogManager); _api.FinalizationManager = new AuRaBlockFinalizationManager( _api.BlockTree!, _api.ChainLevelInfoRepository!, @@ -96,7 +100,8 @@ protected override BlockProcessor CreateBlockProcessor(BlockCachePreWarmer? preW protected virtual AuRaBlockProcessor NewAuraBlockProcessor(ITxFilter txFilter, BlockCachePreWarmer? preWarmer) { - IDictionary> rewriteBytecode = _api.ChainSpec.AuRa.RewriteBytecode; + var chainSpecAuRa = _api.ChainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); + IDictionary> rewriteBytecode = chainSpecAuRa.RewriteBytecode; ContractRewriter? contractRewriter = rewriteBytecode?.Count > 0 ? new ContractRewriter(rewriteBytecode) : null; IWorldState worldState = _api.WorldState!; @@ -133,7 +138,7 @@ protected IAuRaValidator CreateAuRaValidator() if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); if (_api.NonceManager is null) throw new StepDependencyException(nameof(_api.NonceManager)); - var chainSpecAuRa = _api.ChainSpec.AuRa; + var chainSpecAuRa = _api.ChainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); IWorldState worldState = _api.WorldState!; IAuRaValidator validator = new AuRaValidatorFactory( @@ -167,7 +172,7 @@ protected IAuRaValidator CreateAuRaValidator() protected AuRaContractGasLimitOverride? GetGasLimitCalculator() { if (_api.ChainSpec is null) throw new StepDependencyException(nameof(_api.ChainSpec)); - var blockGasLimitContractTransitions = _api.ChainSpec.AuRa.BlockGasLimitContractTransitions; + var blockGasLimitContractTransitions = _parameters.BlockGasLimitContractTransitions; if (blockGasLimitContractTransitions?.Any() == true) { @@ -199,8 +204,8 @@ protected override void InitSealEngine() if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); ValidSealerStrategy validSealerStrategy = new ValidSealerStrategy(); - _api.SealValidator = _sealValidator = new AuRaSealValidator(_api.ChainSpec.AuRa, _auRaStepCalculator, _api.BlockTree, _api.ValidatorStore, validSealerStrategy, _api.EthereumEcdsa, _api.LogManager); - _api.RewardCalculatorSource = new AuRaRewardCalculator.AuRaRewardCalculatorSource(_api.ChainSpec.AuRa, _api.AbiEncoder); + _api.SealValidator = _sealValidator = new AuRaSealValidator(_parameters, _auRaStepCalculator, _api.BlockTree, _api.ValidatorStore, validSealerStrategy, _api.EthereumEcdsa, _api.LogManager); + _api.RewardCalculatorSource = new AuRaRewardCalculator.AuRaRewardCalculatorSource(_parameters, _api.AbiEncoder); _api.Sealer = new AuRaSealer(_api.BlockTree, _api.ValidatorStore, _auRaStepCalculator, _api.EngineSigner, validSealerStrategy, _api.LogManager); } @@ -211,7 +216,7 @@ protected override void InitSealEngine() protected override IHeaderValidator CreateHeaderValidator() { if (_api.ChainSpec is null) throw new StepDependencyException(nameof(_api.ChainSpec)); - var blockGasLimitContractTransitions = _api.ChainSpec.AuRa.BlockGasLimitContractTransitions; + IDictionary blockGasLimitContractTransitions = _parameters.BlockGasLimitContractTransitions; return blockGasLimitContractTransitions?.Any() == true ? new AuRaHeaderValidator( _api.BlockTree, diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs index 2b62d16c021..39faddc8c85 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs @@ -33,6 +33,7 @@ namespace Nethermind.Consensus.AuRa.InitializationSteps; public class StartBlockProducerAuRa { private readonly AuRaNethermindApi _api; + private readonly AuRaChainSpecEngineParameters _parameters; private BlockProducerEnv? _blockProducerContext; private INethermindApi NethermindApi => _api; @@ -47,6 +48,8 @@ public class StartBlockProducerAuRa public StartBlockProducerAuRa(AuRaNethermindApi api) { _api = api; + _parameters = _api.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(); _auraConfig = NethermindApi.Config(); } @@ -54,7 +57,7 @@ private IAuRaStepCalculator StepCalculator { get { - return _stepCalculator ??= new AuRaStepCalculator(_api.ChainSpec.AuRa.StepDuration, _api.Timestamper, _api.LogManager); + return _stepCalculator ??= new AuRaStepCalculator(_parameters.StepDuration, _api.Timestamper, _api.LogManager); } } @@ -113,8 +116,6 @@ private BlockProcessor CreateBlockProcessor(IReadOnlyTxProcessingScope changeabl if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); if (_api.GasPriceOracle is null) throw new StepDependencyException(nameof(_api.GasPriceOracle)); - var chainSpecAuRa = _api.ChainSpec.AuRa; - ITxFilter auRaTxFilter = TxAuRaFilterBuilders.CreateAuRaTxFilter( _api, new LocalTxFilter(_api.EngineSigner)); @@ -135,16 +136,16 @@ private BlockProcessor CreateBlockProcessor(IReadOnlyTxProcessingScope changeabl _api.SpecProvider, _api.GasPriceOracle, _api.ReportingContractValidatorCache, - chainSpecAuRa.PosdaoTransition, + _parameters.PosdaoTransition, true) - .CreateValidatorProcessor(chainSpecAuRa.Validators, _api.BlockTree.Head?.Header); + .CreateValidatorProcessor(_parameters.Validators, _api.BlockTree.Head?.Header); if (_validator is IDisposable disposableValidator) { _api.DisposeStack.Push(disposableValidator); } - IDictionary> rewriteBytecode = chainSpecAuRa.RewriteBytecode; + IDictionary> rewriteBytecode = _parameters.RewriteBytecode; ContractRewriter? contractRewriter = rewriteBytecode?.Count > 0 ? new ContractRewriter(rewriteBytecode) : null; return new AuRaBlockProcessor( @@ -276,7 +277,7 @@ private ITxSource CreateTxSourceForProducer(ITxSource? additionalTxSource) { bool CheckAddPosdaoTransactions(IList list, long auRaPosdaoTransition) { - if (auRaPosdaoTransition < AuRaParameters.TransitionDisabled && _validator is ITxSource validatorSource) + if (auRaPosdaoTransition != AuRaChainSpecEngineParameters.TransitionDisabled && _validator is ITxSource validatorSource) { list.Insert(0, validatorSource); return true; @@ -331,8 +332,8 @@ IList GetRandomContracts( { txSources.Insert(0, additionalTxSource); } - needSigner |= CheckAddPosdaoTransactions(txSources, _api.ChainSpec.AuRa.PosdaoTransition); - needSigner |= CheckAddRandomnessTransactions(txSources, _api.ChainSpec.AuRa.RandomnessContractAddress, _api.EngineSigner); + needSigner |= CheckAddPosdaoTransactions(txSources, _parameters.PosdaoTransition); + needSigner |= CheckAddRandomnessTransactions(txSources, _parameters.RandomnessContractAddress, _api.EngineSigner); ITxSource txSource = txSources.Count > 1 ? new CompositeTxSource(txSources.ToArray()) : txSources[0]; @@ -355,11 +356,11 @@ IList GetRandomContracts( private static IGasLimitCalculator CreateGasLimitCalculator(AuRaNethermindApi api) { if (api.ChainSpec is null) throw new StepDependencyException(nameof(api.ChainSpec)); - var blockGasLimitContractTransitions = api.ChainSpec.AuRa.BlockGasLimitContractTransitions; + var blockGasLimitContractTransitions = api.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters().BlockGasLimitContractTransitions; - IGasLimitCalculator gasLimitCalculator = - new TargetAdjustedGasLimitCalculator(api.SpecProvider, api.Config()); - if (blockGasLimitContractTransitions?.Any() == true) + IGasLimitCalculator gasLimitCalculator = new TargetAdjustedGasLimitCalculator(api.SpecProvider, api.Config()); + if (blockGasLimitContractTransitions?.Count > 0) { AuRaContractGasLimitOverride auRaContractGasLimitOverride = new( blockGasLimitContractTransitions.Select(blockGasLimitContractTransition => diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Rewards/AuRaRewardCalculator.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Rewards/AuRaRewardCalculator.cs index 280741ec67c..4241943283f 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/Rewards/AuRaRewardCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/Rewards/AuRaRewardCalculator.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Nethermind.Abi; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.Rewards; using Nethermind.Core; @@ -18,7 +19,7 @@ public class AuRaRewardCalculator : IRewardCalculator private readonly StaticRewardCalculator _blockRewardCalculator; private readonly IList _contracts; - public AuRaRewardCalculator(AuRaParameters auRaParameters, IAbiEncoder abiEncoder, ITransactionProcessor transactionProcessor) + public AuRaRewardCalculator(AuRaChainSpecEngineParameters auRaParameters, IAbiEncoder abiEncoder, ITransactionProcessor transactionProcessor) { ArgumentNullException.ThrowIfNull(auRaParameters); ArgumentNullException.ThrowIfNull(abiEncoder); @@ -106,10 +107,10 @@ private static BlockReward[] CalculateRewardsWithContract(Block block, IRewardCo public class AuRaRewardCalculatorSource : IRewardCalculatorSource { - private readonly AuRaParameters _auRaParameters; + private readonly AuRaChainSpecEngineParameters _auRaParameters; private readonly IAbiEncoder _abiEncoder; - public AuRaRewardCalculatorSource(AuRaParameters auRaParameters, IAbiEncoder abiEncoder) + public AuRaRewardCalculatorSource(AuRaChainSpecEngineParameters auRaParameters, IAbiEncoder abiEncoder) { _auRaParameters = auRaParameters; _abiEncoder = abiEncoder; diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaParameters.cs b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaParameters.cs new file mode 100644 index 00000000000..ce3ae20c29f --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus.AuRa/Validators/AuRaParameters.cs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using System.Linq; +using Nethermind.Core; + +namespace Nethermind.Consensus.AuRa.Validators; + +public class AuRaParameters +{ + public enum ValidatorType + { + List, + Contract, + ReportingContract, + Multi + } + + public class Validator + { + public ValidatorType ValidatorType { get; set; } + + /// + /// Dictionary of Validators per their starting block. + /// + /// + /// Only Valid for of type . + /// + /// This has to sorted in order of starting blocks. + /// + public IDictionary? Validators { get; set; } + + /// + /// Addresses for validator. + /// + /// + /// For of type should contain at least one address. + /// For of type and should contain exactly one address. + /// For of type will be empty. + /// + public Address[]? Addresses { get; set; } + + public Address GetContractAddress() + { + switch (ValidatorType) + { + case ValidatorType.Contract: + case ValidatorType.ReportingContract: + return Addresses?.FirstOrDefault() ?? throw new ArgumentException("Missing contract address for AuRa validator.", nameof(Addresses)); + default: + throw new InvalidOperationException($"AuRa validator {ValidatorType} doesn't have contract address."); + } + } + } +} + +public static class ValidatorTypeExtensions +{ + public static bool CanChangeImmediately(this AuRaParameters.ValidatorType validatorType) => + validatorType switch + { + AuRaParameters.ValidatorType.Contract => false, + AuRaParameters.ValidatorType.ReportingContract => false, + AuRaParameters.ValidatorType.List => true, + AuRaParameters.ValidatorType.Multi => true, + _ => false + }; +} diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueChainSpecEngineParameters.cs new file mode 100644 index 00000000000..d9028ec2560 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueChainSpecEngineParameters.cs @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Generic; +using Nethermind.Int256; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; + +namespace Nethermind.Consensus.Clique; + +public class CliqueChainSpecEngineParameters : IChainSpecEngineParameters +{ + public string? EngineName => SealEngineType; + public string? SealEngineType => Core.SealEngineType.Clique; + public ulong Epoch { get; set; } + public ulong Period { get; set; } + public UInt256? Reward { get; set; } = UInt256.Zero; +} diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueHealthHintService.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueHealthHintService.cs index 6ba4fbd2044..fbf4765a05d 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueHealthHintService.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueHealthHintService.cs @@ -10,21 +10,21 @@ namespace Nethermind.Consensus.Clique internal class CliqueHealthHintService : IHealthHintService { private readonly ISnapshotManager _snapshotManager; - private readonly ChainSpec _chainSpec; + private readonly CliqueChainSpecEngineParameters _chainSpec; - public CliqueHealthHintService(ISnapshotManager snapshotManager, ChainSpec chainSpec) + public CliqueHealthHintService(ISnapshotManager snapshotManager, CliqueChainSpecEngineParameters chainSpec) { _snapshotManager = snapshotManager; _chainSpec = chainSpec; } public ulong? MaxSecondsIntervalForProcessingBlocksHint() { - return _chainSpec.Clique.Period * HealthHintConstants.ProcessingSafetyMultiplier; + return _chainSpec.Period * HealthHintConstants.ProcessingSafetyMultiplier; } public ulong? MaxSecondsIntervalForProducingBlocksHint() { - return Math.Max(_snapshotManager.GetLastSignersCount(), 1) * _chainSpec.Clique.Period * + return Math.Max(_snapshotManager.GetLastSignersCount(), 1) * _chainSpec.Period * HealthHintConstants.ProducingSafetyMultiplier; } } diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs index 4ee9ad51f3a..0b46b7dd1d2 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs @@ -24,9 +24,9 @@ namespace Nethermind.Consensus.Clique { public class CliquePlugin : IConsensusPlugin { - public string Name => "Clique"; + public string Name => SealEngineType; - public string Description => "Clique Consensus Engine"; + public string Description => $"{SealEngineType} Consensus Engine"; public string Author => "Nethermind"; @@ -41,10 +41,12 @@ public Task Init(INethermindApi nethermindApi) (IApiWithStores getFromApi, IApiWithBlockchain setInApi) = _nethermindApi.ForInit; + var chainSpec = getFromApi!.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(); _cliqueConfig = new CliqueConfig { - BlockPeriod = getFromApi!.ChainSpec!.Clique.Period, - Epoch = getFromApi.ChainSpec.Clique.Epoch + BlockPeriod = chainSpec.Period, + Epoch = chainSpec.Epoch }; _snapshotManager = new SnapshotManager( @@ -54,7 +56,9 @@ public Task Init(INethermindApi nethermindApi) getFromApi.EthereumEcdsa!, getFromApi.LogManager); - setInApi.HealthHintService = new CliqueHealthHintService(_snapshotManager, getFromApi.ChainSpec); + setInApi.HealthHintService = new CliqueHealthHintService(_snapshotManager, + getFromApi.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters()); setInApi.SealValidator = new CliqueSealValidator( _cliqueConfig, diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/EthashChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Consensus.Ethash/EthashChainSpecEngineParameters.cs new file mode 100644 index 00000000000..f9d8a0c7fb7 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus.Ethash/EthashChainSpecEngineParameters.cs @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Generic; +using System.Linq; +using Nethermind.Core; +using Nethermind.Int256; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.ChainSpecStyle.Json; +using Newtonsoft.Json; + +namespace Nethermind.Consensus.Ethash; + +public class EthashChainSpecEngineParameters : IChainSpecEngineParameters +{ + public string? EngineName => SealEngineType; + public string? SealEngineType => Core.SealEngineType.Ethash; + + public long HomesteadTransition { get; set; } = 0; + public long? DaoHardforkTransition { get; set; } + public Address DaoHardforkBeneficiary { get; set; } + public Address[] DaoHardforkAccounts { get; set; } = []; + public long? Eip100bTransition { get; set; } + public long? FixedDifficulty { get; set; } + public long DifficultyBoundDivisor { get; set; } = 0x0800; + public long DurationLimit { get; set; } = 13; + public UInt256 MinimumDifficulty { get; set; } = 0; + + [JsonConverter(typeof(BlockRewardConverter))] + public SortedDictionary? BlockReward { get; set; } + public IDictionary? DifficultyBombDelays { get; set; } + + public void AddTransitions(SortedSet blockNumbers, SortedSet timestamps) + { + if (DifficultyBombDelays is not null) + { + foreach ((long blockNumber, _) in DifficultyBombDelays) + { + blockNumbers.Add(blockNumber); + } + } + + if (BlockReward is not null) + { + foreach ((long blockNumber, _) in BlockReward) + { + blockNumbers.Add(blockNumber); + } + } + + blockNumbers.Add(HomesteadTransition); + if (DaoHardforkTransition is not null) blockNumbers.Add(DaoHardforkTransition.Value); + if (Eip100bTransition is not null) blockNumbers.Add(Eip100bTransition.Value); + } + + public void ApplyToReleaseSpec(ReleaseSpec spec, long startBlock, ulong? startTimestamp) + { + SetDifficultyBombDelays(spec, startBlock); + + spec.IsEip2Enabled = HomesteadTransition <= startBlock; + spec.IsEip7Enabled = HomesteadTransition <= startBlock; + spec.IsEip100Enabled = (Eip100bTransition ?? 0) <= startBlock; + spec.DifficultyBoundDivisor = DifficultyBoundDivisor; + spec.FixedDifficulty = FixedDifficulty; + } + + private void SetDifficultyBombDelays(ReleaseSpec spec, long startBlock) + { + if (BlockReward is not null) + { + foreach (KeyValuePair blockReward in BlockReward) + { + if (blockReward.Key <= startBlock) + { + spec.BlockReward = blockReward.Value; + } + } + } + + if (DifficultyBombDelays is not null) + { + foreach (KeyValuePair bombDelay in DifficultyBombDelays) + { + if (bombDelay.Key <= startBlock) + { + spec.DifficultyBombDelay += bombDelay.Value; + } + } + } + } + + public void ApplyToChainSpec(ChainSpec chainSpec) + { + chainSpec.MuirGlacierNumber = DifficultyBombDelays?.Keys.Skip(2).FirstOrDefault(); + chainSpec.ArrowGlacierBlockNumber = DifficultyBombDelays?.Keys.Skip(4).FirstOrDefault(); + chainSpec.GrayGlacierBlockNumber = DifficultyBombDelays?.Keys.Skip(5).FirstOrDefault(); + chainSpec.HomesteadBlockNumber = HomesteadTransition; + chainSpec.DaoForkBlockNumber = DaoHardforkTransition; + } +} diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs index 9968d1a132b..f2a7c72280e 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs @@ -15,9 +15,9 @@ public class EthashPlugin : IConsensusPlugin public ValueTask DisposeAsync() { return ValueTask.CompletedTask; } - public string Name => "Ethash"; + public string Name => SealEngineType; - public string Description => "Ethash Consensus"; + public string Description => $"{SealEngineType} Consensus"; public string Author => "Nethermind"; diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevChainSpecEngineParameters.cs new file mode 100644 index 00000000000..32d26832fd9 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevChainSpecEngineParameters.cs @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Generic; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; + +namespace Nethermind.Consensus.Ethash; + +public class NethDevChainSpecEngineParameters : IChainSpecEngineParameters +{ + public string? EngineName => NethDevPlugin.NethDev; + public string? SealEngineType => NethDevPlugin.NethDev; +} diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs index 4fb7b8895f7..bd2bac63a5d 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs @@ -22,13 +22,14 @@ namespace Nethermind.Consensus.Ethash { public class NethDevPlugin : IConsensusPlugin { + public const string NethDev = "NethDev"; private INethermindApi? _nethermindApi; public ValueTask DisposeAsync() { return ValueTask.CompletedTask; } - public string Name => "NethDev"; + public string Name => NethDev; - public string Description => "NethDev (Spaceneth)"; + public string Description => $"{NethDev} (Spaceneth)"; public string Author => "Nethermind"; @@ -40,7 +41,7 @@ public Task Init(INethermindApi nethermindApi) public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null) { - if (_nethermindApi!.SealEngineType != Nethermind.Core.SealEngineType.NethDev) + if (_nethermindApi!.SealEngineType != SealEngineType) { return null; } @@ -106,7 +107,8 @@ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null) return blockProducer; } - public string SealEngineType => Nethermind.Core.SealEngineType.NethDev; + public string SealEngineType => NethDev; + public IBlockProducerRunner CreateBlockProducerRunner() { IBlockProductionTrigger trigger = new BuildBlocksRegularly(TimeSpan.FromMilliseconds(200)) diff --git a/src/Nethermind/Nethermind.Core/Exceptions/InvalidConfigurationException.cs b/src/Nethermind/Nethermind.Core/Exceptions/InvalidConfigurationException.cs index f740be80f35..7e35cc2d18c 100644 --- a/src/Nethermind/Nethermind.Core/Exceptions/InvalidConfigurationException.cs +++ b/src/Nethermind/Nethermind.Core/Exceptions/InvalidConfigurationException.cs @@ -5,12 +5,7 @@ namespace Nethermind.Core.Exceptions; -public class InvalidConfigurationException : Exception, IExceptionWithExitCode +public class InvalidConfigurationException(string message, int exitCode) : Exception(message), IExceptionWithExitCode { - public InvalidConfigurationException(string message, int exitCode) : base(message) - { - ExitCode = exitCode; - } - - public int ExitCode { get; } + public int ExitCode { get; } = exitCode; } diff --git a/src/Nethermind/Nethermind.Ethash.Test/ChainSpecLoaderTests.cs b/src/Nethermind/Nethermind.Ethash.Test/ChainSpecLoaderTests.cs new file mode 100644 index 00000000000..11ae88f52b1 --- /dev/null +++ b/src/Nethermind/Nethermind.Ethash.Test/ChainSpecLoaderTests.cs @@ -0,0 +1,118 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.IO; +using Nethermind.Consensus.Ethash; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Int256; +using Nethermind.Serialization.Json; +using Nethermind.Specs.ChainSpecStyle; +using NUnit.Framework; + +namespace Nethermind.Ethash.Test; + +public class ChainSpecLoaderTests +{ + private static ChainSpec LoadChainSpec(string path) + { + ChainSpecLoader chainSpecLoader = new(new EthereumJsonSerializer()); + ChainSpec chainSpec = chainSpecLoader.LoadFromFile(path); + return chainSpec; + } + + [Test] + public void Can_load_hive() + { + string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Specs/hive.json"); + ChainSpec chainSpec = LoadChainSpec(path); + + Assert.That(chainSpec.Name, Is.EqualTo("Foundation"), $"{nameof(chainSpec.Name)}"); + Assert.That(chainSpec.DataDir, Is.EqualTo("ethereum"), $"{nameof(chainSpec.Name)}"); + + var parametrs = chainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); + + Assert.That(parametrs.MinimumDifficulty, Is.EqualTo((UInt256)0x020000), $"{nameof(parametrs.MinimumDifficulty)}"); + Assert.That(parametrs.DifficultyBoundDivisor, Is.EqualTo((long)0x0800), $"{nameof(parametrs.DifficultyBoundDivisor)}"); + Assert.That(parametrs.DurationLimit, Is.EqualTo(0xdL), $"{nameof(parametrs.DurationLimit)}"); + + Assert.That(parametrs.BlockReward.Count, Is.EqualTo(3), $"{nameof(parametrs.BlockReward.Count)}"); + Assert.That(parametrs.BlockReward[0L], Is.EqualTo((UInt256)5000000000000000000)); + Assert.That(parametrs.BlockReward[4370000L], Is.EqualTo((UInt256)3000000000000000000)); + Assert.That(parametrs.BlockReward[7080000L], Is.EqualTo((UInt256)2000000000000000000)); + + Assert.That(parametrs.DifficultyBombDelays.Count, Is.EqualTo(2), $"{nameof(parametrs.DifficultyBombDelays.Count)}"); + Assert.That(parametrs.DifficultyBombDelays[4370000], Is.EqualTo(3000000L)); + Assert.That(parametrs.DifficultyBombDelays[7080000], Is.EqualTo(2000000L)); + + Assert.That(parametrs.HomesteadTransition, Is.EqualTo(0L)); + Assert.That(parametrs.DaoHardforkTransition, Is.EqualTo(1920000L)); + Assert.That(parametrs.DaoHardforkBeneficiary, Is.EqualTo(new Address("0xbf4ed7b27f1d666546e30d74d50d173d20bca754"))); + Assert.That(parametrs.DaoHardforkAccounts.Length, Is.EqualTo(0)); + Assert.That(parametrs.Eip100bTransition, Is.EqualTo(0L)); + + Assert.That(chainSpec.ChainId, Is.EqualTo(1), $"{nameof(chainSpec.ChainId)}"); + Assert.That(chainSpec.NetworkId, Is.EqualTo(1), $"{nameof(chainSpec.NetworkId)}"); + Assert.That(chainSpec.Genesis, Is.Not.Null, $"{nameof(ChainSpec.Genesis)}"); + + Assert.That(chainSpec.Parameters.Eip1559BaseFeeInitialValue, Is.EqualTo(1.GWei()), $"initial base fee value"); + Assert.That(chainSpec.Parameters.Eip1559ElasticityMultiplier, Is.EqualTo((long)1), $"elasticity multiplier"); + Assert.That(chainSpec.Parameters.Eip1559BaseFeeMaxChangeDenominator, Is.EqualTo((UInt256)7), $"base fee max change denominator"); + Assert.That(chainSpec.Genesis.BaseFeePerGas, Is.EqualTo((UInt256)11), $"genesis base fee"); + + Assert.That(chainSpec.Genesis.Header.Nonce, Is.EqualTo(0xdeadbeefdeadbeef), $"genesis {nameof(BlockHeader.Nonce)}"); + Assert.That(chainSpec.Genesis.Header.MixHash, Is.EqualTo(Keccak.Zero), $"genesis {nameof(BlockHeader.MixHash)}"); + Assert.That((long)chainSpec.Genesis.Header.Difficulty, Is.EqualTo(0x10), $"genesis {nameof(BlockHeader.Difficulty)}"); + Assert.That(chainSpec.Genesis.Header.Beneficiary, Is.EqualTo(Address.Zero), $"genesis {nameof(BlockHeader.Beneficiary)}"); + Assert.That((long)chainSpec.Genesis.Header.Timestamp, Is.EqualTo(0x00L), $"genesis {nameof(BlockHeader.Timestamp)}"); + Assert.That(chainSpec.Genesis.Header.ParentHash, Is.EqualTo(Keccak.Zero), $"genesis {nameof(BlockHeader.ParentHash)}"); + Assert.That( + chainSpec.Genesis.Header.ExtraData, Is.EqualTo(Bytes.FromHexString("0x0000000000000000000000000000000000000000000000000000000000000000")), + $"genesis {nameof(BlockHeader.ExtraData)}"); + Assert.That(chainSpec.Genesis.Header.GasLimit, Is.EqualTo(0x8000000L), $"genesis {nameof(BlockHeader.GasLimit)}"); + + Assert.That(chainSpec.Allocations, Is.Not.Null, $"{nameof(ChainSpec.Allocations)}"); + Assert.That(chainSpec.Allocations.Count, Is.EqualTo(1), $"allocations count"); + Assert.That( + chainSpec.Allocations[new Address("0x71562b71999873db5b286df957af199ec94617f7")].Balance, Is.EqualTo(new UInt256(0xf4240)), + "account 0x71562b71999873db5b286df957af199ec94617f7 - balance"); + + Assert.That( + chainSpec.Allocations[new Address("0x71562b71999873db5b286df957af199ec94617f7")].Code, Is.EqualTo(Bytes.FromHexString("0xabcd")), + "account 0x71562b71999873db5b286df957af199ec94617f7 - code"); + + Assert.That(chainSpec.SealEngineType, Is.EqualTo(SealEngineType.Ethash), "engine"); + + Assert.That(chainSpec.HomesteadBlockNumber, Is.EqualTo((long?)0), "homestead transition"); + Assert.That(chainSpec.TangerineWhistleBlockNumber, Is.EqualTo((long?)0), "tangerine whistle transition"); + Assert.That(chainSpec.SpuriousDragonBlockNumber, Is.EqualTo((long?)0), "spurious dragon transition"); + Assert.That(chainSpec.ByzantiumBlockNumber, Is.EqualTo((long?)0), "byzantium transition"); + Assert.That(chainSpec.DaoForkBlockNumber, Is.EqualTo((long?)1920000), "dao transition"); + Assert.That(chainSpec.ConstantinopleFixBlockNumber, Is.EqualTo((long?)7080000), "constantinople transition"); + + Assert.That(chainSpec.Parameters.MaxCodeSize, Is.EqualTo((long?)24576L), "max code size"); + Assert.That(chainSpec.Parameters.MaxCodeSizeTransition, Is.EqualTo((long?)0L), "max code size transition"); + Assert.That(chainSpec.Parameters.MinGasLimit, Is.EqualTo((long?)0x1388L), "min gas limit"); + Assert.That(chainSpec.Parameters.Registrar, Is.EqualTo(new Address("0xe3389675d0338462dC76C6f9A3e432550c36A142")), "registrar"); + Assert.That(chainSpec.Parameters.ForkBlock, Is.EqualTo((long?)0x1d4c00L), "fork block"); + Assert.That(chainSpec.Parameters.ForkCanonHash, Is.EqualTo(new Hash256("0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb")), "fork block"); + + Assert.That(chainSpec.Parameters.Eip150Transition, Is.EqualTo((long?)0L), "eip150"); + Assert.That(chainSpec.Parameters.Eip160Transition, Is.EqualTo((long?)0L), "eip160"); + Assert.That(chainSpec.Parameters.Eip161abcTransition, Is.EqualTo((long?)0L), "eip161abc"); + Assert.That(chainSpec.Parameters.Eip161dTransition, Is.EqualTo((long?)0L), "eip161d"); + Assert.That(chainSpec.Parameters.Eip155Transition, Is.EqualTo((long?)0L), "eip155"); + Assert.That(chainSpec.Parameters.Eip140Transition, Is.EqualTo((long?)0L), "eip140"); + Assert.That(chainSpec.Parameters.Eip211Transition, Is.EqualTo((long?)0L), "eip211"); + Assert.That(chainSpec.Parameters.Eip214Transition, Is.EqualTo((long?)0L), "eip214"); + Assert.That(chainSpec.Parameters.Eip658Transition, Is.EqualTo((long?)0L), "eip658"); + Assert.That(chainSpec.Parameters.Eip145Transition, Is.EqualTo((long?)7080000L), "eip145"); + Assert.That(chainSpec.Parameters.Eip1014Transition, Is.EqualTo((long?)7080000L), "eip1014"); + Assert.That(chainSpec.Parameters.Eip1052Transition, Is.EqualTo((long?)7080000L), "eip1052"); + Assert.That(chainSpec.Parameters.Eip1283Transition, Is.EqualTo((long?)7080000L), "eip1283"); + + Assert.That(chainSpec.Parameters.MaximumExtraDataSize, Is.EqualTo((long)32), "extra data"); + Assert.That(chainSpec.Parameters.GasLimitBoundDivisor, Is.EqualTo((long)0x0400), "gas limit bound divisor"); + } +} diff --git a/src/Nethermind/Nethermind.Ethash.Test/ChainSpecTest.cs b/src/Nethermind/Nethermind.Ethash.Test/ChainSpecTest.cs new file mode 100644 index 00000000000..521b717a873 --- /dev/null +++ b/src/Nethermind/Nethermind.Ethash.Test/ChainSpecTest.cs @@ -0,0 +1,215 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using FluentAssertions; +using Nethermind.Consensus.Ethash; +using Nethermind.Core; +using Nethermind.Core.Specs; +using Nethermind.Int256; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.Test.ChainSpecStyle; +using NUnit.Framework; + +namespace Nethermind.Ethash.Test; + +public class ChainSpecTest +{ + [Test] + public void Bound_divisors_set_correctly() + { + ChainSpec chainSpec = new() + { + Parameters = new ChainParameters { GasLimitBoundDivisor = 17 } + }; + + chainSpec.EngineChainSpecParametersProvider = + new TestChainSpecParametersProvider(new EthashChainSpecEngineParameters { DifficultyBoundDivisor = 19 }); + + + ChainSpecBasedSpecProvider provider = new(chainSpec); + Assert.That(provider.GenesisSpec.DifficultyBoundDivisor, Is.EqualTo(19)); + Assert.That(provider.GenesisSpec.GasLimitBoundDivisor, Is.EqualTo(17)); + } + + [Test] + public void Difficulty_bomb_delays_loaded_correctly() + { + ChainSpec chainSpec = new() + { + Parameters = new ChainParameters(), + }; + chainSpec.EngineChainSpecParametersProvider = new TestChainSpecParametersProvider( + new EthashChainSpecEngineParameters + { + DifficultyBombDelays = new Dictionary + { + { 3, 100 }, + { 7, 200 }, + { 13, 300 }, + { 17, 400 }, + { 19, 500 }, + } + }); + + ChainSpecBasedSpecProvider provider = new(chainSpec); + Assert.That(provider.GetSpec((ForkActivation)3).DifficultyBombDelay, Is.EqualTo(100)); + Assert.That(provider.GetSpec((ForkActivation)7).DifficultyBombDelay, Is.EqualTo(300)); + Assert.That(provider.GetSpec((ForkActivation)13).DifficultyBombDelay, Is.EqualTo(600)); + Assert.That(provider.GetSpec((ForkActivation)17).DifficultyBombDelay, Is.EqualTo(1000)); + Assert.That(provider.GetSpec((ForkActivation)19).DifficultyBombDelay, Is.EqualTo(1500)); + } + + [Test] + public void Eip_transitions_loaded_correctly() + { + const long maxCodeTransition = 1; + const long maxCodeSize = 1; + + ChainSpec chainSpec = new() + { + ByzantiumBlockNumber = 1960, + ConstantinopleBlockNumber = 6490, + Parameters = new ChainParameters + { + MaxCodeSizeTransition = maxCodeTransition, + MaxCodeSize = maxCodeSize, + Registrar = Address.Zero, + MinGasLimit = 11, + GasLimitBoundDivisor = 13, + MaximumExtraDataSize = 17, + Eip140Transition = 1400L, + Eip145Transition = 1450L, + Eip150Transition = 1500L, + Eip152Transition = 1520L, + Eip155Transition = 1550L, + Eip160Transition = 1600L, + Eip161abcTransition = 1580L, + Eip161dTransition = 1580L, + Eip211Transition = 2110L, + Eip214Transition = 2140L, + Eip658Transition = 6580L, + Eip1014Transition = 10140L, + Eip1052Transition = 10520L, + Eip1108Transition = 11080L, + Eip1283Transition = 12830L, + Eip1283DisableTransition = 12831L, + Eip1344Transition = 13440L, + Eip1884Transition = 18840L, + Eip2028Transition = 20280L, + Eip2200Transition = 22000L, + Eip2315Transition = 23150L, + Eip2565Transition = 25650L, + Eip2929Transition = 29290L, + Eip2930Transition = 29300L, + Eip1559Transition = 15590L, + Eip1559FeeCollectorTransition = 15591L, + FeeCollector = Address.SystemUser, + Eip1559BaseFeeMinValueTransition = 15592L, + Eip1559BaseFeeMinValue = UInt256.UInt128MaxValue, + Eip3198Transition = 31980L, + Eip3529Transition = 35290L, + Eip3541Transition = 35410L, + Eip1283ReenableTransition = 23000L, + ValidateChainIdTransition = 24000L, + ValidateReceiptsTransition = 24000L, + MergeForkIdTransition = 40000L, + Eip3651TransitionTimestamp = 1000000012, + Eip3855TransitionTimestamp = 1000000012, + Eip3860TransitionTimestamp = 1000000012, + Eip1153TransitionTimestamp = 1000000024, + Eip2537TransitionTimestamp = 1000000024, + + Eip7702TransitionTimestamp = 1000000032, + } + }; + chainSpec.EngineChainSpecParametersProvider = new TestChainSpecParametersProvider( + new EthashChainSpecEngineParameters + { + HomesteadTransition = 70, + Eip100bTransition = 1000 + }); + + + ChainSpecBasedSpecProvider provider = new(chainSpec); + Assert.That(provider.GetSpec((ForkActivation)(maxCodeTransition - 1)).MaxCodeSize, Is.EqualTo(long.MaxValue), "one before"); + Assert.That(provider.GetSpec((ForkActivation)maxCodeTransition).MaxCodeSize, Is.EqualTo(maxCodeSize), "at transition"); + Assert.That(provider.GetSpec((ForkActivation)(maxCodeTransition + 1)).MaxCodeSize, Is.EqualTo(maxCodeSize), "one after"); + + ReleaseSpec expected = new(); + + void TestTransitions(ForkActivation activation, Action changes) + { + changes(expected); + IReleaseSpec underTest = provider.GetSpec(activation); + underTest.Should().BeEquivalentTo(expected); + } + + TestTransitions((ForkActivation)0L, r => + { + r.DifficultyBoundDivisor = 0x800; + r.MinGasLimit = 11L; + r.GasLimitBoundDivisor = 13L; + r.MaximumExtraDataSize = 17L; + r.MaxCodeSize = long.MaxValue; + r.Eip1559TransitionBlock = 15590L; + r.IsTimeAdjustmentPostOlympic = true; + r.MaximumUncleCount = 2; + r.WithdrawalTimestamp = ulong.MaxValue; + r.Eip4844TransitionTimestamp = ulong.MaxValue; + }); + + TestTransitions((ForkActivation)1L, r => + { + r.MaxCodeSize = maxCodeSize; + r.IsEip170Enabled = true; + }); + TestTransitions((ForkActivation)70L, r => { r.IsEip2Enabled = r.IsEip7Enabled = true; }); + TestTransitions((ForkActivation)1000L, r => { r.IsEip100Enabled = true; }); + TestTransitions((ForkActivation)1400L, r => { r.IsEip140Enabled = true; }); + TestTransitions((ForkActivation)1450L, r => { r.IsEip145Enabled = true; }); + TestTransitions((ForkActivation)1500L, r => { r.IsEip150Enabled = true; }); + TestTransitions((ForkActivation)1520L, r => { r.IsEip152Enabled = true; }); + TestTransitions((ForkActivation)1550L, r => { r.IsEip155Enabled = true; }); + TestTransitions((ForkActivation)1580L, r => { r.IsEip158Enabled = true; }); + TestTransitions((ForkActivation)1600L, r => { r.IsEip160Enabled = true; }); + TestTransitions((ForkActivation)1960L, + r => { r.IsEip196Enabled = r.IsEip197Enabled = r.IsEip198Enabled = r.IsEip649Enabled = true; }); + TestTransitions((ForkActivation)2110L, r => { r.IsEip211Enabled = true; }); + TestTransitions((ForkActivation)2140L, r => { r.IsEip214Enabled = true; }); + TestTransitions((ForkActivation)6580L, r => { r.IsEip658Enabled = r.IsEip1234Enabled = true; }); + TestTransitions((ForkActivation)10140L, r => { r.IsEip1014Enabled = true; }); + TestTransitions((ForkActivation)10520L, r => { r.IsEip1052Enabled = true; }); + TestTransitions((ForkActivation)11180L, r => { r.IsEip1108Enabled = true; }); + TestTransitions((ForkActivation)12830L, r => { r.IsEip1283Enabled = true; }); + TestTransitions((ForkActivation)12831L, r => { r.IsEip1283Enabled = false; }); + TestTransitions((ForkActivation)13440L, r => { r.IsEip1344Enabled = true; }); + TestTransitions((ForkActivation)15590L, r => { r.IsEip1559Enabled = true; }); + TestTransitions((ForkActivation)15591L, r => { r.FeeCollector = Address.SystemUser; }); + TestTransitions((ForkActivation)15592L, r => { r.Eip1559BaseFeeMinValue = UInt256.UInt128MaxValue; }); + TestTransitions((ForkActivation)18840L, r => { r.IsEip1884Enabled = true; }); + TestTransitions((ForkActivation)20280L, r => { r.IsEip2028Enabled = true; }); + TestTransitions((ForkActivation)22000L, r => { r.IsEip2200Enabled = true; }); + TestTransitions((ForkActivation)23000L, r => { r.IsEip1283Enabled = r.IsEip1344Enabled = true; }); + TestTransitions((ForkActivation)24000L, r => { r.ValidateChainId = r.ValidateReceipts = true; }); + TestTransitions((ForkActivation)29290L, r => { r.IsEip2929Enabled = r.IsEip2565Enabled = true; }); + TestTransitions((ForkActivation)29300L, r => { r.IsEip2930Enabled = true; }); + TestTransitions((ForkActivation)31980L, r => { r.IsEip3198Enabled = true; }); + TestTransitions((ForkActivation)35290L, r => { r.IsEip3529Enabled = true; }); + TestTransitions((ForkActivation)35410L, r => { r.IsEip3541Enabled = true; }); + TestTransitions((ForkActivation)35410L, r => { r.IsEip3541Enabled = true; }); + + + TestTransitions((41000L, 1000000012), r => + { + r.IsEip3651Enabled = true; + r.IsEip3855Enabled = true; + r.IsEip3860Enabled = true; + }); + TestTransitions((40001L, 1000000024), r => { r.IsEip1153Enabled = r.IsEip2537Enabled = true; }); + TestTransitions((40001L, 1000000032), r => { r.IsEip7702Enabled = true; }); + } + +} 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 26077b2de8b..181e0fd06fc 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EstimateGas.cs @@ -16,6 +16,7 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.Specs.Test; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.State; using Newtonsoft.Json.Linq; using NUnit.Framework; 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 caeb411c8d5..afbce2b63e2 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.EthCall.cs @@ -15,6 +15,7 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.Specs.Test; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.State; using Newtonsoft.Json.Linq; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.GasPrice.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.GasPrice.cs index 62e7e81d9be..26415e9be23 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.GasPrice.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.GasPrice.cs @@ -12,6 +12,7 @@ using Nethermind.Int256; using Nethermind.JsonRpc.Modules.Eth.GasPrice; using Nethermind.Logging; +using Nethermind.Specs.Test.ChainSpecStyle; using NUnit.Framework; using static Nethermind.JsonRpc.Test.Modules.GasPriceOracleTests; diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs index cba118364b4..dd87b6515d8 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs @@ -32,6 +32,7 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.Specs.Test; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.TxPool; using Newtonsoft.Json.Linq; using NSubstitute; diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index 20c674df14a..2938cc32807 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -29,6 +29,8 @@ using Nethermind.JsonRpc.Data; using Nethermind.Serialization.Rlp; using Newtonsoft.Json.Linq; +using Nethermind.JsonRpc.Modules; +using Nethermind.Specs.Test.ChainSpecStyle; namespace Nethermind.JsonRpc.Test.Modules; diff --git a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs index 663c941b485..f1e2ace6075 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs @@ -34,6 +34,7 @@ using Nethermind.Serialization.Json; using Nethermind.Specs; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.Synchronization.ParallelSync; using NSubstitute; using NUnit.Framework; @@ -123,10 +124,11 @@ protected override IBlockProcessor CreateBlockProcessor() _api = new(new ConfigProvider(), new EthereumJsonSerializer(), LogManager, new ChainSpec { - AuRa = new() - { - WithdrawalContractAddress = new("0xbabe2bed00000000000000000000000000000003") - }, + EngineChainSpecParametersProvider = new TestChainSpecParametersProvider( + new AuRaChainSpecEngineParameters + { + WithdrawalContractAddress = new("0xbabe2bed00000000000000000000000000000003") + }), Parameters = new() }) { @@ -138,10 +140,11 @@ protected override IBlockProcessor CreateBlockProcessor() TxPool = TxPool }; - WithdrawalContractFactory withdrawalContractFactory = new(_api.ChainSpec!.AuRa, _api.AbiEncoder); + WithdrawalContractFactory withdrawalContractFactory = new(_api.ChainSpec!.EngineChainSpecParametersProvider + .GetChainSpecParameters(), _api.AbiEncoder); WithdrawalProcessor = new AuraWithdrawalProcessor( - withdrawalContractFactory.Create(TxProcessor), - LogManager + withdrawalContractFactory.Create(TxProcessor), + LogManager ); BlockValidator = CreateBlockValidator(); diff --git a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs index faf77f16d32..9dd11bc4de6 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs @@ -5,6 +5,7 @@ using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Receipts; using Nethermind.Config; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.InitializationSteps; using Nethermind.Consensus.Comparers; using Nethermind.Consensus.Processing; @@ -16,6 +17,7 @@ using Nethermind.Evm.TransactionProcessing; using Nethermind.Logging; using Nethermind.Merge.AuRa.Withdrawals; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; using Nethermind.TxPool; @@ -66,7 +68,9 @@ protected override BlockProcessor CreateBlockProcessor( ILogManager logManager, IBlocksConfig blocksConfig) { - var withdrawalContractFactory = new WithdrawalContractFactory(_auraApi.ChainSpec!.AuRa, _auraApi.AbiEncoder); + var withdrawalContractFactory = new WithdrawalContractFactory( + _auraApi.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(), _auraApi.AbiEncoder); return new AuRaMergeBlockProcessor( specProvider, diff --git a/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs b/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs index 6fec278699c..700fb7ccadd 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Consensus.AuRa; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Consensus.AuRa.InitializationSteps; using Nethermind.Consensus.AuRa.Validators; using Nethermind.Consensus.Withdrawals; @@ -14,6 +15,7 @@ using Nethermind.Evm.TransactionProcessing; using Nethermind.Init.Steps; using Nethermind.Merge.AuRa.Withdrawals; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; namespace Nethermind.Merge.AuRa.InitializationSteps @@ -21,18 +23,21 @@ namespace Nethermind.Merge.AuRa.InitializationSteps public class InitializeBlockchainAuRaMerge : InitializeBlockchainAuRa { private readonly AuRaNethermindApi _api; + private readonly AuRaChainSpecEngineParameters _parameters; public InitializeBlockchainAuRaMerge(AuRaNethermindApi api) : base(api) { _api = api; + _parameters = _api.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(); } protected override AuRaBlockProcessor NewAuraBlockProcessor(ITxFilter txFilter, BlockCachePreWarmer? preWarmer) { - IDictionary> rewriteBytecode = _api.ChainSpec.AuRa.RewriteBytecode; + IDictionary> rewriteBytecode = _parameters.RewriteBytecode; ContractRewriter? contractRewriter = rewriteBytecode?.Count > 0 ? new ContractRewriter(rewriteBytecode) : null; - WithdrawalContractFactory withdrawalContractFactory = new WithdrawalContractFactory(_api.ChainSpec!.AuRa, _api.AbiEncoder); + WithdrawalContractFactory withdrawalContractFactory = new WithdrawalContractFactory(_parameters, _api.AbiEncoder); IWorldState worldState = _api.WorldState!; ITransactionProcessor transactionProcessor = _api.TransactionProcessor!; diff --git a/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/WithdrawalContractFactory.cs b/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/WithdrawalContractFactory.cs index d52616916f2..1f0711feb9b 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/WithdrawalContractFactory.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/WithdrawalContractFactory.cs @@ -3,6 +3,7 @@ using System; using Nethermind.Abi; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Core; using Nethermind.Evm.TransactionProcessing; using Nethermind.Merge.AuRa.Contracts; @@ -15,7 +16,7 @@ public class WithdrawalContractFactory : IWithdrawalContractFactory private readonly IAbiEncoder _abiEncoder; private readonly Address _contractAddress; - public WithdrawalContractFactory(AuRaParameters parameters, IAbiEncoder abiEncoder) + public WithdrawalContractFactory(AuRaChainSpecEngineParameters parameters, IAbiEncoder abiEncoder) { ArgumentNullException.ThrowIfNull(parameters); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs index 5501820429f..0f9b4874fbe 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/ChainSpecBasedSpecProviderTests.TheMerge.cs @@ -6,6 +6,7 @@ using Nethermind.Int256; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.Test.ChainSpecStyle; using NUnit.Framework; namespace Nethermind.Merge.Plugin.Test; @@ -21,7 +22,8 @@ public void Correctly_read_merge_block_number() Parameters = new ChainParameters { TerminalPoWBlockNumber = terminalBlockNumber - } + }, + EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev }; ChainSpecBasedSpecProvider provider = new(chainSpec); @@ -51,7 +53,8 @@ public void Merge_block_number_should_be_null_when_not_set() { ChainSpec chainSpec = new() { - Parameters = new ChainParameters { } + Parameters = new ChainParameters { }, + EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev }; ChainSpecBasedSpecProvider provider = new(chainSpec); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs index 72baf781716..878fae85bee 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs @@ -21,9 +21,9 @@ using Nethermind.Specs.Forks; using Nethermind.State; using Nethermind.Core.ConsensusRequests; -using Microsoft.CodeAnalysis; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Core.Specs; +using Nethermind.Specs.Test.ChainSpecStyle; using Nethermind.Evm.Tracing; namespace Nethermind.Merge.Plugin.Test diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs index e86e16fc5a8..9810fb3c89f 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs @@ -16,6 +16,7 @@ using Nethermind.JsonRpc.Modules; using Nethermind.Merge.Plugin.BlockProduction; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.Test.ChainSpecStyle; using NUnit.Framework; using NSubstitute; using Build = Nethermind.Runner.Test.Ethereum.Build; @@ -58,11 +59,9 @@ public void Setup() _context.LogManager!); _context.ProcessExit = Substitute.For(); _context.ChainSpec.SealEngineType = SealEngineType.Clique; - _context.ChainSpec!.Clique = new CliqueParameters() - { - Epoch = CliqueConfig.Default.Epoch, - Period = CliqueConfig.Default.BlockPeriod - }; + var chainSpecParametersProvider = new TestChainSpecParametersProvider( + new CliqueChainSpecEngineParameters { Epoch = CliqueConfig.Default.Epoch, Period = CliqueConfig.Default.BlockPeriod }); + _context.ChainSpec.EngineChainSpecParametersProvider = chainSpecParametersProvider; _plugin = new MergePlugin(); _consensusPlugin = new(); diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs index 81b83425ace..205b643ea26 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs @@ -36,6 +36,7 @@ using Nethermind.Merge.Plugin.Synchronization; using Nethermind.Synchronization; using Nethermind.Synchronization.Blocks; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.Synchronization.ParallelSync; using Nethermind.TxPool; diff --git a/src/Nethermind/Nethermind.Optimism/IOptimismSpecHelper.cs b/src/Nethermind/Nethermind.Optimism/IOptimismSpecHelper.cs index 799678f69b7..5b994dab33d 100644 --- a/src/Nethermind/Nethermind.Optimism/IOptimismSpecHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/IOptimismSpecHelper.cs @@ -7,7 +7,7 @@ namespace Nethermind.Optimism; public interface IOptimismSpecHelper { - Address L1FeeReceiver { get; } + Address? L1FeeReceiver { get; } bool IsBedrock(BlockHeader header); bool IsRegolith(BlockHeader header); diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index 79208162e76..e1c185d2aea 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -25,10 +25,13 @@ public class InitializeBlockchainOptimism(OptimismNethermindApi api) : Initializ { private readonly IBlocksConfig _blocksConfig = api.Config(); + private readonly OptimismChainSpecEngineParameters _chainSpecParameters = api.ChainSpec + .EngineChainSpecParametersProvider.GetChainSpecParameters(); + protected override async Task InitBlockchain() { - api.SpecHelper = new(api.ChainSpec.Optimism); - api.L1CostHelper = new(api.SpecHelper, api.ChainSpec.Optimism.L1BlockAddress); + api.SpecHelper = new(_chainSpecParameters); + api.L1CostHelper = new(api.SpecHelper, _chainSpecParameters.L1BlockAddress!); await base.InitBlockchain(); diff --git a/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs b/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs index e4429ba0ac9..251803fafaa 100644 --- a/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs @@ -6,16 +6,16 @@ namespace Nethermind.Optimism; -public class OptimismSpecHelper(OptimismParameters parameters) : IOptimismSpecHelper +public class OptimismSpecHelper(OptimismChainSpecEngineParameters parameters) : IOptimismSpecHelper { - private readonly long _bedrockBlockNumber = parameters.BedrockBlockNumber; - private readonly ulong _regolithTimestamp = parameters.RegolithTimestamp; + private readonly long? _bedrockBlockNumber = parameters.BedrockBlockNumber; + private readonly ulong? _regolithTimestamp = parameters.RegolithTimestamp; private readonly ulong? _canyonTimestamp = parameters.CanyonTimestamp; private readonly ulong? _ecotoneTimestamp = parameters.EcotoneTimestamp; private readonly ulong? _fjordTimestamp = parameters.FjordTimestamp; private readonly ulong? _graniteTimestamp = parameters.GraniteTimestamp; - public Address L1FeeReceiver { get; init; } = parameters.L1FeeRecipient; + public Address? L1FeeReceiver { get; init; } = parameters.L1FeeRecipient; public bool IsRegolith(BlockHeader header) { diff --git a/src/Nethermind/Nethermind.Optimism/OptimismChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Optimism/OptimismChainSpecEngineParameters.cs new file mode 100644 index 00000000000..37f14bb91c1 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/OptimismChainSpecEngineParameters.cs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using Nethermind.Core; +using Nethermind.Int256; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; + +namespace Nethermind.Optimism; + +public class OptimismChainSpecEngineParameters : IChainSpecEngineParameters +{ + public string? EngineName => SealEngineType; + public string? SealEngineType => Core.SealEngineType.Optimism; + + public ulong? RegolithTimestamp { get; set; } + + public long? BedrockBlockNumber { get; set; } + + public ulong? CanyonTimestamp { get; set; } + + public ulong? EcotoneTimestamp { get; set; } + + public ulong? FjordTimestamp { get; set; } + + public ulong? GraniteTimestamp { get; set; } + + public Address? L1FeeRecipient { get; set; } + + public Address? L1BlockAddress { get; set; } + + public UInt256? CanyonBaseFeeChangeDenominator { get; set; } + + public Address? Create2DeployerAddress { get; set; } + + public byte[]? Create2DeployerCode { get; set; } + + public void AddTransitions(SortedSet blockNumbers, SortedSet timestamps) + { + ArgumentNullException.ThrowIfNull(BedrockBlockNumber); + ArgumentNullException.ThrowIfNull(RegolithTimestamp); + ArgumentNullException.ThrowIfNull(CanyonTimestamp); + ArgumentNullException.ThrowIfNull(EcotoneTimestamp); + ArgumentNullException.ThrowIfNull(FjordTimestamp); + ArgumentNullException.ThrowIfNull(GraniteTimestamp); + blockNumbers.Add(BedrockBlockNumber.Value); + timestamps.Add(RegolithTimestamp.Value); + timestamps.Add(CanyonTimestamp.Value); + timestamps.Add(EcotoneTimestamp.Value); + timestamps.Add(FjordTimestamp.Value); + timestamps.Add(GraniteTimestamp.Value); + } + + public void ApplyToReleaseSpec(ReleaseSpec spec, long startBlock, ulong? startTimestamp) + { + ArgumentNullException.ThrowIfNull(CanyonBaseFeeChangeDenominator); + if (CanyonTimestamp <= startTimestamp) + { + spec.BaseFeeMaxChangeDenominator = CanyonBaseFeeChangeDenominator.Value; + } + } +} diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index 5f2fcf7c7f4..0afaefd7d78 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -41,6 +41,7 @@ public class OptimismPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitial public string Description => "Optimism support for Nethermind"; private OptimismNethermindApi? _api; + private OptimismChainSpecEngineParameters? _chainSpecParameters; private ILogger _logger; private IMergeConfig _mergeConfig = null!; private ISyncConfig _syncConfig = null!; @@ -103,7 +104,9 @@ public Task Init(INethermindApi api) ArgumentNullException.ThrowIfNull(_api.SpecProvider); - _api.PoSSwitcher = new OptimismPoSSwitcher(_api.SpecProvider, _api.ChainSpec.Optimism.BedrockBlockNumber); + _chainSpecParameters = _api.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(); + _api.PoSSwitcher = new OptimismPoSSwitcher(_api.SpecProvider, _chainSpecParameters.BedrockBlockNumber!.Value); _blockCacheService = new BlockCacheService(); _api.EthereumEcdsa = new OptimismEthereumEcdsa(_api.EthereumEcdsa); @@ -162,7 +165,7 @@ public Task InitSynchronization() builder.RegisterModule(new SynchronizerModule(_syncConfig)); builder.RegisterModule(new MergeSynchronizerModule()); - builder.RegisterModule(new OptimismSynchronizerModule(_api.ChainSpec.Optimism, _api.SpecProvider)); + builder.RegisterModule(new OptimismSynchronizerModule(_chainSpecParameters!, _api.SpecProvider)); IContainer container = builder.Build(); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismSynchronizerModule.cs b/src/Nethermind/Nethermind.Optimism/OptimismSynchronizerModule.cs index b1a1e60aba3..d8feb664137 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismSynchronizerModule.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismSynchronizerModule.cs @@ -16,7 +16,7 @@ namespace Nethermind.Optimism; /// Calculation is still the same: the current block's is the parent's plus the current block's . /// /// -public sealed class OptimismSynchronizerModule(OptimismParameters parameters, ISpecProvider provider) : Module +public sealed class OptimismSynchronizerModule(OptimismChainSpecEngineParameters parameters, ISpecProvider provider) : Module { private const ulong OptimismMainnetChainId = 0xA; @@ -24,10 +24,11 @@ protected override void Load(ContainerBuilder builder) { if (provider.ChainId == OptimismMainnetChainId) { + ArgumentNullException.ThrowIfNull(parameters.BedrockBlockNumber); builder.AddSingleton( new FixedTotalDifficultyStrategy( new CumulativeTotalDifficultyStrategy(), - fixesBlockNumber: parameters.BedrockBlockNumber - 1, + fixesBlockNumber: parameters.BedrockBlockNumber.Value - 1, toTotalDifficulty: provider.TerminalTotalDifficulty ?? throw new ArgumentNullException(nameof(provider.TerminalTotalDifficulty)) ) ); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs index b188989eb00..b2a4fec5b0c 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs @@ -147,7 +147,7 @@ protected override void PayFees(Transaction tx, BlockHeader header, IReleaseSpec if (opSpecHelper.IsBedrock(header)) { UInt256 l1Cost = _currentTxL1Cost ??= l1CostHelper.ComputeL1Cost(tx, header, WorldState); - WorldState.AddToBalanceAndCreateIfNotExists(opSpecHelper.L1FeeReceiver, l1Cost, spec); + WorldState.AddToBalanceAndCreateIfNotExists(opSpecHelper.L1FeeReceiver!, l1Cost, spec); } } } diff --git a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs index 8a46d508bef..3f3690ece0f 100644 --- a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs @@ -12,6 +12,9 @@ using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Config; +using Nethermind.Consensus.AuRa.Config; +using Nethermind.Consensus.Clique; +using Nethermind.Consensus.Ethash; using Nethermind.Core.Test.IO; using Nethermind.Hive; using Nethermind.JsonRpc; @@ -19,7 +22,9 @@ using Nethermind.Logging; using Nethermind.Network.Config; using Nethermind.Runner.Ethereum; +using Nethermind.Optimism; using Nethermind.Runner.Ethereum.Api; +using Nethermind.Taiko; using NUnit.Framework; namespace Nethermind.Runner.Test; @@ -29,16 +34,16 @@ public class EthereumRunnerTests { static EthereumRunnerTests() { - AssemblyLoadContext.Default.Resolving += (context, name) => - { - return null; - }; + AssemblyLoadContext.Default.Resolving += (_, _) => null; } private static readonly Lazy? _cachedProviders = new(InitOnce); private static ICollection InitOnce() { + // we need this to discover ChainSpecEngineParameters + _ = new[] { typeof(CliqueChainSpecEngineParameters), typeof(OptimismChainSpecEngineParameters), typeof(TaikoChainSpecEngineParameters) }; + // by pre-caching configs providers we make the tests do lot less work ConcurrentQueue<(string, ConfigProvider)> result = new(); Parallel.ForEach(Directory.GetFiles("configs"), configFile => diff --git a/src/Nethermind/Nethermind.Runner.Test/Nethermind.Runner.Test.csproj b/src/Nethermind/Nethermind.Runner.Test/Nethermind.Runner.Test.csproj index 1a486552b62..3b363b262d2 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Nethermind.Runner.Test.csproj +++ b/src/Nethermind/Nethermind.Runner.Test/Nethermind.Runner.Test.csproj @@ -27,6 +27,8 @@ + + Chains\AuRaTest.json diff --git a/src/Nethermind/Nethermind.Runner.Test/testspec.json b/src/Nethermind/Nethermind.Runner.Test/testspec.json index a1c0ec05f21..65a54ff2cda 100644 --- a/src/Nethermind/Nethermind.Runner.Test/testspec.json +++ b/src/Nethermind/Nethermind.Runner.Test/testspec.json @@ -2,10 +2,8 @@ "name": "A Testnet", "dataDir": "testspecdir", "engine": { - "clique": { + "NethDev": { "params": { - "period": 15, - "epoch": 30000 } } }, diff --git a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs index 01e23bfccf6..6c8b9b74c20 100644 --- a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs +++ b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs @@ -34,6 +34,11 @@ public EthereumJsonSerializer(int? maxDepth = null) _jsonOptions = maxDepth.HasValue ? CreateOptions(indented: false, maxDepth: maxDepth.Value) : JsonOptions; } + public object Deserialize(string json, Type type) + { + return JsonSerializer.Deserialize(json, type, _jsonOptions); + } + public T Deserialize(Stream stream) { return JsonSerializer.Deserialize(stream, _jsonOptions); diff --git a/src/Nethermind/Nethermind.Serialization.Json/IJsonSerializer.cs b/src/Nethermind/Nethermind.Serialization.Json/IJsonSerializer.cs index 490e98153fd..43b0d5cd7d6 100644 --- a/src/Nethermind/Nethermind.Serialization.Json/IJsonSerializer.cs +++ b/src/Nethermind/Nethermind.Serialization.Json/IJsonSerializer.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Buffers; using System.IO; using System.Threading.Tasks; @@ -9,6 +10,7 @@ namespace Nethermind.Serialization.Json { public interface IJsonSerializer { + object Deserialize(string json, Type type); T Deserialize(Stream stream); T Deserialize(string json); string Serialize(T value, bool indented = false); diff --git a/src/Nethermind/Nethermind.Serialization.Json/LongConverter.cs b/src/Nethermind/Nethermind.Serialization.Json/LongConverter.cs index 991256c119b..a28322aa1c3 100644 --- a/src/Nethermind/Nethermind.Serialization.Json/LongConverter.cs +++ b/src/Nethermind/Nethermind.Serialization.Json/LongConverter.cs @@ -43,6 +43,12 @@ public static long FromString(string s) return long.Parse(s, NumberStyles.Integer); } + public override long ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + ReadOnlySpan hex = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; + return FromString(hex); + } + public static long FromString(ReadOnlySpan s) { if (s.Length == 0) diff --git a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs index ba794b320b1..4c8061036ce 100644 --- a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs +++ b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Reflection; using FluentAssertions; +using Nethermind.Consensus.AuRa.Config; using Nethermind.Core; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -201,6 +202,8 @@ public static IEnumerable ChiadoActivations [TestCaseSource(nameof(ChiadoActivations))] public void Chiado_loads_properly(ForkActivation forkActivation) { + // We need this to discover AuthorityRoundEngineParams + new AuRaConfig(); ChainSpec chainSpec = LoadChainSpecFromChainFolder("chiado"); ChainSpecBasedSpecProvider provider = new(chainSpec); ChiadoSpecProvider chiado = ChiadoSpecProvider.Instance; @@ -235,11 +238,16 @@ public static IEnumerable GnosisActivations yield return new TestCaseData((ForkActivation)GnosisSpecProvider.BerlinBlockNumber) { TestName = "Berlin" }; yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber - 1)) { TestName = "Before London" }; yield return new TestCaseData((ForkActivation)GnosisSpecProvider.LondonBlockNumber) { TestName = "London" }; - yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 1, GnosisSpecProvider.ShanghaiTimestamp - 1)) { TestName = "Before Shanghai" }; - yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 1, GnosisSpecProvider.ShanghaiTimestamp)) { TestName = "Shanghai" }; - yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 2, GnosisSpecProvider.CancunTimestamp - 1)) { TestName = "Before Cancun" }; - yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 2, GnosisSpecProvider.CancunTimestamp)) { TestName = "Cancun" }; - yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 2, GnosisSpecProvider.CancunTimestamp + 100000000)) { TestName = "Future" }; + yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 1, GnosisSpecProvider.ShanghaiTimestamp - 1)) + { TestName = "Before Shanghai" }; + yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 1, GnosisSpecProvider.ShanghaiTimestamp)) + { TestName = "Shanghai" }; + yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 2, GnosisSpecProvider.CancunTimestamp - 1)) + { TestName = "Before Cancun" }; + yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 2, GnosisSpecProvider.CancunTimestamp)) + { TestName = "Cancun" }; + yield return new TestCaseData((ForkActivation)(GnosisSpecProvider.LondonBlockNumber + 2, GnosisSpecProvider.CancunTimestamp + 100000000)) + { TestName = "Future" }; } } @@ -414,7 +422,6 @@ private static void CompareSpecs(IReleaseSpec expectedSpec, IReleaseSpec actualS typeof(IReleaseSpec).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo propertyInfo in propertyInfos .Where(p => p.Name != nameof(IReleaseSpec.Name)) - // handle mainnet specific exceptions .Where(p => isMainnet || p.Name != nameof(IReleaseSpec.MaximumExtraDataSize)) .Where(p => isMainnet || p.Name != nameof(IReleaseSpec.BlockReward)) @@ -422,18 +429,15 @@ private static void CompareSpecs(IReleaseSpec expectedSpec, IReleaseSpec actualS p.Name != nameof(IReleaseSpec.DifficultyBombDelay)) .Where(p => isMainnet || checkDifficultyBomb || p.Name != nameof(IReleaseSpec.DifficultyBoundDivisor)) - // handle RLP decoders .Where(p => p.Name != nameof(IReleaseSpec.Eip1559TransitionBlock)) .Where(p => p.Name != nameof(IReleaseSpec.WithdrawalTimestamp)) .Where(p => p.Name != nameof(IReleaseSpec.Eip4844TransitionTimestamp)) - // Skip EIP-4844 parameter validation .Where(p => p.Name != nameof(Eip4844Constants.BlobGasPriceUpdateFraction)) .Where(p => p.Name != nameof(Eip4844Constants.MaxBlobGasPerBlock)) .Where(p => p.Name != nameof(Eip4844Constants.MinBlobGasPrice)) .Where(p => p.Name != nameof(Eip4844Constants.TargetBlobGasPerBlock)) - // handle gnosis specific exceptions .Where(p => !isGnosis || p.Name != nameof(IReleaseSpec.MaxCodeSize)) .Where(p => !isGnosis || p.Name != nameof(IReleaseSpec.MaxInitCodeSize)) @@ -459,6 +463,7 @@ private ChainSpec LoadChainSpecFromChainFolder(string chain) public void Chain_id_is_set_correctly() { ChainSpec chainSpec = new() { Parameters = new ChainParameters(), NetworkId = 2, ChainId = 5 }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); Assert.That(provider.NetworkId, Is.EqualTo(2)); @@ -469,6 +474,7 @@ public void Chain_id_is_set_correctly() public void Dao_block_number_is_set_correctly() { ChainSpec chainSpec = new(); + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; chainSpec.Parameters = new ChainParameters(); chainSpec.DaoForkBlockNumber = 23; @@ -476,47 +482,6 @@ public void Dao_block_number_is_set_correctly() Assert.That(provider.DaoBlockNumber, Is.EqualTo(23)); } - [Test] - public void Bound_divisors_set_correctly() - { - ChainSpec chainSpec = new() - { - Parameters = new ChainParameters { GasLimitBoundDivisor = 17 }, - Ethash = new EthashParameters { DifficultyBoundDivisor = 19 } - }; - - ChainSpecBasedSpecProvider provider = new(chainSpec); - Assert.That(provider.GenesisSpec.DifficultyBoundDivisor, Is.EqualTo(19)); - Assert.That(provider.GenesisSpec.GasLimitBoundDivisor, Is.EqualTo(17)); - } - - [Test] - public void Difficulty_bomb_delays_loaded_correctly() - { - ChainSpec chainSpec = new() - { - Parameters = new ChainParameters(), - Ethash = new EthashParameters - { - DifficultyBombDelays = new Dictionary - { - { 3, 100 }, - { 7, 200 }, - { 13, 300 }, - { 17, 400 }, - { 19, 500 }, - } - } - }; - - ChainSpecBasedSpecProvider provider = new(chainSpec); - Assert.That(provider.GetSpec((ForkActivation)3).DifficultyBombDelay, Is.EqualTo(100)); - Assert.That(provider.GetSpec((ForkActivation)7).DifficultyBombDelay, Is.EqualTo(300)); - Assert.That(provider.GetSpec((ForkActivation)13).DifficultyBombDelay, Is.EqualTo(600)); - Assert.That(provider.GetSpec((ForkActivation)17).DifficultyBombDelay, Is.EqualTo(1000)); - Assert.That(provider.GetSpec((ForkActivation)19).DifficultyBombDelay, Is.EqualTo(1500)); - } - [Test] public void Max_code_transition_loaded_correctly() { @@ -531,6 +496,7 @@ public void Max_code_transition_loaded_correctly() MaxCodeSize = maxCodeSize } }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); Assert.That(provider.GetSpec((ForkActivation)(maxCodeTransition - 1)).MaxCodeSize, Is.EqualTo(long.MaxValue), "one before"); @@ -542,6 +508,7 @@ public void Max_code_transition_loaded_correctly() public void Eip2200_is_set_correctly_directly() { ChainSpec chainSpec = new() { Parameters = new ChainParameters { Eip2200Transition = 5 } }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); provider.GetSpec((ForkActivation)5).IsEip2200Enabled.Should().BeTrue(); @@ -552,6 +519,7 @@ public void Eip2200_is_set_correctly_indirectly() { ChainSpec chainSpec = new() { Parameters = new ChainParameters { Eip1706Transition = 5, Eip1283Transition = 5 } }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); provider.GetSpec((ForkActivation)5).IsEip2200Enabled.Should().BeTrue(); @@ -570,6 +538,7 @@ public void Eip2200_is_set_correctly_indirectly_after_disabling_eip1283_and_reen Eip1283ReenableTransition = 5 } }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); provider.GetSpec((ForkActivation)5).IsEip2200Enabled.Should().BeTrue(); @@ -587,6 +556,7 @@ public void Eip2200_is_not_set_correctly_indirectly_after_disabling_eip1283() Eip1283DisableTransition = 4 } }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); provider.GetSpec((ForkActivation)5).IsEip2200Enabled.Should().BeFalse(); @@ -604,6 +574,7 @@ public void Eip150_and_Eip2537_fork_by_block_number() MaxCodeSize = 1 } }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); @@ -630,6 +601,7 @@ public void Eip150_and_Eip2537_fork_by_timestamp() MaxCodeSize = 1 } }; + chainSpec.EngineChainSpecParametersProvider = TestChainSpecParametersProvider.NethDev; ChainSpecBasedSpecProvider provider = new(chainSpec); @@ -644,154 +616,6 @@ public void Eip150_and_Eip2537_fork_by_timestamp() provider.GetSpec((100, 21)).IsEip2537Enabled.Should().BeTrue(); } - [Test] - public void Eip_transitions_loaded_correctly() - { - const long maxCodeTransition = 1; - const long maxCodeSize = 1; - - ChainSpec chainSpec = new() - { - Ethash = - new EthashParameters - { - HomesteadTransition = 70, - Eip100bTransition = 1000 - }, - ByzantiumBlockNumber = 1960, - ConstantinopleBlockNumber = 6490, - Parameters = new ChainParameters - { - MaxCodeSizeTransition = maxCodeTransition, - MaxCodeSize = maxCodeSize, - Registrar = Address.Zero, - MinGasLimit = 11, - GasLimitBoundDivisor = 13, - MaximumExtraDataSize = 17, - Eip140Transition = 1400L, - Eip145Transition = 1450L, - Eip150Transition = 1500L, - Eip152Transition = 1520L, - Eip155Transition = 1550L, - Eip160Transition = 1600L, - Eip161abcTransition = 1580L, - Eip161dTransition = 1580L, - Eip211Transition = 2110L, - Eip214Transition = 2140L, - Eip658Transition = 6580L, - Eip1014Transition = 10140L, - Eip1052Transition = 10520L, - Eip1108Transition = 11080L, - Eip1283Transition = 12830L, - Eip1283DisableTransition = 12831L, - Eip1344Transition = 13440L, - Eip1884Transition = 18840L, - Eip2028Transition = 20280L, - Eip2200Transition = 22000L, - Eip2315Transition = 23150L, - Eip2565Transition = 25650L, - Eip2929Transition = 29290L, - Eip2930Transition = 29300L, - Eip1559Transition = 15590L, - Eip1559FeeCollectorTransition = 15591L, - FeeCollector = Address.SystemUser, - Eip1559BaseFeeMinValueTransition = 15592L, - Eip1559BaseFeeMinValue = UInt256.UInt128MaxValue, - Eip3198Transition = 31980L, - Eip3529Transition = 35290L, - Eip3541Transition = 35410L, - Eip1283ReenableTransition = 23000L, - ValidateChainIdTransition = 24000L, - ValidateReceiptsTransition = 24000L, - MergeForkIdTransition = 40000L, - Eip3651TransitionTimestamp = 1000000012, - Eip3855TransitionTimestamp = 1000000012, - Eip3860TransitionTimestamp = 1000000012, - Eip1153TransitionTimestamp = 1000000024, - Eip2537TransitionTimestamp = 1000000024, - - Eip7702TransitionTimestamp = 1000000032, - } - }; - - ChainSpecBasedSpecProvider provider = new(chainSpec); - Assert.That(provider.GetSpec((ForkActivation)(maxCodeTransition - 1)).MaxCodeSize, Is.EqualTo(long.MaxValue), "one before"); - Assert.That(provider.GetSpec((ForkActivation)maxCodeTransition).MaxCodeSize, Is.EqualTo(maxCodeSize), "at transition"); - Assert.That(provider.GetSpec((ForkActivation)(maxCodeTransition + 1)).MaxCodeSize, Is.EqualTo(maxCodeSize), "one after"); - - ReleaseSpec expected = new(); - - void TestTransitions(ForkActivation activation, Action changes) - { - changes(expected); - IReleaseSpec underTest = provider.GetSpec(activation); - underTest.Should().BeEquivalentTo(expected); - } - - TestTransitions((ForkActivation)0L, r => - { - r.MinGasLimit = 11L; - r.GasLimitBoundDivisor = 13L; - r.MaximumExtraDataSize = 17L; - r.MaxCodeSize = long.MaxValue; - r.Eip1559TransitionBlock = 15590L; - r.IsTimeAdjustmentPostOlympic = true; - r.MaximumUncleCount = 2; - r.WithdrawalTimestamp = ulong.MaxValue; - r.Eip4844TransitionTimestamp = ulong.MaxValue; - }); - - TestTransitions((ForkActivation)1L, r => - { - r.MaxCodeSize = maxCodeSize; - r.IsEip170Enabled = true; - }); - TestTransitions((ForkActivation)70L, r => { r.IsEip2Enabled = r.IsEip7Enabled = true; }); - TestTransitions((ForkActivation)1000L, r => { r.IsEip100Enabled = true; }); - TestTransitions((ForkActivation)1400L, r => { r.IsEip140Enabled = true; }); - TestTransitions((ForkActivation)1450L, r => { r.IsEip145Enabled = true; }); - TestTransitions((ForkActivation)1500L, r => { r.IsEip150Enabled = true; }); - TestTransitions((ForkActivation)1520L, r => { r.IsEip152Enabled = true; }); - TestTransitions((ForkActivation)1550L, r => { r.IsEip155Enabled = true; }); - TestTransitions((ForkActivation)1580L, r => { r.IsEip158Enabled = true; }); - TestTransitions((ForkActivation)1600L, r => { r.IsEip160Enabled = true; }); - TestTransitions((ForkActivation)1960L, - r => { r.IsEip196Enabled = r.IsEip197Enabled = r.IsEip198Enabled = r.IsEip649Enabled = true; }); - TestTransitions((ForkActivation)2110L, r => { r.IsEip211Enabled = true; }); - TestTransitions((ForkActivation)2140L, r => { r.IsEip214Enabled = true; }); - TestTransitions((ForkActivation)6580L, r => { r.IsEip658Enabled = r.IsEip1234Enabled = true; }); - TestTransitions((ForkActivation)10140L, r => { r.IsEip1014Enabled = true; }); - TestTransitions((ForkActivation)10520L, r => { r.IsEip1052Enabled = true; }); - TestTransitions((ForkActivation)11180L, r => { r.IsEip1108Enabled = true; }); - TestTransitions((ForkActivation)12830L, r => { r.IsEip1283Enabled = true; }); - TestTransitions((ForkActivation)12831L, r => { r.IsEip1283Enabled = false; }); - TestTransitions((ForkActivation)13440L, r => { r.IsEip1344Enabled = true; }); - TestTransitions((ForkActivation)15590L, r => { r.IsEip1559Enabled = true; }); - TestTransitions((ForkActivation)15591L, r => { r.FeeCollector = Address.SystemUser; }); - TestTransitions((ForkActivation)15592L, r => { r.Eip1559BaseFeeMinValue = UInt256.UInt128MaxValue; }); - TestTransitions((ForkActivation)18840L, r => { r.IsEip1884Enabled = true; }); - TestTransitions((ForkActivation)20280L, r => { r.IsEip2028Enabled = true; }); - TestTransitions((ForkActivation)22000L, r => { r.IsEip2200Enabled = true; }); - TestTransitions((ForkActivation)23000L, r => { r.IsEip1283Enabled = r.IsEip1344Enabled = true; }); - TestTransitions((ForkActivation)24000L, r => { r.ValidateChainId = r.ValidateReceipts = true; }); - TestTransitions((ForkActivation)29290L, r => { r.IsEip2929Enabled = r.IsEip2565Enabled = true; }); - TestTransitions((ForkActivation)29300L, r => { r.IsEip2930Enabled = true; }); - TestTransitions((ForkActivation)31980L, r => { r.IsEip3198Enabled = true; }); - TestTransitions((ForkActivation)35290L, r => { r.IsEip3529Enabled = true; }); - TestTransitions((ForkActivation)35410L, r => { r.IsEip3541Enabled = true; }); - TestTransitions((ForkActivation)35410L, r => { r.IsEip3541Enabled = true; }); - - - TestTransitions((41000L, 1000000012), r => - { - r.IsEip3651Enabled = true; - r.IsEip3855Enabled = true; - r.IsEip3860Enabled = true; - }); - TestTransitions((40001L, 1000000024), r => { r.IsEip1153Enabled = r.IsEip2537Enabled = true; }); - TestTransitions((40001L, 1000000032), r => { r.IsEip7702Enabled = true; }); - } - [TestCaseSource(nameof(BlockNumbersAndTimestampsNearForkActivations))] public void Forks_should_be_selected_properly_for_exact_matches(ForkActivation forkActivation, bool isEip3651Enabled, bool isEip3198Enabled, bool isEip3855Enabled) { diff --git a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs index 0560bacc6dd..ef77ec10fd9 100644 --- a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs +++ b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecLoaderTests.cs @@ -4,10 +4,9 @@ using System.Collections.Generic; using System.IO; using FluentAssertions; +using Nethermind.Consensus.Ethash; using Nethermind.Core; -using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; -using Nethermind.Int256; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using NUnit.Framework; @@ -17,98 +16,6 @@ namespace Nethermind.Specs.Test.ChainSpecStyle; [Parallelizable(ParallelScope.All)] public class ChainSpecLoaderTests { - [Test] - public void Can_load_hive() - { - string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Specs/hive.json"); - ChainSpec chainSpec = LoadChainSpec(path); - - Assert.That(chainSpec.Name, Is.EqualTo("Foundation"), $"{nameof(chainSpec.Name)}"); - Assert.That(chainSpec.DataDir, Is.EqualTo("ethereum"), $"{nameof(chainSpec.Name)}"); - - Assert.That(chainSpec.Ethash.MinimumDifficulty, Is.EqualTo((UInt256)0x020000), $"{nameof(chainSpec.Ethash.MinimumDifficulty)}"); - Assert.That(chainSpec.Ethash.DifficultyBoundDivisor, Is.EqualTo((long)0x0800), $"{nameof(chainSpec.Ethash.DifficultyBoundDivisor)}"); - Assert.That(chainSpec.Ethash.DurationLimit, Is.EqualTo(0xdL), $"{nameof(chainSpec.Ethash.DurationLimit)}"); - - Assert.That(chainSpec.Ethash.BlockRewards.Count, Is.EqualTo(3), $"{nameof(chainSpec.Ethash.BlockRewards.Count)}"); - Assert.That(chainSpec.Ethash.BlockRewards[0L], Is.EqualTo((UInt256)5000000000000000000)); - Assert.That(chainSpec.Ethash.BlockRewards[4370000L], Is.EqualTo((UInt256)3000000000000000000)); - Assert.That(chainSpec.Ethash.BlockRewards[7080000L], Is.EqualTo((UInt256)2000000000000000000)); - - Assert.That(chainSpec.Ethash.DifficultyBombDelays.Count, Is.EqualTo(2), $"{nameof(chainSpec.Ethash.DifficultyBombDelays.Count)}"); - Assert.That(chainSpec.Ethash.DifficultyBombDelays[4370000], Is.EqualTo(3000000L)); - Assert.That(chainSpec.Ethash.DifficultyBombDelays[7080000L], Is.EqualTo(2000000L)); - - Assert.That(chainSpec.Ethash.HomesteadTransition, Is.EqualTo(0L)); - Assert.That(chainSpec.Ethash.DaoHardforkTransition, Is.EqualTo(1920000L)); - Assert.That(chainSpec.Ethash.DaoHardforkBeneficiary, Is.EqualTo(new Address("0xbf4ed7b27f1d666546e30d74d50d173d20bca754"))); - Assert.That(chainSpec.Ethash.DaoHardforkAccounts.Length, Is.EqualTo(0)); - Assert.That(chainSpec.Ethash.Eip100bTransition, Is.EqualTo(0L)); - - Assert.That(chainSpec.ChainId, Is.EqualTo(1), $"{nameof(chainSpec.ChainId)}"); - Assert.That(chainSpec.NetworkId, Is.EqualTo(1), $"{nameof(chainSpec.NetworkId)}"); - Assert.That(chainSpec.Genesis, Is.Not.Null, $"{nameof(ChainSpec.Genesis)}"); - - Assert.That(chainSpec.Parameters.Eip1559BaseFeeInitialValue, Is.EqualTo(1.GWei()), $"initial base fee value"); - Assert.That(chainSpec.Parameters.Eip1559ElasticityMultiplier, Is.EqualTo((long)1), $"elasticity multiplier"); - Assert.That(chainSpec.Parameters.Eip1559BaseFeeMaxChangeDenominator, Is.EqualTo((UInt256)7), $"base fee max change denominator"); - Assert.That(chainSpec.Genesis.BaseFeePerGas, Is.EqualTo((UInt256)11), $"genesis base fee"); - - Assert.That(chainSpec.Genesis.Header.Nonce, Is.EqualTo(0xdeadbeefdeadbeef), $"genesis {nameof(BlockHeader.Nonce)}"); - Assert.That(chainSpec.Genesis.Header.MixHash, Is.EqualTo(Keccak.Zero), $"genesis {nameof(BlockHeader.MixHash)}"); - Assert.That((long)chainSpec.Genesis.Header.Difficulty, Is.EqualTo(0x10), $"genesis {nameof(BlockHeader.Difficulty)}"); - Assert.That(chainSpec.Genesis.Header.Beneficiary, Is.EqualTo(Address.Zero), $"genesis {nameof(BlockHeader.Beneficiary)}"); - Assert.That((long)chainSpec.Genesis.Header.Timestamp, Is.EqualTo(0x00L), $"genesis {nameof(BlockHeader.Timestamp)}"); - Assert.That(chainSpec.Genesis.Header.ParentHash, Is.EqualTo(Keccak.Zero), $"genesis {nameof(BlockHeader.ParentHash)}"); - Assert.That( - chainSpec.Genesis.Header.ExtraData, Is.EqualTo(Bytes.FromHexString("0x0000000000000000000000000000000000000000000000000000000000000000")), - $"genesis {nameof(BlockHeader.ExtraData)}"); - Assert.That(chainSpec.Genesis.Header.GasLimit, Is.EqualTo(0x8000000L), $"genesis {nameof(BlockHeader.GasLimit)}"); - - Assert.That(chainSpec.Allocations, Is.Not.Null, $"{nameof(ChainSpec.Allocations)}"); - Assert.That(chainSpec.Allocations.Count, Is.EqualTo(1), $"allocations count"); - Assert.That( - chainSpec.Allocations[new Address("0x71562b71999873db5b286df957af199ec94617f7")].Balance, Is.EqualTo(new UInt256(0xf4240)), - "account 0x71562b71999873db5b286df957af199ec94617f7 - balance"); - - Assert.That( - chainSpec.Allocations[new Address("0x71562b71999873db5b286df957af199ec94617f7")].Code, Is.EqualTo(Bytes.FromHexString("0xabcd")), - "account 0x71562b71999873db5b286df957af199ec94617f7 - code"); - - Assert.That(chainSpec.SealEngineType, Is.EqualTo(SealEngineType.Ethash), "engine"); - - Assert.That(chainSpec.HomesteadBlockNumber, Is.EqualTo((long?)0), "homestead transition"); - Assert.That(chainSpec.TangerineWhistleBlockNumber, Is.EqualTo((long?)0), "tangerine whistle transition"); - Assert.That(chainSpec.SpuriousDragonBlockNumber, Is.EqualTo((long?)0), "spurious dragon transition"); - Assert.That(chainSpec.ByzantiumBlockNumber, Is.EqualTo((long?)0), "byzantium transition"); - Assert.That(chainSpec.DaoForkBlockNumber, Is.EqualTo((long?)1920000), "dao transition"); - Assert.That(chainSpec.ConstantinopleFixBlockNumber, Is.EqualTo((long?)7080000), "constantinople transition"); - - Assert.That(chainSpec.Parameters.MaxCodeSize, Is.EqualTo((long?)24576L), "max code size"); - Assert.That(chainSpec.Parameters.MaxCodeSizeTransition, Is.EqualTo((long?)0L), "max code size transition"); - Assert.That(chainSpec.Parameters.MinGasLimit, Is.EqualTo((long?)0x1388L), "min gas limit"); - Assert.That(chainSpec.Parameters.Registrar, Is.EqualTo(new Address("0xe3389675d0338462dC76C6f9A3e432550c36A142")), "registrar"); - Assert.That(chainSpec.Parameters.ForkBlock, Is.EqualTo((long?)0x1d4c00L), "fork block"); - Assert.That(chainSpec.Parameters.ForkCanonHash, Is.EqualTo(new Hash256("0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb")), "fork block"); - - Assert.That(chainSpec.Parameters.Eip150Transition, Is.EqualTo((long?)0L), "eip150"); - Assert.That(chainSpec.Parameters.Eip160Transition, Is.EqualTo((long?)0L), "eip160"); - Assert.That(chainSpec.Parameters.Eip161abcTransition, Is.EqualTo((long?)0L), "eip161abc"); - Assert.That(chainSpec.Parameters.Eip161dTransition, Is.EqualTo((long?)0L), "eip161d"); - Assert.That(chainSpec.Parameters.Eip155Transition, Is.EqualTo((long?)0L), "eip155"); - Assert.That(chainSpec.Parameters.Eip140Transition, Is.EqualTo((long?)0L), "eip140"); - Assert.That(chainSpec.Parameters.Eip211Transition, Is.EqualTo((long?)0L), "eip211"); - Assert.That(chainSpec.Parameters.Eip214Transition, Is.EqualTo((long?)0L), "eip214"); - Assert.That(chainSpec.Parameters.Eip658Transition, Is.EqualTo((long?)0L), "eip658"); - Assert.That(chainSpec.Parameters.Eip145Transition, Is.EqualTo((long?)7080000L), "eip145"); - Assert.That(chainSpec.Parameters.Eip1014Transition, Is.EqualTo((long?)7080000L), "eip1014"); - Assert.That(chainSpec.Parameters.Eip1052Transition, Is.EqualTo((long?)7080000L), "eip1052"); - Assert.That(chainSpec.Parameters.Eip1283Transition, Is.EqualTo((long?)7080000L), "eip1283"); - - Assert.That(chainSpec.Parameters.MaximumExtraDataSize, Is.EqualTo((long)32), "extra data"); - Assert.That(chainSpec.Parameters.GasLimitBoundDivisor, Is.EqualTo((long)0x0400), "gas limit bound divisor"); - } - private static ChainSpec LoadChainSpec(string path) { ChainSpecLoader chainSpecLoader = new(new EthereumJsonSerializer()); @@ -116,54 +23,10 @@ private static ChainSpec LoadChainSpec(string path) return chainSpec; } - [Test] - public void Can_load_gnosis() - { - string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../../../", "Chains/gnosis.json"); - ChainSpec chainSpec = LoadChainSpec(path); - - Assert.That(chainSpec.Parameters.Eip1559BaseFeeInitialValue, Is.EqualTo(1.GWei()), $"fork base fee"); - Assert.That(chainSpec.NetworkId, Is.EqualTo(100), $"{nameof(chainSpec.NetworkId)}"); - Assert.That(chainSpec.Name, Is.EqualTo("GnosisChain"), $"{nameof(chainSpec.Name)}"); - Assert.That(chainSpec.SealEngineType, Is.EqualTo(SealEngineType.AuRa), "engine"); - - int berlinGnosisBlockNumber = 16101500; - chainSpec.Parameters.Eip2565Transition.Should().Be(berlinGnosisBlockNumber); - chainSpec.Parameters.Eip2929Transition.Should().Be(berlinGnosisBlockNumber); - chainSpec.Parameters.Eip2930Transition.Should().Be(berlinGnosisBlockNumber); - - chainSpec.Parameters.TerminalTotalDifficulty.ToString() - .Should().Be("8626000000000000000000058750000000000000000000"); - - chainSpec.AuRa.WithdrawalContractAddress.ToString(true) - .Should().Be("0x0B98057eA310F4d31F2a452B414647007d1645d9"); - } - - [Test] - public void Can_load_chiado() - { - string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../../../", "Chains/chiado.json"); - ChainSpec chainSpec = LoadChainSpec(path); - - Assert.That(chainSpec.Parameters.Eip1559BaseFeeInitialValue, Is.EqualTo(1.GWei()), $"fork base fee"); - Assert.That(chainSpec.NetworkId, Is.EqualTo(10200), $"{nameof(chainSpec.NetworkId)}"); - Assert.That(chainSpec.Name, Is.EqualTo("chiado"), $"{nameof(chainSpec.Name)}"); - Assert.That(chainSpec.SealEngineType, Is.EqualTo(SealEngineType.AuRa), "engine"); - - chainSpec.Parameters.TerminalTotalDifficulty.ToString() - .Should().Be("231707791542740786049188744689299064356246512"); - - chainSpec.AuRa.WithdrawalContractAddress.ToString(true) - .Should().Be("0xb97036A26259B7147018913bD58a774cf91acf25"); - - chainSpec.ShanghaiTimestamp.Should().Be(ChiadoSpecProvider.ShanghaiTimestamp); - chainSpec.ShanghaiTimestamp.Should().Be(ChiadoSpecProvider.Instance.TimestampFork); - - } - [Test] public void Can_load_mainnet() { + new EthashChainSpecEngineParameters(); string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../../../", "Chains/foundation.json"); ChainSpec chainSpec = LoadChainSpec(path); @@ -225,7 +88,7 @@ public void Can_load_sepolia() Assert.That(chainSpec.NetworkId, Is.EqualTo(11155111), $"{nameof(chainSpec.NetworkId)}"); Assert.That(chainSpec.Name, Is.EqualTo("Sepolia Testnet"), $"{nameof(chainSpec.Name)}"); Assert.That(chainSpec.DataDir, Is.EqualTo("sepolia"), $"{nameof(chainSpec.Name)}"); - Assert.That(chainSpec.SealEngineType, Is.EqualTo("Ethash"), "engine"); + Assert.That(chainSpec.SealEngineType, Is.EqualTo(SealEngineType.Ethash), "engine"); chainSpec.LondonBlockNumber.Should().Be(0L); chainSpec.ShanghaiTimestamp.Should().Be(1677557088); @@ -265,23 +128,4 @@ public void Can_load_posdao_with_openethereum_pricing_transitions() chainSpec.Parameters.Eip152Transition.Should().Be(15); chainSpec.Parameters.Eip1108Transition.Should().Be(10); } - - [Test] - public void Can_load_posdao_with_rewriteBytecode() - { - // TODO: modexp 2565 - string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "Specs/posdao.json"); - ChainSpec chainSpec = LoadChainSpec(path); - IDictionary> expected = new Dictionary> - { - { - 21300000, new Dictionary() - { - {new Address("0x1234000000000000000000000000000000000001"), Bytes.FromHexString("0x111")}, - {new Address("0x1234000000000000000000000000000000000002"), Bytes.FromHexString("0x222")}, - } - } - }; - chainSpec.AuRa.RewriteBytecode.Should().BeEquivalentTo(expected); - } } diff --git a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/TestChainSpecParametersProvider.cs b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/TestChainSpecParametersProvider.cs new file mode 100644 index 00000000000..20c63293943 --- /dev/null +++ b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/TestChainSpecParametersProvider.cs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using FastEnumUtility; +using Nethermind.Consensus.Ethash; +using Nethermind.Specs.ChainSpecStyle; + +namespace Nethermind.Specs.Test.ChainSpecStyle; + +public class TestChainSpecParametersProvider : IChainSpecParametersProvider +{ + public static readonly TestChainSpecParametersProvider NethDev = new(new NethDevChainSpecEngineParameters()); + + private readonly IChainSpecEngineParameters _parameters; + + public TestChainSpecParametersProvider(IChainSpecEngineParameters parameters) + { + _parameters = parameters; + } + + public string SealEngineType => _parameters.SealEngineType!; + + public IEnumerable AllChainSpecParameters => + new[] { _parameters }; + public T GetChainSpecParameters() where T : IChainSpecEngineParameters + { + if (typeof(T) == _parameters.GetType()) + { + return (T)_parameters; + } + else + { + throw new NotSupportedException($"Only {_parameters.GetType().Name} engine in {nameof(TestChainSpecParametersProvider)}"); + } + } +} diff --git a/src/Nethermind/Nethermind.Specs.Test/Nethermind.Specs.Test.csproj b/src/Nethermind/Nethermind.Specs.Test/Nethermind.Specs.Test.csproj index b4ec57d3baa..6ebc5259764 100644 --- a/src/Nethermind/Nethermind.Specs.Test/Nethermind.Specs.Test.csproj +++ b/src/Nethermind/Nethermind.Specs.Test/Nethermind.Specs.Test.csproj @@ -23,6 +23,8 @@ + + diff --git a/src/Nethermind/Nethermind.Specs.Test/Specs/Logs_warning_when_timestampActivation_happens_before_blockActivation_test.json b/src/Nethermind/Nethermind.Specs.Test/Specs/Logs_warning_when_timestampActivation_happens_before_blockActivation_test.json index 32afc1c00c8..ca829c9dbcd 100644 --- a/src/Nethermind/Nethermind.Specs.Test/Specs/Logs_warning_when_timestampActivation_happens_before_blockActivation_test.json +++ b/src/Nethermind/Nethermind.Specs.Test/Specs/Logs_warning_when_timestampActivation_happens_before_blockActivation_test.json @@ -1,11 +1,8 @@ { "version": "1", "engine": { - "clique": { + "NethDev": { "params": { - "period": 1, - "epoch": 30000, - "blockReward": "0x0" } } }, diff --git a/src/Nethermind/Nethermind.Specs.Test/Specs/Timstamp_activation_equal_to_genesis_timestamp_test.json b/src/Nethermind/Nethermind.Specs.Test/Specs/Timstamp_activation_equal_to_genesis_timestamp_test.json index 3372fa81974..a12cf15f01b 100644 --- a/src/Nethermind/Nethermind.Specs.Test/Specs/Timstamp_activation_equal_to_genesis_timestamp_test.json +++ b/src/Nethermind/Nethermind.Specs.Test/Specs/Timstamp_activation_equal_to_genesis_timestamp_test.json @@ -1,11 +1,8 @@ { "version": "1", "engine": { - "clique": { + "NethDev": { "params": { - "period": 1, - "epoch": 30000, - "blockReward": "0x0" } } }, diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/AuRaParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/AuRaParameters.cs deleted file mode 100644 index 3115f9a2b26..00000000000 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/AuRaParameters.cs +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using System.Collections.Generic; -using System.Linq; -using Nethermind.Core; -using Nethermind.Int256; - -namespace Nethermind.Specs.ChainSpecStyle; - -/// -/// "stepDuration": 5, -/// "blockReward": "0xDE0B6B3A7640000", -/// "maximumUncleCountTransition": 0, -/// "maximumUncleCount": 0, -/// "validators": { -/// "multi": { -/// "0": { -/// "safeContract": "0x8bf38d4764929064f2d4d3a56520a76ab3df415b" -/// }, -/// "362296": { -/// "safeContract": "0xf5cE3f5D0366D6ec551C74CCb1F67e91c56F2e34" -/// }, -/// "509355": { -/// "safeContract": "0x03048F666359CFD3C74a1A5b9a97848BF71d5038" -/// }, -/// "4622420": { -/// "safeContract": "0x4c6a159659CCcb033F4b2e2Be0C16ACC62b89DDB" -/// } -/// } -/// }, -/// "blockRewardContractAddress": "0x3145197AD50D7083D0222DE4fCCf67d9BD05C30D", -/// "blockRewardContractTransition": 4639000 -/// -public class AuRaParameters -{ - public const long TransitionDisabled = long.MaxValue; - - public IDictionary StepDuration { get; set; } - - public IDictionary BlockReward { get; set; } - - public long MaximumUncleCountTransition { get; set; } - - public long? MaximumUncleCount { get; set; } - - public Address BlockRewardContractAddress { get; set; } - - public long? BlockRewardContractTransition { get; set; } - - public IDictionary BlockRewardContractTransitions { get; set; } - - public long ValidateScoreTransition { get; set; } - - public long ValidateStepTransition { get; set; } - - public long PosdaoTransition { get; set; } - - public Validator Validators { get; set; } - - public long TwoThirdsMajorityTransition { get; set; } - - public IDictionary RandomnessContractAddress { get; set; } - - public IDictionary BlockGasLimitContractTransitions { get; set; } - - public IDictionary> RewriteBytecode { get; set; } - - public Address WithdrawalContractAddress { get; set; } - - public enum ValidatorType - { - List, - Contract, - ReportingContract, - Multi - } - - public class Validator - { - public ValidatorType ValidatorType { get; set; } - - /// - /// Dictionary of Validators per their starting block. - /// - /// - /// Only Valid for of type . - /// - /// This has to sorted in order of starting blocks. - /// - public IDictionary Validators { get; set; } - - /// - /// Addresses for validator. - /// - /// - /// For of type should contain at least one address. - /// For of type and should contain exactly one address. - /// For of type will be empty. - /// - public Address[] Addresses { get; set; } - - public Address GetContractAddress() - { - switch (ValidatorType) - { - case ValidatorType.Contract: - case ValidatorType.ReportingContract: - return Addresses?.FirstOrDefault() ?? throw new ArgumentException("Missing contract address for AuRa validator.", nameof(Addresses)); - default: - throw new InvalidOperationException($"AuRa validator {ValidatorType} doesn't have contract address."); - } - - } - } -} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpec.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpec.cs index 73f2e45726e..b6bc42a1d45 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpec.cs @@ -34,16 +34,10 @@ public class ChainSpec public string SealEngineType { get; set; } - public AuRaParameters AuRa { get; set; } - - public CliqueParameters Clique { get; set; } - - public EthashParameters Ethash { get; set; } - - public OptimismParameters Optimism { get; set; } - public ChainParameters Parameters { get; set; } + public IChainSpecParametersProvider EngineChainSpecParametersProvider { get; set; } + public Dictionary Allocations { get; set; } public long? FixedDifficulty { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index 7e2bd8cf7ba..7b44d28dc29 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -7,7 +7,6 @@ using System.Numerics; using System.Reflection; using Nethermind.Core; -using Nethermind.Core.Collections; using Nethermind.Core.Specs; using Nethermind.Int256; using Nethermind.Logging; @@ -33,17 +32,14 @@ private void BuildTransitions() SortedSet transitionTimestamps = new(); transitionBlockNumbers.Add(0L); - if (_chainSpec.Ethash?.BlockRewards is not null) + foreach (IChainSpecEngineParameters item in _chainSpec.EngineChainSpecParametersProvider + .AllChainSpecParameters) { - foreach ((long blockNumber, _) in _chainSpec.Ethash.BlockRewards) - { - transitionBlockNumbers.Add(blockNumber); - } + item.AddTransitions(transitionBlockNumbers, transitionTimestamps); } AddTransitions(transitionBlockNumbers, _chainSpec, n => n.EndsWith("BlockNumber") && n != "TerminalPoWBlockNumber"); AddTransitions(transitionBlockNumbers, _chainSpec.Parameters, n => n.EndsWith("Transition")); - AddTransitions(transitionBlockNumbers, _chainSpec.Ethash, n => n.EndsWith("Transition")); AddTransitions(transitionTimestamps, _chainSpec.Parameters, n => n.EndsWith("TransitionTimestamp"), _chainSpec.Genesis?.Timestamp ?? 0); TimestampFork = transitionTimestamps.Count > 0 ? transitionTimestamps.Min : ISpecProvider.TimestampForkNever; @@ -87,12 +83,6 @@ static void Add(SortedSet transitions, T value, T? minValueExclusive) } } - foreach (KeyValuePair bombDelay in _chainSpec.Ethash?.DifficultyBombDelays ?? Enumerable.Empty>()) - { - transitionBlockNumbers.Add(bombDelay.Key); - } - - (ForkActivation Activation, IReleaseSpec Spec)[] allTransitions = CreateTransitions(_chainSpec, transitionBlockNumbers, transitionTimestamps); LoadTransitions(allTransitions); @@ -107,7 +97,7 @@ static void Add(SortedSet transitions, T value, T? minValueExclusive) TerminalTotalDifficulty = _chainSpec.Parameters.TerminalTotalDifficulty; } - private static (ForkActivation, IReleaseSpec Spec)[] CreateTransitions( + private (ForkActivation, IReleaseSpec Spec)[] CreateTransitions( ChainSpec chainSpec, SortedSet transitionBlockNumbers, SortedSet transitionTimestamps) @@ -153,23 +143,21 @@ private static ForkActivation[] CreateTransitionActivations(SortedSet tran return transitionActivations; } - private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseStartBlock, ulong? releaseStartTimestamp = null) + private ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseStartBlock, ulong? releaseStartTimestamp = null) { ReleaseSpec releaseSpec = new(); - releaseSpec.MaximumUncleCount = (int)(releaseStartBlock >= (chainSpec.AuRa?.MaximumUncleCountTransition ?? long.MaxValue) ? chainSpec.AuRa?.MaximumUncleCount ?? 2 : 2); + releaseSpec.MaximumUncleCount = 2; + releaseSpec.DifficultyBoundDivisor = 1; releaseSpec.IsTimeAdjustmentPostOlympic = true; // TODO: this is Duration, review releaseSpec.MaximumExtraDataSize = chainSpec.Parameters.MaximumExtraDataSize; releaseSpec.MinGasLimit = chainSpec.Parameters.MinGasLimit; releaseSpec.GasLimitBoundDivisor = chainSpec.Parameters.GasLimitBoundDivisor; - releaseSpec.DifficultyBoundDivisor = chainSpec.Ethash?.DifficultyBoundDivisor ?? 1; - releaseSpec.FixedDifficulty = chainSpec.Ethash?.FixedDifficulty; releaseSpec.IsEip170Enabled = (chainSpec.Parameters.MaxCodeSizeTransition ?? long.MaxValue) <= releaseStartBlock || (chainSpec.Parameters.MaxCodeSizeTransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.MaxCodeSize = releaseSpec.IsEip170Enabled ? (chainSpec.Parameters.MaxCodeSize ?? long.MaxValue) : long.MaxValue; - releaseSpec.IsEip2Enabled = (chainSpec.Ethash?.HomesteadTransition ?? 0) <= releaseStartBlock; - releaseSpec.IsEip7Enabled = (chainSpec.Ethash?.HomesteadTransition ?? 0) <= releaseStartBlock || - (chainSpec.Parameters.Eip7Transition ?? long.MaxValue) <= releaseStartBlock; - releaseSpec.IsEip100Enabled = (chainSpec.Ethash?.Eip100bTransition ?? 0) <= releaseStartBlock; + releaseSpec.IsEip2Enabled = true; + releaseSpec.IsEip100Enabled = true; + releaseSpec.IsEip7Enabled = (chainSpec.Parameters.Eip7Transition ?? 0) <= releaseStartBlock; releaseSpec.IsEip140Enabled = (chainSpec.Parameters.Eip140Transition ?? 0) <= releaseStartBlock; releaseSpec.IsEip145Enabled = (chainSpec.Parameters.Eip145Transition ?? 0) <= releaseStartBlock; releaseSpec.IsEip150Enabled = (chainSpec.Parameters.Eip150Transition ?? 0) <= releaseStartBlock; @@ -216,31 +204,6 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt releaseSpec.ForkBaseFee = chainSpec.Parameters.Eip1559BaseFeeInitialValue ?? Eip1559Constants.DefaultForkBaseFee; releaseSpec.BaseFeeMaxChangeDenominator = chainSpec.Parameters.Eip1559BaseFeeMaxChangeDenominator ?? Eip1559Constants.DefaultBaseFeeMaxChangeDenominator; - if (chainSpec.Optimism?.CanyonTimestamp <= releaseStartTimestamp) - { - releaseSpec.BaseFeeMaxChangeDenominator = chainSpec.Optimism.CanyonBaseFeeChangeDenominator; - } - - - if (chainSpec.Ethash is not null) - { - foreach (KeyValuePair blockReward in chainSpec.Ethash.BlockRewards ?? Enumerable.Empty>()) - { - if (blockReward.Key <= releaseStartBlock) - { - releaseSpec.BlockReward = blockReward.Value; - } - } - - foreach (KeyValuePair bombDelay in chainSpec.Ethash.DifficultyBombDelays ?? Enumerable.Empty>()) - { - if (bombDelay.Key <= releaseStartBlock) - { - releaseSpec.DifficultyBombDelay += bombDelay.Value; - } - } - } - releaseSpec.IsEip1153Enabled = (chainSpec.Parameters.Eip1153TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEip3651Enabled = (chainSpec.Parameters.Eip3651TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEip3855Enabled = (chainSpec.Parameters.Eip3855TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; @@ -271,6 +234,13 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt releaseSpec.Eip7251ContractAddress = chainSpec.Parameters.Eip7251ContractAddress; releaseSpec.IsOntakeEnabled = (chainSpec.Parameters.OntakeTransition ?? long.MaxValue) <= releaseStartBlock; + + foreach (IChainSpecEngineParameters item in _chainSpec.EngineChainSpecParametersProvider + .AllChainSpecParameters) + { + item.ApplyToReleaseSpec(releaseSpec, releaseStartBlock, releaseStartTimestamp); + } + return releaseSpec; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index 618da928c6c..4df70834b08 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -210,21 +210,7 @@ private static void ValidateParams(ChainSpecParamsJson parameters) private static void LoadTransitions(ChainSpecJson chainSpecJson, ChainSpec chainSpec) { - if (chainSpecJson.Engine?.Ethash is not null) - { - chainSpec.HomesteadBlockNumber = chainSpecJson.Engine.Ethash.HomesteadTransition; - chainSpec.DaoForkBlockNumber = chainSpecJson.Engine.Ethash.DaoHardforkTransition; - } - else - { - chainSpec.HomesteadBlockNumber = 0; - } - - IEnumerable difficultyBombDelaysBlockNumbers = chainSpec.Ethash?.DifficultyBombDelays - .Keys - .Cast() - .ToArray(); - + chainSpec.HomesteadBlockNumber = 0; chainSpec.TangerineWhistleBlockNumber = chainSpec.Parameters.Eip150Transition; chainSpec.SpuriousDragonBlockNumber = chainSpec.Parameters.Eip160Transition; chainSpec.ByzantiumBlockNumber = chainSpec.Parameters.Eip140Transition; @@ -235,11 +221,8 @@ chainSpec.Parameters.Eip1283DisableTransition is null chainSpec.ConstantinopleFixBlockNumber = chainSpec.Parameters.Eip1283DisableTransition ?? chainSpec.Parameters.Eip145Transition; chainSpec.IstanbulBlockNumber = chainSpec.Parameters.Eip2200Transition; - chainSpec.MuirGlacierNumber = difficultyBombDelaysBlockNumbers?.Skip(2).FirstOrDefault(); chainSpec.BerlinBlockNumber = chainSpec.Parameters.Eip2929Transition; chainSpec.LondonBlockNumber = chainSpec.Parameters.Eip1559Transition; - chainSpec.ArrowGlacierBlockNumber = difficultyBombDelaysBlockNumbers?.Skip(4).FirstOrDefault(); - chainSpec.GrayGlacierBlockNumber = difficultyBombDelaysBlockNumbers?.Skip(5).FirstOrDefault(); chainSpec.ShanghaiTimestamp = chainSpec.Parameters.Eip3651TransitionTimestamp; chainSpec.CancunTimestamp = chainSpec.Parameters.Eip4844TransitionTimestamp; @@ -247,134 +230,28 @@ chainSpec.Parameters.Eip1283DisableTransition is null chainSpec.MergeForkIdBlockNumber = chainSpec.Parameters.MergeForkIdTransition; chainSpec.TerminalPoWBlockNumber = chainSpec.Parameters.TerminalPoWBlockNumber; chainSpec.TerminalTotalDifficulty = chainSpec.Parameters.TerminalTotalDifficulty; - } - private static void LoadEngine(ChainSpecJson chainSpecJson, ChainSpec chainSpec) - { - static AuRaParameters.Validator LoadValidator(ChainSpecJson.AuRaValidatorJson validatorJson, int level = 0) - { - AuRaParameters.ValidatorType validatorType = validatorJson.GetValidatorType(); - AuRaParameters.Validator validator = new() { ValidatorType = validatorType }; - switch (validator.ValidatorType) - { - case AuRaParameters.ValidatorType.List: - validator.Addresses = validatorJson.List; - break; - case AuRaParameters.ValidatorType.Contract: - validator.Addresses = new[] { validatorJson.SafeContract }; - break; - case AuRaParameters.ValidatorType.ReportingContract: - validator.Addresses = new[] { validatorJson.Contract }; - break; - case AuRaParameters.ValidatorType.Multi: - if (level != 0) throw new ArgumentException("AuRa multi validator cannot be inner validator."); - validator.Validators = validatorJson.Multi - .ToDictionary(kvp => kvp.Key, kvp => LoadValidator(kvp.Value, level + 1)) - .ToImmutableSortedDictionary(); - break; - default: - throw new ArgumentOutOfRangeException(); - } - return validator; - } - - if (chainSpecJson.Engine?.AuthorityRound is not null) - { - chainSpec.SealEngineType = SealEngineType.AuRa; - chainSpec.AuRa = new AuRaParameters - { - MaximumUncleCount = chainSpecJson.Engine.AuthorityRound.MaximumUncleCount, - MaximumUncleCountTransition = chainSpecJson.Engine.AuthorityRound.MaximumUncleCountTransition, - StepDuration = chainSpecJson.Engine.AuthorityRound.StepDuration, - BlockReward = chainSpecJson.Engine.AuthorityRound.BlockReward, - BlockRewardContractAddress = chainSpecJson.Engine.AuthorityRound.BlockRewardContractAddress, - BlockRewardContractTransition = chainSpecJson.Engine.AuthorityRound.BlockRewardContractTransition, - BlockRewardContractTransitions = chainSpecJson.Engine.AuthorityRound.BlockRewardContractTransitions, - ValidateScoreTransition = chainSpecJson.Engine.AuthorityRound.ValidateScoreTransition, - ValidateStepTransition = chainSpecJson.Engine.AuthorityRound.ValidateStepTransition, - Validators = LoadValidator(chainSpecJson.Engine.AuthorityRound.Validator), - RandomnessContractAddress = chainSpecJson.Engine.AuthorityRound.RandomnessContractAddress, - BlockGasLimitContractTransitions = chainSpecJson.Engine.AuthorityRound.BlockGasLimitContractTransitions, - TwoThirdsMajorityTransition = chainSpecJson.Engine.AuthorityRound.TwoThirdsMajorityTransition ?? AuRaParameters.TransitionDisabled, - PosdaoTransition = chainSpecJson.Engine.AuthorityRound.PosdaoTransition ?? AuRaParameters.TransitionDisabled, - RewriteBytecode = chainSpecJson.Engine.AuthorityRound.RewriteBytecode, - WithdrawalContractAddress = chainSpecJson.Engine.AuthorityRound.WithdrawalContractAddress, - }; - } - else if (chainSpecJson.Engine?.Clique is not null) - { - chainSpec.SealEngineType = SealEngineType.Clique; - chainSpec.Clique = new CliqueParameters - { - Epoch = chainSpecJson.Engine.Clique.Epoch, - Period = chainSpecJson.Engine.Clique.Period, - Reward = chainSpecJson.Engine.Clique.BlockReward ?? UInt256.Zero - }; - } - else if (chainSpecJson.Engine?.Ethash is not null) + if (chainSpec.EngineChainSpecParametersProvider is not null) { - chainSpec.SealEngineType = SealEngineType.Ethash; - chainSpec.Ethash = new EthashParameters + foreach (IChainSpecEngineParameters chainSpecEngineParameters in chainSpec.EngineChainSpecParametersProvider + .AllChainSpecParameters) { - MinimumDifficulty = chainSpecJson.Engine.Ethash.MinimumDifficulty ?? 0L, - DifficultyBoundDivisor = chainSpecJson.Engine.Ethash.DifficultyBoundDivisor ?? 0x0800L, - DurationLimit = chainSpecJson.Engine.Ethash.DurationLimit ?? 13L, - HomesteadTransition = chainSpecJson.Engine.Ethash.HomesteadTransition ?? 0, - DaoHardforkTransition = chainSpecJson.Engine.Ethash.DaoHardforkTransition, - DaoHardforkBeneficiary = chainSpecJson.Engine.Ethash.DaoHardforkBeneficiary, - DaoHardforkAccounts = chainSpecJson.Engine.Ethash.DaoHardforkAccounts ?? Array.Empty
(), - Eip100bTransition = chainSpecJson.Engine.Ethash.Eip100bTransition ?? 0L, - FixedDifficulty = chainSpecJson.Engine.Ethash.FixedDifficulty, - BlockRewards = chainSpecJson.Engine.Ethash.BlockReward - }; - - chainSpec.Ethash.DifficultyBombDelays = new Dictionary(); - if (chainSpecJson.Engine.Ethash.DifficultyBombDelays is not null) - { - foreach (KeyValuePair reward in chainSpecJson.Engine.Ethash.DifficultyBombDelays) - { - long key = reward.Key.StartsWith("0x") ? - long.Parse(reward.Key.AsSpan(2), NumberStyles.HexNumber) : - long.Parse(reward.Key); - - chainSpec.Ethash.DifficultyBombDelays.Add(key, reward.Value); - } + chainSpecEngineParameters.ApplyToChainSpec(chainSpec); } } - else if (chainSpecJson.Engine?.Optimism is not null) - { - chainSpec.SealEngineType = SealEngineType.Optimism; - chainSpec.Optimism = new OptimismParameters - { - RegolithTimestamp = chainSpecJson.Engine.Optimism.RegolithTimestamp, - BedrockBlockNumber = chainSpecJson.Engine.Optimism.BedrockBlockNumber, - CanyonTimestamp = chainSpecJson.Engine.Optimism.CanyonTimestamp, - EcotoneTimestamp = chainSpecJson.Engine.Optimism.EcotoneTimestamp, - FjordTimestamp = chainSpecJson.Engine.Optimism.FjordTimestamp, - GraniteTimestamp = chainSpecJson.Engine.Optimism.GraniteTimestamp, - - L1FeeRecipient = chainSpecJson.Engine.Optimism.L1FeeRecipient, - L1BlockAddress = chainSpecJson.Engine.Optimism.L1BlockAddress, - CanyonBaseFeeChangeDenominator = chainSpecJson.Engine.Optimism.CanyonBaseFeeChangeDenominator, - Create2DeployerAddress = chainSpecJson.Engine.Optimism.Create2DeployerAddress, - Create2DeployerCode = chainSpecJson.Engine.Optimism.Create2DeployerCode - }; - } - else if (chainSpecJson.Engine?.Taiko is not null) - { - chainSpec.SealEngineType = SealEngineType.Taiko; - } - else if (chainSpecJson.Engine?.NethDev is not null) - { - chainSpec.SealEngineType = SealEngineType.NethDev; - } + } - var customEngineType = chainSpecJson.Engine?.CustomEngineData?.FirstOrDefault().Key; + private void LoadEngine(ChainSpecJson chainSpecJson, ChainSpec chainSpec) + { + var engineParameters = chainSpecJson.Engine.CustomEngineData.ToDictionary( + engine => engine.Key, + engine => engine.Value.TryGetProperty("params", out JsonElement value) ? value : engine.Value); - if (!string.IsNullOrEmpty(customEngineType)) + chainSpec.EngineChainSpecParametersProvider = new ChainSpecParametersProvider(engineParameters, serializer); + if (string.IsNullOrEmpty(chainSpec.SealEngineType)) { - chainSpec.SealEngineType = customEngineType; + chainSpec.SealEngineType = chainSpec.EngineChainSpecParametersProvider.SealEngineType; } if (string.IsNullOrEmpty(chainSpec.SealEngineType)) diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecParametersProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecParametersProvider.cs new file mode 100644 index 00000000000..66f31efe023 --- /dev/null +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecParametersProvider.cs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + + +using System.Reflection; +using System.Text.Json; +using Nethermind.Config; +using Nethermind.Core.Exceptions; +using Nethermind.Serialization.Json; + +namespace Nethermind.Specs.ChainSpecStyle; + +using System; +using System.Collections.Generic; +using System.Linq; +using Nethermind.Core; + +public class ChainSpecParametersProvider : IChainSpecParametersProvider +{ + private readonly Dictionary _chainSpecParameters; + private readonly Dictionary _instances = new(); + private readonly IJsonSerializer _jsonSerializer; + + public string SealEngineType { get; } + + public ChainSpecParametersProvider(Dictionary engineParameters, IJsonSerializer jsonSerializer) + { + _chainSpecParameters = new Dictionary(engineParameters, StringComparer.InvariantCultureIgnoreCase); + _jsonSerializer = jsonSerializer; + + InitializeInstances(); + SealEngineType = CalculateSealEngineType(); + } + + private string CalculateSealEngineType() + { + string? result = null; + foreach (IChainSpecEngineParameters item in _instances.Values) + { + if (item.SealEngineType is not null) + { + if (result is not null) + { + throw new InvalidOperationException("Multiple seal engines in chain spec"); + } + + result = item.SealEngineType; + } + } + + return result ?? throw new InvalidOperationException("No seal engine in chain spec"); + } + + private void InitializeInstances() + { + IEnumerable types = TypeDiscovery.FindNethermindBasedTypes(typeof(IChainSpecEngineParameters)).Where(x => x.IsClass); + foreach (Type type in types) + { + IChainSpecEngineParameters instance = (IChainSpecEngineParameters)Activator.CreateInstance(type)!; + if (_chainSpecParameters.TryGetValue(instance.EngineName!, out JsonElement json)) + { + _instances[type] = (IChainSpecEngineParameters)_jsonSerializer.Deserialize(json.ToString(), type); + } + } + } + + public IEnumerable AllChainSpecParameters => _instances.Values; + + public T GetChainSpecParameters() where T : IChainSpecEngineParameters => (T)_instances[typeof(T)]; +} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/CliqueParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/CliqueParameters.cs deleted file mode 100644 index 6edc6a57bd7..00000000000 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/CliqueParameters.cs +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using Nethermind.Int256; - -namespace Nethermind.Specs.ChainSpecStyle -{ - public class CliqueParameters - { - public ulong Epoch { get; set; } - - public ulong Period { get; set; } - - public UInt256? Reward { get; set; } - } -} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/EthashParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/EthashParameters.cs deleted file mode 100644 index 40271ef722f..00000000000 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/EthashParameters.cs +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System.Collections.Generic; -using Nethermind.Core; -using Nethermind.Int256; - -namespace Nethermind.Specs.ChainSpecStyle -{ - public class EthashParameters - { - public UInt256 MinimumDifficulty { get; set; } - - public long DifficultyBoundDivisor { get; set; } - - public long DurationLimit { get; set; } - - // why is it here??? (this is what chainspec does) - public long HomesteadTransition { get; set; } - - public long? DaoHardforkTransition { get; set; } - - /// - /// This is stored in the Nethermind.Blockchain.DaoData class instead. - /// - public Address DaoHardforkBeneficiary { get; set; } - - /// - /// This is stored in the Nethermind.Blockchain.DaoData class instead. - /// - public Address[] DaoHardforkAccounts { get; set; } - - public long Eip100bTransition { get; set; } - - public long? FixedDifficulty { get; set; } - - public IDictionary BlockRewards { get; set; } - - public IDictionary DifficultyBombDelays { get; set; } - } -} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecEngineParameters.cs new file mode 100644 index 00000000000..877e97eeb6d --- /dev/null +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecEngineParameters.cs @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Specs.ChainSpecStyle; + +using System.Collections.Generic; + +public interface IChainSpecEngineParameters +{ + string? EngineName { get; } + string? SealEngineType { get; } + void ApplyToChainSpec(ChainSpec chainSpec) { } + void AddTransitions(SortedSet blockNumbers, SortedSet timestamps) { } + void ApplyToReleaseSpec(ReleaseSpec spec, long startBlock, ulong? startTimestamp) { } +} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecParametersProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecParametersProvider.cs new file mode 100644 index 00000000000..86a100c041d --- /dev/null +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/IChainSpecParametersProvider.cs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Specs.ChainSpecStyle; + +using System.Collections.Generic; + +public interface IChainSpecParametersProvider +{ + string SealEngineType { get; } + IEnumerable AllChainSpecParameters { get; } + T GetChainSpecParameters() where T : IChainSpecEngineParameters; +} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardConverter.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardConverter.cs new file mode 100644 index 00000000000..3bd50ddb6a8 --- /dev/null +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardConverter.cs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using Nethermind.Int256; +using Nethermind.Serialization.Json; + +namespace Nethermind.Specs.ChainSpecStyle.Json; + +public class BlockRewardConverter : JsonConverter> +{ + public override void Write(Utf8JsonWriter writer, SortedDictionary value, + JsonSerializerOptions options) + { + throw new NotSupportedException(); + } + + public override SortedDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, + JsonSerializerOptions options) + { + var value = new SortedDictionary(); + if (reader.TokenType == JsonTokenType.String) + { + var blockReward = JsonSerializer.Deserialize(ref reader, options); + value.Add(0, blockReward); + } + else if (reader.TokenType == JsonTokenType.Number) + { + value.Add(0, new UInt256(reader.GetUInt64())); + } + else if (reader.TokenType == JsonTokenType.StartObject) + { + reader.Read(); + while (reader.TokenType != JsonTokenType.EndObject) + { + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new ArgumentException("Cannot deserialize dictionary."); + } + + var property = + UInt256Converter.Read(reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan); + var key = (long)property; + reader.Read(); + if (reader.TokenType != JsonTokenType.String) + { + throw new ArgumentException("Cannot deserialize dictionary."); + } + + var blockReward = + UInt256Converter.Read(reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan); + value.Add(key, blockReward); + + reader.Read(); + } + } + else + { + throw new ArgumentException("Cannot deserialize dictionary."); + } + + return value; + } +} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardJsonConverter.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardJsonConverter.cs deleted file mode 100644 index e87fb6a2bc9..00000000000 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/BlockRewardJsonConverter.cs +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using Nethermind.Int256; - -using System.Text.Json; -using System.Text.Json.Serialization; -using Nethermind.Serialization.Json; -using System.Buffers; - -namespace Nethermind.Specs.ChainSpecStyle.Json -{ - internal class BlockRewardJsonConverter : JsonConverter - { - public override void Write(Utf8JsonWriter writer, ChainSpecJson.BlockRewardJson value, JsonSerializerOptions options) - { - throw new NotSupportedException(); - } - - public override ChainSpecJson.BlockRewardJson Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var value = new ChainSpecJson.BlockRewardJson(); - if (reader.TokenType == JsonTokenType.String) - { - var blockReward = JsonSerializer.Deserialize(ref reader, options); - value.Add(0, blockReward); - } - else if (reader.TokenType == JsonTokenType.Number) - { - value.Add(0, new UInt256(reader.GetUInt64())); - } - else if (reader.TokenType == JsonTokenType.StartObject) - { - reader.Read(); - while (reader.TokenType != JsonTokenType.EndObject) - { - if (reader.TokenType != JsonTokenType.PropertyName) - { - throw new ArgumentException("Cannot deserialize BlockReward."); - } - var property = UInt256Converter.Read(reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan); - var key = (long)property; - reader.Read(); - if (reader.TokenType != JsonTokenType.String) - { - throw new ArgumentException("Cannot deserialize BlockReward."); - } - - var blockReward = UInt256Converter.Read(reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan); - value.Add(key, blockReward); - - reader.Read(); - } - } - else - { - throw new ArgumentException("Cannot deserialize BlockReward."); - } - - return value; - } - } -} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs index e12db5f544f..25712d814d6 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs @@ -26,195 +26,8 @@ internal class ChainSpecJson [JsonPropertyName("accounts")] public Dictionary Accounts { get; set; } - internal class EthashEngineJson - { - public long? HomesteadTransition => Params?.HomesteadTransition; - public long? DaoHardforkTransition => Params?.DaoHardforkTransition; - public Address DaoHardforkBeneficiary => Params?.DaoHardforkBeneficiary; - public Address[] DaoHardforkAccounts => Params?.DaoHardforkAccounts; - public long? Eip100bTransition => Params?.Eip100bTransition; - public long? FixedDifficulty => Params?.FixedDifficulty; - public long? DifficultyBoundDivisor => Params?.DifficultyBoundDivisor; - public long? DurationLimit => Params?.DurationLimit; - public UInt256? MinimumDifficulty => Params?.MinimumDifficulty; - public IDictionary BlockReward => Params?.BlockReward; - public IDictionary DifficultyBombDelays => Params?.DifficultyBombDelays; - public EthashEngineParamsJson Params { get; set; } - } - - internal class EthashEngineParamsJson - { - public UInt256? MinimumDifficulty { get; set; } - public long? DifficultyBoundDivisor { get; set; } - public long? DurationLimit { get; set; } - public long HomesteadTransition { get; set; } - public long? DaoHardforkTransition { get; set; } - public Address DaoHardforkBeneficiary { get; set; } - public Address[] DaoHardforkAccounts { get; set; } - public long Eip100bTransition { get; set; } - public long? FixedDifficulty { get; set; } - public BlockRewardJson BlockReward { get; set; } - public Dictionary DifficultyBombDelays { get; set; } - } - - internal class CliqueEngineJson - { - public ulong Period => Params.Period; - public ulong Epoch => Params.Epoch; - public UInt256? BlockReward => Params.BlockReward; - public CliqueEngineParamsJson Params { get; set; } - } - - internal class CliqueEngineParamsJson - { - public ulong Period { get; set; } - public ulong Epoch { get; set; } - public UInt256? BlockReward { get; set; } - } - - internal class AuraEngineParamsJson - { - public StepDurationJson StepDuration { get; set; } - public BlockRewardJson BlockReward { get; set; } - public long MaximumUncleCountTransition { get; set; } - public long? MaximumUncleCount { get; set; } - public Address BlockRewardContractAddress { get; set; } - public long? BlockRewardContractTransition { get; set; } - public IDictionary BlockRewardContractTransitions { get; set; } = new Dictionary(); - public long ValidateScoreTransition { get; set; } - public long ValidateStepTransition { get; set; } - public AuRaValidatorJson Validators { get; set; } - public IDictionary RandomnessContractAddress { get; set; } = new Dictionary(); - public IDictionary BlockGasLimitContractTransitions { get; set; } = new Dictionary(); - public long? TwoThirdsMajorityTransition { get; set; } - public long? PosdaoTransition { get; set; } - public IDictionary> RewriteBytecode { get; set; } = new Dictionary>(); - public Address WithdrawalContractAddress { get; set; } - - [JsonConverter(typeof(StepDurationJsonConverter))] - public class StepDurationJson : SortedDictionary { } - } - - [JsonConverter(typeof(BlockRewardJsonConverter))] - public class BlockRewardJson : SortedDictionary { } - - internal class AuRaValidatorJson - { - public Address[] List { get; set; } - public Address Contract { get; set; } - public Address SafeContract { get; set; } - public Dictionary Multi { get; set; } - - public AuRaParameters.ValidatorType GetValidatorType() - { - if (List is not null) - { - return AuRaParameters.ValidatorType.List; - } - else if (Contract is not null) - { - return AuRaParameters.ValidatorType.ReportingContract; - } - else if (SafeContract is not null) - { - return AuRaParameters.ValidatorType.Contract; - } - else if (Multi is not null) - { - return AuRaParameters.ValidatorType.Multi; - } - else - { - throw new NotSupportedException("AuRa validator type not supported."); - } - } - } - - internal class AuraEngineJson - { - public IDictionary StepDuration => Params.StepDuration; - - public IDictionary BlockReward => Params.BlockReward; - - public long MaximumUncleCountTransition => Params.MaximumUncleCountTransition; - - public long? MaximumUncleCount => Params.MaximumUncleCount; - - public Address BlockRewardContractAddress => Params.BlockRewardContractAddress; - - public long? BlockRewardContractTransition => Params.BlockRewardContractTransition; - - public IDictionary BlockRewardContractTransitions => Params.BlockRewardContractTransitions; - - public long ValidateScoreTransition => Params.ValidateScoreTransition; - - public long ValidateStepTransition => Params.ValidateStepTransition; - - public long? PosdaoTransition => Params.PosdaoTransition; - - public long? TwoThirdsMajorityTransition => Params.TwoThirdsMajorityTransition; - - public AuRaValidatorJson Validator => Params.Validators; - - public IDictionary RandomnessContractAddress => Params.RandomnessContractAddress; - - public IDictionary BlockGasLimitContractTransitions => Params.BlockGasLimitContractTransitions; - - public IDictionary> RewriteBytecode => Params.RewriteBytecode; - - public Address WithdrawalContractAddress => Params.WithdrawalContractAddress; - - public AuraEngineParamsJson Params { get; set; } - } - - internal class OptimismEngineJson - { - public ulong RegolithTimestamp => Params.RegolithTimestamp; - public long BedrockBlockNumber => Params.BedrockBlockNumber; - public ulong? CanyonTimestamp => Params.CanyonTimestamp; - public ulong? EcotoneTimestamp => Params.EcotoneTimestamp; - public ulong? FjordTimestamp => Params.FjordTimestamp; - public ulong? GraniteTimestamp => Params.GraniteTimestamp; - public Address L1FeeRecipient => Params.L1FeeRecipient; - public Address L1BlockAddress => Params.L1BlockAddress; - public UInt256 CanyonBaseFeeChangeDenominator => Params.CanyonBaseFeeChangeDenominator; - public Address Create2DeployerAddress => Params.Create2DeployerAddress; - public byte[] Create2DeployerCode => Params.Create2DeployerCode; - public OptimismEngineParamsJson Params { get; set; } - } - - internal class TaikoEngineJson - { - } - - internal class OptimismEngineParamsJson - { - public ulong RegolithTimestamp { get; set; } - public long BedrockBlockNumber { get; set; } - public ulong? CanyonTimestamp { get; set; } - public ulong? EcotoneTimestamp { get; set; } - public ulong? FjordTimestamp { get; set; } - public ulong? GraniteTimestamp { get; set; } - public Address L1FeeRecipient { get; set; } - public Address L1BlockAddress { get; set; } - public UInt256 CanyonBaseFeeChangeDenominator { get; set; } - public Address Create2DeployerAddress { get; set; } - public byte[] Create2DeployerCode { get; set; } - } - - internal class NethDevJson - { - } - internal class EngineJson { - public EthashEngineJson Ethash { get; set; } - public CliqueEngineJson Clique { get; set; } - public AuraEngineJson AuthorityRound { get; set; } - public OptimismEngineJson Optimism { get; set; } - public TaikoEngineJson Taiko { get; set; } - public NethDevJson NethDev { get; set; } - [JsonExtensionData] public Dictionary CustomEngineData { get; set; } } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/StepDurationJsonConverter.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/StepDurationJsonConverter.cs deleted file mode 100644 index 4d82b30b88e..00000000000 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/StepDurationJsonConverter.cs +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; - -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Nethermind.Specs.ChainSpecStyle.Json -{ - internal class StepDurationJsonConverter : JsonConverter - { - public override void Write(Utf8JsonWriter writer, ChainSpecJson.AuraEngineParamsJson.StepDurationJson value, JsonSerializerOptions options) - { - throw new NotSupportedException(); - } - - public override ChainSpecJson.AuraEngineParamsJson.StepDurationJson Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var value = new ChainSpecJson.AuraEngineParamsJson.StepDurationJson(); - if (reader.TokenType == JsonTokenType.String) - { - value.Add(0, JsonSerializer.Deserialize(ref reader, options)); - } - else if (reader.TokenType == JsonTokenType.Number) - { - value.Add(0, reader.GetInt64()); - } - else if (reader.TokenType == JsonTokenType.StartObject) - { - reader.Read(); - while (reader.TokenType != JsonTokenType.EndObject) - { - if (reader.TokenType != JsonTokenType.PropertyName) - { - throw new ArgumentException("Cannot deserialize BlockReward."); - } - var key = long.Parse(reader.GetString()); - reader.Read(); - if (reader.TokenType == JsonTokenType.String) - { - value.Add(key, long.Parse(reader.GetString())); - } - else if (reader.TokenType == JsonTokenType.Number) - { - value.Add(key, reader.GetInt64()); - } - else - { - throw new ArgumentException("Cannot deserialize BlockReward."); - } - - reader.Read(); - } - } - else - { - throw new ArgumentException("Cannot deserialize BlockReward."); - } - - return value; - } - } -} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs deleted file mode 100644 index b4234df0da7..00000000000 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using Nethermind.Core; -using Nethermind.Int256; - -namespace Nethermind.Specs.ChainSpecStyle -{ - public class OptimismParameters - { - public ulong RegolithTimestamp { get; set; } - - public long BedrockBlockNumber { get; set; } - - public ulong? CanyonTimestamp { get; set; } - - public ulong? EcotoneTimestamp { get; set; } - - public ulong? FjordTimestamp { get; set; } - public ulong? GraniteTimestamp { get; set; } - - public Address L1FeeRecipient { get; set; } - - public Address L1BlockAddress { get; set; } - - public UInt256 CanyonBaseFeeChangeDenominator { get; set; } - - public Address Create2DeployerAddress { get; set; } - - public byte[] Create2DeployerCode { get; set; } - } -} diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ValidatorTypeExtensions.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ValidatorTypeExtensions.cs deleted file mode 100644 index 4c480eb8d14..00000000000 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ValidatorTypeExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -namespace Nethermind.Specs.ChainSpecStyle -{ - public static class ValidatorTypeExtensions - { - public static bool CanChangeImmediately(this AuRaParameters.ValidatorType validatorType) => - validatorType switch - { - AuRaParameters.ValidatorType.Contract => false, - AuRaParameters.ValidatorType.ReportingContract => false, - AuRaParameters.ValidatorType.List => true, - AuRaParameters.ValidatorType.Multi => true, - _ => false - }; - } -} diff --git a/src/Nethermind/Nethermind.Specs/Nethermind.Specs.csproj b/src/Nethermind/Nethermind.Specs/Nethermind.Specs.csproj index 088a79d66b8..4e8761c9cfa 100644 --- a/src/Nethermind/Nethermind.Specs/Nethermind.Specs.csproj +++ b/src/Nethermind/Nethermind.Specs/Nethermind.Specs.csproj @@ -1,5 +1,9 @@ + + annotations + + diff --git a/src/Nethermind/Nethermind.Taiko/TaikoChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Taiko/TaikoChainSpecEngineParameters.cs new file mode 100644 index 00000000000..67277871a87 --- /dev/null +++ b/src/Nethermind/Nethermind.Taiko/TaikoChainSpecEngineParameters.cs @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Generic; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; + +namespace Nethermind.Taiko; + +public class TaikoChainSpecEngineParameters : IChainSpecEngineParameters +{ + public string? EngineName => TaikoPlugin.Taiko; + public string? SealEngineType => TaikoPlugin.Taiko; +} diff --git a/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs b/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs index f0267083079..1305e7ec83f 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs @@ -42,8 +42,10 @@ namespace Nethermind.Taiko; public class TaikoPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitializationPlugin { + public const string Taiko = "Taiko"; + private const string L1OriginDbName = "L1Origin"; public string Author => "Nethermind"; - public string Name => "Taiko"; + public string Name => Taiko; public string Description => "Taiko support for Nethermind"; private TaikoNethermindApi? _api; @@ -57,8 +59,6 @@ public class TaikoPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitializa private IBeaconPivot? _beaconPivot; private BeaconSync? _beaconSync; - private const string L1OriginDbName = "L1Origin"; - public Task Init(INethermindApi api) { if (!ShouldRunSteps(api))