From d33add6f4768dcf08b287fda22ebdd1fcaad8a06 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 16 Aug 2024 13:08:59 +0530 Subject: [PATCH 001/113] add init code for block validation --- .../BlockValidation.cs | 26 +++++++ .../Data/BidTrace.cs | 21 ++++++ .../Data/BlockValidationResult.cs | 47 ++++++++++++ .../Data/BlockValidationStatus.cs | 17 +++++ .../Data/BuilderBlockValidationRequest.cs | 19 +++++ .../Data/SubmitBlockRequest.cs | 21 ++++++ .../FlashbotsRpcModule.cs | 23 ++++++ .../ValidateBuilderSubmissionHandler.cs | 73 +++++++++++++++++++ .../IFlashbotsRpcModule.cs | 19 +++++ .../Nethermind.BlockValidation.csproj | 12 +++ .../Nethermind.JsonRpc/Modules/ModuleType.cs | 2 + src/Nethermind/Nethermind.sln | 6 ++ 12 files changed, 286 insertions(+) create mode 100644 src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationResult.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/IFlashbotsRpcModule.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/Nethermind.BlockValidation.csproj diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs new file mode 100644 index 00000000000..c7caf078df7 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Threading.Tasks; +using Nethermind.Api; +using Nethermind.Api.Extensions; + +namespace Nethermind.BlockValidation; + +public class BlockValidation: INethermindPlugin +{ + public virtual string Name => "BlockValidation"; + public virtual string Description => "BlockValidation"; + public string Author => "Nethermind"; + public Task InitRpcModules() + { + return Task.CompletedTask; + } + + public Task Init(INethermindApi api) + { + return Task.CompletedTask; + } + + public ValueTask DisposeAsync() => ValueTask.CompletedTask; +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs new file mode 100644 index 00000000000..04a48002bb3 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Int256; + +namespace Nethermind.BlockValidation.Data; + +public readonly struct BidTrace +{ + public ulong Slot { get; } + public Hash256 ParentHash { get; } + public Hash256 BlockHash { get; } + public PublicKey BuilderPublicKey { get; } + public PublicKey ProposerPublicKey { get; } + public Address ProposerFeeRecipient { get; } + public long GasLimit { get; } + public long GasUsed { get; } + public UInt256 Value { get; } +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationResult.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationResult.cs new file mode 100644 index 00000000000..cb30aef279e --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationResult.cs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Text.Json.Serialization; +using Nethermind.JsonRpc; + +namespace Nethermind.BlockValidation.Data; + +/// +/// Represents the result of a block validation. +/// +public class BlockValidationResult +{ + + public static ResultWrapper Invalid(string error) + { + return ResultWrapper.Success(new BlockValidationResult + { + Status = BlockValidationStatus.Invalid, + ValidationError = error + }); + } + + public static ResultWrapper Valid() + { + return ResultWrapper.Success(new BlockValidationResult + { + Status = BlockValidationStatus.Valid + }); + } + + public static ResultWrapper Error(string error) + { + return ResultWrapper.Fail(error); + } + + /// + /// The status of the validation of the builder submissions + /// + public string Status { get; set; } = BlockValidationStatus.Invalid; + + /// + /// Message providing additional details on the validation error if the payload is classified as . + /// + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public string? ValidationError { get; set; } +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs new file mode 100644 index 00000000000..0540ff79d54 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.BlockValidation.Data; + +public static class BlockValidationStatus +{ + /// + /// The submissions are invalid. + /// + public const string Invalid = "Invalid"; + + /// + /// The submissions are valid. + /// + public const string Valid = "Valid"; +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs new file mode 100644 index 00000000000..4ef936d7286 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core.Crypto; + +namespace Nethermind.BlockValidation.Data; + +public class BuilderBlockValidationRequest +{ + /// + /// The block hash of the parent beacon block. + /// + /// + public Hash256 ParentBeaconBlockRoot { get; set; } = Keccak.Zero; + + public ulong RegisterGasLimit { get; set; } + + public SubmitBlockRequest BlockRequest { get; set; } +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs new file mode 100644 index 00000000000..adb79de8018 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core.Crypto; +using Nethermind.Merge.Plugin.Data; + +namespace Nethermind.BlockValidation.Data; + +public readonly struct SubmitBlockRequest { + private readonly ExecutionPayload _executionPayload; + private readonly BlobsBundleV1 _blobsBundle; + + public SubmitBlockRequest(ExecutionPayload executionPayload, BlobsBundleV1 blobsBundle, BidTrace message) { + _executionPayload = executionPayload; + _blobsBundle = blobsBundle; + Message = message; + } + public readonly ExecutionPayload ExecutionPayload => _executionPayload; + public readonly BlobsBundleV1 BlobsBundle => _blobsBundle; + public BidTrace Message { get;} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs new file mode 100644 index 00000000000..d1024684088 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Threading.Tasks; +using Nethermind.BlockValidation.Data; +using Nethermind.BlockValidation.Handlers; +using Nethermind.JsonRpc; + +namespace Nethermind.BlockValidation; + +public class FlashbotsRpcModule: IFlashbotsRpcModule +{ + private readonly ValidateSubmissionHandler _validateSubmissionHandler; + + public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) + { + _validateSubmissionHandler = validateSubmissionHandler; + } + + Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => + _validateSubmissionHandler.ValidateSubmission(@params); + +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs new file mode 100644 index 00000000000..882eb260911 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Threading.Tasks; +using Nethermind.BlockValidation.Data; +using Nethermind.Consensus.Validators; +using Nethermind.Core; +using Nethermind.JsonRpc; +using Nethermind.Logging; +using Nethermind.Merge.Plugin.Data; + +namespace Nethermind.BlockValidation.Handlers; + +public class ValidateSubmissionHandler +{ + private readonly ILogger _logger; + + public ValidateSubmissionHandler(ILogManager logManager) + { + _logger = logManager.GetClassLogger(); + } + + private bool ValidateBlock(Block block, BidTrace message, ulong registerGasLimit, out string? error) + { + error = null; + + if (message.ParentHash != block.Header.ParentHash) + { + error = $"Parent hash mismatch. Expected {message.ParentHash} but got {block.Header.ParentHash}"; + return false; + } + + if (message.BlockHash != block.Header.Hash) + { + error = $"Block hash mismatch. Expected {message.BlockHash} but got {block.Header.Hash}"; + return false; + } + + if(message.GasLimit != block.GasLimit) + { + error = $"Gas limit mismatch. Expected {message.GasLimit} but got {block.GasLimit}"; + return false; + } + + if(message.GasUsed != block.GasUsed) + { + error = $"Gas used mismatch. Expected {message.GasUsed} but got {block.GasUsed}"; + return false; + } + + return true; + } + + public Task> ValidateSubmission(BuilderBlockValidationRequest request) + { + ExecutionPayload payload = request.BlockRequest.ExecutionPayload; + BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; + + string payloadStr = $"BuilderBlock: {payload}"; + + _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length}"); + + if(!payload.TryGetBlock(out Block? block)) + { + if(_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}."); + return BlockValidationResult.Invalid($"Block {payload} coud not be parsed as a block"); + } + + + + return BlockValidationResult.Valid(); + } +} diff --git a/src/Nethermind/Nethermind.BlockValidation/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.BlockValidation/IFlashbotsRpcModule.cs new file mode 100644 index 00000000000..f764fed0ed5 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/IFlashbotsRpcModule.cs @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Threading.Tasks; +using Nethermind.BlockValidation.Data; +using Nethermind.JsonRpc; +using Nethermind.JsonRpc.Modules; + +namespace Nethermind.BlockValidation; + +[RpcModule(ModuleType.Flashbots)] +public interface IFlashbotsRpcModule : IRpcModule +{ + [JsonRpcMethod( + Description = " validate the builder submissions as received by a relay", + IsSharable = true, + IsImplemented = true)] + Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Nethermind.BlockValidation.csproj b/src/Nethermind/Nethermind.BlockValidation/Nethermind.BlockValidation.csproj new file mode 100644 index 00000000000..11efa636a6d --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Nethermind.BlockValidation.csproj @@ -0,0 +1,12 @@ + + + + Nethermind.BlockValidation + enable + + + + + + + diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs index 045f201109b..6d730ad3628 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs @@ -15,6 +15,7 @@ public static class ModuleType public const string Erc20 = nameof(Erc20); public const string Eth = nameof(Eth); public const string Evm = nameof(Evm); + public const string Flashbots = nameof(Flashbots); public const string Net = nameof(Net); public const string Nft = nameof(Nft); public const string Parity = nameof(Parity); @@ -39,6 +40,7 @@ public static class ModuleType Erc20, Eth, Evm, + Flashbots, Net, Nft, Parity, diff --git a/src/Nethermind/Nethermind.sln b/src/Nethermind/Nethermind.sln index a0ac7f0e84c..bd3a5c58c8f 100644 --- a/src/Nethermind/Nethermind.sln +++ b/src/Nethermind/Nethermind.sln @@ -218,6 +218,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Signer", "Signer", "{89311B EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.ExternalSigner.Plugin", "Nethermind.ExternalSigner.Plugin\Nethermind.ExternalSigner.Plugin.csproj", "{6528010D-7DCE-4935-9785-5270FF515F3E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.BlockValidation", "Nethermind.BlockValidation\Nethermind.BlockValidation.csproj", "{580DB104-AE89-444F-BD99-7FE0C84C615C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -600,6 +602,10 @@ Global {6528010D-7DCE-4935-9785-5270FF515F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU {6528010D-7DCE-4935-9785-5270FF515F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU {6528010D-7DCE-4935-9785-5270FF515F3E}.Release|Any CPU.Build.0 = Release|Any CPU + {580DB104-AE89-444F-BD99-7FE0C84C615C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {580DB104-AE89-444F-BD99-7FE0C84C615C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {580DB104-AE89-444F-BD99-7FE0C84C615C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {580DB104-AE89-444F-BD99-7FE0C84C615C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 9eb6f704f2d2d15b6212cbe8550938c44db82243 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 16 Aug 2024 13:21:08 +0530 Subject: [PATCH 002/113] format files --- .../Nethermind.BlockValidation/BlockValidation.cs | 4 ++-- .../Nethermind.BlockValidation/Data/BidTrace.cs | 4 ++-- .../Data/BlockValidationStatus.cs | 2 +- .../Data/BuilderBlockValidationRequest.cs | 2 +- .../Data/SubmitBlockRequest.cs | 10 ++++++---- .../Nethermind.BlockValidation/FlashbotsRpcModule.cs | 6 +++--- .../Handlers/ValidateBuilderSubmissionHandler.cs | 12 ++++++------ 7 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs index c7caf078df7..c7d20d71abe 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs @@ -7,7 +7,7 @@ namespace Nethermind.BlockValidation; -public class BlockValidation: INethermindPlugin +public class BlockValidation : INethermindPlugin { public virtual string Name => "BlockValidation"; public virtual string Description => "BlockValidation"; @@ -23,4 +23,4 @@ public Task Init(INethermindApi api) } public ValueTask DisposeAsync() => ValueTask.CompletedTask; -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs index 04a48002bb3..37f38520119 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs @@ -7,7 +7,7 @@ namespace Nethermind.BlockValidation.Data; -public readonly struct BidTrace +public readonly struct BidTrace { public ulong Slot { get; } public Hash256 ParentHash { get; } @@ -18,4 +18,4 @@ public readonly struct BidTrace public long GasLimit { get; } public long GasUsed { get; } public UInt256 Value { get; } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs index 0540ff79d54..1788c2991b3 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs @@ -14,4 +14,4 @@ public static class BlockValidationStatus /// The submissions are valid. /// public const string Valid = "Valid"; -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs index 4ef936d7286..38b2fe3324f 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs @@ -16,4 +16,4 @@ public class BuilderBlockValidationRequest public ulong RegisterGasLimit { get; set; } public SubmitBlockRequest BlockRequest { get; set; } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs index adb79de8018..e22e5696933 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs @@ -6,16 +6,18 @@ namespace Nethermind.BlockValidation.Data; -public readonly struct SubmitBlockRequest { +public readonly struct SubmitBlockRequest +{ private readonly ExecutionPayload _executionPayload; private readonly BlobsBundleV1 _blobsBundle; - public SubmitBlockRequest(ExecutionPayload executionPayload, BlobsBundleV1 blobsBundle, BidTrace message) { + public SubmitBlockRequest(ExecutionPayload executionPayload, BlobsBundleV1 blobsBundle, BidTrace message) + { _executionPayload = executionPayload; _blobsBundle = blobsBundle; Message = message; } public readonly ExecutionPayload ExecutionPayload => _executionPayload; public readonly BlobsBundleV1 BlobsBundle => _blobsBundle; - public BidTrace Message { get;} -} \ No newline at end of file + public BidTrace Message { get; } +} diff --git a/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs index d1024684088..d8e02044e9e 100644 --- a/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs @@ -8,7 +8,7 @@ namespace Nethermind.BlockValidation; -public class FlashbotsRpcModule: IFlashbotsRpcModule +public class FlashbotsRpcModule : IFlashbotsRpcModule { private readonly ValidateSubmissionHandler _validateSubmissionHandler; @@ -17,7 +17,7 @@ public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) _validateSubmissionHandler = validateSubmissionHandler; } - Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => + Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => _validateSubmissionHandler.ValidateSubmission(@params); -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index 882eb260911..dbfaa637414 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -36,13 +36,13 @@ private bool ValidateBlock(Block block, BidTrace message, ulong registerGasLimit return false; } - if(message.GasLimit != block.GasLimit) + if (message.GasLimit != block.GasLimit) { error = $"Gas limit mismatch. Expected {message.GasLimit} but got {block.GasLimit}"; return false; } - if(message.GasUsed != block.GasUsed) + if (message.GasUsed != block.GasUsed) { error = $"Gas used mismatch. Expected {message.GasUsed} but got {block.GasUsed}"; return false; @@ -50,7 +50,7 @@ private bool ValidateBlock(Block block, BidTrace message, ulong registerGasLimit return true; } - + public Task> ValidateSubmission(BuilderBlockValidationRequest request) { ExecutionPayload payload = request.BlockRequest.ExecutionPayload; @@ -59,10 +59,10 @@ public Task> ValidateSubmission(BuilderBloc string payloadStr = $"BuilderBlock: {payload}"; _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length}"); - - if(!payload.TryGetBlock(out Block? block)) + + if (!payload.TryGetBlock(out Block? block)) { - if(_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}."); + if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}."); return BlockValidationResult.Invalid($"Block {payload} coud not be parsed as a block"); } From ae4357fb351248a6064730b9125c62185d8e39b6 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Tue, 27 Aug 2024 12:34:03 +0530 Subject: [PATCH 003/113] verify blobs --- .../ValidateBuilderSubmissionHandler.cs | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index dbfaa637414..211dc66c6b1 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -1,10 +1,12 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Linq; using System.Threading.Tasks; using Nethermind.BlockValidation.Data; -using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Crypto; +using Nethermind.Int256; using Nethermind.JsonRpc; using Nethermind.Logging; using Nethermind.Merge.Plugin.Data; @@ -20,6 +22,49 @@ public ValidateSubmissionHandler(ILogManager logManager) _logger = logManager.GetClassLogger(); } + private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobsBundle, out string? error) + { + // get sum of length of blobs of each transaction + int totalBlobsLength = transactions.Sum(t => t.BlobVersionedHashes!.Length); + + if (totalBlobsLength != blobsBundle.Blobs.Length) + { + error = $"Total blobs length mismatch. Expected {totalBlobsLength} but got {blobsBundle.Blobs.Length}"; + return false; + } + + if (totalBlobsLength != blobsBundle.Commitments.Length) + { + error = $"Total commitments length mismatch. Expected {totalBlobsLength} but got {blobsBundle.Commitments.Length}"; + return false; + } + + if (totalBlobsLength != blobsBundle.Proofs.Length) + { + error = $"Total proofs length mismatch. Expected {totalBlobsLength} but got {blobsBundle.Proofs.Length}"; + return false; + } + + if (!KzgPolynomialCommitments.AreProofsValid(blobsBundle.Proofs, blobsBundle.Commitments, blobsBundle.Blobs)) + { + error = "Invalid KZG proofs"; + return false; + } + + error = null; + + _logger.Info($"Validated blobs bundle with {totalBlobsLength} blobs, commitments: {blobsBundle.Commitments.Length}, proofs: {blobsBundle.Proofs.Length}"); + + return true; + } + + private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, ulong registerGasLimit, out string? error) + { + // TODO: Implement this method + error = null; + return true; + } + private bool ValidateBlock(Block block, BidTrace message, ulong registerGasLimit, out string? error) { error = null; @@ -48,6 +93,16 @@ private bool ValidateBlock(Block block, BidTrace message, ulong registerGasLimit return false; } + Address feeRecipient = message.ProposerFeeRecipient; + UInt256 expectedProfit = message.Value; + + if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, out error)) + { + return false; + } + + _logger.Info($"Validated block Hash: {block.Header.Hash} Number: {block.Header.Number} ParentHash: {block.Header.ParentHash}"); + return true; } @@ -66,6 +121,17 @@ public Task> ValidateSubmission(BuilderBloc return BlockValidationResult.Invalid($"Block {payload} coud not be parsed as a block"); } + if (block is not null && !ValidateBlock(block, request.BlockRequest.Message, request.RegisterGasLimit, out string? error)) + { + if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}. Error: {error}"); + return BlockValidationResult.Invalid(error ?? "Block validation failed"); + } + + if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) + { + if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); + return BlockValidationResult.Invalid(blobsError ?? "Blobs bundle validation failed"); + } return BlockValidationResult.Valid(); From 346330d394cc382deb31b06925c25b56f6e6f3dd Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 2 Sep 2024 18:24:10 +0530 Subject: [PATCH 004/113] create block processor --- .../Data/BuilderBlockValidationRequest.cs | 2 +- .../ValidateBuilderSubmissionHandler.cs | 79 +++++++++++++++++-- .../AuRaContractGasLimitOverride.cs | 2 +- .../ManualGasLimitCalculator.cs | 2 +- .../Nethermind.Consensus/FollowOtherMiners.cs | 2 +- .../IGasLimitCalculator.cs | 2 +- .../Processing/ReadOnlyTxProcessingEnv.cs | 2 +- .../TargetAdjustedGasLimitCalculator.cs | 4 +- .../OptimismGasLimitCalculator.cs | 2 +- 9 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs index 38b2fe3324f..c4bb08457e5 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs @@ -13,7 +13,7 @@ public class BuilderBlockValidationRequest /// public Hash256 ParentBeaconBlockRoot { get; set; } = Keccak.Zero; - public ulong RegisterGasLimit { get; set; } + public long RegisterGasLimit { get; set; } public SubmitBlockRequest BlockRequest { get; set; } } diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index 211dc66c6b1..e006a0a5986 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -3,23 +3,43 @@ using System.Linq; using System.Threading.Tasks; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Receipts; using Nethermind.BlockValidation.Data; +using Nethermind.Consensus; +using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Validators; +using Nethermind.Consensus.Withdrawals; using Nethermind.Core; using Nethermind.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; using Nethermind.JsonRpc; using Nethermind.Logging; using Nethermind.Merge.Plugin.Data; +using Nethermind.State; namespace Nethermind.BlockValidation.Handlers; public class ValidateSubmissionHandler { + private readonly ReadOnlyTxProcessingEnv _txProcessingEnv; + private readonly IBlockTree _blockTree; + private readonly IBlockValidator _blockValidator; + private readonly IGasLimitCalculator _gasLimitCalculator; private readonly ILogger _logger; - public ValidateSubmissionHandler(ILogManager logManager) + public ValidateSubmissionHandler( + IBlockValidator blockValidator, + ReadOnlyTxProcessingEnv txProcessingEnv, + IGasLimitCalculator gasLimitCalculator) { - _logger = logManager.GetClassLogger(); + _blockValidator = blockValidator; + _txProcessingEnv = txProcessingEnv; + _blockTree = _txProcessingEnv.BlockTree; + _gasLimitCalculator = gasLimitCalculator; + _logger = txProcessingEnv.LogManager!.GetClassLogger(); } private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobsBundle, out string? error) @@ -58,14 +78,63 @@ private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobs return true; } - private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, ulong registerGasLimit, out string? error) + private BlockProcessor CreateBlockProcessor(IWorldState stateProvider) { - // TODO: Implement this method + return new BlockProcessor( + _txProcessingEnv.SpecProvider, + _blockValidator, + new Consensus.Rewards.RewardCalculator(_txProcessingEnv.SpecProvider), + new BlockProcessor.BlockValidationTransactionsExecutor(_txProcessingEnv.TransactionProcessor, stateProvider), + stateProvider, + new InMemoryReceiptStorage(), + new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), + _txProcessingEnv.LogManager, + new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), + new ReceiptsRootCalculator() + ); + } + + private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, long registerGasLimit, out string? error) + { + if(!HeaderValidator.ValidateHash(block.Header)){ + error = $"Invalid block header hash {block.Header.Hash}"; + return false; + } + + if(!_blockTree.IsBetterThanHead(block.Header)){ + error = $"Block {block.Header.Hash} is not better than head"; + return false; + } + + BlockHeader? parentHeader = _blockTree.FindHeader(block.ParentHash!, BlockTreeLookupOptions.DoNotCreateLevelIfMissing); + + if (parentHeader is null){ + error = $"Parent header {block.ParentHash} not found"; + return false; + } + + long calculatedGasLimit = _gasLimitCalculator.GetGasLimit(parentHeader, registerGasLimit); + + if (calculatedGasLimit != block.Header.GasLimit){ + error = $"Gas limit mismatch. Expected {calculatedGasLimit} but got {block.Header.GasLimit}"; + return false; + } + + IReadOnlyTxProcessingScope processingScope = _txProcessingEnv.Build(parentHeader.StateRoot!); + IWorldState currentState = processingScope.WorldState; + + UInt256 feeRecipientBalanceBefore = currentState.GetBalance(feeRecipient); + + BlockProcessor blockProcessor = CreateBlockProcessor(currentState); + + + UInt256 feeRecipientBalanceAfter = currentState.GetBalance(feeRecipient); + error = null; return true; } - private bool ValidateBlock(Block block, BidTrace message, ulong registerGasLimit, out string? error) + private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, out string? error) { error = null; diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs index f83c7df2081..e300275893d 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs @@ -46,7 +46,7 @@ public AuRaContractGasLimitOverride( _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); } - public long GetGasLimit(BlockHeader parentHeader) => GetGasLimitFromContract(parentHeader) ?? _innerCalculator.GetGasLimit(parentHeader); + public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) => GetGasLimitFromContract(parentHeader) ?? _innerCalculator.GetGasLimit(parentHeader); private long? GetGasLimitFromContract(BlockHeader parentHeader) { diff --git a/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs b/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs index c5ef4bc8e31..31dc32d4c00 100644 --- a/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs @@ -8,6 +8,6 @@ namespace Nethermind.Consensus.Test public class ManualGasLimitCalculator : IGasLimitCalculator { public long GasLimit { get; set; } - public long GetGasLimit(BlockHeader parentHeader) => GasLimit; + public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) => GasLimit; } } diff --git a/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs b/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs index 96f46098512..639acc44583 100644 --- a/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs +++ b/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs @@ -15,7 +15,7 @@ public FollowOtherMiners(ISpecProvider specProvider) _specProvider = specProvider; } - public long GetGasLimit(BlockHeader parentHeader) + public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) { long gasLimit = parentHeader.GasLimit; long newBlockNumber = parentHeader.Number + 1; diff --git a/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs b/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs index 1660ef75aa7..ce010f94128 100644 --- a/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs @@ -7,6 +7,6 @@ namespace Nethermind.Consensus { public interface IGasLimitCalculator { - long GetGasLimit(BlockHeader parentHeader); + long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null); } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index 183a594d6d0..e04c3f06f18 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -19,7 +19,7 @@ public class ReadOnlyTxProcessingEnv : ReadOnlyTxProcessingEnvBase, IReadOnlyTxP protected readonly ILogManager _logManager; protected ITransactionProcessor? _transactionProcessor; - protected ITransactionProcessor TransactionProcessor + public ITransactionProcessor TransactionProcessor { get { diff --git a/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs b/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs index 9fc619e58d2..c4c26936f2e 100644 --- a/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs @@ -19,12 +19,12 @@ public TargetAdjustedGasLimitCalculator(ISpecProvider? specProvider, IBlocksConf _blocksConfig = miningConfig ?? throw new ArgumentNullException(nameof(miningConfig)); } - public long GetGasLimit(BlockHeader parentHeader) + public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) { long parentGasLimit = parentHeader.GasLimit; long gasLimit = parentGasLimit; - long? targetGasLimit = _blocksConfig.TargetBlockGasLimit; + long? targetGasLimit = desiredGasLimit ?? _blocksConfig.TargetBlockGasLimit; long newBlockNumber = parentHeader.Number + 1; IReleaseSpec spec = _specProvider.GetSpec(newBlockNumber, parentHeader.Timestamp); // taking the parent timestamp is a temporary solution if (targetGasLimit is not null) diff --git a/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs b/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs index 5e5a6932e95..0c30768ed99 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs @@ -9,6 +9,6 @@ namespace Nethermind.Optimism; public class OptimismGasLimitCalculator : IGasLimitCalculator { - public long GetGasLimit(BlockHeader parentHeader) => + public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) => throw new InvalidOperationException("GasLimit in Optimism should come from payload attributes."); } From b802039f5480f0b6dc830fd104379604ddb20930 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Wed, 4 Sep 2024 15:34:57 +0530 Subject: [PATCH 005/113] add modal validate payload --- .../ValidateBuilderSubmissionHandler.cs | 120 +++++++++++++++++- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index e006a0a5986..6e717e21c15 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Nethermind.Blockchain; @@ -12,7 +14,10 @@ using Nethermind.Consensus.Validators; using Nethermind.Consensus.Withdrawals; using Nethermind.Core; +using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.Evm; +using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; using Nethermind.JsonRpc; @@ -30,6 +35,8 @@ public class ValidateSubmissionHandler private readonly IGasLimitCalculator _gasLimitCalculator; private readonly ILogger _logger; + private readonly IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); + public ValidateSubmissionHandler( IBlockValidator blockValidator, ReadOnlyTxProcessingEnv txProcessingEnv, @@ -86,7 +93,7 @@ private BlockProcessor CreateBlockProcessor(IWorldState stateProvider) new Consensus.Rewards.RewardCalculator(_txProcessingEnv.SpecProvider), new BlockProcessor.BlockValidationTransactionsExecutor(_txProcessingEnv.TransactionProcessor, stateProvider), stateProvider, - new InMemoryReceiptStorage(), + _receiptStorage, new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), _txProcessingEnv.LogManager, new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), @@ -94,7 +101,17 @@ private BlockProcessor CreateBlockProcessor(IWorldState stateProvider) ); } - private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, long registerGasLimit, out string? error) + private static void FinalizeStateAndBlock(IWorldState stateProvider, Block processedBlock, IReleaseSpec currentSpec, Block currentBlock, IBlockTree blockTree) + { + stateProvider.StateRoot = processedBlock.StateRoot!; + stateProvider.Commit(currentSpec); + stateProvider.CommitTree(currentBlock.Number); + blockTree.SuggestBlock(processedBlock, BlockTreeSuggestOptions.ForceSetAsMain); + blockTree.UpdateHeadBlock(processedBlock.Hash!); + } + + + private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, long registerGasLimit, bool useBalanceDiffProfit, bool excludeWithdrawals, out string? error) { if(!HeaderValidator.ValidateHash(block.Header)){ error = $"Invalid block header hash {block.Header.Hash}"; @@ -127,9 +144,106 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected BlockProcessor blockProcessor = CreateBlockProcessor(currentState); + List suggestedBlocks = [block]; + BlockReceiptsTracer blockReceiptsTracer = new (); + + ProcessingOptions processingOptions = new ProcessingOptions(); + + try + { + Block processedBlock = blockProcessor.Process(currentState.StateRoot, suggestedBlocks, processingOptions, blockReceiptsTracer)[0]; + FinalizeStateAndBlock(currentState, processedBlock, _txProcessingEnv.SpecProvider.GetSpec(parentHeader) , block, _blockTree); + } + catch (Exception e) + { + error = $"Block processing failed: {e.Message}"; + return false; + } UInt256 feeRecipientBalanceAfter = currentState.GetBalance(feeRecipient); + UInt256 amtBeforeOrWithdrawn = feeRecipientBalanceBefore; + + if (excludeWithdrawals) + { + foreach(Withdrawal withdrawal in block.Withdrawals ?? []) + { + if (withdrawal.Address == feeRecipient) + { + amtBeforeOrWithdrawn += withdrawal.AmountInGwei; + } + } + } + + if(!_blockValidator.ValidateSuggestedBlock(block, out error)){ + return false; + } + + // validate proposer payment + + if (useBalanceDiffProfit && feeRecipientBalanceAfter >= amtBeforeOrWithdrawn) + { + UInt256 feeRecipientBalanceDelta = feeRecipientBalanceAfter - amtBeforeOrWithdrawn; + if (feeRecipientBalanceDelta >= expectedProfit) + { + if(feeRecipientBalanceDelta > expectedProfit) + { + _logger.Warn($"Builder claimed profit is lower than calculated profit. Expected {expectedProfit} but actual {feeRecipientBalanceDelta}"); + } + return true; + } + _logger.Warn($"Proposer payment is not enough, trying last tx payment validation, expected: {expectedProfit}, actual: {feeRecipientBalanceDelta}"); + } + + TxReceipt[] receipts = block.Hash != null ? _receiptStorage.Get(block.Hash) : []; + + if (receipts.Length == 0) + { + error = "No proposer payment receipt"; + return false; + } + + TxReceipt lastReceipt = receipts[^1]; + + if (lastReceipt.StatusCode != StatusCode.Success) + { + error = $"Proposer payment failed "; + return false; + } + + int txIndex = lastReceipt.Index; + + if (txIndex+1 != block.Transactions.Length) + { + error = $"Proposer payment index not last transaction in the block({txIndex} of {block.Transactions.Length-1})"; + return false; + } + + Transaction paymentTx = block.Transactions[txIndex]; + + if (paymentTx.To != feeRecipient) + { + error = $"Proposer payment transaction recipient is not the proposer,received {paymentTx.To} expected {feeRecipient}"; + return false; + } + + if (paymentTx.Value != expectedProfit) + { + error = $"Proposer payment transaction value is not the expected profit, received {paymentTx.Value} expected {expectedProfit}"; + return false; + } + + if (paymentTx.Data != null && paymentTx.Data.Value.Length != 0) + { + error = "Proposer payment transaction data is not empty"; + return false; + } + + if (paymentTx.GasPrice != block.BaseFeePerGas) + { + error = "Malformed proposer payment, gas price not equal to base fee"; + return false; + } error = null; return true; } @@ -165,7 +279,7 @@ private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, Address feeRecipient = message.ProposerFeeRecipient; UInt256 expectedProfit = message.Value; - if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, out error)) + if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, false, false, out error)) // TODO: exclude withdrawals and useBalanceDiffProfit config option for the APIs { return false; } From 6ad5909021274723e9f3d4ee8effd2d28beaceed Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Wed, 4 Sep 2024 15:35:20 +0530 Subject: [PATCH 006/113] format files --- .../ValidateBuilderSubmissionHandler.cs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index 6e717e21c15..414032c6ea1 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -111,28 +111,32 @@ private static void FinalizeStateAndBlock(IWorldState stateProvider, Block proce } - private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, long registerGasLimit, bool useBalanceDiffProfit, bool excludeWithdrawals, out string? error) + private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, long registerGasLimit, bool useBalanceDiffProfit, bool excludeWithdrawals, out string? error) { - if(!HeaderValidator.ValidateHash(block.Header)){ + if (!HeaderValidator.ValidateHash(block.Header)) + { error = $"Invalid block header hash {block.Header.Hash}"; return false; } - if(!_blockTree.IsBetterThanHead(block.Header)){ + if (!_blockTree.IsBetterThanHead(block.Header)) + { error = $"Block {block.Header.Hash} is not better than head"; return false; } BlockHeader? parentHeader = _blockTree.FindHeader(block.ParentHash!, BlockTreeLookupOptions.DoNotCreateLevelIfMissing); - if (parentHeader is null){ + if (parentHeader is null) + { error = $"Parent header {block.ParentHash} not found"; return false; } long calculatedGasLimit = _gasLimitCalculator.GetGasLimit(parentHeader, registerGasLimit); - if (calculatedGasLimit != block.Header.GasLimit){ + if (calculatedGasLimit != block.Header.GasLimit) + { error = $"Gas limit mismatch. Expected {calculatedGasLimit} but got {block.Header.GasLimit}"; return false; } @@ -145,14 +149,14 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected BlockProcessor blockProcessor = CreateBlockProcessor(currentState); List suggestedBlocks = [block]; - BlockReceiptsTracer blockReceiptsTracer = new (); + BlockReceiptsTracer blockReceiptsTracer = new(); ProcessingOptions processingOptions = new ProcessingOptions(); - try - { + try + { Block processedBlock = blockProcessor.Process(currentState.StateRoot, suggestedBlocks, processingOptions, blockReceiptsTracer)[0]; - FinalizeStateAndBlock(currentState, processedBlock, _txProcessingEnv.SpecProvider.GetSpec(parentHeader) , block, _blockTree); + FinalizeStateAndBlock(currentState, processedBlock, _txProcessingEnv.SpecProvider.GetSpec(parentHeader), block, _blockTree); } catch (Exception e) { @@ -166,7 +170,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected if (excludeWithdrawals) { - foreach(Withdrawal withdrawal in block.Withdrawals ?? []) + foreach (Withdrawal withdrawal in block.Withdrawals ?? []) { if (withdrawal.Address == feeRecipient) { @@ -175,7 +179,8 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected } } - if(!_blockValidator.ValidateSuggestedBlock(block, out error)){ + if (!_blockValidator.ValidateSuggestedBlock(block, out error)) + { return false; } @@ -186,7 +191,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected UInt256 feeRecipientBalanceDelta = feeRecipientBalanceAfter - amtBeforeOrWithdrawn; if (feeRecipientBalanceDelta >= expectedProfit) { - if(feeRecipientBalanceDelta > expectedProfit) + if (feeRecipientBalanceDelta > expectedProfit) { _logger.Warn($"Builder claimed profit is lower than calculated profit. Expected {expectedProfit} but actual {feeRecipientBalanceDelta}"); } @@ -213,9 +218,9 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected int txIndex = lastReceipt.Index; - if (txIndex+1 != block.Transactions.Length) + if (txIndex + 1 != block.Transactions.Length) { - error = $"Proposer payment index not last transaction in the block({txIndex} of {block.Transactions.Length-1})"; + error = $"Proposer payment index not last transaction in the block({txIndex} of {block.Transactions.Length - 1})"; return false; } @@ -239,7 +244,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return false; } - if (paymentTx.GasPrice != block.BaseFeePerGas) + if (paymentTx.GasPrice != block.BaseFeePerGas) { error = "Malformed proposer payment, gas price not equal to base fee"; return false; @@ -279,7 +284,7 @@ private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, Address feeRecipient = message.ProposerFeeRecipient; UInt256 expectedProfit = message.Value; - if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, false, false, out error)) // TODO: exclude withdrawals and useBalanceDiffProfit config option for the APIs + if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, false, false, out error)) // TODO: exclude withdrawals and useBalanceDiffProfit config option for the APIs { return false; } From 256da82a0cd0f6c5f11f3aef7a714785b3e317cd Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 5 Sep 2024 13:50:52 +0530 Subject: [PATCH 007/113] add hook step --- .../BlockValidation.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs index c7d20d71abe..0567e3583d7 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs @@ -1,24 +1,46 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Api.Extensions; +using Nethermind.BlockValidation.Handlers; +using Nethermind.Consensus.Processing; +using Nethermind.JsonRpc.Modules; namespace Nethermind.BlockValidation; public class BlockValidation : INethermindPlugin { + protected INethermindApi _api = null!; public virtual string Name => "BlockValidation"; public virtual string Description => "BlockValidation"; public string Author => "Nethermind"; public Task InitRpcModules() { + ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv( + _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), + _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), + _api.SpecProvider, + _api.LogManager + ); + ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( + _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), + readOnlyTxProcessingEnv, + _api.GasLimitCalculator ?? throw new ArgumentNullException(nameof(_api.GasLimitCalculator)) + ); + IFlashbotsRpcModule flashbotsRpcModule = new FlashbotsRpcModule(validateSubmissionHandler); + + ArgumentNullException.ThrowIfNull(_api.RpcModuleProvider); + _api.RpcModuleProvider.RegisterSingle(flashbotsRpcModule); + return Task.CompletedTask; } public Task Init(INethermindApi api) { + _api = api; return Task.CompletedTask; } From 09b46b4a675cc50efea9b8384253eb1be81d6641 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 5 Sep 2024 14:45:39 +0530 Subject: [PATCH 008/113] add config --- .../Nethermind.BlockValidation/BlockValidation.cs | 9 +++++++-- .../BlockValidationConfig.cs | 13 +++++++++++++ .../Handlers/ValidateBuilderSubmissionHandler.cs | 8 ++++++-- .../IBlockValidationConfig.cs | 15 +++++++++++++++ 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs create mode 100644 src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs index 0567e3583d7..7bcdbe13c06 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs @@ -13,7 +13,10 @@ namespace Nethermind.BlockValidation; public class BlockValidation : INethermindPlugin { - protected INethermindApi _api = null!; + private INethermindApi _api = null!; + + private IBlockValidationConfig _blockValidationConfig = null!; + public virtual string Name => "BlockValidation"; public virtual string Description => "BlockValidation"; public string Author => "Nethermind"; @@ -28,7 +31,8 @@ public Task InitRpcModules() ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), readOnlyTxProcessingEnv, - _api.GasLimitCalculator ?? throw new ArgumentNullException(nameof(_api.GasLimitCalculator)) + _api.GasLimitCalculator ?? throw new ArgumentNullException(nameof(_api.GasLimitCalculator)), + _blockValidationConfig ); IFlashbotsRpcModule flashbotsRpcModule = new FlashbotsRpcModule(validateSubmissionHandler); @@ -41,6 +45,7 @@ public Task InitRpcModules() public Task Init(INethermindApi api) { _api = api; + _blockValidationConfig = api.Config(); return Task.CompletedTask; } diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs new file mode 100644 index 00000000000..d3e73d6b5fb --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Config; + +namespace Nethermind.BlockValidation; + +public class BlockValidationConfig: IBlockValidationConfig +{ + public bool UseBalanceDiffProfit { get; set; } = false ; + + public bool ExcludeWithdrawals { get; set; } = false; +} diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index 414032c6ea1..f56d6f4f37d 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -35,18 +35,22 @@ public class ValidateSubmissionHandler private readonly IGasLimitCalculator _gasLimitCalculator; private readonly ILogger _logger; + private readonly IBlockValidationConfig _blockValidationConfig; + private readonly IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); public ValidateSubmissionHandler( IBlockValidator blockValidator, ReadOnlyTxProcessingEnv txProcessingEnv, - IGasLimitCalculator gasLimitCalculator) + IGasLimitCalculator gasLimitCalculator, + IBlockValidationConfig blockValidationConfig) { _blockValidator = blockValidator; _txProcessingEnv = txProcessingEnv; _blockTree = _txProcessingEnv.BlockTree; _gasLimitCalculator = gasLimitCalculator; _logger = txProcessingEnv.LogManager!.GetClassLogger(); + _blockValidationConfig = blockValidationConfig; } private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobsBundle, out string? error) @@ -284,7 +288,7 @@ private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, Address feeRecipient = message.ProposerFeeRecipient; UInt256 expectedProfit = message.Value; - if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, false, false, out error)) // TODO: exclude withdrawals and useBalanceDiffProfit config option for the APIs + if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, _blockValidationConfig.UseBalanceDiffProfit, _blockValidationConfig.ExcludeWithdrawals, out error)) { return false; } diff --git a/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs b/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs new file mode 100644 index 00000000000..9d77aaf6e5f --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Config; + +namespace Nethermind.BlockValidation; + +public interface IBlockValidationConfig: IConfig +{ + [ConfigItem(Description = "If set to true, proposer payment is calculated as a balance difference of the fee recipient", DefaultValue = "false")] + public bool UseBalanceDiffProfit { get; set; } + + [ConfigItem(Description = "If set to true, withdrawals to the fee recipient are excluded from the balance delta", DefaultValue = "false")] + public bool ExcludeWithdrawals { get; set; } +} From 621e2973a40b5c1235445a5fdd8b7379181a8925 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 5 Sep 2024 14:47:23 +0530 Subject: [PATCH 009/113] format files --- .../Nethermind.BlockValidation/BlockValidationConfig.cs | 4 ++-- .../Nethermind.BlockValidation/IBlockValidationConfig.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs index d3e73d6b5fb..b4c49ec3fc9 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs @@ -5,9 +5,9 @@ namespace Nethermind.BlockValidation; -public class BlockValidationConfig: IBlockValidationConfig +public class BlockValidationConfig : IBlockValidationConfig { - public bool UseBalanceDiffProfit { get; set; } = false ; + public bool UseBalanceDiffProfit { get; set; } = false; public bool ExcludeWithdrawals { get; set; } = false; } diff --git a/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs b/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs index 9d77aaf6e5f..65106d17aa6 100644 --- a/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs +++ b/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs @@ -5,7 +5,7 @@ namespace Nethermind.BlockValidation; -public interface IBlockValidationConfig: IConfig +public interface IBlockValidationConfig : IConfig { [ConfigItem(Description = "If set to true, proposer payment is calculated as a balance difference of the fee recipient", DefaultValue = "false")] public bool UseBalanceDiffProfit { get; set; } From ffc25f04e197ebc3f50222afa1b6060941491b5e Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 12 Sep 2024 15:24:25 +0530 Subject: [PATCH 010/113] address PR comments --- .../Nethermind.Api/Extensions/PluginConfig.cs | 2 +- .../BlockValidation.cs | 12 +- .../ValidateBuilderSubmissionHandler.cs | 288 ++++++++++-------- .../Flashbots}/FlashbotsRpcModule.cs | 2 +- .../Flashbots/FlashbotsRpcModuleFactory.cs | 21 ++ .../Flashbots}/IFlashbotsRpcModule.cs | 4 +- .../AuRaContractGasLimitOverride.cs | 2 +- .../ManualGasLimitCalculator.cs | 2 +- .../Nethermind.Consensus/FollowOtherMiners.cs | 2 +- .../IGasLimitCalculator.cs | 2 +- .../Processing/ReadOnlyTxProcessingEnv.cs | 2 +- .../TargetAdjustedGasLimitCalculator.cs | 4 +- .../Nethermind.JsonRpc/IJsonRpcConfig.cs | 9 + .../Nethermind.JsonRpc/JsonRpcConfig.cs | 1 + .../OptimismGasLimitCalculator.cs | 2 +- 15 files changed, 220 insertions(+), 135 deletions(-) rename src/Nethermind/Nethermind.BlockValidation/{ => Modules/Flashbots}/FlashbotsRpcModule.cs (93%) create mode 100644 src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs rename src/Nethermind/Nethermind.BlockValidation/{ => Modules/Flashbots}/IFlashbotsRpcModule.cs (87%) diff --git a/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs b/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs index 43b49b27342..7e00a7f8f6f 100644 --- a/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs +++ b/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs @@ -5,5 +5,5 @@ namespace Nethermind.Api.Extensions; public class PluginConfig : IPluginConfig { - public string[] PluginOrder { get; set; } = { "Clique", "Aura", "Ethash", "Optimism", "AuRaMerge", "Merge", "MEV", "HealthChecks", "Hive" }; + public string[] PluginOrder { get; set; } = { "Clique", "Aura", "Ethash", "Optimism", "AuRaMerge", "Merge", "BlockValidation", "MEV", "HealthChecks", "Hive" }; } diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs index 7bcdbe13c06..62a004ea45c 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs @@ -6,7 +6,9 @@ using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.BlockValidation.Handlers; +using Nethermind.BlockValidation.Modules.Flashbots; using Nethermind.Consensus.Processing; +using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; namespace Nethermind.BlockValidation; @@ -17,6 +19,8 @@ public class BlockValidation : INethermindPlugin private IBlockValidationConfig _blockValidationConfig = null!; + private IJsonRpcConfig _jsonRpcConfig = null!; + public virtual string Name => "BlockValidation"; public virtual string Description => "BlockValidation"; public string Author => "Nethermind"; @@ -31,13 +35,14 @@ public Task InitRpcModules() ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), readOnlyTxProcessingEnv, - _api.GasLimitCalculator ?? throw new ArgumentNullException(nameof(_api.GasLimitCalculator)), _blockValidationConfig ); - IFlashbotsRpcModule flashbotsRpcModule = new FlashbotsRpcModule(validateSubmissionHandler); + + ModuleFactoryBase flashbotsRpcModule = new FlashbotsRpcModuleFactory(validateSubmissionHandler); ArgumentNullException.ThrowIfNull(_api.RpcModuleProvider); - _api.RpcModuleProvider.RegisterSingle(flashbotsRpcModule); + _api.RpcModuleProvider.RegisterBounded(flashbotsRpcModule, + _jsonRpcConfig.EthModuleConcurrentInstances ?? Environment.ProcessorCount, _jsonRpcConfig.Timeout); return Task.CompletedTask; } @@ -46,6 +51,7 @@ public Task Init(INethermindApi api) { _api = api; _blockValidationConfig = api.Config(); + _jsonRpcConfig = api.Config(); return Task.CompletedTask; } diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index f56d6f4f37d..c590aa346b2 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -29,10 +29,13 @@ namespace Nethermind.BlockValidation.Handlers; public class ValidateSubmissionHandler { + private const ProcessingOptions ValidateSubmissionProcessingOptions = ProcessingOptions.ReadOnlyChain + | ProcessingOptions.IgnoreParentNotOnMainChain + | ProcessingOptions.ForceProcessing; + private readonly ReadOnlyTxProcessingEnv _txProcessingEnv; private readonly IBlockTree _blockTree; private readonly IBlockValidator _blockValidator; - private readonly IGasLimitCalculator _gasLimitCalculator; private readonly ILogger _logger; private readonly IBlockValidationConfig _blockValidationConfig; @@ -42,17 +45,87 @@ public class ValidateSubmissionHandler public ValidateSubmissionHandler( IBlockValidator blockValidator, ReadOnlyTxProcessingEnv txProcessingEnv, - IGasLimitCalculator gasLimitCalculator, IBlockValidationConfig blockValidationConfig) { _blockValidator = blockValidator; _txProcessingEnv = txProcessingEnv; _blockTree = _txProcessingEnv.BlockTree; - _gasLimitCalculator = gasLimitCalculator; _logger = txProcessingEnv.LogManager!.GetClassLogger(); _blockValidationConfig = blockValidationConfig; } + public Task> ValidateSubmission(BuilderBlockValidationRequest request) + { + ExecutionPayload payload = request.BlockRequest.ExecutionPayload; + BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; + + string payloadStr = $"BuilderBlock: {payload}"; + + _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length}"); + + if (!payload.TryGetBlock(out Block? block)) + { + if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}."); + return BlockValidationResult.Invalid($"Block {payload} coud not be parsed as a block"); + } + + if (block is not null && !ValidateBlock(block, request.BlockRequest.Message, request.RegisterGasLimit, out string? error)) + { + if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}. Error: {error}"); + return BlockValidationResult.Invalid(error ?? "Block validation failed"); + } + + if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) + { + if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); + return BlockValidationResult.Invalid(blobsError ?? "Blobs bundle validation failed"); + } + + + return BlockValidationResult.Valid(); + } + + private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, out string? error) + { + error = null; + + if (message.ParentHash != block.Header.ParentHash) + { + error = $"Parent hash mismatch. Expected {message.ParentHash} but got {block.Header.ParentHash}"; + return false; + } + + if (message.BlockHash != block.Header.Hash) + { + error = $"Block hash mismatch. Expected {message.BlockHash} but got {block.Header.Hash}"; + return false; + } + + if (message.GasLimit != block.GasLimit) + { + error = $"Gas limit mismatch. Expected {message.GasLimit} but got {block.GasLimit}"; + return false; + } + + if (message.GasUsed != block.GasUsed) + { + error = $"Gas used mismatch. Expected {message.GasUsed} but got {block.GasUsed}"; + return false; + } + + Address feeRecipient = message.ProposerFeeRecipient; + UInt256 expectedProfit = message.Value; + + if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, _blockValidationConfig.UseBalanceDiffProfit, _blockValidationConfig.ExcludeWithdrawals, out error)) + { + return false; + } + + _logger.Info($"Validated block Hash: {block.Header.Hash} Number: {block.Header.Number} ParentHash: {block.Header.ParentHash}"); + + return true; + } + private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobsBundle, out string? error) { // get sum of length of blobs of each transaction @@ -89,46 +162,8 @@ private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobs return true; } - private BlockProcessor CreateBlockProcessor(IWorldState stateProvider) - { - return new BlockProcessor( - _txProcessingEnv.SpecProvider, - _blockValidator, - new Consensus.Rewards.RewardCalculator(_txProcessingEnv.SpecProvider), - new BlockProcessor.BlockValidationTransactionsExecutor(_txProcessingEnv.TransactionProcessor, stateProvider), - stateProvider, - _receiptStorage, - new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), - _txProcessingEnv.LogManager, - new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), - new ReceiptsRootCalculator() - ); - } - - private static void FinalizeStateAndBlock(IWorldState stateProvider, Block processedBlock, IReleaseSpec currentSpec, Block currentBlock, IBlockTree blockTree) - { - stateProvider.StateRoot = processedBlock.StateRoot!; - stateProvider.Commit(currentSpec); - stateProvider.CommitTree(currentBlock.Number); - blockTree.SuggestBlock(processedBlock, BlockTreeSuggestOptions.ForceSetAsMain); - blockTree.UpdateHeadBlock(processedBlock.Hash!); - } - - private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expectedProfit, long registerGasLimit, bool useBalanceDiffProfit, bool excludeWithdrawals, out string? error) { - if (!HeaderValidator.ValidateHash(block.Header)) - { - error = $"Invalid block header hash {block.Header.Hash}"; - return false; - } - - if (!_blockTree.IsBetterThanHead(block.Header)) - { - error = $"Block {block.Header.Hash} is not better than head"; - return false; - } - BlockHeader? parentHeader = _blockTree.FindHeader(block.ParentHash!, BlockTreeLookupOptions.DoNotCreateLevelIfMissing); if (parentHeader is null) @@ -137,29 +172,26 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return false; } - long calculatedGasLimit = _gasLimitCalculator.GetGasLimit(parentHeader, registerGasLimit); - - if (calculatedGasLimit != block.Header.GasLimit) + if (!ValidateBlockMetadata(block, registerGasLimit, parentHeader, out error)) { - error = $"Gas limit mismatch. Expected {calculatedGasLimit} but got {block.Header.GasLimit}"; return false; } + IReadOnlyTxProcessingScope processingScope = _txProcessingEnv.Build(parentHeader.StateRoot!); IWorldState currentState = processingScope.WorldState; + ITransactionProcessor transactionProcessor = processingScope.TransactionProcessor; UInt256 feeRecipientBalanceBefore = currentState.GetBalance(feeRecipient); - BlockProcessor blockProcessor = CreateBlockProcessor(currentState); + BlockProcessor blockProcessor = CreateBlockProcessor(currentState, transactionProcessor); List suggestedBlocks = [block]; BlockReceiptsTracer blockReceiptsTracer = new(); - ProcessingOptions processingOptions = new ProcessingOptions(); - try { - Block processedBlock = blockProcessor.Process(currentState.StateRoot, suggestedBlocks, processingOptions, blockReceiptsTracer)[0]; + Block processedBlock = blockProcessor.Process(currentState.StateRoot, suggestedBlocks, ValidateSubmissionProcessingOptions, blockReceiptsTracer)[0]; FinalizeStateAndBlock(currentState, processedBlock, _txProcessingEnv.SpecProvider.GetSpec(parentHeader), block, _blockTree); } catch (Exception e) @@ -188,6 +220,64 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return false; } + if (ValidateProposerPayment(expectedProfit, useBalanceDiffProfit, feeRecipientBalanceAfter, amtBeforeOrWithdrawn)) return true; + + if (!ValidateProcessedBlock(block, feeRecipient, expectedProfit, out error)) + { + return false; + } + + error = null; + return true; + } + + private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHeader parentHeader, out string? error) + { + if (!HeaderValidator.ValidateHash(block.Header)) + { + error = $"Invalid block header hash {block.Header.Hash}"; + return false; + } + + if (!_blockTree.IsBetterThanHead(block.Header)) + { + error = $"Block {block.Header.Hash} is not better than head"; + return false; + } + + long calculatedGasLimit = GetGasLimit(parentHeader, registerGasLimit); + + if (calculatedGasLimit != block.Header.GasLimit) + { + error = $"Gas limit mismatch. Expected {calculatedGasLimit} but got {block.Header.GasLimit}"; + return false; + } + error = null; + return true; + } + + private long GetGasLimit(BlockHeader parentHeader, long desiredGasLimit) + { + long parentGasLimit = parentHeader.GasLimit; + long gasLimit = parentGasLimit; + + long? targetGasLimit = desiredGasLimit; + long newBlockNumber = parentHeader.Number + 1; + IReleaseSpec spec = _txProcessingEnv.SpecProvider.GetSpec(newBlockNumber, parentHeader.Timestamp); + if (targetGasLimit is not null) + { + long maxGasLimitDifference = Math.Max(0, parentGasLimit / spec.GasLimitBoundDivisor - 1); + gasLimit = targetGasLimit.Value > parentGasLimit + ? parentGasLimit + Math.Min(targetGasLimit.Value - parentGasLimit, maxGasLimitDifference) + : parentGasLimit - Math.Min(parentGasLimit - targetGasLimit.Value, maxGasLimitDifference); + } + + gasLimit = Eip1559GasLimitAdjuster.AdjustGasLimit(spec, gasLimit, newBlockNumber); + return gasLimit; + } + + private bool ValidateProposerPayment(UInt256 expectedProfit, bool useBalanceDiffProfit, UInt256 feeRecipientBalanceAfter, UInt256 amtBeforeOrWithdrawn) + { // validate proposer payment if (useBalanceDiffProfit && feeRecipientBalanceAfter >= amtBeforeOrWithdrawn) @@ -204,7 +294,12 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected _logger.Warn($"Proposer payment is not enough, trying last tx payment validation, expected: {expectedProfit}, actual: {feeRecipientBalanceDelta}"); } - TxReceipt[] receipts = block.Hash != null ? _receiptStorage.Get(block.Hash) : []; + return false; + } + + private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, UInt256 expectedProfit, out string? error) + { + TxReceipt[] receipts = processedBlock.Hash != null ? _receiptStorage.Get(processedBlock.Hash) : []; if (receipts.Length == 0) { @@ -222,13 +317,13 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected int txIndex = lastReceipt.Index; - if (txIndex + 1 != block.Transactions.Length) + if (txIndex + 1 != processedBlock.Transactions.Length) { - error = $"Proposer payment index not last transaction in the block({txIndex} of {block.Transactions.Length - 1})"; + error = $"Proposer payment index not last transaction in the block({txIndex} of {processedBlock.Transactions.Length - 1})"; return false; } - Transaction paymentTx = block.Transactions[txIndex]; + Transaction paymentTx = processedBlock.Transactions[txIndex]; if (paymentTx.To != feeRecipient) { @@ -248,7 +343,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return false; } - if (paymentTx.GasPrice != block.BaseFeePerGas) + if (paymentTx.GasPrice != processedBlock.BaseFeePerGas) { error = "Malformed proposer payment, gas price not equal to base fee"; return false; @@ -257,75 +352,28 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return true; } - private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, out string? error) + private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransactionProcessor transactionProcessor) { - error = null; - - if (message.ParentHash != block.Header.ParentHash) - { - error = $"Parent hash mismatch. Expected {message.ParentHash} but got {block.Header.ParentHash}"; - return false; - } - - if (message.BlockHash != block.Header.Hash) - { - error = $"Block hash mismatch. Expected {message.BlockHash} but got {block.Header.Hash}"; - return false; - } - - if (message.GasLimit != block.GasLimit) - { - error = $"Gas limit mismatch. Expected {message.GasLimit} but got {block.GasLimit}"; - return false; - } - - if (message.GasUsed != block.GasUsed) - { - error = $"Gas used mismatch. Expected {message.GasUsed} but got {block.GasUsed}"; - return false; - } - - Address feeRecipient = message.ProposerFeeRecipient; - UInt256 expectedProfit = message.Value; - - if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, _blockValidationConfig.UseBalanceDiffProfit, _blockValidationConfig.ExcludeWithdrawals, out error)) - { - return false; - } - - _logger.Info($"Validated block Hash: {block.Header.Hash} Number: {block.Header.Number} ParentHash: {block.Header.ParentHash}"); - - return true; + return new BlockProcessor( + _txProcessingEnv.SpecProvider, + _blockValidator, + new Consensus.Rewards.RewardCalculator(_txProcessingEnv.SpecProvider), + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), + stateProvider, + _receiptStorage, + new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), + _txProcessingEnv.LogManager, + new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), + new ReceiptsRootCalculator() + ); } - public Task> ValidateSubmission(BuilderBlockValidationRequest request) + private static void FinalizeStateAndBlock(IWorldState stateProvider, Block processedBlock, IReleaseSpec currentSpec, Block currentBlock, IBlockTree blockTree) { - ExecutionPayload payload = request.BlockRequest.ExecutionPayload; - BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; - - string payloadStr = $"BuilderBlock: {payload}"; - - _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length}"); - - if (!payload.TryGetBlock(out Block? block)) - { - if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}."); - return BlockValidationResult.Invalid($"Block {payload} coud not be parsed as a block"); - } - - if (block is not null && !ValidateBlock(block, request.BlockRequest.Message, request.RegisterGasLimit, out string? error)) - { - if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}. Error: {error}"); - return BlockValidationResult.Invalid(error ?? "Block validation failed"); - } - - if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) - { - if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); - return BlockValidationResult.Invalid(blobsError ?? "Blobs bundle validation failed"); - } - - - return BlockValidationResult.Valid(); + stateProvider.StateRoot = processedBlock.StateRoot!; + stateProvider.Commit(currentSpec); + stateProvider.CommitTree(currentBlock.Number); + blockTree.SuggestBlock(processedBlock, BlockTreeSuggestOptions.ForceSetAsMain); + blockTree.UpdateHeadBlock(processedBlock.Hash!); } } diff --git a/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModule.cs similarity index 93% rename from src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs rename to src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModule.cs index d8e02044e9e..9f2b58b36ea 100644 --- a/src/Nethermind/Nethermind.BlockValidation/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModule.cs @@ -6,7 +6,7 @@ using Nethermind.BlockValidation.Handlers; using Nethermind.JsonRpc; -namespace Nethermind.BlockValidation; +namespace Nethermind.BlockValidation.Modules.Flashbots; public class FlashbotsRpcModule : IFlashbotsRpcModule { diff --git a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs new file mode 100644 index 00000000000..9ccdc70a731 --- /dev/null +++ b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.BlockValidation.Handlers; +using Nethermind.JsonRpc.Modules; + +namespace Nethermind.BlockValidation.Modules.Flashbots +{ + public class FlashbotsRpcModuleFactory( + ValidateSubmissionHandler validateSubmissionHandler + ): ModuleFactoryBase + { + private readonly ValidateSubmissionHandler _validateSubmissionHandler = validateSubmissionHandler ?? throw new ArgumentNullException(nameof(validateSubmissionHandler)); + + public override IFlashbotsRpcModule Create() + { + return new FlashbotsRpcModule(_validateSubmissionHandler); + } + } +} diff --git a/src/Nethermind/Nethermind.BlockValidation/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/IFlashbotsRpcModule.cs similarity index 87% rename from src/Nethermind/Nethermind.BlockValidation/IFlashbotsRpcModule.cs rename to src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/IFlashbotsRpcModule.cs index f764fed0ed5..6abe67edbcf 100644 --- a/src/Nethermind/Nethermind.BlockValidation/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -6,14 +6,14 @@ using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; -namespace Nethermind.BlockValidation; +namespace Nethermind.BlockValidation.Modules.Flashbots; [RpcModule(ModuleType.Flashbots)] public interface IFlashbotsRpcModule : IRpcModule { [JsonRpcMethod( Description = " validate the builder submissions as received by a relay", - IsSharable = true, + IsSharable = false, IsImplemented = true)] Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs index e300275893d..f83c7df2081 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaContractGasLimitOverride.cs @@ -46,7 +46,7 @@ public AuRaContractGasLimitOverride( _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); } - public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) => GetGasLimitFromContract(parentHeader) ?? _innerCalculator.GetGasLimit(parentHeader); + public long GetGasLimit(BlockHeader parentHeader) => GetGasLimitFromContract(parentHeader) ?? _innerCalculator.GetGasLimit(parentHeader); private long? GetGasLimitFromContract(BlockHeader parentHeader) { diff --git a/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs b/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs index 31dc32d4c00..c5ef4bc8e31 100644 --- a/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus.Test/ManualGasLimitCalculator.cs @@ -8,6 +8,6 @@ namespace Nethermind.Consensus.Test public class ManualGasLimitCalculator : IGasLimitCalculator { public long GasLimit { get; set; } - public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) => GasLimit; + public long GetGasLimit(BlockHeader parentHeader) => GasLimit; } } diff --git a/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs b/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs index 639acc44583..96f46098512 100644 --- a/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs +++ b/src/Nethermind/Nethermind.Consensus/FollowOtherMiners.cs @@ -15,7 +15,7 @@ public FollowOtherMiners(ISpecProvider specProvider) _specProvider = specProvider; } - public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) + public long GetGasLimit(BlockHeader parentHeader) { long gasLimit = parentHeader.GasLimit; long newBlockNumber = parentHeader.Number + 1; diff --git a/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs b/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs index ce010f94128..1660ef75aa7 100644 --- a/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus/IGasLimitCalculator.cs @@ -7,6 +7,6 @@ namespace Nethermind.Consensus { public interface IGasLimitCalculator { - long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null); + long GetGasLimit(BlockHeader parentHeader); } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index e04c3f06f18..183a594d6d0 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -19,7 +19,7 @@ public class ReadOnlyTxProcessingEnv : ReadOnlyTxProcessingEnvBase, IReadOnlyTxP protected readonly ILogManager _logManager; protected ITransactionProcessor? _transactionProcessor; - public ITransactionProcessor TransactionProcessor + protected ITransactionProcessor TransactionProcessor { get { diff --git a/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs b/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs index c4c26936f2e..9fc619e58d2 100644 --- a/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus/TargetAdjustedGasLimitCalculator.cs @@ -19,12 +19,12 @@ public TargetAdjustedGasLimitCalculator(ISpecProvider? specProvider, IBlocksConf _blocksConfig = miningConfig ?? throw new ArgumentNullException(nameof(miningConfig)); } - public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) + public long GetGasLimit(BlockHeader parentHeader) { long parentGasLimit = parentHeader.GasLimit; long gasLimit = parentGasLimit; - long? targetGasLimit = desiredGasLimit ?? _blocksConfig.TargetBlockGasLimit; + long? targetGasLimit = _blocksConfig.TargetBlockGasLimit; long newBlockNumber = parentHeader.Number + 1; IReleaseSpec spec = _specProvider.GetSpec(newBlockNumber, parentHeader.Timestamp); // taking the parent timestamp is a temporary solution if (targetGasLimit is not null) diff --git a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs index 5acc461118f..9483b56751a 100644 --- a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs @@ -128,6 +128,15 @@ public interface IJsonRpcConfig : IConfig """)] int? EthModuleConcurrentInstances { get; set; } + + [ConfigItem( + Description = """ + The number of concurrent instances for non-sharable calls: + - `flashbots_validateBuilderSubmissionV3` + This limits the load on the CPU and I/O to reasonable levels. If the limit is exceeded, HTTP 503 is returned along with the JSON-RPC error. Defaults to the number of logical processors. + """)] + int? FlashbotsModuleConcurrentInstances { get; set; } + [ConfigItem(Description = "The path to the JWT secret file required for the Engine API authentication.", DefaultValue = "keystore/jwt-secret")] public string JwtSecretFile { get; set; } diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs index 26d3d32760e..269dca89971 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs @@ -39,6 +39,7 @@ public int WebSocketsPort public long? MaxRequestBodySize { get; set; } = 30000000; public int MaxLogsPerResponse { get; set; } = 20_000; public int? EthModuleConcurrentInstances { get; set; } = null; + public int? FlashbotsModuleConcurrentInstances { get; set; } = null; public string JwtSecretFile { get; set; } = "keystore/jwt-secret"; public bool UnsecureDevNoRpcAuthentication { get; set; } public int? MaxLoggedRequestParametersCharacters { get; set; } = null; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs b/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs index 0c30768ed99..5e5a6932e95 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismGasLimitCalculator.cs @@ -9,6 +9,6 @@ namespace Nethermind.Optimism; public class OptimismGasLimitCalculator : IGasLimitCalculator { - public long GetGasLimit(BlockHeader parentHeader, long? desiredGasLimit = null) => + public long GetGasLimit(BlockHeader parentHeader) => throw new InvalidOperationException("GasLimit in Optimism should come from payload attributes."); } From 1bebf60dff07b27f3da2af170bb959132ed63cab Mon Sep 17 00:00:00 2001 From: "lukasz.rozmej" Date: Thu, 12 Sep 2024 15:51:09 +0200 Subject: [PATCH 011/113] Hookup BlockValidation plugin in Nethermind.Runner --- .../Nethermind.Runner/Nethermind.Runner.csproj | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj index 7302df1c758..15d6f745f56 100644 --- a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj +++ b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj @@ -33,6 +33,7 @@ + @@ -89,11 +90,11 @@ - - + + - - + + From 570dce0cb9205bc0a69c11ac2839fee6aa3b341b Mon Sep 17 00:00:00 2001 From: "core-repository-dispatch-app[bot]" <173070810+core-repository-dispatch-app[bot]@users.noreply.github.com> Date: Sun, 8 Sep 2024 01:25:36 +0100 Subject: [PATCH 012/113] Update Fast Sync configuration in Nethermind repository (#7401) Co-authored-by: LukaszRozmej --- src/Nethermind/Nethermind.Runner/configs/chiado.cfg | 4 ++-- src/Nethermind/Nethermind.Runner/configs/energyweb.cfg | 6 +++--- src/Nethermind/Nethermind.Runner/configs/exosama.cfg | 6 +++--- src/Nethermind/Nethermind.Runner/configs/gnosis.cfg | 4 ++-- src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg | 6 +++--- src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg | 6 +++--- src/Nethermind/Nethermind.Runner/configs/mainnet.cfg | 4 ++-- src/Nethermind/Nethermind.Runner/configs/sepolia.cfg | 4 ++-- src/Nethermind/Nethermind.Runner/configs/volta.cfg | 6 +++--- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg index a5759f613fc..063329376f5 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg @@ -16,8 +16,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 11560000, - "PivotHash": "0x494d1e447b6e3e232ce5e3546a0aa523f2f5685b514cf155ecf06d256a9eafb3", + "PivotNumber": 11680000, + "PivotHash": "0x8dc08befcac4ed4f8770b74af45ef0cf0110fc0eba6664a0b5496146d5832044", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", "FastSyncCatchUpHeightDelta": "10000000000", "UseGethLimitsInFastBlocks": false diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg b/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg index e96e81359df..c542f12694c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 31620000, - "PivotHash": "0x7227c2165b426326520350507c570ac4384d940c8c8176ee8121a780eda9acb5", - "PivotTotalDifficulty": "10759728442040074214711905086992510845862220300", + "PivotNumber": 31740000, + "PivotHash": "0xef7d4930d209fde12f8f874d42f7cef7ff5c26a153a7be90dd44848e3d03da8a", + "PivotTotalDifficulty": "10800562326070586830327510039884323031236690394", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama.cfg b/src/Nethermind/Nethermind.Runner/configs/exosama.cfg index 06bce3d7afa..ad7c2288ac5 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.cfg @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 11740000, - "PivotHash": "0xc1f9872c9a2e917f65d6d09aa527e385a2c9b1e37a8e80fcb9ea449fb0141e9c", - "PivotTotalDifficulty": "3994914987651817561060017891248958802136813285", + "PivotNumber": 11860000, + "PivotHash": "0x73fe5d99cb0c11f5bc89356e47dbf4cb6716e14063b13aaeb53998f079787f31", + "PivotTotalDifficulty": "4035748871682330176675622844140770987511293285", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg b/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg index 6672623e61e..b828d7affd2 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg @@ -13,8 +13,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 35760000, - "PivotHash": "0xc58982687352c2ba3a818abf7e65f5e3b274b29136673deed85e2845f5701dc5", + "PivotNumber": 35870000, + "PivotHash": "0x37e4a9f028d674377e16ce3ea4ca4ef0cd7474fde33200fe8c944a73c900c3c6", "PivotTotalDifficulty": "8626000110427538733349499292577475819600160930", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg index 0c6c8a39543..8b6526c91b7 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 13100000, - "PivotHash": "0x6cc042124e9659f08e6686293fa115ba012fdbd7d637ef4ead0f8eec473b1054", - "PivotTotalDifficulty": "26078305" + "PivotNumber": 13220000, + "PivotHash": "0xde8589a868bd8eb13e9073cae9746d26dfafb1d9cab660968f49422f43a5e0bf", + "PivotTotalDifficulty": "26287111" }, "Metrics": { "NodeName": "JOC-Mainnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg index 1d78ba2fc73..27d3b94cb4f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 6710000, - "PivotHash": "0x0a3736e3f6df43c743a14f69c33cdcdd403427cb646ff0d5d5cbe86b3784e62d", - "PivotTotalDifficulty": "12605413" + "PivotNumber": 6830000, + "PivotHash": "0x6badab4d5bf7a34b908022f09280c1ca99ce9b23c7332e43960fd3ebc65e5ba4", + "PivotTotalDifficulty": "12796646" }, "Metrics": { "NodeName": "JOC-Testnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg b/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg index 3451c37baa3..9595eb08bad 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg @@ -9,8 +9,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 20651000, - "PivotHash": "0x1ca2913d5bded888225fbea3b08c0e4916ececd6abb52a7f7becc4058ac531da", + "PivotNumber": 20701000, + "PivotHash": "0x823f8bc86daa1a1fdeb6abfe793fce6a269072b31feac20310873610dac6ecfb", "PivotTotalDifficulty": "58750003716598352816469", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg b/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg index a48392ad826..66acfce2e24 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg @@ -17,8 +17,8 @@ "FastSync": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 6608000, - "PivotHash": "0x22a653172e994f219b103b5acd9c886fb605cc3afce47527c92535e143a15e4d", + "PivotNumber": 6651000, + "PivotHash": "0x7778040c3b649871b6d987685633d78b44ab14ff0de2759258a6296325993b95", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.cfg b/src/Nethermind/Nethermind.Runner/configs/volta.cfg index f41df4796d4..9c246791f48 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/volta.cfg @@ -15,9 +15,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 29130000, - "PivotHash": "0x33a9d3df9a045019a280bd9d607773c436c9ddba9be6d218fb934e731639f137", - "PivotTotalDifficulty": "9912425348406937440688102314487407999339265468", + "PivotNumber": 29210000, + "PivotHash": "0x515eba2255b858fb08054da66d45c7812ce2283e85a3afe9ab4cf7c4fdbab285", + "PivotTotalDifficulty": "9939647937760612517765172283081949456255551917", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, From bec7a5d71a1f52b79a3d4445982c05348dcee8f1 Mon Sep 17 00:00:00 2001 From: Lukasz Rozmej Date: Mon, 9 Sep 2024 11:53:14 +0200 Subject: [PATCH 013/113] Feature/geth like system tx (#7252) Co-authored-by: MarekM25 Co-authored-by: Ahmad Bitar --- .../Ethereum.Test.Base/BlockchainTestBase.cs | 18 +- .../AuraBlockProcessorTests.cs | 5 +- .../AuRaContractGasLimitOverrideTests.cs | 2 + .../Contract/TestContractBlockchain.cs | 2 +- .../Contract/TxPriorityContractTests.cs | 2 +- .../Transactions/PermissionTxComparerTests.cs | 1 - .../Transactions/TxCertifierFilterTests.cs | 3 +- .../Transactions/TxPermissionFilterTest.cs | 9 +- .../BlockProcessorTests.cs | 3 + .../Find/LogFinderTests.cs | 1 - .../GenesisLoaderTests.cs | 1 - .../Producers/DevBlockproducerTests.cs | 2 + .../Nethermind.Blockchain.Test/ReorgTests.cs | 2 + .../TransactionGasPriceComparisonTests.cs | 6 +- .../TransactionSelectorTests.cs | 2 - .../TransactionsExecutorTests.cs | 2 - .../BeaconBlockRoot/BeaconBlockRootHandler.cs | 63 ++++--- .../IBeaconBlockRootHandler.cs | 7 +- .../Nethermind.Blockchain/GenesisLoader.cs | 29 +-- .../Spec/ChainHeadSpecProvider.cs | 20 +- .../CliqueBlockProducerTests.cs | 3 + .../AuRaBlockProcessor.cs | 6 +- .../NullBeaconBlockRootHandler.cs | 17 -- .../InitializeBlockchainAuRa.cs | 2 + .../StartBlockProducerAuRa.cs | 2 + .../CliquePlugin.cs | 2 + .../NethDevPlugin.cs | 2 + ...sor.BlockProductionTransactionsExecutor.cs | 34 ++-- .../Processing/BlockProcessor.cs | 92 +++++---- .../Processing/IBlockProcessor.cs | 1 + .../Processing/ReadOnlyChainProcessingEnv.cs | 2 + .../Processing/ReadOnlyTxProcessingEnv.cs | 6 +- .../TransactionProcessorAdapterExtensions.cs | 2 +- .../Producers/BlockProducerEnvFactory.cs | 5 +- .../Blockchain/TestBlockchain.cs | 12 +- .../FixedBlockChainHeadSpecProvider.cs | 38 ++-- .../Nethermind.Core/Eip4788Constants.cs | 5 - .../Nethermind.Core/Specs/AuraSpecProvider.cs | 11 ++ .../Nethermind.Core/Specs/ForkActivation.cs | 13 +- .../Nethermind.Core/Specs/IReleaseSpec.cs | 2 +- .../Nethermind.Core/Specs/ISpecProvider.cs | 24 ++- .../Specs/ReleaseSpecDecorator.cs | 78 ++++++++ .../DifficultyCalculatorTests.cs | 10 - .../Nethermind.Evm/Tracing/ITxTracer.cs | 2 +- .../Tracing/Proofs/ProofTxTracer.cs | 10 - .../Nethermind.Evm/TransactionExtensions.cs | 8 +- ...llAndRestoreTransactionProcessorAdapter.cs | 12 +- .../ExecuteTransactionProcessorAdapter.cs | 12 +- .../SystemTransactionProcessor.cs | 71 +++++++ .../TraceTransactionProcessorAdapter.cs | 12 +- .../TransactionProcessor.cs | 175 ++++++++++-------- .../SimulateReadOnlyBlocksProcessingEnv.cs | 4 +- .../Simulate/SimulateTransactionProcessor.cs | 4 +- .../Steps/InitializeBlockchain.cs | 2 + .../Steps/InitializePrecompiles.cs | 1 + .../EthModuleBenchmarks.cs | 13 +- .../Modules/Eth/EthRpcModuleTests.cs | 6 +- .../Modules/SubscribeModuleTests.cs | 2 - .../Modules/Trace/ParityStyleTracerTests.cs | 2 + .../Modules/TraceRpcModuleTests.cs | 2 +- .../Modules/RpcBlockTransactionsExecutor.cs | 10 +- .../AuRaMergeEngineModuleTests.cs | 9 + .../AuRaMergeBlockProcessor.cs | 66 ++++--- .../AuRaMergeBlockProducerEnvFactory.cs | 2 + .../InitializeBlockchainAuRaMerge.cs | 9 +- .../EngineModuleTests.HelperFunctions.cs | 3 - .../EngineModuleTests.Setup.cs | 2 + .../MinGasPriceTests.cs | 10 - .../InitializeBlockchainOptimism.cs | 17 +- .../OptimismBlockProcessor.cs | 18 +- .../OptimismBlockProducerEnvFactory.cs | 2 + .../OptimismReadOnlyTxProcessingEnv.cs | 2 +- .../OptimismTransactionProcessor.cs | 12 +- .../ReadOnlyChainProcessingEnv.cs | 2 + .../OverridableReleaseSpec.cs | 7 +- .../OverridableSpecProvider.cs | 1 + .../ChainSpecBasedSpecProvider.cs | 1 + .../ChainSpecStyle/ChainSpecLoader.cs | 7 +- .../Nethermind.Specs/ChiadoSpecProvider.cs | 1 + .../Nethermind.Specs/Forks/00_Olympic.cs | 1 - .../Nethermind.Specs/GnosisSpecProvider.cs | 1 + .../Nethermind.Specs/GoerliSpecProvider.cs | 1 + .../Nethermind.Specs/ReleaseSpec.cs | 6 +- .../Nethermind.Specs/SepoliaSpecProvider.cs | 2 + .../SingleReleaseSpecProvider.cs | 11 +- .../SystemTransactionReleaseSpec.cs | 129 +------------ .../SyncThreadTests.cs | 3 + src/Nethermind/Nethermind.Trie/TreeDumper.cs | 2 +- .../Nethermind.TxPool.Test/TxPoolTests.cs | 4 +- 89 files changed, 621 insertions(+), 607 deletions(-) delete mode 100644 src/Nethermind/Nethermind.Consensus.AuRa/BeaconBlockRoot/NullBeaconBlockRootHandler.cs create mode 100644 src/Nethermind/Nethermind.Core/Specs/AuraSpecProvider.cs create mode 100644 src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs create mode 100644 src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs index 8ef9df33603..e2a090fa996 100644 --- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs +++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; @@ -155,21 +156,22 @@ protected async Task RunTest(BlockchainTest test, Stopwatch? codeInfoRepository, _logManager); + TransactionProcessor transactionProcessor = new( + specProvider, + stateProvider, + virtualMachine, + codeInfoRepository, + _logManager); + IBlockProcessor blockProcessor = new BlockProcessor( specProvider, blockValidator, rewardCalculator, - new BlockProcessor.BlockValidationTransactionsExecutor( - new TransactionProcessor( - specProvider, - stateProvider, - virtualMachine, - codeInfoRepository, - _logManager), - stateProvider), + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), stateProvider, receiptStorage, new BlockhashStore(specProvider, stateProvider), + new BeaconBlockRootHandler(transactionProcessor), _logManager); IBlockchainProcessor blockchainProcessor = new BlockchainProcessor( diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuraBlockProcessorTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuraBlockProcessorTests.cs index cfbfb9cb9d7..383d0d6da6d 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/AuraBlockProcessorTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/AuraBlockProcessorTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using FluentAssertions; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Test.Validators; using Nethermind.Consensus.AuRa; @@ -157,11 +158,11 @@ void Process(AuRaBlockProcessor auRaBlockProcessor, int blockNumber, Hash256 sta new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), stateProvider, NullReceiptStorage.Instance, + new BeaconBlockRootHandler(transactionProcessor), LimboLogs.Instance, Substitute.For(), new WithdrawalProcessor(stateProvider, LimboLogs.Instance), - null, - txFilter, + txFilter: txFilter, contractRewriter: contractRewriter); return (processor, stateProvider); diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs index 3e05e43fde1..ea6880f55f6 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs @@ -7,6 +7,7 @@ using FluentAssertions; using Nethermind.Abi; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Consensus; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Contracts; @@ -96,6 +97,7 @@ protected override BlockProcessor CreateBlockProcessor() new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State), State, ReceiptStorage, + new BeaconBlockRootHandler(TxProcessor), LimboLogs.Instance, BlockTree, NullWithdrawalProcessor.Instance, diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/TestContractBlockchain.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/TestContractBlockchain.cs index bde491cbd4f..0dfd5420027 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Contract/TestContractBlockchain.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/TestContractBlockchain.cs @@ -21,7 +21,7 @@ protected TestContractBlockchain() SealEngineType = Nethermind.Core.SealEngineType.AuRa; } - public static async Task ForTest(string testSuffix = null) where TTest : TestContractBlockchain, new() + public static async Task ForTest(string? testSuffix = null) where TTest : TestContractBlockchain, new() { (ChainSpec ChainSpec, ISpecProvider SpecProvider) GetSpecProvider() { diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs index d1554f7b638..17a0bad2438 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs @@ -299,7 +299,7 @@ protected override async Task AddBlocksOnStart() EthereumEcdsa ecdsa = new(ChainSpec.ChainId); await AddBlock( - SignTransactions(ecdsa, TestItem.PrivateKeyA, 0, + SignTransactions(ecdsa, TestItem.PrivateKeyA, 1, TxPriorityContract.SetPriority(TestItem.AddressA, FnSignature2, UInt256.One), TxPriorityContract.SetPriority(TestItem.AddressB, FnSignature, 10), TxPriorityContract.SetPriority(TestItem.AddressB, FnSignature2, 4), diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/PermissionTxComparerTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/PermissionTxComparerTests.cs index ddf72060de7..621a177664f 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/PermissionTxComparerTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/PermissionTxComparerTests.cs @@ -261,7 +261,6 @@ public void order_is_correct(Func, IEnumerable(); var spec = new ReleaseSpec() { IsEip1559Enabled = false }; - specProvider.GetSpec(Arg.Any()).Returns(spec); specProvider.GetSpec(Arg.Any()).Returns(spec); TransactionComparerProvider transactionComparerProvider = new(specProvider, blockTree); IComparer defaultComparer = transactionComparerProvider.GetDefaultComparer(); diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs index 92a33ae4941..849711461bb 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs @@ -7,6 +7,7 @@ using Nethermind.Abi; using Nethermind.AuRa.Test.Contract; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.AuRa.Transactions; @@ -154,10 +155,10 @@ protected override BlockProcessor CreateBlockProcessor() new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State), State, ReceiptStorage, + new BeaconBlockRootHandler(TxProcessor), LimboLogs.Instance, BlockTree, NullWithdrawalProcessor.Instance, - null, preWarmer: CreateBlockCachePreWarmer()); } diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs index dbaa774b2ff..3afab033df9 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs @@ -9,6 +9,7 @@ using Nethermind.Abi; using Nethermind.AuRa.Test.Contract; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.AuRa.Transactions; @@ -295,14 +296,12 @@ protected override BlockProcessor CreateBlockProcessor() new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State), State, ReceiptStorage, + new BeaconBlockRootHandler(TxProcessor), LimboLogs.Instance, BlockTree, NullWithdrawalProcessor.Instance, - null, - PermissionBasedTxFilter, - null, - null, - CreateBlockCachePreWarmer()); + txFilter: PermissionBasedTxFilter, + preWarmer: CreateBlockCachePreWarmer()); } protected override async Task AddBlocksOnStart() diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs index 58b3d0317bf..f4ca94b9304 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockProcessorTests.cs @@ -23,6 +23,7 @@ using System.Threading.Tasks; using System.Threading; using FluentAssertions; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Rewards; @@ -50,6 +51,7 @@ public void Prepared_block_contains_author_field() stateProvider, NullReceiptStorage.Instance, Substitute.For(), + new BeaconBlockRootHandler(transactionProcessor), LimboLogs.Instance); BlockHeader header = Build.A.BlockHeader.WithAuthor(TestItem.AddressD).TestObject; @@ -79,6 +81,7 @@ public void Recovers_state_on_cancel() stateProvider, NullReceiptStorage.Instance, Substitute.For(), + new BeaconBlockRootHandler(transactionProcessor), LimboLogs.Instance); BlockHeader header = Build.A.BlockHeader.WithNumber(1).WithAuthor(TestItem.AddressD).TestObject; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs index ad39a53138e..2d7ea7a3ae4 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Find/LogFinderTests.cs @@ -47,7 +47,6 @@ public void SetUp() private void SetUp(bool allowReceiptIterator) { var specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any()).IsEip155Enabled.Returns(true); specProvider.GetSpec(Arg.Any()).IsEip155Enabled.Returns(true); _receiptStorage = new InMemoryReceiptStorage(allowReceiptIterator); _rawBlockTree = Build.A.BlockTree() diff --git a/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs index 539e2505405..47f983dcbab 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/GenesisLoaderTests.cs @@ -61,7 +61,6 @@ private Block GetGenesisBlock(string chainspecPath) TrieStore trieStore = new(stateDb, LimboLogs.Instance); IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance); ISpecProvider specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any()).Returns(Berlin.Instance); specProvider.GetSpec(Arg.Any()).Returns(Berlin.Instance); ITransactionProcessor transactionProcessor = Substitute.For(); GenesisLoader genesisLoader = new(chainSpec, specProvider, stateProvider, transactionProcessor); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs index 3afe77c9aa6..7f4b9d2bb2b 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs @@ -3,6 +3,7 @@ using System.Threading; using FluentAssertions; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -78,6 +79,7 @@ public void Test() stateProvider, NullReceiptStorage.Instance, new BlockhashStore(specProvider, stateProvider), + new BeaconBlockRootHandler(txProcessor), LimboLogs.Instance); BlockchainProcessor blockchainProcessor = new( blockTree, diff --git a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs index f48be888945..a7c40c63652 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/ReorgTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using FluentAssertions; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Comparers; @@ -78,6 +79,7 @@ public void Setup() stateProvider, NullReceiptStorage.Instance, new BlockhashStore(MainnetSpecProvider.Instance, stateProvider), + new BeaconBlockRootHandler(transactionProcessor), LimboLogs.Instance); _blockchainProcessor = new BlockchainProcessor( _blockTree, diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs index 60e373f4445..ca342190624 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionGasPriceComparisonTests.cs @@ -160,10 +160,8 @@ public TestingContext(bool isEip1559Enabled = false, long eip1559TransitionBlock ReleaseSpec releaseSpec = new(); ReleaseSpec eip1559ReleaseSpec = new() { IsEip1559Enabled = isEip1559Enabled, Eip1559TransitionBlock = eip1559TransitionBlock }; ISpecProvider specProvider = Substitute.For(); - specProvider.GetSpecFor1559(Arg.Is(x => x >= eip1559TransitionBlock)).Returns(eip1559ReleaseSpec); - specProvider.GetSpecFor1559(Arg.Is(x => x < eip1559TransitionBlock)).Returns(releaseSpec); - specProvider.GetSpec(Arg.Is(x => x.Number >= eip1559TransitionBlock)).Returns(eip1559ReleaseSpec); - specProvider.GetSpec(Arg.Is(x => x.Number < eip1559TransitionBlock)).Returns(releaseSpec); + specProvider.GetSpec(Arg.Is(x => x.BlockNumber >= eip1559TransitionBlock)).Returns(eip1559ReleaseSpec); + specProvider.GetSpec(Arg.Is(x => x.BlockNumber < eip1559TransitionBlock)).Returns(releaseSpec); _blockTree = Substitute.For(); UpdateBlockTreeHead(); _transactionComparerProvider = diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs index 6b833e60048..4ba502850e1 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs @@ -222,8 +222,6 @@ void SetAccountStates(IEnumerable
missingAddresses) Block block = Build.A.Block.WithNumber(0).TestObject; blockTree.Head.Returns(block); IReleaseSpec spec = testCase.ReleaseSpec; - specProvider.GetSpec(Arg.Any(), Arg.Any()).Returns(spec); - specProvider.GetSpec(Arg.Any()).Returns(spec); specProvider.GetSpec(Arg.Any()).Returns(spec); TransactionComparerProvider transactionComparerProvider = new(specProvider, blockTree); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs index 8799490191a..ceca5d5b060 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs @@ -266,8 +266,6 @@ public void Proper_transactions_selected(TransactionSelectorTests.ProperTransact ISpecProvider specProvider = Substitute.For(); IReleaseSpec spec = testCase.ReleaseSpec; - specProvider.GetSpec(Arg.Any(), Arg.Any()).Returns(spec); - specProvider.GetSpec(Arg.Any()).Returns(spec); specProvider.GetSpec(Arg.Any()).Returns(spec); ITransactionProcessor transactionProcessor = Substitute.For(); diff --git a/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/BeaconBlockRootHandler.cs b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/BeaconBlockRootHandler.cs index 89276e3c7f8..78e482250b6 100644 --- a/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/BeaconBlockRootHandler.cs +++ b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/BeaconBlockRootHandler.cs @@ -1,39 +1,44 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Core.Specs; +using System; using Nethermind.Core; +using Nethermind.Core.Eip2930; +using Nethermind.Core.Specs; +using Nethermind.Crypto; +using Nethermind.Evm.Tracing; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; -using Nethermind.State; -using Nethermind.Core.Crypto; -using Nethermind.Core.Extensions; - -namespace Nethermind.Consensus.BeaconBlockRoot; -public class BeaconBlockRootHandler : IBeaconBlockRootHandler +namespace Nethermind.Blockchain.BeaconBlockRoot; +public class BeaconBlockRootHandler(ITransactionProcessor processor) : IBeaconBlockRootHandler { - public void ApplyContractStateChanges(Block block, IReleaseSpec spec, IWorldState stateProvider) - { - if (!spec.IsBeaconBlockRootAvailable || - block.IsGenesis || - block.Header.ParentBeaconBlockRoot is null) - return; - - Address eip4788Account = spec.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress; + private const long GasLimit = 30_000_000L; - if (!stateProvider.AccountExists(eip4788Account)) - return; - - UInt256 timestamp = (UInt256)block.Timestamp; - Hash256 parentBeaconBlockRoot = block.ParentBeaconBlockRoot; - - UInt256.Mod(timestamp, Eip4788Constants.HistoryBufferLength, out UInt256 timestampReduced); - UInt256 rootIndex = timestampReduced + Eip4788Constants.HistoryBufferLength; - - StorageCell tsStorageCell = new(eip4788Account, timestampReduced); - StorageCell brStorageCell = new(eip4788Account, rootIndex); - - stateProvider.Set(tsStorageCell, Bytes.WithoutLeadingZeros(timestamp.ToBigEndian()).ToArray()); - stateProvider.Set(brStorageCell, Bytes.WithoutLeadingZeros(parentBeaconBlockRoot.Bytes).ToArray()); + public void StoreBeaconRoot(Block block, IReleaseSpec spec) + { + BlockHeader? header = block.Header; + var canInsertBeaconRoot = spec.IsBeaconBlockRootAvailable + && !header.IsGenesis + && header.ParentBeaconBlockRoot is not null; + + if (canInsertBeaconRoot) + { + Address beaconRootsAddress = spec.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress; + Transaction transaction = new() + { + Value = UInt256.Zero, + Data = header.ParentBeaconBlockRoot.Bytes.ToArray(), + To = beaconRootsAddress, + SenderAddress = Address.SystemUser, + GasLimit = GasLimit, + GasPrice = UInt256.Zero, + AccessList = new AccessList.Builder().AddAddress(beaconRootsAddress).Build() + }; + + transaction.Hash = transaction.CalculateHash(); + + processor.Execute(transaction, header, NullTxTracer.Instance); + } } } diff --git a/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/IBeaconBlockRootHandler.cs b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/IBeaconBlockRootHandler.cs index d30074fc4cc..047af4ffb99 100644 --- a/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/IBeaconBlockRootHandler.cs +++ b/src/Nethermind/Nethermind.Blockchain/BeaconBlockRoot/IBeaconBlockRootHandler.cs @@ -1,12 +1,11 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Core.Specs; using Nethermind.Core; -using Nethermind.State; +using Nethermind.Core.Specs; -namespace Nethermind.Consensus.BeaconBlockRoot; +namespace Nethermind.Blockchain.BeaconBlockRoot; public interface IBeaconBlockRootHandler { - void ApplyContractStateChanges(Block block, IReleaseSpec spec, IWorldState state); + void StoreBeaconRoot(Block block, IReleaseSpec spec); } diff --git a/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs b/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs index 28f4979bafe..2c94e4d7c6d 100644 --- a/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs +++ b/src/Nethermind/Nethermind.Blockchain/GenesisLoader.cs @@ -14,30 +14,19 @@ using Nethermind.Evm.TransactionProcessing; using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; -using Nethermind.Consensus.BeaconBlockRoot; namespace Nethermind.Blockchain { - public class GenesisLoader + public class GenesisLoader( + ChainSpec chainSpec, + ISpecProvider specProvider, + IWorldState stateProvider, + ITransactionProcessor transactionProcessor) { - private readonly ChainSpec _chainSpec; - private readonly ISpecProvider _specProvider; - private readonly IWorldState _stateProvider; - private readonly ITransactionProcessor _transactionProcessor; - private readonly BeaconBlockRootHandler _beaconBlockRootHandler; - - public GenesisLoader( - ChainSpec chainSpec, - ISpecProvider specProvider, - IWorldState stateProvider, - ITransactionProcessor transactionProcessor) - { - _chainSpec = chainSpec ?? throw new ArgumentNullException(nameof(chainSpec)); - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider)); - _transactionProcessor = transactionProcessor ?? throw new ArgumentNullException(nameof(transactionProcessor)); - _beaconBlockRootHandler = new BeaconBlockRootHandler(); - } + private readonly ChainSpec _chainSpec = chainSpec ?? throw new ArgumentNullException(nameof(chainSpec)); + private readonly ISpecProvider _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + private readonly IWorldState _stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider)); + private readonly ITransactionProcessor _transactionProcessor = transactionProcessor ?? throw new ArgumentNullException(nameof(transactionProcessor)); public Block Load() { diff --git a/src/Nethermind/Nethermind.Blockchain/Spec/ChainHeadSpecProvider.cs b/src/Nethermind/Nethermind.Blockchain/Spec/ChainHeadSpecProvider.cs index da843c2ad06..f1d38e94778 100644 --- a/src/Nethermind/Nethermind.Blockchain/Spec/ChainHeadSpecProvider.cs +++ b/src/Nethermind/Nethermind.Blockchain/Spec/ChainHeadSpecProvider.cs @@ -9,20 +9,14 @@ namespace Nethermind.Blockchain.Spec { - public class ChainHeadSpecProvider : IChainHeadSpecProvider + public class ChainHeadSpecProvider(ISpecProvider specProvider, IBlockFinder blockFinder) : IChainHeadSpecProvider { - private readonly ISpecProvider _specProvider; - private readonly IBlockFinder _blockFinder; + private readonly ISpecProvider _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + private readonly IBlockFinder _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); private long _lastHeader = -1; - private IReleaseSpec? _headerSpec = null; + private IReleaseSpec? _headerSpec; private readonly object _lock = new(); - public ChainHeadSpecProvider(ISpecProvider specProvider, IBlockFinder blockFinder) - { - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); - } - public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalDifficulty = null) { _specProvider.UpdateMergeTransitionInfo(blockNumber, terminalTotalDifficulty); @@ -67,9 +61,9 @@ public IReleaseSpec GetCurrentHeadSpec() lock (_lock) { _lastHeader = headerNumber; - if (header is not null) - return _headerSpec = _specProvider.GetSpec(header); - return _headerSpec = GetSpec((ForkActivation)headerNumber); + return _headerSpec = header is not null + ? _specProvider.GetSpec(header) + : GetSpec((ForkActivation)headerNumber); } } } diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs index 04c64ea3eaf..dbb56948e14 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using FluentAssertions; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus; @@ -141,6 +142,7 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f stateProvider, NullReceiptStorage.Instance, new BlockhashStore(goerliSpecProvider, stateProvider), + new BeaconBlockRootHandler(transactionProcessor), nodeLogManager); BlockchainProcessor processor = new(blockTree, blockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); @@ -160,6 +162,7 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f minerStateProvider, NullReceiptStorage.Instance, new BlockhashStore(goerliSpecProvider, minerStateProvider), + new BeaconBlockRootHandler(minerTransactionProcessor), nodeLogManager); BlockchainProcessor minerProcessor = new(blockTree, minerBlockProcessor, new AuthorRecoveryStep(snapshotManager), stateReader, nodeLogManager, BlockchainProcessor.Options.NoReceipts); diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs index 51190c3dd7e..2661da25d01 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs @@ -3,6 +3,7 @@ using System; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; @@ -19,6 +20,7 @@ using Nethermind.Evm.Tracing; using Nethermind.Logging; using Nethermind.State; +using Nethermind.Trie; using Nethermind.TxPool; namespace Nethermind.Consensus.AuRa @@ -39,10 +41,11 @@ public AuRaBlockProcessor( IBlockProcessor.IBlockTransactionsExecutor blockTransactionsExecutor, IWorldState stateProvider, IReceiptStorage receiptStorage, + IBeaconBlockRootHandler beaconBlockRootHandler, ILogManager logManager, IBlockFinder blockTree, IWithdrawalProcessor withdrawalProcessor, - IAuRaValidator? auRaValidator, + IAuRaValidator? auRaValidator = null, ITxFilter? txFilter = null, AuRaContractGasLimitOverride? gasLimitOverride = null, ContractRewriter? contractRewriter = null, @@ -55,6 +58,7 @@ public AuRaBlockProcessor( stateProvider, receiptStorage, new BlockhashStore(specProvider, stateProvider), + beaconBlockRootHandler, logManager, withdrawalProcessor, preWarmer: preWarmer) diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/BeaconBlockRoot/NullBeaconBlockRootHandler.cs b/src/Nethermind/Nethermind.Consensus.AuRa/BeaconBlockRoot/NullBeaconBlockRootHandler.cs deleted file mode 100644 index 96138999814..00000000000 --- a/src/Nethermind/Nethermind.Consensus.AuRa/BeaconBlockRoot/NullBeaconBlockRootHandler.cs +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using Nethermind.Consensus.BeaconBlockRoot; -using Nethermind.Core; -using Nethermind.Core.Specs; -using Nethermind.State; - -namespace Nethermind.Consensus.AuRa.BeaconBlockRoot; -internal class NullBeaconBlockRootHandler : IBeaconBlockRootHandler -{ - public void ApplyContractStateChanges(Block block, IReleaseSpec spec, IWorldState state) - { - } - - public static IBeaconBlockRootHandler Instance { get; } = new NullBeaconBlockRootHandler(); -} diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs index 63b74023691..9e3e849e4af 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/InitializeBlockchainAuRa.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Data; using Nethermind.Blockchain.Services; using Nethermind.Config; @@ -106,6 +107,7 @@ protected virtual AuRaBlockProcessor NewAuraBlockProcessor(ITxFilter txFilter, B new BlockProcessor.BlockValidationTransactionsExecutor(_api.TransactionProcessor, worldState), worldState, _api.ReceiptStorage!, + new BeaconBlockRootHandler(_api.TransactionProcessor!), _api.LogManager, _api.BlockTree!, NullWithdrawalProcessor.Instance, diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs index 948eaef9a97..b55a38265e6 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/StartBlockProducerAuRa.cs @@ -8,6 +8,7 @@ using Nethermind.Abi; using Nethermind.Api; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Data; using Nethermind.Config; using Nethermind.Consensus.AuRa.Config; @@ -154,6 +155,7 @@ private BlockProcessor CreateBlockProcessor(IReadOnlyTxProcessingScope changeabl _api.BlockProducerEnvFactory.TransactionsExecutorFactory.Create(changeableTxProcessingEnv), changeableTxProcessingEnv.WorldState, _api.ReceiptStorage, + new BeaconBlockRootHandler(changeableTxProcessingEnv.TransactionProcessor), _api.LogManager, _api.BlockTree, NullWithdrawalProcessor.Instance, diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs index e8dbbcf0175..32d2616aca1 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs @@ -6,6 +6,7 @@ using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -112,6 +113,7 @@ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null) scope.WorldState, NullReceiptStorage.Instance, new BlockhashStore(getFromApi.SpecProvider, scope.WorldState), + new BeaconBlockRootHandler(scope.TransactionProcessor), getFromApi.LogManager, new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(scope.WorldState, getFromApi.LogManager))); diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs index 4297e243a42..93a485fabff 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs @@ -6,6 +6,7 @@ using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -82,6 +83,7 @@ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null) scope.WorldState, NullReceiptStorage.Instance, new BlockhashStore(getFromApi.SpecProvider, scope.WorldState), + new BeaconBlockRootHandler(scope.TransactionProcessor), getFromApi.LogManager); IBlockchainProcessor producerChainProcessor = new BlockchainProcessor( diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs index bd8740c7c2f..9725e29b7fd 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs @@ -18,12 +18,15 @@ namespace Nethermind.Consensus.Processing { public partial class BlockProcessor { - public class BlockProductionTransactionsExecutor : IBlockProductionTransactionsExecutor + public class BlockProductionTransactionsExecutor( + ITransactionProcessor txProcessor, + IWorldState stateProvider, + IBlockProductionTransactionPicker txPicker, + ILogManager logManager) + : IBlockProductionTransactionsExecutor { - private readonly ITransactionProcessorAdapter _transactionProcessor; - private readonly IWorldState _stateProvider; - private readonly IBlockProductionTransactionPicker _blockProductionTransactionPicker; - private readonly ILogger _logger; + private readonly ITransactionProcessorAdapter _transactionProcessor = new BuildUpTransactionProcessorAdapter(txProcessor); + private readonly ILogger _logger = logManager.GetClassLogger(); public BlockProductionTransactionsExecutor( IReadOnlyTxProcessingScope readOnlyTxProcessingEnv, @@ -46,15 +49,6 @@ public BlockProductionTransactionsExecutor( { } - public BlockProductionTransactionsExecutor(ITransactionProcessor txProcessor, IWorldState stateProvider, - IBlockProductionTransactionPicker txPicker, ILogManager logManager) - { - _transactionProcessor = new BuildUpTransactionProcessorAdapter(txProcessor); - _stateProvider = stateProvider; - _blockProductionTransactionPicker = txPicker; - _logger = logManager.GetClassLogger(); - } - protected EventHandler? _transactionProcessed; event EventHandler? IBlockProcessor.IBlockTransactionsExecutor.TransactionProcessed @@ -65,8 +59,8 @@ event EventHandler? IBlockProcessor.IBlockTransactionsExec event EventHandler? IBlockProductionTransactionsExecutor.AddingTransaction { - add => _blockProductionTransactionPicker.AddingTransaction += value; - remove => _blockProductionTransactionPicker.AddingTransaction -= value; + add => txPicker.AddingTransaction += value; + remove => txPicker.AddingTransaction -= value; } public virtual TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, @@ -83,7 +77,7 @@ public virtual TxReceipt[] ProcessTransactions(Block block, ProcessingOptions pr if (action == TxAction.Stop) break; } - _stateProvider.Commit(spec, receiptsTracer); + stateProvider.Commit(spec, receiptsTracer); SetTransactions(block, transactionsInBlock); return receiptsTracer.TxReceipts.ToArray(); @@ -99,9 +93,7 @@ protected TxAction ProcessTransaction( LinkedHashSet transactionsInBlock, bool addToBlock = true) { - AddingTxEventArgs args = - _blockProductionTransactionPicker.CanAddTransaction(block, currentTx, transactionsInBlock, - _stateProvider); + AddingTxEventArgs args = txPicker.CanAddTransaction(block, currentTx, transactionsInBlock, stateProvider); if (args.Action != TxAction.Add) { @@ -109,7 +101,7 @@ protected TxAction ProcessTransaction( } else { - TransactionResult result = _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); + TransactionResult result = _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, stateProvider); if (result) { diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs index 0908e40db32..7a2b7a6dfa9 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs @@ -9,10 +9,10 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; -using Nethermind.Consensus.BeaconBlockRoot; using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; using Nethermind.Consensus.Withdrawals; @@ -30,57 +30,40 @@ namespace Nethermind.Consensus.Processing; -public partial class BlockProcessor : IBlockProcessor +public partial class BlockProcessor( + ISpecProvider? specProvider, + IBlockValidator? blockValidator, + IRewardCalculator? rewardCalculator, + IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor, + IWorldState? stateProvider, + IReceiptStorage? receiptStorage, + IBlockhashStore? blockHashStore, + IBeaconBlockRootHandler? beaconBlockRootHandler, + ILogManager? logManager, + IWithdrawalProcessor? withdrawalProcessor = null, + IReceiptsRootCalculator? receiptsRootCalculator = null, + IBlockCachePreWarmer? preWarmer = null) + : IBlockProcessor { - private readonly ILogger _logger; - private readonly ISpecProvider _specProvider; - protected readonly IWorldState _stateProvider; - private readonly IReceiptStorage _receiptStorage; - private readonly IReceiptsRootCalculator _receiptsRootCalculator; - private readonly IWithdrawalProcessor _withdrawalProcessor; - private readonly IBeaconBlockRootHandler _beaconBlockRootHandler; - private readonly IBlockValidator _blockValidator; - private readonly IRewardCalculator _rewardCalculator; - private readonly IBlockProcessor.IBlockTransactionsExecutor _blockTransactionsExecutor; - private readonly IBlockhashStore _blockhashStore; - private readonly IBlockCachePreWarmer? _preWarmer; + private readonly ILogger _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); + private readonly ISpecProvider _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + protected readonly IWorldState _stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider)); + private readonly IReceiptStorage _receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage)); + private readonly IReceiptsRootCalculator _receiptsRootCalculator = receiptsRootCalculator ?? ReceiptsRootCalculator.Instance; + private readonly IWithdrawalProcessor _withdrawalProcessor = withdrawalProcessor ?? new WithdrawalProcessor(stateProvider, logManager); + private readonly IBeaconBlockRootHandler _beaconBlockRootHandler = beaconBlockRootHandler ?? throw new ArgumentNullException(nameof(beaconBlockRootHandler)); + private readonly IBlockValidator _blockValidator = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator)); + private readonly IRewardCalculator _rewardCalculator = rewardCalculator ?? throw new ArgumentNullException(nameof(rewardCalculator)); + private readonly IBlockProcessor.IBlockTransactionsExecutor _blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor)); + private readonly IBlockhashStore _blockhashStore = blockHashStore ?? throw new ArgumentNullException(nameof(blockHashStore)); private const int MaxUncommittedBlocks = 64; + private readonly Func _clearCaches = _ => preWarmer.ClearCachesInBackground(); /// /// We use a single receipt tracer for all blocks. Internally receipt tracer forwards most of the calls /// to any block-specific tracers. /// - protected BlockReceiptsTracer ReceiptsTracer { get; set; } - private readonly Func _clearCaches; - - public BlockProcessor( - ISpecProvider? specProvider, - IBlockValidator? blockValidator, - IRewardCalculator? rewardCalculator, - IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor, - IWorldState? stateProvider, - IReceiptStorage? receiptStorage, - IBlockhashStore? blockHashStore, - ILogManager? logManager, - IWithdrawalProcessor? withdrawalProcessor = null, - IReceiptsRootCalculator? receiptsRootCalculator = null, - IBlockCachePreWarmer? preWarmer = null) - { - _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _blockValidator = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator)); - _stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider)); - _receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage)); - _withdrawalProcessor = withdrawalProcessor ?? new WithdrawalProcessor(stateProvider, logManager); - _rewardCalculator = rewardCalculator ?? throw new ArgumentNullException(nameof(rewardCalculator)); - _blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor)); - _receiptsRootCalculator = receiptsRootCalculator ?? ReceiptsRootCalculator.Instance; - _blockhashStore = blockHashStore ?? throw new ArgumentNullException(nameof(blockHashStore)); - _preWarmer = preWarmer; - _beaconBlockRootHandler = new BeaconBlockRootHandler(); - ReceiptsTracer = new BlockReceiptsTracer(); - _clearCaches = _ => _preWarmer.ClearCachesInBackground(); - } + protected BlockReceiptsTracer ReceiptsTracer { get; set; } = new(); public event EventHandler? BlockProcessed; @@ -122,7 +105,7 @@ the previous head state.*/ using CancellationTokenSource cancellationTokenSource = new(); Task? preWarmTask = suggestedBlock.Transactions.Length < 3 ? null - : _preWarmer?.PreWarmCaches(suggestedBlock, preBlockStateRoot!, cancellationTokenSource.Token); + : preWarmer?.PreWarmCaches(suggestedBlock, preBlockStateRoot!, cancellationTokenSource.Token); (Block processedBlock, TxReceipt[] receipts) = ProcessOne(suggestedBlock, options, blockTracer); // Block is processed, we can cancel the prewarm task if (preWarmTask is not null) @@ -173,7 +156,7 @@ the previous head state.*/ } finally { - _preWarmer?.ClearCaches(); + preWarmer?.ClearCaches(); } } @@ -264,9 +247,8 @@ protected virtual TxReceipt[] ProcessBlock( ReceiptsTracer.SetOtherTracer(blockTracer); ReceiptsTracer.StartNewBlockTrace(block); - _beaconBlockRootHandler.ApplyContractStateChanges(block, spec, _stateProvider); + StoreBeaconRoot(block, spec); _blockhashStore.ApplyBlockhashStateChanges(block.Header); - _stateProvider.Commit(spec, commitStorageRoots: false); TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, ReceiptsTracer, spec); @@ -300,6 +282,18 @@ protected virtual TxReceipt[] ProcessBlock( return receipts; } + private void StoreBeaconRoot(Block block, IReleaseSpec spec) + { + try + { + _beaconBlockRootHandler.StoreBeaconRoot(block, spec); + } + catch (Exception e) + { + if (_logger.IsWarn) _logger.Warn($"Storing beacon block root for block {block.ToString(Block.Format.FullHashAndNumber)} failed: {e}"); + } + } + // TODO: block processor pipeline private void StoreTxReceipts(Block block, TxReceipt[] txReceipts) { diff --git a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs index 88aba737926..8b2af1574b7 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs @@ -7,6 +7,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Evm.Tracing; +using Nethermind.Evm.TransactionProcessing; namespace Nethermind.Consensus.Processing { diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs index f4bc42832c2..48d1c0a22fa 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs @@ -3,6 +3,7 @@ using System; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Rewards; @@ -68,6 +69,7 @@ IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor scope.WorldState, receiptStorage, new BlockhashStore(specProvider, scope.WorldState), + new BeaconBlockRootHandler(scope.TransactionProcessor), logManager); } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index 183a594d6d0..5e7d4ea28da 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -56,10 +56,8 @@ public ReadOnlyTxProcessingEnv( _logManager = logManager; } - protected virtual TransactionProcessor CreateTransactionProcessor() - { - return new TransactionProcessor(SpecProvider, StateProvider, Machine, CodeInfoRepository, _logManager); - } + protected virtual ITransactionProcessor CreateTransactionProcessor() => + new TransactionProcessor(SpecProvider, StateProvider, Machine, CodeInfoRepository, _logManager); public IReadOnlyTxProcessingScope Build(Hash256 stateRoot) { diff --git a/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs b/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs index bd569caf479..f0dbbdcd45e 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs @@ -18,7 +18,7 @@ public static TransactionResult ProcessTransaction(this ITransactionProcessorAda ProcessingOptions processingOptions, IWorldState stateProvider) { - if (processingOptions.ContainsFlag(ProcessingOptions.DoNotVerifyNonce)) + if (processingOptions.ContainsFlag(ProcessingOptions.DoNotVerifyNonce) && currentTx.SenderAddress != Address.SystemUser) { currentTx.Nonce = stateProvider.GetNonce(currentTx.SenderAddress!); } diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs index a2c71caa342..01561beb4ce 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -141,7 +142,8 @@ protected virtual BlockProcessor CreateBlockProcessor( IBlockValidator blockValidator, IRewardCalculatorSource rewardCalculatorSource, IReceiptStorage receiptStorage, - ILogManager logManager, IBlocksConfig blocksConfig) => + ILogManager logManager, + IBlocksConfig blocksConfig) => new(specProvider, blockValidator, rewardCalculatorSource.Get(readOnlyTxProcessingEnv.TransactionProcessor), @@ -149,6 +151,7 @@ protected virtual BlockProcessor CreateBlockProcessor( readOnlyTxProcessingEnv.WorldState, receiptStorage, new BlockhashStore(_specProvider, readOnlyTxProcessingEnv.WorldState), + new BeaconBlockRootHandler(readOnlyTxProcessingEnv.TransactionProcessor), logManager, new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(readOnlyTxProcessingEnv.WorldState, logManager))); diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index 97978d42447..f93aa06571f 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.FullPruning; @@ -14,7 +15,6 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Consensus; -using Nethermind.Consensus.BeaconBlockRoot; using Nethermind.Consensus.Comparers; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Producers; @@ -159,7 +159,7 @@ protected virtual async Task Build(ISpecProvider? specProvider = State.CommitTree(0); ReadOnlyTrieStore = TrieStore.AsReadOnly(new NodeStorage(StateDb)); - WorldStateManager = new WorldStateManager(State, TrieStore, DbProvider, LimboLogs.Instance); + WorldStateManager = new WorldStateManager(State, TrieStore, DbProvider, LogManager); StateReader = new StateReader(ReadOnlyTrieStore, CodeDb, LogManager); ChainLevelInfoRepository = new ChainLevelInfoRepository(this.DbProvider.BlockInfosDb); @@ -172,7 +172,7 @@ protected virtual async Task Build(ISpecProvider? specProvider = SpecProvider, NullBloomStorage.Instance, new SyncConfig(), - LimboLogs.Instance); + LogManager); ReadOnlyState = new ChainHeadReadOnlyStateProvider(BlockTree, StateReader); TransactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockTree); @@ -208,7 +208,7 @@ protected virtual async Task Build(ISpecProvider? specProvider = BloomStorage bloomStorage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory()); ReceiptsRecovery receiptsRecovery = new(new EthereumEcdsa(SpecProvider.ChainId), SpecProvider); LogFinder = new LogFinder(BlockTree, ReceiptStorage, ReceiptStorage, bloomStorage, LimboLogs.Instance, receiptsRecovery); - BeaconBlockRootHandler = new BeaconBlockRootHandler(); + BeaconBlockRootHandler = new BeaconBlockRootHandler(TxProcessor); BlockProcessor = CreateBlockProcessor(); BlockchainProcessor chainProcessor = new(BlockTree, BlockProcessor, BlockPreprocessorStep, StateReader, LogManager, Consensus.Processing.BlockchainProcessor.Options.Default); @@ -325,8 +325,7 @@ protected virtual TxPoolTxSource CreateTxPoolTxSource() { MinGasPrice = 0 }; - ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(LimboLogs.Instance, - SpecProvider, blocksConfig); + ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(LogManager, SpecProvider, blocksConfig); return new TxPoolTxSource(TxPool, SpecProvider, TransactionComparerProvider, LogManager, txFilterPipeline); } @@ -377,6 +376,7 @@ protected virtual IBlockProcessor CreateBlockProcessor() => State, ReceiptStorage, new BlockhashStore(SpecProvider, State), + new BeaconBlockRootHandler(TxProcessor), LogManager, preWarmer: CreateBlockCachePreWarmer()); diff --git a/src/Nethermind/Nethermind.Core.Test/FixedBlockChainHeadSpecProvider.cs b/src/Nethermind/Nethermind.Core.Test/FixedBlockChainHeadSpecProvider.cs index 4fd8524bcca..7030287b6ef 100644 --- a/src/Nethermind/Nethermind.Core.Test/FixedBlockChainHeadSpecProvider.cs +++ b/src/Nethermind/Nethermind.Core.Test/FixedBlockChainHeadSpecProvider.cs @@ -6,38 +6,32 @@ namespace Nethermind.Core.Test { - public class FixedForkActivationChainHeadSpecProvider : IChainHeadSpecProvider + public class FixedForkActivationChainHeadSpecProvider( + ISpecProvider specProvider, + long fixedBlock = 10_000_000, + ulong? timestamp = null) + : IChainHeadSpecProvider { public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalDifficulty = null) { - _specProvider.UpdateMergeTransitionInfo(blockNumber, terminalTotalDifficulty); + specProvider.UpdateMergeTransitionInfo(blockNumber, terminalTotalDifficulty); } - public ForkActivation? MergeBlockNumber => _specProvider.MergeBlockNumber; - public ulong TimestampFork => _specProvider.TimestampFork; - public UInt256? TerminalTotalDifficulty => _specProvider.TerminalTotalDifficulty; - private readonly ISpecProvider _specProvider; - private readonly long _fixedBlock; - private readonly ulong? _timestamp; + public ForkActivation? MergeBlockNumber => specProvider.MergeBlockNumber; + public ulong TimestampFork => specProvider.TimestampFork; + public UInt256? TerminalTotalDifficulty => specProvider.TerminalTotalDifficulty; - public FixedForkActivationChainHeadSpecProvider(ISpecProvider specProvider, long fixedBlock = 10_000_000, ulong? timestamp = null) - { - _specProvider = specProvider; - _fixedBlock = fixedBlock; - _timestamp = timestamp; - } - - public IReleaseSpec GenesisSpec => _specProvider.GenesisSpec; + public IReleaseSpec GenesisSpec => specProvider.GenesisSpec; - public IReleaseSpec GetSpec(ForkActivation forkActivation) => _specProvider.GetSpec(forkActivation); + public IReleaseSpec GetSpec(ForkActivation forkActivation) => specProvider.GetSpec(forkActivation); - public long? DaoBlockNumber => _specProvider.DaoBlockNumber; + public long? DaoBlockNumber => specProvider.DaoBlockNumber; - public ulong NetworkId => _specProvider.NetworkId; - public ulong ChainId => _specProvider.ChainId; + public ulong NetworkId => specProvider.NetworkId; + public ulong ChainId => specProvider.ChainId; - public ForkActivation[] TransitionActivations => _specProvider.TransitionActivations; + public ForkActivation[] TransitionActivations => specProvider.TransitionActivations; - public IReleaseSpec GetCurrentHeadSpec() => GetSpec((_fixedBlock, _timestamp)); + public IReleaseSpec GetCurrentHeadSpec() => GetSpec((fixedBlock, timestamp)); } } diff --git a/src/Nethermind/Nethermind.Core/Eip4788Constants.cs b/src/Nethermind/Nethermind.Core/Eip4788Constants.cs index 6b74dd2a245..9097397d58f 100644 --- a/src/Nethermind/Nethermind.Core/Eip4788Constants.cs +++ b/src/Nethermind/Nethermind.Core/Eip4788Constants.cs @@ -14,9 +14,4 @@ public static class Eip4788Constants /// Gets the BEACON_ROOTS_ADDRESS parameter. /// public static readonly Address BeaconRootsAddress = new("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"); - - /// - /// Gets the HISTORY_BUFFER_LENGTH parameter. - /// - public static readonly UInt256 HistoryBufferLength = 8191; } diff --git a/src/Nethermind/Nethermind.Core/Specs/AuraSpecProvider.cs b/src/Nethermind/Nethermind.Core/Specs/AuraSpecProvider.cs new file mode 100644 index 00000000000..0fa1f8a7dfd --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Specs/AuraSpecProvider.cs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Int256; + +namespace Nethermind.Core.Specs; + +public class AuraSpecProvider(IReleaseSpec spec) : ReleaseSpecDecorator(spec) +{ + public override bool IsEip158IgnoredAccount(Address address) => address == Address.SystemUser; +} diff --git a/src/Nethermind/Nethermind.Core/Specs/ForkActivation.cs b/src/Nethermind/Nethermind.Core/Specs/ForkActivation.cs index 4ebb6f02460..7965f6390b2 100644 --- a/src/Nethermind/Nethermind.Core/Specs/ForkActivation.cs +++ b/src/Nethermind/Nethermind.Core/Specs/ForkActivation.cs @@ -5,18 +5,13 @@ namespace Nethermind.Core.Specs; -public readonly struct ForkActivation : IEquatable, IComparable +public readonly struct ForkActivation(long blockNumber, ulong? timestamp = null) + : IEquatable, IComparable { - public long BlockNumber { get; } - public ulong? Timestamp { get; } + public long BlockNumber { get; } = blockNumber; + public ulong? Timestamp { get; } = timestamp; public ulong Activation => Timestamp ?? (ulong)BlockNumber; - public ForkActivation(long blockNumber, ulong? timestamp = null) - { - BlockNumber = blockNumber; - Timestamp = timestamp; - } - /// /// Fork activation for forks past The Merge/Paris /// diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs index 2762f4c0460..a2e7a87cec3 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs @@ -202,7 +202,7 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec /// THis is needed for SystemUser account compatibility with Parity. /// /// - bool IsEip158IgnoredAccount(Address address); + bool IsEip158IgnoredAccount(Address address) => false; /// /// BaseFee opcode diff --git a/src/Nethermind/Nethermind.Core/Specs/ISpecProvider.cs b/src/Nethermind/Nethermind.Core/Specs/ISpecProvider.cs index 3374e4c1733..15b13965d91 100644 --- a/src/Nethermind/Nethermind.Core/Specs/ISpecProvider.cs +++ b/src/Nethermind/Nethermind.Core/Specs/ISpecProvider.cs @@ -62,6 +62,11 @@ public interface ISpecProvider /// ulong ChainId { get; } + /// + /// Original engine of the chain + /// + string SealEngine => SealEngineType.Ethash; + /// /// All block numbers at which a change in spec (a fork) happens. /// @@ -72,17 +77,26 @@ public interface ISpecProvider /// /// /// A spec that is valid at the given chain height - IReleaseSpec GetSpec(ForkActivation forkActivation); - IReleaseSpec GetSpec(long blockNumber, ulong? timestamp) => GetSpec((blockNumber, timestamp)); - IReleaseSpec GetSpec(BlockHeader blockHeader) => GetSpec((blockHeader.Number, blockHeader.Timestamp)); + protected internal IReleaseSpec GetSpec(ForkActivation forkActivation); + } + + public static class SpecProviderExtensions + { + public static IReleaseSpec GetSpec(this ISpecProvider specProvider, ForkActivation forkActivation) + => specProvider.SealEngine == SealEngineType.AuRa + ? new AuraSpecProvider(specProvider.GetSpec(forkActivation)) + : specProvider.GetSpec(forkActivation); + + public static IReleaseSpec GetSpec(this ISpecProvider specProvider, long blockNumber, ulong? timestamp) => specProvider.GetSpec(new ForkActivation(blockNumber, timestamp)); + public static IReleaseSpec GetSpec(this ISpecProvider specProvider, BlockHeader blockHeader) => specProvider.GetSpec(new ForkActivation(blockHeader.Number, blockHeader.Timestamp)); /// /// Resolves a spec for all planned forks applied. /// - /// A spec for all planned forks appliedA spec for all planned forks applied /// The default value is long.MaxValue for block numbers and ulong.MaxValue for timestamps /// for every new not yet scheduled EIP. Because of that we can't use long.MaxValue and /// ulong.MaxValue for GetFinalSpec that is why we have long.MaxValue-1, ulong.MaxValue-1 - IReleaseSpec GetFinalSpec() => GetSpec(long.MaxValue - 1, ulong.MaxValue - 1); + public static IReleaseSpec GetFinalSpec(this ISpecProvider specProvider) => specProvider.GetSpec(long.MaxValue - 1, ulong.MaxValue - 1); } } diff --git a/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs b/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs new file mode 100644 index 00000000000..3ef10dc0c72 --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Int256; + +namespace Nethermind.Core.Specs; + +public class ReleaseSpecDecorator(IReleaseSpec spec) : IReleaseSpec +{ + public virtual bool IsEip1559Enabled => spec.IsEip1559Enabled; + public virtual long Eip1559TransitionBlock => spec.Eip1559TransitionBlock; + public virtual UInt256 ForkBaseFee => spec.ForkBaseFee; + public virtual UInt256 BaseFeeMaxChangeDenominator => spec.BaseFeeMaxChangeDenominator; + public virtual long ElasticityMultiplier => spec.ElasticityMultiplier; + public virtual bool IsEip658Enabled => spec.IsEip658Enabled; + public virtual string Name => spec.Name; + public virtual long MaximumExtraDataSize => spec.MaximumExtraDataSize; + public virtual long MaxCodeSize => spec.MaxCodeSize; + public virtual long MinGasLimit => spec.MinGasLimit; + public virtual long GasLimitBoundDivisor => spec.GasLimitBoundDivisor; + public virtual UInt256 BlockReward => spec.BlockReward; + public virtual long DifficultyBombDelay => spec.DifficultyBombDelay; + public virtual long DifficultyBoundDivisor => spec.DifficultyBoundDivisor; + public virtual long? FixedDifficulty => spec.FixedDifficulty; + public virtual int MaximumUncleCount => spec.MaximumUncleCount; + public virtual bool IsTimeAdjustmentPostOlympic => spec.IsTimeAdjustmentPostOlympic; + public virtual bool IsEip2Enabled => spec.IsEip2Enabled; + public virtual bool IsEip7Enabled => spec.IsEip7Enabled; + public virtual bool IsEip100Enabled => spec.IsEip100Enabled; + public virtual bool IsEip140Enabled => spec.IsEip140Enabled; + public virtual bool IsEip150Enabled => spec.IsEip150Enabled; + public virtual bool IsEip155Enabled => spec.IsEip155Enabled; + public virtual bool IsEip158Enabled => spec.IsEip158Enabled; + public virtual bool IsEip160Enabled => spec.IsEip160Enabled; + public virtual bool IsEip170Enabled => spec.IsEip170Enabled; + public virtual bool IsEip196Enabled => spec.IsEip196Enabled; + public virtual bool IsEip197Enabled => spec.IsEip197Enabled; + public virtual bool IsEip198Enabled => spec.IsEip198Enabled; + public virtual bool IsEip211Enabled => spec.IsEip211Enabled; + public virtual bool IsEip214Enabled => spec.IsEip214Enabled; + public virtual bool IsEip649Enabled => spec.IsEip649Enabled; + public virtual bool IsEip145Enabled => spec.IsEip145Enabled; + public virtual bool IsEip1014Enabled => spec.IsEip1014Enabled; + public virtual bool IsEip1052Enabled => spec.IsEip1052Enabled; + public virtual bool IsEip1283Enabled => spec.IsEip1283Enabled; + public virtual bool IsEip1234Enabled => spec.IsEip1234Enabled; + public virtual bool IsEip1344Enabled => spec.IsEip1344Enabled; + public virtual bool IsEip2028Enabled => spec.IsEip2028Enabled; + public virtual bool IsEip152Enabled => spec.IsEip152Enabled; + public virtual bool IsEip1108Enabled => spec.IsEip1108Enabled; + public virtual bool IsEip1884Enabled => spec.IsEip1884Enabled; + public virtual bool IsEip2200Enabled => spec.IsEip2200Enabled; + public virtual bool IsEip2537Enabled => spec.IsEip2537Enabled; + public virtual bool IsEip2565Enabled => spec.IsEip2565Enabled; + public virtual bool IsEip2929Enabled => spec.IsEip2929Enabled; + public virtual bool IsEip2930Enabled => spec.IsEip2930Enabled; + public virtual bool IsEip3198Enabled => spec.IsEip3198Enabled; + public virtual bool IsEip3529Enabled => spec.IsEip3529Enabled; + public virtual bool IsEip3541Enabled => spec.IsEip3541Enabled; + public virtual bool IsEip3607Enabled => spec.IsEip3607Enabled; + public virtual bool IsEip3651Enabled => spec.IsEip3651Enabled; + public virtual bool IsEip1153Enabled => spec.IsEip1153Enabled; + public virtual bool IsEip3855Enabled => spec.IsEip3855Enabled; + public virtual bool IsEip5656Enabled => spec.IsEip5656Enabled; + public virtual bool IsEip3860Enabled => spec.IsEip3860Enabled; + public virtual bool IsEip4895Enabled => spec.IsEip4895Enabled; + public virtual bool IsEip4844Enabled => spec.IsEip4844Enabled; + public virtual bool IsEip4788Enabled => spec.IsEip4788Enabled; + public virtual Address Eip4788ContractAddress => spec.Eip4788ContractAddress; + public virtual bool IsEip2935Enabled => spec.IsEip2935Enabled; + public virtual bool IsEip7709Enabled => spec.IsEip7709Enabled; + public virtual Address Eip2935ContractAddress => spec.Eip2935ContractAddress; + public virtual bool IsEip6780Enabled => spec.IsEip6780Enabled; + public virtual bool IsRip7212Enabled => spec.IsRip7212Enabled; + public virtual ulong WithdrawalTimestamp => spec.WithdrawalTimestamp; + public virtual ulong Eip4844TransitionTimestamp => spec.Eip4844TransitionTimestamp; + public virtual bool IsEip158IgnoredAccount(Address address) => spec.IsEip158IgnoredAccount(address); +} diff --git a/src/Nethermind/Nethermind.Ethash.Test/DifficultyCalculatorTests.cs b/src/Nethermind/Nethermind.Ethash.Test/DifficultyCalculatorTests.cs index 5266141b0bc..a07299cd280 100644 --- a/src/Nethermind/Nethermind.Ethash.Test/DifficultyCalculatorTests.cs +++ b/src/Nethermind/Nethermind.Ethash.Test/DifficultyCalculatorTests.cs @@ -23,8 +23,6 @@ public void Calculate_should_returns_expected_results() releaseSpec.IsEip100Enabled.Returns(true); releaseSpec.IsTimeAdjustmentPostOlympic.Returns(true); ISpecProvider specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any(), Arg.Any()).Returns(releaseSpec); - specProvider.GetSpec(Arg.Any()).Returns(releaseSpec); specProvider.GetSpec(Arg.Any()).Returns(releaseSpec); EthashDifficultyCalculator difficultyCalculator = new(specProvider); UInt256 result = difficultyCalculator.Calculate(0x55f78f7, 1613570258, 0x602d20d2, 200000, false); @@ -36,8 +34,6 @@ public void Calculate_should_returns_expected_results() public void CalculateOlympic_should_returns_expected_results() { ISpecProvider specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any(), Arg.Any()).Returns(Olympic.Instance); - specProvider.GetSpec(Arg.Any()).Returns(Olympic.Instance); specProvider.GetSpec(Arg.Any()).Returns(Olympic.Instance); EthashDifficultyCalculator difficultyCalculator = new(specProvider); UInt256 result = difficultyCalculator.Calculate(0x55f78f7, 1613570258, 0x602d20d2, 200000, false); @@ -48,8 +44,6 @@ public void CalculateOlympic_should_returns_expected_results() public void CalculateBerlin_should_returns_expected_results() { ISpecProvider specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any(), Arg.Any()).Returns(Berlin.Instance); - specProvider.GetSpec(Arg.Any()).Returns(Berlin.Instance); specProvider.GetSpec(Arg.Any()).Returns(Berlin.Instance); EthashDifficultyCalculator difficultyCalculator = new(specProvider); UInt256 result = difficultyCalculator.Calculate(0x55f78f7, 1613570258, 0x602d20d2, 200000, false); @@ -93,15 +87,11 @@ private void Calculation_should_not_be_equal_on_different_difficulty_hard_forks( ulong parentTimestamp = 1613570258; ulong currentTimestamp = 0x602d20d2; ISpecProvider firstHardForkSpecProvider = Substitute.For(); - firstHardForkSpecProvider.GetSpec(Arg.Any(), Arg.Any()).Returns(firstHardfork); - firstHardForkSpecProvider.GetSpec(Arg.Any()).Returns(firstHardfork); firstHardForkSpecProvider.GetSpec(Arg.Any()).Returns(firstHardfork); EthashDifficultyCalculator firstHardforkDifficultyCalculator = new(firstHardForkSpecProvider); UInt256 firstHardforkResult = firstHardforkDifficultyCalculator.Calculate(parentDifficulty, parentTimestamp, currentTimestamp, blocksAbove, false); ISpecProvider secondHardforkSpecProvider = Substitute.For(); - secondHardforkSpecProvider.GetSpec(Arg.Any(), Arg.Any()).Returns(secondHardfork); - secondHardforkSpecProvider.GetSpec(Arg.Any()).Returns(secondHardfork); secondHardforkSpecProvider.GetSpec(Arg.Any()).Returns(secondHardfork); EthashDifficultyCalculator secondHardforkDifficultyCalculator = new(secondHardforkSpecProvider); UInt256 secondHardforkResult = secondHardforkDifficultyCalculator.Calculate(parentDifficulty, parentTimestamp, currentTimestamp, blocksAbove, false); diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs index 4552b43b2d1..500b83e8e0c 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs @@ -169,7 +169,7 @@ public interface ITxTracer : IWorldStateTracer, IDisposable /// Error that failed the transaction /// State root after transaction, depends on EIP-658 /// Depends on - void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null); + void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string? error, Hash256? stateRoot = null); /// /// diff --git a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs index 79b6de32165..3fcc82c3bdf 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs @@ -80,18 +80,8 @@ public override void ReportStorageRead(in StorageCell storageCell) Storages.Add(storageCell); } - private bool _wasSystemAccountAccessedOnceAlready; - public override void ReportAccountRead(Address address) { - if (_treatSystemAccountDifferently && !_wasSystemAccountAccessedOnceAlready && address == Address.SystemUser) - { - // we want to ignore the system account the first time only - // TODO: I think this should only be done if the system account should be treated differently? - _wasSystemAccountAccessedOnceAlready = true; - return; - } - Accounts.Add(address); } diff --git a/src/Nethermind/Nethermind.Evm/TransactionExtensions.cs b/src/Nethermind/Nethermind.Evm/TransactionExtensions.cs index 5bba6aace32..831fdd67d64 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionExtensions.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionExtensions.cs @@ -10,11 +10,9 @@ namespace Nethermind.Evm public static class TransactionExtensions { public static Address? GetRecipient(this Transaction tx, in UInt256 nonce) => - tx.To is not null - ? tx.To - : tx.IsSystem() - ? tx.SenderAddress - : ContractAddress.From(tx.SenderAddress, nonce > 0 ? nonce - 1 : nonce); + tx.To ?? (tx.IsSystem() + ? tx.SenderAddress + : ContractAddress.From(tx.SenderAddress, nonce > 0 ? nonce - 1 : nonce)); public static TxGasInfo GetGasInfo(this Transaction tx, bool is1559Enabled, BlockHeader header) { diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs index 31232e3b7c6..46316db20c8 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs @@ -6,16 +6,10 @@ namespace Nethermind.Evm.TransactionProcessing { - public class CallAndRestoreTransactionProcessorAdapter : ITransactionProcessorAdapter + public class CallAndRestoreTransactionProcessorAdapter(ITransactionProcessor transactionProcessor) + : ITransactionProcessorAdapter { - private readonly ITransactionProcessor _transactionProcessor; - - public CallAndRestoreTransactionProcessorAdapter(ITransactionProcessor transactionProcessor) - { - _transactionProcessor = transactionProcessor; - } - public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => - _transactionProcessor.CallAndRestore(transaction, in blkCtx, txTracer); + transactionProcessor.CallAndRestore(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs index 729db62505e..8dc2274bc54 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs @@ -6,16 +6,10 @@ namespace Nethermind.Evm.TransactionProcessing { - public class ExecuteTransactionProcessorAdapter : ITransactionProcessorAdapter + public class ExecuteTransactionProcessorAdapter(ITransactionProcessor transactionProcessor) + : ITransactionProcessorAdapter { - private readonly ITransactionProcessor _transactionProcessor; - - public ExecuteTransactionProcessorAdapter(ITransactionProcessor transactionProcessor) - { - _transactionProcessor = transactionProcessor; - } - public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => - _transactionProcessor.Execute(transaction, in blkCtx, txTracer); + transactionProcessor.Execute(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs new file mode 100644 index 00000000000..1110dd289a1 --- /dev/null +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Core.Specs; +using Nethermind.Evm.Tracing; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.Specs; +using Nethermind.State; + +namespace Nethermind.Evm.TransactionProcessing; + +public sealed class SystemTransactionProcessor : TransactionProcessorBase +{ + private readonly bool _isAura; + + /// + /// Hacky flag to execution options, to pass information how original validate should behave. + /// Needed to decide if we need to subtract transaction value. + /// + private const int OriginalValidate = 2 << 30; + + public SystemTransactionProcessor(ISpecProvider? specProvider, + IWorldState? worldState, + IVirtualMachine? virtualMachine, + ICodeInfoRepository? codeInfoRepository, + ILogManager? logManager) + : base(specProvider, worldState, virtualMachine, codeInfoRepository, logManager) + { + _isAura = SpecProvider.SealEngine == SealEngineType.AuRa; + } + + protected override TransactionResult Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) + { + if (_isAura && !blCtx.Header.IsGenesis) + { + WorldState.CreateAccountIfNotExists(Address.SystemUser, UInt256.Zero, UInt256.Zero); + } + + return base.Execute(tx, in blCtx, tracer, !opts.HasFlag(ExecutionOptions.NoValidation) + ? opts | (ExecutionOptions)OriginalValidate | ExecutionOptions.NoValidation + : opts); + } + + + protected override IReleaseSpec GetSpec(Transaction tx, BlockHeader header) => new SystemTransactionReleaseSpec(base.GetSpec(tx, header), _isAura, header.IsGenesis); + + protected override TransactionResult ValidateGas(Transaction tx, BlockHeader header, long intrinsicGas, bool validate) => TransactionResult.Ok; + + protected override TransactionResult IncrementNonce(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) => TransactionResult.Ok; + + protected override void DecrementNonce(Transaction tx) { } + + protected override void PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in byte statusCode) { } + + protected override void PayValue(Transaction tx, IReleaseSpec spec, ExecutionOptions opts) + { + if (opts.HasFlag((ExecutionOptions)OriginalValidate)) + { + base.PayValue(tx, spec, opts); + } + } + + protected override bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, ExecutionOptions opts, in UInt256 effectiveGasPrice) + { + Address? sender = tx.SenderAddress; + return (sender is null || (spec.IsEip158IgnoredAccount(sender) && !WorldState.AccountExists(sender))) + && base.RecoverSenderIfNeeded(tx, spec, opts, in effectiveGasPrice); + } +} diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs index f272308db25..12f2daf3168 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs @@ -6,16 +6,10 @@ namespace Nethermind.Evm.TransactionProcessing { - public class TraceTransactionProcessorAdapter : ITransactionProcessorAdapter + public class TraceTransactionProcessorAdapter(ITransactionProcessor transactionProcessor) + : ITransactionProcessorAdapter { - private readonly ITransactionProcessor _transactionProcessor; - - public TraceTransactionProcessorAdapter(ITransactionProcessor transactionProcessor) - { - _transactionProcessor = transactionProcessor; - } - public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => - _transactionProcessor.Trace(transaction, in blkCtx, txTracer); + transactionProcessor.Trace(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index f01be3bfdeb..3e4a8c2fe4d 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -15,7 +15,6 @@ using Nethermind.Evm.Tracing; using Nethermind.Int256; using Nethermind.Logging; -using Nethermind.Specs; using Nethermind.State; using Nethermind.State.Tracing; using static Nethermind.Core.Extensions.MemoryExtensions; @@ -24,14 +23,24 @@ namespace Nethermind.Evm.TransactionProcessing { - public class TransactionProcessor : ITransactionProcessor + public sealed class TransactionProcessor( + ISpecProvider? specProvider, + IWorldState? worldState, + IVirtualMachine? virtualMachine, + ICodeInfoRepository? codeInfoRepository, + ILogManager? logManager) + : TransactionProcessorBase(specProvider, worldState, virtualMachine, codeInfoRepository, logManager); + + public abstract class TransactionProcessorBase : ITransactionProcessor { - protected EthereumEcdsa Ecdsa { get; private init; } - protected ILogger Logger { get; private init; } - protected ISpecProvider SpecProvider { get; private init; } - protected IWorldState WorldState { get; private init; } - protected IVirtualMachine VirtualMachine { get; private init; } + protected EthereumEcdsa Ecdsa { get; } + protected ILogger Logger { get; } + protected ISpecProvider SpecProvider { get; } + protected IWorldState WorldState { get; } + protected IVirtualMachine VirtualMachine { get; } private readonly ICodeInfoRepository _codeInfoRepository; + private SystemTransactionProcessor? _systemTransactionProcessor; + private readonly ILogManager _logManager; [Flags] protected enum ExecutionOptions @@ -62,7 +71,7 @@ protected enum ExecutionOptions CommitAndRestore = Commit | Restore | NoValidation } - public TransactionProcessor( + protected TransactionProcessorBase( ISpecProvider? specProvider, IWorldState? worldState, IVirtualMachine? virtualMachine, @@ -82,31 +91,41 @@ public TransactionProcessor( _codeInfoRepository = codeInfoRepository; Ecdsa = new EthereumEcdsa(specProvider.ChainId); + _logManager = logManager; } public TransactionResult CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => - Execute(transaction, in blCtx, txTracer, ExecutionOptions.CommitAndRestore); + ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.CommitAndRestore); public TransactionResult BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) { // we need to treat the result of previous transaction as the original value of next transaction // when we do not commit WorldState.TakeSnapshot(true); - return Execute(transaction, in blCtx, txTracer, ExecutionOptions.None); + return ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.None); } public TransactionResult Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => - Execute(transaction, in blCtx, txTracer, ExecutionOptions.Commit); + ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.Commit); public TransactionResult Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => - Execute(transaction, in blCtx, txTracer, ExecutionOptions.NoValidation); + ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.NoValidation); + + private TransactionResult ExecuteCore(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) + { + if (tx.IsSystem()) + { + _systemTransactionProcessor ??= new SystemTransactionProcessor(SpecProvider, WorldState, VirtualMachine, _codeInfoRepository, _logManager); + return _systemTransactionProcessor.Execute(tx, blCtx.Header, tracer, opts); + } + + return Execute(tx, in blCtx, tracer, opts); + } protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { BlockHeader header = blCtx.Header; - IReleaseSpec spec = SpecProvider.GetSpec(header); - if (tx.IsSystem()) - spec = new SystemTransactionReleaseSpec(spec); + IReleaseSpec spec = GetSpec(tx, header); // restore is CallAndRestore - previous call, we will restore state after the execution bool restore = opts.HasFlag(ExecutionOptions.Restore); @@ -116,7 +135,7 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon bool commit = opts.HasFlag(ExecutionOptions.Commit) || !spec.IsEip658Enabled; TransactionResult result; - if (!(result = ValidateStatic(tx, header, spec, tracer, opts, out long intrinsicGas))) return result; + if (!(result = ValidateStatic(tx, header, spec, opts, out long intrinsicGas))) return result; UInt256 effectiveGasPrice = tx.CalculateEffectiveGasPrice(spec.IsEip1559Enabled, header.BaseFeePerGas); @@ -142,15 +161,13 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon WorldState.Reset(); if (deleteCallerAccount) { - WorldState.DeleteAccount(tx.SenderAddress); + WorldState.DeleteAccount(tx.SenderAddress!); } else { if (!opts.HasFlag(ExecutionOptions.NoValidation)) - WorldState.AddToBalance(tx.SenderAddress, senderReservedGasPayment, spec); - if (!tx.IsSystem()) - WorldState.DecrementNonce(tx.SenderAddress); - + WorldState.AddToBalance(tx.SenderAddress!, senderReservedGasPayment, spec); + DecrementNonce(tx); WorldState.Commit(spec); } } @@ -183,6 +200,8 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon return TransactionResult.Ok; } + protected virtual IReleaseSpec GetSpec(Transaction tx, BlockHeader header) => SpecProvider.GetSpec(header); + private static void UpdateMetrics(ExecutionOptions opts, UInt256 effectiveGasPrice) { if (opts is ExecutionOptions.Commit or ExecutionOptions.None && (effectiveGasPrice[2] | effectiveGasPrice[3]) == 0) @@ -214,11 +233,15 @@ private static void UpdateMetrics(ExecutionOptions opts, UInt256 effectiveGasPri /// The transaction to validate /// The block containing the transaction. Only BaseFee is being used from the block atm. /// The release spec with which the transaction will be executed - /// The transaction tracer /// Options (Flags) to use for execution - /// Computed premium per gas + /// Calculated intrinsic gas /// - protected virtual TransactionResult ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, out long intrinsicGas) + protected TransactionResult ValidateStatic( + Transaction tx, + BlockHeader header, + IReleaseSpec spec, + ExecutionOptions opts, + out long intrinsicGas) { intrinsicGas = IntrinsicGasCalculator.Calculate(tx, spec); @@ -247,36 +270,37 @@ protected virtual TransactionResult ValidateStatic(Transaction tx, BlockHeader h return "EIP-3860 - transaction size over max init code size"; } - if (!tx.IsSystem()) + return ValidateGas(tx, header, intrinsicGas, validate); + } + + protected virtual TransactionResult ValidateGas(Transaction tx, BlockHeader header, long intrinsicGas, bool validate) + { + if (tx.GasLimit < intrinsicGas) { - if (tx.GasLimit < intrinsicGas) - { - TraceLogInvalidTx(tx, $"GAS_LIMIT_BELOW_INTRINSIC_GAS {tx.GasLimit} < {intrinsicGas}"); - return "gas limit below intrinsic gas"; - } + TraceLogInvalidTx(tx, $"GAS_LIMIT_BELOW_INTRINSIC_GAS {tx.GasLimit} < {intrinsicGas}"); + return "gas limit below intrinsic gas"; + } - if (validate && tx.GasLimit > header.GasLimit - header.GasUsed) - { - TraceLogInvalidTx(tx, $"BLOCK_GAS_LIMIT_EXCEEDED {tx.GasLimit} > {header.GasLimit} - {header.GasUsed}"); - return "block gas limit exceeded"; - } + if (validate && tx.GasLimit > header.GasLimit - header.GasUsed) + { + TraceLogInvalidTx(tx, $"BLOCK_GAS_LIMIT_EXCEEDED {tx.GasLimit} > {header.GasLimit} - {header.GasUsed}"); + return "block gas limit exceeded"; } return TransactionResult.Ok; } // TODO Should we remove this already - protected bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, ExecutionOptions opts, in UInt256 effectiveGasPrice) + protected virtual bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, ExecutionOptions opts, in UInt256 effectiveGasPrice) { - bool commit = opts.HasFlag(ExecutionOptions.Commit) || !spec.IsEip658Enabled; - bool restore = opts.HasFlag(ExecutionOptions.Restore); - bool noValidation = opts.HasFlag(ExecutionOptions.NoValidation); - bool deleteCallerAccount = false; - - Address sender = tx.SenderAddress; + Address? sender = tx.SenderAddress; if (sender is null || !WorldState.AccountExists(sender)) { + bool commit = opts.HasFlag(ExecutionOptions.Commit) || !spec.IsEip658Enabled; + bool restore = opts.HasFlag(ExecutionOptions.Restore); + bool noValidation = opts.HasFlag(ExecutionOptions.NoValidation); + if (Logger.IsDebug) Logger.Debug($"TX sender account does not exist {sender} - trying to recover it"); // hacky fix for the potential recovery issue @@ -285,8 +309,7 @@ protected bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, Executio if (sender != tx.SenderAddress) { - if (Logger.IsWarn) - Logger.Warn($"TX recovery issue fixed - tx was coming with sender {sender} and the now it recovers to {tx.SenderAddress}"); + if (Logger.IsWarn) Logger.Warn($"TX recovery issue fixed - tx was coming with sender {sender} and the now it recovers to {tx.SenderAddress}"); sender = tx.SenderAddress; } else @@ -313,7 +336,7 @@ protected virtual TransactionResult ValidateSender(Transaction tx, BlockHeader h { bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); - if (validate && WorldState.IsInvalidContractSender(spec, tx.SenderAddress)) + if (validate && WorldState.IsInvalidContractSender(spec, tx.SenderAddress!)) { TraceLogInvalidTx(tx, "SENDER_IS_CONTRACT"); return "sender has deployed code"; @@ -329,7 +352,7 @@ protected virtual TransactionResult BuyGas(Transaction tx, BlockHeader header, I senderReservedGasPayment = UInt256.Zero; bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); - if (!tx.IsSystem() && validate) + if (validate) { if (!tx.TryCalculatePremiumPerGas(header.BaseFeePerGas, out premiumPerGas)) { @@ -337,7 +360,7 @@ protected virtual TransactionResult BuyGas(Transaction tx, BlockHeader header, I return "miner premium is negative"; } - UInt256 senderBalance = WorldState.GetBalance(tx.SenderAddress); + UInt256 senderBalance = WorldState.GetBalance(tx.SenderAddress!); if (UInt256.SubtractUnderflow(senderBalance, tx.Value, out UInt256 balanceLeft)) { TraceLogInvalidTx(tx, $"INSUFFICIENT_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); @@ -355,7 +378,7 @@ protected virtual TransactionResult BuyGas(Transaction tx, BlockHeader header, I } if (tx.SupportsBlobs) { - overflows = UInt256.MultiplyOverflow(BlobGasCalculator.CalculateBlobGas(tx), (UInt256)tx.MaxFeePerBlobGas, out UInt256 maxBlobGasFee); + overflows = UInt256.MultiplyOverflow(BlobGasCalculator.CalculateBlobGas(tx), (UInt256)tx.MaxFeePerBlobGas!, out UInt256 maxBlobGasFee); if (overflows || UInt256.AddOverflow(maxGasFee, maxBlobGasFee, out UInt256 multidimGasFee) || multidimGasFee > balanceLeft) { TraceLogInvalidTx(tx, $"INSUFFICIENT_MAX_FEE_PER_BLOB_GAS_FOR_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); @@ -388,9 +411,7 @@ protected virtual TransactionResult BuyGas(Transaction tx, BlockHeader header, I protected virtual TransactionResult IncrementNonce(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) { - if (tx.IsSystem()) return TransactionResult.Ok; - - if (tx.Nonce != WorldState.GetNonce(tx.SenderAddress)) + if (tx.Nonce != WorldState.GetNonce(tx.SenderAddress!)) { TraceLogInvalidTx(tx, $"WRONG_TRANSACTION_NONCE: {tx.Nonce} (expected {WorldState.GetNonce(tx.SenderAddress)})"); return "wrong transaction nonce"; @@ -400,16 +421,21 @@ protected virtual TransactionResult IncrementNonce(Transaction tx, BlockHeader h return TransactionResult.Ok; } - protected ExecutionEnvironment BuildExecutionEnvironment( + protected virtual void DecrementNonce(Transaction tx) + { + WorldState.DecrementNonce(tx.SenderAddress!); + } + + private ExecutionEnvironment BuildExecutionEnvironment( Transaction tx, in BlockExecutionContext blCtx, IReleaseSpec spec, in UInt256 effectiveGasPrice) { - Address recipient = tx.GetRecipient(tx.IsContractCreation ? WorldState.GetNonce(tx.SenderAddress) : 0); + Address recipient = tx.GetRecipient(tx.IsContractCreation ? WorldState.GetNonce(tx.SenderAddress!) : 0); if (recipient is null) ThrowInvalidDataException("Recipient has not been resolved properly before tx execution"); - TxExecutionContext executionContext = new(in blCtx, tx.SenderAddress, effectiveGasPrice, tx.BlobVersionedHashes); + TxExecutionContext executionContext = new(in blCtx, tx.SenderAddress!, effectiveGasPrice, tx.BlobVersionedHashes!); CodeInfo codeInfo = tx.IsContractCreation ? new(tx.Data ?? Memory.Empty) @@ -434,7 +460,7 @@ protected ExecutionEnvironment BuildExecutionEnvironment( protected virtual bool ShouldValidate(ExecutionOptions opts) => !opts.HasFlag(ExecutionOptions.NoValidation); - protected void ExecuteEvmCall( + protected virtual void ExecuteEvmCall( Transaction tx, BlockHeader header, IReleaseSpec spec, @@ -456,10 +482,7 @@ protected void ExecuteEvmCall( Snapshot snapshot = WorldState.TakeSnapshot(); - // Fixes eth_estimateGas. - // If sender is SystemUser subtracting value will cause InsufficientBalanceException - if (validate || !tx.IsSystem()) - WorldState.SubtractFromBalance(tx.SenderAddress, tx.Value, spec); + PayValue(tx, spec, opts); try { @@ -480,13 +503,13 @@ protected void ExecuteEvmCall( if (spec.UseHotAndColdStorage) { - state.WarmUp(tx.SenderAddress); // eip-2929 + state.WarmUp(tx.SenderAddress!); // eip-2929 state.WarmUp(env.ExecutingAccount); // eip-2929 } if (spec.AddCoinbaseToTxAccessList) { - state.WarmUp(header.GasBeneficiary); + state.WarmUp(header.GasBeneficiary!); } substate = !tracer.IsTracingActions @@ -556,28 +579,30 @@ protected void ExecuteEvmCall( WorldState.Restore(snapshot); } - if (validate && !tx.IsSystem()) + if (!opts.HasFlag(ExecutionOptions.NoValidation)) header.GasUsed += spentGas; } + protected virtual void PayValue(Transaction tx, IReleaseSpec spec, ExecutionOptions opts) + { + WorldState.SubtractFromBalance(tx.SenderAddress!, tx.Value, spec); + } + protected virtual void PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in byte statusCode) { - if (!tx.IsSystem()) + bool gasBeneficiaryNotDestroyed = substate?.DestroyList.Contains(header.GasBeneficiary) != true; + if (statusCode == StatusCode.Failure || gasBeneficiaryNotDestroyed) { - bool gasBeneficiaryNotDestroyed = substate?.DestroyList.Contains(header.GasBeneficiary) != true; - if (statusCode == StatusCode.Failure || gasBeneficiaryNotDestroyed) - { - UInt256 fees = (UInt256)spentGas * premiumPerGas; - UInt256 burntFees = !tx.IsFree() ? (UInt256)spentGas * header.BaseFeePerGas : 0; + UInt256 fees = (UInt256)spentGas * premiumPerGas; + UInt256 burntFees = !tx.IsFree() ? (UInt256)spentGas * header.BaseFeePerGas : 0; - WorldState.AddToBalanceAndCreateIfNotExists(header.GasBeneficiary, fees, spec); + WorldState.AddToBalanceAndCreateIfNotExists(header.GasBeneficiary!, fees, spec); - if (spec.IsEip1559Enabled && spec.Eip1559FeeCollector is not null && !burntFees.IsZero) - WorldState.AddToBalanceAndCreateIfNotExists(spec.Eip1559FeeCollector, burntFees, spec); + if (spec.IsEip1559Enabled && spec.Eip1559FeeCollector is not null && !burntFees.IsZero) + WorldState.AddToBalanceAndCreateIfNotExists(spec.Eip1559FeeCollector, burntFees, spec); - if (tracer.IsTracingFees) - tracer.ReportFees(fees, burntFees); - } + if (tracer.IsTracingFees) + tracer.ReportFees(fees, burntFees); } } @@ -613,7 +638,7 @@ protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec s Logger.Trace("Refunding unused gas of " + unspentGas + " and refund of " + refund); // If noValidation we didn't charge for gas, so do not refund if (!opts.HasFlag(ExecutionOptions.NoValidation)) - WorldState.AddToBalance(tx.SenderAddress, (ulong)(unspentGas + refund) * gasPrice, spec); + WorldState.AddToBalance(tx.SenderAddress!, (ulong)(unspentGas + refund) * gasPrice, spec); spentGas -= refund; } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs index 3f70c14789f..907b7a10d17 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs @@ -3,6 +3,7 @@ using System; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Processing; @@ -47,7 +48,7 @@ public class SimulateReadOnlyBlocksProcessingEnv : ReadOnlyTxProcessingEnvBase, { private readonly IBlockValidator _blockValidator; private readonly ILogManager? _logManager; - private readonly TransactionProcessor _transactionProcessor; + private readonly ITransactionProcessor _transactionProcessor; public IWorldState WorldState => StateProvider; public SimulateReadOnlyBlocksProcessingEnv( @@ -114,5 +115,6 @@ public IBlockProcessor GetProcessor(bool validate, UInt256? blobBaseFeeOverride) StateProvider, NullReceiptStorage.Instance, new BlockhashStore(SpecProvider, StateProvider), + new BeaconBlockRootHandler(_transactionProcessor), _logManager); } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs index 9b6ebb52192..705a68ec071 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs @@ -12,14 +12,14 @@ namespace Nethermind.Facade.Simulate; -public class SimulateTransactionProcessor( +public sealed class SimulateTransactionProcessor( ISpecProvider? specProvider, IWorldState? worldState, IVirtualMachine? virtualMachine, ICodeInfoRepository? codeInfoRepository, ILogManager? logManager, bool validate) - : TransactionProcessor(specProvider, worldState, virtualMachine, codeInfoRepository, logManager), ITransactionProcessor + : TransactionProcessorBase(specProvider, worldState, virtualMachine, codeInfoRepository, logManager), ITransactionProcessor { protected override bool ShouldValidate(ExecutionOptions opts) => true; diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs index 21189802d53..5bbdd17de96 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Filters; using Nethermind.Blockchain.FullPruning; @@ -238,6 +239,7 @@ protected virtual BlockProcessor CreateBlockProcessor(BlockCachePreWarmer? preWa worldState, _api.ReceiptStorage, new BlockhashStore(_api.SpecProvider!, worldState), + new BeaconBlockRootHandler(_api.TransactionProcessor), _api.LogManager, preWarmer: preWarmer ); diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializePrecompiles.cs b/src/Nethermind/Nethermind.Init/Steps/InitializePrecompiles.cs index 2369dcc5923..37b1706f28e 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializePrecompiles.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializePrecompiles.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Api; +using Nethermind.Core.Specs; using Nethermind.Crypto; using Nethermind.Logging; diff --git a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs index 4d3ee0b8392..6e2270e2446 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs @@ -3,6 +3,7 @@ using BenchmarkDotNet.Attributes; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Filters; using Nethermind.Blockchain.Find; @@ -94,8 +95,16 @@ TransactionProcessor transactionProcessor = new(MainnetSpecProvider.Instance, stateProvider, _virtualMachine, codeInfoRepository, LimboLogs.Instance); IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor = new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider); - BlockProcessor blockProcessor = new(specProvider, Always.Valid, new RewardCalculator(specProvider), transactionsExecutor, - stateProvider, NullReceiptStorage.Instance, new BlockhashStore(specProvider, stateProvider), LimboLogs.Instance); + BlockProcessor blockProcessor = new( + specProvider, + Always.Valid, + new RewardCalculator(specProvider), + transactionsExecutor, + stateProvider, + NullReceiptStorage.Instance, + new BlockhashStore(specProvider, stateProvider), + new BeaconBlockRootHandler(transactionProcessor), + LimboLogs.Instance); EthereumEcdsa ecdsa = new(specProvider.ChainId); BlockchainProcessor blockchainProcessor = new( diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs index c5b2ae5db1a..46033f3ed70 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcModuleTests.cs @@ -314,17 +314,17 @@ void handleNewBlock(object? sender, BlockEventArgs e) string getFilterLogsSerialized1 = await test.TestEthRpc("eth_getFilterChanges", (newFilterResp as JsonRpcSuccessResponse)!.Result?.ToString() ?? "0x0"); //expect empty - no changes so far - Assert.That(getFilterLogsSerialized1, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":[],\"id\":67}")); + getFilterLogsSerialized1.Should().Be("{\"jsonrpc\":\"2.0\",\"result\":[],\"id\":67}"); await test.AddBlock(createCodeTx); //expect new transaction logs string getFilterLogsSerialized2 = await test.TestEthRpc("eth_getFilterChanges", (newFilterResp as JsonRpcSuccessResponse)!.Result?.ToString() ?? "0x0"); - Assert.That(getFilterLogsSerialized2, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":[{\"address\":\"0x0ffd3e46594919c04bcfd4e146203c8255670828\",\"blockHash\":\"0x2eb166ba88c43f96f980a573aebcee792fda4d34ad4c353dfd3d08cdf80adfae\",\"blockNumber\":\"0x4\",\"data\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"logIndex\":\"0x0\",\"removed\":false,\"topics\":[],\"transactionHash\":\"0x8c9c109bff7969c8aed8e51ab4ea35c6f835a0c3266bc5c5721821a38cbf5445\",\"transactionIndex\":\"0x0\",\"transactionLogIndex\":\"0x0\"}],\"id\":67}")); + getFilterLogsSerialized2.Should().Be("{\"jsonrpc\":\"2.0\",\"result\":[{\"address\":\"0x0ffd3e46594919c04bcfd4e146203c8255670828\",\"blockHash\":\"0xf9fc52a47b7da4e8227cd60e9c368fa7d44df7f3226d5163005eec015588d64b\",\"blockNumber\":\"0x4\",\"data\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"logIndex\":\"0x0\",\"removed\":false,\"topics\":[],\"transactionHash\":\"0x8c9c109bff7969c8aed8e51ab4ea35c6f835a0c3266bc5c5721821a38cbf5445\",\"transactionIndex\":\"0x0\",\"transactionLogIndex\":\"0x0\"}],\"id\":67}"); //expect empty - previous call cleans logs string getFilterLogsSerialized3 = await test.TestEthRpc("eth_getFilterChanges", (newFilterResp as JsonRpcSuccessResponse)!.Result?.ToString() ?? "0x0"); - Assert.That(getFilterLogsSerialized3, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":[],\"id\":67}")); + getFilterLogsSerialized3.Should().Be("{\"jsonrpc\":\"2.0\",\"result\":[],\"id\":67}"); } [Test] diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs index 5134da7c20b..1d132d4bf33 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs @@ -917,8 +917,6 @@ public async Task MultipleSubscriptions_concurrent_fast_messages(int messages) [Test] public void NewHeadSubscription_with_baseFeePerGas_test() { - _specProvider.GetSpec(Arg.Any(), Arg.Any()).IsEip1559Enabled.Returns(true); - _specProvider.GetSpec(Arg.Any()).IsEip1559Enabled.Returns(true); _specProvider.GetSpec(Arg.Any()).IsEip1559Enabled.Returns(true); Block block = Build.A.Block.Genesis.WithTotalDifficulty(0L).WithBaseFeePerGas(10000).TestObject; BlockReplacementEventArgs blockReplacementEventArgs = new(block); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs index e45f59a631b..901c35bdbd0 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs @@ -4,6 +4,7 @@ using System.Linq; using FluentAssertions; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; @@ -76,6 +77,7 @@ public void Setup() stateProvider, NullReceiptStorage.Instance, new BlockhashStore(specProvider, stateProvider), + new BeaconBlockRootHandler(transactionProcessor), LimboLogs.Instance); RecoverSignatures txRecovery = new(new EthereumEcdsa(TestBlockchainIds.ChainId), NullTxPool.Instance, specProvider, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index 1fab4d08e2b..165cc9310c6 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -541,7 +541,7 @@ public async Task Trace_transaction_with_error_reverted() traces.Data.ElementAt(0).TransactionHash.Should().Be(transaction2.Hash!); string serialized = new EthereumJsonSerializer().Serialize(traces.Data); - Assert.That(serialized, Is.EqualTo("[{\"action\":{\"creationMethod\":\"create\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x9a6c\",\"init\":\"0x60006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f160006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f1fd\",\"value\":\"0x1\"},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"subtraces\":2,\"traceAddress\":[],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"create\",\"error\":\"Reverted\"},{\"action\":{\"callType\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"gas\":\"0x2dcd\",\"input\":\"0x\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"value\":\"0x0\"},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[0],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"gas\":\"0x2d56\",\"input\":\"0x\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"value\":\"0x0\"},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[1],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"}]"), serialized.Replace("\"", "\\\"")); + Assert.That(serialized, Is.EqualTo("[{\"action\":{\"creationMethod\":\"create\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x9a6c\",\"init\":\"0x60006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f160006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f1fd\",\"value\":\"0x1\"},\"blockHash\":\"0xeb0d05efb43e565c4a677e64dde4cd1339459310afe8f578acab57ad45dd8f44\",\"blockNumber\":18,\"subtraces\":2,\"traceAddress\":[],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"create\",\"error\":\"Reverted\"},{\"action\":{\"callType\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"gas\":\"0x8def\",\"input\":\"0x\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"value\":\"0x0\"},\"blockHash\":\"0xeb0d05efb43e565c4a677e64dde4cd1339459310afe8f578acab57ad45dd8f44\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[0],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"gas\":\"0x8d78\",\"input\":\"0x\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"value\":\"0x0\"},\"blockHash\":\"0xeb0d05efb43e565c4a677e64dde4cd1339459310afe8f578acab57ad45dd8f44\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[1],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"}]"), serialized.Replace("\"", "\\\"")); } [Test] public async Task trace_timeout_is_separate_for_rpc_calls() diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/RpcBlockTransactionsExecutor.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/RpcBlockTransactionsExecutor.cs index 63dbf44dc05..38b04afb218 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/RpcBlockTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/RpcBlockTransactionsExecutor.cs @@ -7,11 +7,7 @@ namespace Nethermind.JsonRpc.Modules { - public class RpcBlockTransactionsExecutor : BlockProcessor.BlockValidationTransactionsExecutor - { - public RpcBlockTransactionsExecutor(ITransactionProcessor transactionProcessor, IWorldState stateProvider) - : base(new TraceTransactionProcessorAdapter(transactionProcessor), stateProvider) - { - } - } + public class RpcBlockTransactionsExecutor(ITransactionProcessor transactionProcessor, IWorldState stateProvider) + : BlockProcessor.BlockValidationTransactionsExecutor(new TraceTransactionProcessorAdapter(transactionProcessor), + stateProvider); } diff --git a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs index 1b2c2b804d6..698f42f8877 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; @@ -18,6 +19,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; +using Nethermind.Core.Test.Blockchain; using Nethermind.Core.Timers; using Nethermind.Facade.Eth; using Nethermind.Int256; @@ -97,6 +99,12 @@ public MergeAuRaTestBlockchain(IMergeConfig? mergeConfig = null, IPayloadPrepara SealEngineType = Core.SealEngineType.AuRa; } + protected override Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) + { + if (specProvider is TestSingleReleaseSpecProvider provider) provider.SealEngine = SealEngineType; + return base.Build(specProvider, initialValues, addBlockOnStart); + } + protected override IBlockProcessor CreateBlockProcessor() { _api = new(new ConfigProvider(), new EthereumJsonSerializer(), LogManager, @@ -132,6 +140,7 @@ protected override IBlockProcessor CreateBlockProcessor() State, ReceiptStorage, new BlockhashStore(SpecProvider, State), + new BeaconBlockRootHandler(TxProcessor), LogManager, WithdrawalProcessor, preWarmer: CreateBlockCachePreWarmer()); diff --git a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProcessor.cs b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProcessor.cs index 1a55b725abd..e07a4709bbe 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProcessor.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Validators; @@ -18,41 +19,38 @@ namespace Nethermind.Merge.AuRa; -public class AuRaMergeBlockProcessor : AuRaBlockProcessor +public class AuRaMergeBlockProcessor( + ISpecProvider specProvider, + IBlockValidator blockValidator, + IRewardCalculator rewardCalculator, + IBlockProcessor.IBlockTransactionsExecutor blockTransactionsExecutor, + IWorldState stateProvider, + IReceiptStorage receiptStorage, + IBeaconBlockRootHandler beaconBlockRootHandler, + ILogManager logManager, + IBlockTree blockTree, + IWithdrawalProcessor withdrawalProcessor, + IAuRaValidator? validator, + ITxFilter? txFilter = null, + AuRaContractGasLimitOverride? gasLimitOverride = null, + ContractRewriter? contractRewriter = null, + IBlockCachePreWarmer? preWarmer = null) + : AuRaBlockProcessor(specProvider, + blockValidator, + rewardCalculator, + blockTransactionsExecutor, + stateProvider, + receiptStorage, + beaconBlockRootHandler, + logManager, + blockTree, + withdrawalProcessor, + validator, + txFilter, + gasLimitOverride, + contractRewriter, + preWarmer) { - public AuRaMergeBlockProcessor( - ISpecProvider specProvider, - IBlockValidator blockValidator, - IRewardCalculator rewardCalculator, - IBlockProcessor.IBlockTransactionsExecutor blockTransactionsExecutor, - IWorldState stateProvider, - IReceiptStorage receiptStorage, - ILogManager logManager, - IBlockTree blockTree, - IWithdrawalProcessor withdrawalProcessor, - IAuRaValidator? validator, - ITxFilter? txFilter = null, - AuRaContractGasLimitOverride? gasLimitOverride = null, - ContractRewriter? contractRewriter = null, - IBlockCachePreWarmer? preWarmer = null - ) : base( - specProvider, - blockValidator, - rewardCalculator, - blockTransactionsExecutor, - stateProvider, - receiptStorage, - logManager, - blockTree, - withdrawalProcessor, - validator, - txFilter, - gasLimitOverride, - contractRewriter, - preWarmer - ) - { } - protected override TxReceipt[] ProcessBlock(Block block, IBlockTracer blockTracer, ProcessingOptions options) => block.IsPostMerge ? PostMergeProcessBlock(block, blockTracer, options) diff --git a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs index f91dac19352..c725e7164ff 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergeBlockProducerEnvFactory.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.AuRa.Config; @@ -71,6 +72,7 @@ protected override BlockProcessor CreateBlockProcessor( TransactionsExecutorFactory.Create(readOnlyTxProcessingEnv), readOnlyTxProcessingEnv.WorldState, receiptStorage, + new BeaconBlockRootHandler(readOnlyTxProcessingEnv.TransactionProcessor), logManager, _blockTree, new Consensus.Withdrawals.BlockProductionWithdrawalProcessor( diff --git a/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs b/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs index cf4b4d4b6be..cb0bbe3c4c8 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/InitializationSteps/InitializeBlockchainAuRaMerge.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.InitializationSteps; using Nethermind.Consensus.AuRa.Validators; @@ -36,14 +37,14 @@ protected override AuRaBlockProcessor NewAuraBlockProcessor(ITxFilter txFilter, return new AuRaMergeBlockProcessor( _api.SpecProvider!, _api.BlockValidator!, - _api.RewardCalculatorSource!.Get(_api.TransactionProcessor!), - new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor!, worldState), + _api.RewardCalculatorSource!.Get(transactionProcessor), + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, worldState), worldState, _api.ReceiptStorage!, + new BeaconBlockRootHandler(transactionProcessor), _api.LogManager, _api.BlockTree!, - new AuraWithdrawalProcessor( - withdrawalContractFactory.Create(transactionProcessor!), _api.LogManager), + new AuraWithdrawalProcessor(withdrawalContractFactory.Create(transactionProcessor), _api.LogManager), CreateAuRaValidator(), txFilter, GetGasLimitCalculator(), diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs index dd4de68d98d..9db79267ba9 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.HelperFunctions.cs @@ -20,7 +20,6 @@ using Nethermind.Specs; using Nethermind.Specs.Forks; using Nethermind.State; -using Nethermind.Consensus.BeaconBlockRoot; namespace Nethermind.Merge.Plugin.Test { @@ -28,7 +27,6 @@ namespace Nethermind.Merge.Plugin.Test public partial class EngineModuleTests { private static readonly DateTime Timestamp = DateTimeOffset.FromUnixTimeSeconds(1000).UtcDateTime; - private static readonly IBeaconBlockRootHandler _beaconBlockRootHandler = new BeaconBlockRootHandler(); private ITimestamper Timestamper { get; } = new ManualTimestamper(Timestamp); private void AssertExecutionStatusChanged(IBlockFinder blockFinder, Hash256 headBlockHash, Hash256 finalizedBlockHash, Hash256 safeBlockHash) @@ -124,7 +122,6 @@ private static ExecutionPayloadV3 CreateBlockRequestV3(MergeTestBlockchain chain blockRequestV3.TryGetBlock(out Block? block); Snapshot before = chain.State.TakeSnapshot(); - _beaconBlockRootHandler.ApplyContractStateChanges(block!, chain.SpecProvider.GenesisSpec, chain.State); var blockHashStore = new BlockhashStore(chain.SpecProvider, chain.State); blockHashStore.ApplyBlockhashStateChanges(block!.Header); chain.WithdrawalProcessor?.ProcessWithdrawals(block!, chain.SpecProvider.GenesisSpec); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index e07ca73d3e3..0cc6b0a5338 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; @@ -236,6 +237,7 @@ protected override IBlockProcessor CreateBlockProcessor() State, ReceiptStorage, new BlockhashStore(SpecProvider, State), + new BeaconBlockRootHandler(TxProcessor), LogManager, WithdrawalProcessor, preWarmer: CreateBlockCachePreWarmer()); diff --git a/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs b/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs index bd1e9e4db65..fc464fbfa2d 100644 --- a/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs +++ b/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs @@ -51,22 +51,12 @@ public void Test(long minimum, long actual, bool expectedResult) public void Test1559(long minimum, long maxFeePerGas, long maxPriorityFeePerGas, bool expectedResult) { ISpecProvider specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any(), Arg.Any()).IsEip1559Enabled.Returns(true); - specProvider.GetSpec(Arg.Any()).IsEip1559Enabled.Returns(true); specProvider.GetSpec(Arg.Any()).IsEip1559Enabled.Returns(true); specProvider.GetSpec(Arg.Any()).ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); specProvider.GetSpec(Arg.Any()).BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); specProvider.GetSpec(Arg.Any()).ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); - specProvider.GetSpec(Arg.Any(), Arg.Any()).ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); - specProvider.GetSpec(Arg.Any(), Arg.Any()).BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); - specProvider.GetSpec(Arg.Any(), Arg.Any()).ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); - - specProvider.GetSpec(Arg.Any()).ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); - specProvider.GetSpec(Arg.Any()).BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); - specProvider.GetSpec(Arg.Any()).ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); - BlocksConfig blocksConfig = new() { MinGasPrice = (UInt256)minimum diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index 6c42963e032..80c7f2d7e98 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Nethermind.Api; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Services; using Nethermind.Config; @@ -13,6 +14,7 @@ using Nethermind.Evm; using Nethermind.Evm.TransactionProcessing; using Nethermind.Init.Steps; +using Nethermind.Logging; using Nethermind.Merge.Plugin.InvalidChainTracker; namespace Nethermind.Optimism; @@ -85,26 +87,29 @@ protected override IBlockValidator CreateBlockValidator() protected override BlockProcessor CreateBlockProcessor(BlockCachePreWarmer? preWarmer) { + ITransactionProcessor? apiTransactionProcessor = _api.TransactionProcessor; + ILogManager? apiLogManager = _api.LogManager; + if (_api.DbProvider is null) throw new StepDependencyException(nameof(_api.DbProvider)); if (_api.RewardCalculatorSource is null) throw new StepDependencyException(nameof(_api.RewardCalculatorSource)); - if (_api.TransactionProcessor is null) throw new StepDependencyException(nameof(_api.TransactionProcessor)); + if (apiTransactionProcessor is null) throw new StepDependencyException(nameof(apiTransactionProcessor)); if (_api.SpecHelper is null) throw new StepDependencyException(nameof(_api.SpecHelper)); if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); if (_api.WorldState is null) throw new StepDependencyException(nameof(_api.WorldState)); - Create2DeployerContractRewriter contractRewriter = - new(_api.SpecHelper, _api.SpecProvider, _api.BlockTree); + Create2DeployerContractRewriter contractRewriter = new(_api.SpecHelper, _api.SpecProvider, _api.BlockTree); return new OptimismBlockProcessor( _api.SpecProvider, _api.BlockValidator, - _api.RewardCalculatorSource.Get(_api.TransactionProcessor!), - new BlockProcessor.BlockValidationTransactionsExecutor(_api.TransactionProcessor, _api.WorldState), + _api.RewardCalculatorSource.Get(apiTransactionProcessor!), + new BlockProcessor.BlockValidationTransactionsExecutor(apiTransactionProcessor, _api.WorldState), _api.WorldState, _api.ReceiptStorage, new BlockhashStore(_api.SpecProvider, _api.WorldState), - _api.LogManager, + new BeaconBlockRootHandler(apiTransactionProcessor), + apiLogManager, _api.SpecHelper, contractRewriter, new BlockProductionWithdrawalProcessor(new NullWithdrawalProcessor()), diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs index 385e7217e3c..1e05b0fe50b 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Processing; @@ -28,14 +29,25 @@ public OptimismBlockProcessor( IWorldState? stateProvider, IReceiptStorage? receiptStorage, IBlockhashStore? blockhashStore, + IBeaconBlockRootHandler? beaconBlockRootHandler, ILogManager? logManager, IOptimismSpecHelper opSpecHelper, Create2DeployerContractRewriter contractRewriter, IWithdrawalProcessor? withdrawalProcessor = null, IBlockCachePreWarmer? preWarmer = null) - : base(specProvider, blockValidator, rewardCalculator, blockTransactionsExecutor, - stateProvider, receiptStorage, blockhashStore, logManager, withdrawalProcessor, - ReceiptsRootCalculator.Instance, preWarmer) + : base( + specProvider, + blockValidator, + rewardCalculator, + blockTransactionsExecutor, + stateProvider, + receiptStorage, + blockhashStore, + beaconBlockRootHandler, + logManager, + withdrawalProcessor, + ReceiptsRootCalculator.Instance, + preWarmer) { ArgumentNullException.ThrowIfNull(stateProvider); _contractRewriter = contractRewriter; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs index f60c6638468..a72d1d9e4cb 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -87,6 +88,7 @@ protected override BlockProcessor CreateBlockProcessor( readOnlyTxProcessingEnv.WorldState, receiptStorage, new BlockhashStore(specProvider, readOnlyTxProcessingEnv.WorldState), + new BeaconBlockRootHandler(readOnlyTxProcessingEnv.TransactionProcessor), logManager, _specHelper, new Create2DeployerContractRewriter(_specHelper, _specProvider, _blockTree), diff --git a/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs index 499a0c9883f..b374b105bed 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs @@ -27,7 +27,7 @@ public class OptimismReadOnlyTxProcessingEnv( worldStateToWarmUp ) { - protected override TransactionProcessor CreateTransactionProcessor() + protected override ITransactionProcessor CreateTransactionProcessor() { ArgumentNullException.ThrowIfNull(LogManager); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs index aa71d1fae45..d21a3350ed3 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs @@ -13,7 +13,7 @@ namespace Nethermind.Optimism; -public class OptimismTransactionProcessor( +public sealed class OptimismTransactionProcessor( ISpecProvider specProvider, IWorldState worldState, IVirtualMachine virtualMachine, @@ -21,7 +21,7 @@ public class OptimismTransactionProcessor( IL1CostHelper l1CostHelper, IOptimismSpecHelper opSpecHelper, ICodeInfoRepository? codeInfoRepository - ) : TransactionProcessor(specProvider, worldState, virtualMachine, codeInfoRepository, logManager) + ) : TransactionProcessorBase(specProvider, worldState, virtualMachine, codeInfoRepository, logManager) { private UInt256? _currentTxL1Cost; @@ -64,14 +64,6 @@ protected override TransactionResult Execute(Transaction tx, in BlockExecutionCo return result; } - protected override TransactionResult ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, - out long intrinsicGas) - { - TransactionResult result = base.ValidateStatic(tx, header, spec, tracer, opts, out intrinsicGas); - - return result; - } - protected override TransactionResult BuyGas(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, in UInt256 effectiveGasPrice, out UInt256 premiumPerGas, out UInt256 senderReservedGasPayment) { diff --git a/src/Nethermind/Nethermind.Optimism/ReadOnlyChainProcessingEnv.cs b/src/Nethermind/Nethermind.Optimism/ReadOnlyChainProcessingEnv.cs index 96ee2ae5a7d..c07db6d5c56 100644 --- a/src/Nethermind/Nethermind.Optimism/ReadOnlyChainProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Optimism/ReadOnlyChainProcessingEnv.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus.Processing; @@ -63,6 +64,7 @@ IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor scope.WorldState, receiptStorage, new BlockhashStore(specProvider, scope.WorldState), + new BeaconBlockRootHandler(scope.TransactionProcessor), logManager, opSpecHelper, contractRewriter, diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs index 09ee4bc81cd..1fcbe5d6b7c 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs @@ -55,7 +55,7 @@ public OverridableReleaseSpec(IReleaseSpec spec) public bool IsEip155Enabled => _spec.IsEip155Enabled; - public bool IsEip158Enabled => _spec.IsEip1559Enabled; + public bool IsEip158Enabled => _spec.IsEip158Enabled; public bool IsEip160Enabled => _spec.IsEip160Enabled; @@ -114,10 +114,7 @@ public OverridableReleaseSpec(IReleaseSpec spec) public bool IsRip7212Enabled => _spec.IsRip7212Enabled; public bool IsEip3607Enabled { get; set; } - public bool IsEip158IgnoredAccount(Address address) - { - return _spec.IsEip158IgnoredAccount(address); - } + public bool IsEip158IgnoredAccount(Address address) => _spec.IsEip158IgnoredAccount(address); private long? _overridenEip1559TransitionBlock; public long Eip1559TransitionBlock diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableSpecProvider.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableSpecProvider.cs index 817d91feb34..fa2fbe346a2 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableSpecProvider.cs @@ -38,6 +38,7 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD public ulong NetworkId => _specProvider.NetworkId; public ulong ChainId => _specProvider.ChainId; + public string SealEngine => _specProvider.SealEngine; public ForkActivation[] TransitionActivations => _specProvider.TransitionActivations; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index d0b3805a52f..57da659f9bb 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -279,5 +279,6 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD public ulong NetworkId => _chainSpec.NetworkId; public ulong ChainId => _chainSpec.ChainId; + public string SealEngine => _chainSpec.SealEngineType; } } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index 068c4d19365..c1ced60f803 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -432,10 +432,9 @@ private static void LoadGenesis(ChainSpecJson chainSpecJson, ChainSpec chainSpec genesisHeader.AuRaStep = step; genesisHeader.AuRaSignature = auRaSignature; - if (withdrawalsEnabled) - chainSpec.Genesis = new Block(genesisHeader, Array.Empty(), Array.Empty(), Array.Empty()); - else - chainSpec.Genesis = new Block(genesisHeader); + chainSpec.Genesis = withdrawalsEnabled + ? new Block(genesisHeader, Array.Empty(), Array.Empty(), Array.Empty()) + : new Block(genesisHeader); } private static void LoadAllocations(ChainSpecJson chainSpecJson, ChainSpec chainSpec) diff --git a/src/Nethermind/Nethermind.Specs/ChiadoSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChiadoSpecProvider.cs index afdfab47a4c..023778e5096 100644 --- a/src/Nethermind/Nethermind.Specs/ChiadoSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChiadoSpecProvider.cs @@ -42,6 +42,7 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD public long? DaoBlockNumber => null; public ulong NetworkId => BlockchainIds.Chiado; public ulong ChainId => BlockchainIds.Chiado; + public string SealEngine => SealEngineType.AuRa; public ForkActivation[] TransitionActivations { get; } public static ChiadoSpecProvider Instance { get; } = new(); diff --git a/src/Nethermind/Nethermind.Specs/Forks/00_Olympic.cs b/src/Nethermind/Nethermind.Specs/Forks/00_Olympic.cs index 4180bb4cd52..4fa61f4abbc 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/00_Olympic.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/00_Olympic.cs @@ -29,6 +29,5 @@ protected Olympic() } public static IReleaseSpec Instance => LazyInitializer.EnsureInitialized(ref _instance, () => new Olympic()); - public override bool IsEip158IgnoredAccount(Address address) => false; } } diff --git a/src/Nethermind/Nethermind.Specs/GnosisSpecProvider.cs b/src/Nethermind/Nethermind.Specs/GnosisSpecProvider.cs index e79bf4fe228..38ce4fd2552 100644 --- a/src/Nethermind/Nethermind.Specs/GnosisSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/GnosisSpecProvider.cs @@ -55,6 +55,7 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD public long? DaoBlockNumber => null; public ulong NetworkId => BlockchainIds.Gnosis; public ulong ChainId => BlockchainIds.Gnosis; + public string SealEngine => SealEngineType.AuRa; public ForkActivation[] TransitionActivations { get; } public static GnosisSpecProvider Instance { get; } = new(); diff --git a/src/Nethermind/Nethermind.Specs/GoerliSpecProvider.cs b/src/Nethermind/Nethermind.Specs/GoerliSpecProvider.cs index 14a04d2ff14..4408c603aa5 100644 --- a/src/Nethermind/Nethermind.Specs/GoerliSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/GoerliSpecProvider.cs @@ -45,6 +45,7 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD public ulong NetworkId => BlockchainIds.Goerli; public ulong ChainId => BlockchainIds.Goerli; + public string SealEngine => SealEngineType.Clique; public long? DaoBlockNumber => null; public ForkActivation? MergeBlockNumber { get; private set; } public ulong TimestampFork => ShanghaiTimestamp; diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index 249fbd2a200..7db782213af 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -51,13 +51,9 @@ public class ReleaseSpec : IReleaseSpec public bool IsEip2565Enabled { get; set; } public bool IsEip2929Enabled { get; set; } public bool IsEip2930Enabled { get; set; } - public virtual bool IsEip158IgnoredAccount(Address address) => address == Address.SystemUser; // used only in testing - public ReleaseSpec Clone() - { - return (ReleaseSpec)MemberwiseClone(); - } + public ReleaseSpec Clone() => (ReleaseSpec)MemberwiseClone(); public bool IsEip1559Enabled { get; set; } public bool IsEip3198Enabled { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/SepoliaSpecProvider.cs b/src/Nethermind/Nethermind.Specs/SepoliaSpecProvider.cs index 739eea9d2cf..561ec1728c0 100644 --- a/src/Nethermind/Nethermind.Specs/SepoliaSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/SepoliaSpecProvider.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Int256; using Nethermind.Specs.Forks; @@ -33,6 +34,7 @@ public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalD public ulong NetworkId => Core.BlockchainIds.Sepolia; public ulong ChainId => NetworkId; + public string SealEngine => SealEngineType.Clique; public long? DaoBlockNumber => null; public ForkActivation? MergeBlockNumber { get; private set; } = null; public ulong TimestampFork => ISpecProvider.TimestampForkNever; diff --git a/src/Nethermind/Nethermind.Specs/SingleReleaseSpecProvider.cs b/src/Nethermind/Nethermind.Specs/SingleReleaseSpecProvider.cs index 8e6213ec749..ff963a3f420 100644 --- a/src/Nethermind/Nethermind.Specs/SingleReleaseSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/SingleReleaseSpecProvider.cs @@ -45,13 +45,10 @@ public SingleReleaseSpecProvider(IReleaseSpec releaseSpec, ulong networkId, ulon public IReleaseSpec GetSpec(ForkActivation forkActivation) => _releaseSpec; public long? DaoBlockNumber { get; } - } - public class TestSingleReleaseSpecProvider : SingleReleaseSpecProvider - { - public TestSingleReleaseSpecProvider(IReleaseSpec releaseSpec) - : base(releaseSpec, TestBlockchainIds.NetworkId, TestBlockchainIds.ChainId) - { - } + public string SealEngine { get; set; } = SealEngineType.Ethash; } + + public class TestSingleReleaseSpecProvider(IReleaseSpec releaseSpec) + : SingleReleaseSpecProvider(releaseSpec, TestBlockchainIds.NetworkId, TestBlockchainIds.ChainId); } diff --git a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs index 9d1e6bc0670..b09ad342b62 100644 --- a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs @@ -7,133 +7,8 @@ namespace Nethermind.Specs { - public class SystemTransactionReleaseSpec : IReleaseSpec + public class SystemTransactionReleaseSpec(IReleaseSpec spec, bool isAura, bool isGenesis) : ReleaseSpecDecorator(spec) { - private readonly IReleaseSpec _spec; - - public SystemTransactionReleaseSpec(IReleaseSpec spec) - { - _spec = spec; - } - public bool IsEip4844Enabled => _spec.IsEip4844Enabled; - public bool IsRip7212Enabled => _spec.IsRip7212Enabled; - - public string Name => "System"; - - public long MaximumExtraDataSize => _spec.MaximumExtraDataSize; - - public long MaxCodeSize => _spec.MaxCodeSize; - - public long MinGasLimit => _spec.MinGasLimit; - - public long GasLimitBoundDivisor => _spec.GasLimitBoundDivisor; - - public UInt256 BlockReward => _spec.BlockReward; - - public long DifficultyBombDelay => _spec.DifficultyBombDelay; - - public long DifficultyBoundDivisor => _spec.DifficultyBoundDivisor; - - public long? FixedDifficulty => _spec.FixedDifficulty; - - public int MaximumUncleCount => _spec.MaximumUncleCount; - - public bool IsTimeAdjustmentPostOlympic => _spec.IsTimeAdjustmentPostOlympic; - - public bool IsEip2Enabled => _spec.IsEip2Enabled; - - public bool IsEip7Enabled => _spec.IsEip7Enabled; - - public bool IsEip100Enabled => _spec.IsEip100Enabled; - - public bool IsEip140Enabled => _spec.IsEip140Enabled; - - public bool IsEip150Enabled => _spec.IsEip150Enabled; - - public bool IsEip155Enabled => _spec.IsEip155Enabled; - - public bool IsEip158Enabled => false; - - public bool IsEip160Enabled => _spec.IsEip160Enabled; - - public bool IsEip170Enabled => _spec.IsEip170Enabled; - - public bool IsEip196Enabled => _spec.IsEip196Enabled; - - public bool IsEip197Enabled => _spec.IsEip197Enabled; - - public bool IsEip198Enabled => _spec.IsEip198Enabled; - - public bool IsEip211Enabled => _spec.IsEip211Enabled; - - public bool IsEip214Enabled => _spec.IsEip214Enabled; - - public bool IsEip649Enabled => _spec.IsEip649Enabled; - - public bool IsEip658Enabled => _spec.IsEip658Enabled; - - public bool IsEip145Enabled => _spec.IsEip145Enabled; - - public bool IsEip1014Enabled => _spec.IsEip1014Enabled; - - public bool IsEip1052Enabled => _spec.IsEip1052Enabled; - - public bool IsEip1283Enabled => _spec.IsEip1283Enabled; - - public bool IsEip1234Enabled => _spec.IsEip1234Enabled; - - public bool IsEip1344Enabled => _spec.IsEip1344Enabled; - - public bool IsEip2028Enabled => _spec.IsEip2028Enabled; - - public bool IsEip152Enabled => _spec.IsEip152Enabled; - - public bool IsEip1108Enabled => _spec.IsEip1108Enabled; - - public bool IsEip1884Enabled => _spec.IsEip1884Enabled; - - public bool IsEip2200Enabled => _spec.IsEip2200Enabled; - - public bool IsEip2537Enabled => _spec.IsEip2537Enabled; - - public bool IsEip2565Enabled => _spec.IsEip2565Enabled; - - public bool IsEip2929Enabled => _spec.IsEip2929Enabled; - - public bool IsEip2930Enabled => _spec.IsEip2930Enabled; - - public bool IsEip1559Enabled => _spec.IsEip1559Enabled; - public bool IsEip3198Enabled => _spec.IsEip3198Enabled; - public bool IsEip3529Enabled => _spec.IsEip3529Enabled; - - public bool IsEip3541Enabled => _spec.IsEip3541Enabled; - public bool IsEip3607Enabled => _spec.IsEip3607Enabled; - - public bool IsEip158IgnoredAccount(Address address) - { - return _spec.IsEip158IgnoredAccount(address); - } - - public long Eip1559TransitionBlock => _spec.Eip1559TransitionBlock; - public ulong WithdrawalTimestamp => _spec.WithdrawalTimestamp; - - public ulong Eip4844TransitionTimestamp => _spec.Eip4844TransitionTimestamp; - - public Address Eip1559FeeCollector => _spec.Eip1559FeeCollector; - public bool IsEip1153Enabled => _spec.IsEip1153Enabled; - public bool IsEip3651Enabled => _spec.IsEip3651Enabled; - public bool IsEip3855Enabled => _spec.IsEip3855Enabled; - public bool IsEip3860Enabled => _spec.IsEip3860Enabled; - public bool IsEip4895Enabled => _spec.IsEip4895Enabled; - public bool IsEip5656Enabled => _spec.IsEip5656Enabled; - public bool IsEip6780Enabled => _spec.IsEip6780Enabled; - public bool IsEip4788Enabled => _spec.IsEip4788Enabled; - public Address Eip4788ContractAddress => _spec.Eip4788ContractAddress; - public bool IsEip2935Enabled => _spec.IsEip2935Enabled; - public bool IsEip7709Enabled => _spec.IsEip7709Enabled; - public Address Eip2935ContractAddress => _spec.Eip2935ContractAddress; - public UInt256 ForkBaseFee => _spec.ForkBaseFee; - public UInt256 BaseFeeMaxChangeDenominator => _spec.BaseFeeMaxChangeDenominator; - public long ElasticityMultiplier => _spec.ElasticityMultiplier; + public override bool IsEip158Enabled => !isAura && isGenesis && base.IsEip158Enabled; } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs index 1a0ba7d72ee..d2d4a552603 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; @@ -302,6 +303,7 @@ private SyncTestContext CreateSyncManager(int index) stateProvider, receiptStorage, new BlockhashStore(specProvider, stateProvider), + new BeaconBlockRootHandler(txProcessor), logManager); RecoverSignatures step = new(ecdsa, txPool, specProvider, logManager); @@ -324,6 +326,7 @@ private SyncTestContext CreateSyncManager(int index) devState, receiptStorage, new BlockhashStore(specProvider, devState), + new BeaconBlockRootHandler(devTxProcessor), logManager); BlockchainProcessor devChainProcessor = new(tree, devBlockProcessor, step, stateReader, logManager, diff --git a/src/Nethermind/Nethermind.Trie/TreeDumper.cs b/src/Nethermind/Nethermind.Trie/TreeDumper.cs index c7199c09877..c2c03cc695e 100644 --- a/src/Nethermind/Nethermind.Trie/TreeDumper.cs +++ b/src/Nethermind/Nethermind.Trie/TreeDumper.cs @@ -19,7 +19,7 @@ public void Reset() _builder.Clear(); } - public bool IsFullDbScan => true; + public bool IsFullDbScan { get; init; } = true; public bool ShouldVisit(Hash256 nextNode) { diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 2510d106826..289e4604bec 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -183,7 +183,7 @@ public void should_accept_1559_transactions_only_when_eip1559_enabled([Values(fa if (eip1559Enabled) { specProvider = Substitute.For(); - specProvider.GetSpec(Arg.Any()).Returns(London.Instance); + specProvider.GetSpec(Arg.Any()).Returns(London.Instance); } var txPool = CreatePool(null, specProvider); Transaction tx = Build.A.Transaction @@ -1743,7 +1743,6 @@ private static ISpecProvider GetLondonSpecProvider() { var specProvider = Substitute.For(); specProvider.GetSpec(Arg.Any()).Returns(London.Instance); - specProvider.GetSpec(Arg.Any()).Returns(London.Instance); return specProvider; } @@ -1751,7 +1750,6 @@ private static ISpecProvider GetCancunSpecProvider() { var specProvider = Substitute.For(); specProvider.GetSpec(Arg.Any()).Returns(Cancun.Instance); - specProvider.GetSpec(Arg.Any()).Returns(Cancun.Instance); return specProvider; } From 8b8cd01a0caf95b263ab0fd4f89e8ec0eaea3d8d Mon Sep 17 00:00:00 2001 From: Arindam Singh <98768062+Arindam2407@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:02:54 +0530 Subject: [PATCH 014/113] Heuristic tx censorship detection (#7259) Co-authored-by: lukasz.rozmej Co-authored-by: Marcin Sobczak --- .../Nethermind.Api/IApiWithBlockchain.cs | 2 + .../Nethermind.Api/NethermindApi.cs | 2 + .../BlockTreeTests.cs | 2 - .../BlockchainProcessorTests.cs | 3 + .../CensorshipDetectorTests.cs | 291 ++++++++++++++++++ .../Processing/BlockProcessor.cs | 7 + .../CensorshipDetector/CensorshipDetector.cs | 272 ++++++++++++++++ .../CensorshipDetectorConfig.cs | 11 + .../ICensorshipDetectorConfig.cs | 21 ++ .../Processing/CensorshipDetector/Metrics.cs | 26 ++ .../Processing/IBlockProcessor.cs | 5 + .../Processing/NullBlockProcessor.cs | 6 + .../Steps/InitializeBlockchain.cs | 33 +- .../EngineModuleTests.Setup.cs | 7 +- .../Data/GetPayloadV3Result.cs | 3 +- .../Handlers/GetPayloadV3Handler.cs | 19 +- .../Nethermind.Merge.Plugin/MergePlugin.cs | 2 +- .../Nethermind.Optimism/OptimismPlugin.cs | 2 +- .../Collections/SortedPool.cs | 8 + src/Nethermind/Nethermind.TxPool/ITxPool.cs | 2 + .../Nethermind.TxPool/NullTxPool.cs | 4 + src/Nethermind/Nethermind.TxPool/TxPool.cs | 4 + 22 files changed, 705 insertions(+), 27 deletions(-) create mode 100644 src/Nethermind/Nethermind.Consensus.Test/CensorshipDetectorTests.cs create mode 100644 src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs create mode 100644 src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetectorConfig.cs create mode 100644 src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/ICensorshipDetectorConfig.cs create mode 100644 src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/Metrics.cs diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs index 496f107e7ea..867deec5a7a 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs @@ -10,6 +10,7 @@ using Nethermind.Consensus; using Nethermind.Consensus.Comparers; using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Processing.CensorshipDetector; using Nethermind.Consensus.Producers; using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Scheduler; @@ -97,5 +98,6 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory IBlockProductionPolicy? BlockProductionPolicy { get; set; } INodeStorageFactory NodeStorageFactory { get; set; } BackgroundTaskScheduler BackgroundTaskScheduler { get; set; } + CensorshipDetector CensorshipDetector { get; set; } } } diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index e07aa13ba9e..821375276b5 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -56,6 +56,7 @@ using Nethermind.Wallet; using Nethermind.Sockets; using Nethermind.Trie; +using Nethermind.Consensus.Processing.CensorshipDetector; namespace Nethermind.Api { @@ -219,6 +220,7 @@ public ISealEngine SealEngine public IBlockProductionPolicy? BlockProductionPolicy { get; set; } public INodeStorageFactory NodeStorageFactory { get; set; } = null!; public BackgroundTaskScheduler BackgroundTaskScheduler { get; set; } = null!; + public CensorshipDetector CensorshipDetector { get; set; } = null!; public IWallet? Wallet { get; set; } public IBlockStore? BadBlocksStore { get; set; } public ITransactionComparerProvider? TransactionComparerProvider { get; set; } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs index a356bc99816..db457642581 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockTreeTests.cs @@ -1800,8 +1800,6 @@ public void BlockAddedToMain_should_have_updated_Head() Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; AddToMain(blockTree, block0); - blockTree.SuggestBlock(block0); - blockTree.UpdateMainChain(new[] { block0 }, true); long blockAddedToMainHeadNumber = 0; blockTree.BlockAddedToMain += (_, _) => { blockAddedToMainHeadNumber = blockTree.Head!.Header.Number; }; diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs index a5dc4884c80..41bc3472f20 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockchainProcessorTests.cs @@ -89,6 +89,7 @@ public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, { BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks)); Block suggestedBlock = suggestedBlocks[i]; + BlockProcessing?.Invoke(this, new BlockEventArgs(suggestedBlock)); Hash256 hash = suggestedBlock.Hash!; if (!_allowed.Contains(hash)) { @@ -119,6 +120,8 @@ public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, public event EventHandler? BlocksProcessing; + public event EventHandler? BlockProcessing; + public event EventHandler? BlockProcessed; public event EventHandler? TransactionProcessed diff --git a/src/Nethermind/Nethermind.Consensus.Test/CensorshipDetectorTests.cs b/src/Nethermind/Nethermind.Consensus.Test/CensorshipDetectorTests.cs new file mode 100644 index 00000000000..4e8ba989451 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus.Test/CensorshipDetectorTests.cs @@ -0,0 +1,291 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Nethermind.Blockchain; +using Nethermind.Consensus.Comparers; +using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Processing.CensorshipDetector; +using Nethermind.Consensus.Validators; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Core.Specs; +using Nethermind.Core.Test.Builders; +using Nethermind.Crypto; +using Nethermind.Db; +using Nethermind.Logging; +using Nethermind.Specs; +using Nethermind.Specs.Forks; +using Nethermind.State; +using Nethermind.Trie.Pruning; +using Nethermind.TxPool; +using NSubstitute; +using NUnit.Framework; + +namespace Nethermind.Consensus.Test; + +[TestFixture] +public class CensorshipDetectorTests +{ + private ILogManager _logManager; + private WorldState _stateProvider; + private IBlockTree _blockTree; + private IBlockProcessor _blockProcessor; + private ISpecProvider _specProvider; + private IEthereumEcdsa _ethereumEcdsa; + private IComparer _comparer; + private TxPool.TxPool _txPool; + private CensorshipDetector _censorshipDetector; + + [SetUp] + public void Setup() + { + _logManager = LimboLogs.Instance; + TrieStore trieStore = new(new MemDb(), _logManager); + MemDb codeDb = new(); + _stateProvider = new WorldState(trieStore, codeDb, _logManager); + _blockProcessor = Substitute.For(); + } + + [TearDown] + public void TearDown() + { + _txPool.Dispose(); + _censorshipDetector.Dispose(); + } + + // Address Censorship is given to be false here since censorship is not being detected for any address. + [Test] + public void Censorship_when_address_censorship_is_false_and_high_paying_tx_censorship_is_true_for_all_blocks_in_main_cache() + { + _txPool = CreatePool(); + _censorshipDetector = new(_blockTree, _txPool, _comparer, _blockProcessor, _logManager, new CensorshipDetectorConfig() { }); + + Transaction tx1 = SubmitTxToPool(1, TestItem.PrivateKeyA, TestItem.AddressA); + Transaction tx2 = SubmitTxToPool(2, TestItem.PrivateKeyB, TestItem.AddressA); + Transaction tx3 = SubmitTxToPool(3, TestItem.PrivateKeyC, TestItem.AddressA); + Transaction tx4 = SubmitTxToPool(4, TestItem.PrivateKeyD, TestItem.AddressA); + Transaction tx5 = SubmitTxToPool(5, TestItem.PrivateKeyE, TestItem.AddressA); + + Block block1 = Build.A.Block.WithNumber(1).WithBaseFeePerGas(0).WithTransactions([tx4]).WithParentHash(TestItem.KeccakA).TestObject; + ValueHash256 blockHash1 = block1.Hash!; + BlockProcessingWorkflow(block1); + + Block block2 = Build.A.Block.WithNumber(2).WithBaseFeePerGas(0).WithTransactions([tx3]).WithParentHash(blockHash1).TestObject; + ValueHash256 blockHash2 = block2.Hash!; + BlockProcessingWorkflow(block2); + + Block block3 = Build.A.Block.WithNumber(3).WithBaseFeePerGas(0).WithTransactions([tx2]).WithParentHash(blockHash2).TestObject; + ValueHash256 blockHash3 = block3.Hash!; + BlockProcessingWorkflow(block3); + + Block block4 = Build.A.Block.WithNumber(4).WithBaseFeePerGas(0).WithTransactions([tx1]).WithParentHash(blockHash3).TestObject; + BlockProcessingWorkflow(block4); + + Assert.That(() => _censorshipDetector.GetCensoredBlocks().Contains(new BlockNumberHash(block4)), Is.EqualTo(true).After(10, 1)); + } + + // Address Censorship is given to be false here since censorship is not being detected for any address. + [Test] + public void No_censorship_when_address_censorship_is_false_and_high_paying_tx_censorship_is_false_for_some_blocks_in_main_cache() + { + _txPool = CreatePool(); + _censorshipDetector = new(_blockTree, _txPool, _comparer, _blockProcessor, _logManager, new CensorshipDetectorConfig() { }); + + Transaction tx1 = SubmitTxToPool(1, TestItem.PrivateKeyA, TestItem.AddressA); + Transaction tx2 = SubmitTxToPool(2, TestItem.PrivateKeyB, TestItem.AddressA); + Transaction tx3 = SubmitTxToPool(3, TestItem.PrivateKeyC, TestItem.AddressA); + Transaction tx4 = SubmitTxToPool(4, TestItem.PrivateKeyD, TestItem.AddressA); + Transaction tx5 = SubmitTxToPool(5, TestItem.PrivateKeyE, TestItem.AddressA); + + // high-paying tx censorship: true + Block block1 = Build.A.Block.WithNumber(1).WithBaseFeePerGas(0).WithTransactions([tx4]).WithParentHash(TestItem.KeccakA).TestObject; + ValueHash256 blockHash1 = block1.Hash!; + BlockProcessingWorkflow(block1); + + // address censorship: false + Block block2 = Build.A.Block.WithNumber(2).WithBaseFeePerGas(0).WithTransactions([tx3, tx5]).WithParentHash(blockHash1).TestObject; + ValueHash256 blockHash2 = block2.Hash!; + BlockProcessingWorkflow(block2); + + // high-paying tx censorship: false + Block block3 = Build.A.Block.WithNumber(3).WithBaseFeePerGas(0).WithTransactions([tx2]).WithParentHash(blockHash2).TestObject; + ValueHash256 blockHash3 = block3.Hash!; + BlockProcessingWorkflow(block3); + + // high-paying tx censorship: false + Block block4 = Build.A.Block.WithNumber(4).WithBaseFeePerGas(0).WithTransactions([tx1]).WithParentHash(blockHash3).TestObject; + BlockProcessingWorkflow(block4); + + Assert.That(() => _censorshipDetector.GetCensoredBlocks().Contains(new BlockNumberHash(block4)), Is.EqualTo(false).After(10, 1)); + } + + // High-Paying Tx Censorship is given to be false here. + [Test] + public void Censorship_when_high_paying_tx_censorship_is_false_and_address_censorship_is_true_for_all_blocks_in_main_cache() + { + _txPool = CreatePool(); + _censorshipDetector = new( + _blockTree, + _txPool, + _comparer, + _blockProcessor, + _logManager, + new CensorshipDetectorConfig() + { + AddressesForCensorshipDetection = [ + TestItem.AddressA.ToString(), + TestItem.AddressB.ToString(), + TestItem.AddressC.ToString(), + TestItem.AddressD.ToString(), + TestItem.AddressE.ToString(), + TestItem.AddressF.ToString()] + }); + + Transaction tx1 = SubmitTxToPool(1, TestItem.PrivateKeyA, TestItem.AddressA); + Transaction tx2 = SubmitTxToPool(2, TestItem.PrivateKeyB, TestItem.AddressB); + Transaction tx3 = SubmitTxToPool(3, TestItem.PrivateKeyC, TestItem.AddressC); + Transaction tx4 = SubmitTxToPool(4, TestItem.PrivateKeyD, TestItem.AddressD); + Transaction tx5 = SubmitTxToPool(5, TestItem.PrivateKeyE, TestItem.AddressE); + Transaction tx6 = SubmitTxToPool(6, TestItem.PrivateKeyF, TestItem.AddressF); + + Block block1 = Build.A.Block.WithNumber(1).WithBaseFeePerGas(0).WithTransactions([tx1, tx6]).WithParentHash(TestItem.KeccakA).TestObject; + ValueHash256 blockHash1 = block1.Hash!; + BlockProcessingWorkflow(block1); + + Transaction tx7 = SubmitTxToPool(7, TestItem.PrivateKeyA, TestItem.AddressA); + Transaction tx8 = SubmitTxToPool(8, TestItem.PrivateKeyF, TestItem.AddressF); + + Block block2 = Build.A.Block.WithNumber(2).WithBaseFeePerGas(0).WithTransactions([tx2, tx8]).WithParentHash(blockHash1).TestObject; + ValueHash256 blockHash2 = block2.Hash!; + BlockProcessingWorkflow(block2); + + Transaction tx9 = SubmitTxToPool(9, TestItem.PrivateKeyB, TestItem.AddressB); + Transaction tx10 = SubmitTxToPool(10, TestItem.PrivateKeyF, TestItem.AddressF); + + Block block3 = Build.A.Block.WithNumber(3).WithBaseFeePerGas(0).WithTransactions([tx3, tx10]).WithParentHash(blockHash2).TestObject; + ValueHash256 blockHash3 = block3.Hash!; + BlockProcessingWorkflow(block3); + + Transaction tx11 = SubmitTxToPool(11, TestItem.PrivateKeyC, TestItem.AddressC); + Transaction tx12 = SubmitTxToPool(12, TestItem.PrivateKeyF, TestItem.AddressF); + + Block block4 = Build.A.Block.WithNumber(4).WithBaseFeePerGas(0).WithTransactions([tx4, tx12]).WithParentHash(blockHash3).TestObject; + BlockProcessingWorkflow(block4); + + Assert.That(() => _censorshipDetector.GetCensoredBlocks().Contains(new BlockNumberHash(block4)), Is.EqualTo(true).After(10, 1)); + } + + // High-Paying Tx Censorship is given to be false here. + [Test] + public void No_censorship_when_high_paying_tx_censorship_is_false_and_address_censorship_is_false_for_some_blocks_in_main_cache() + { + _txPool = CreatePool(); + _censorshipDetector = new( + _blockTree, + _txPool, + _comparer, + _blockProcessor, + _logManager, + new CensorshipDetectorConfig() + { + AddressesForCensorshipDetection = [ + TestItem.AddressA.ToString(), + TestItem.AddressB.ToString(), + TestItem.AddressC.ToString(), + TestItem.AddressD.ToString(), + TestItem.AddressE.ToString()] + }); + + Transaction tx1 = SubmitTxToPool(1, TestItem.PrivateKeyA, TestItem.AddressA); + Transaction tx2 = SubmitTxToPool(2, TestItem.PrivateKeyB, TestItem.AddressB); + Transaction tx3 = SubmitTxToPool(3, TestItem.PrivateKeyC, TestItem.AddressC); + Transaction tx4 = SubmitTxToPool(4, TestItem.PrivateKeyD, TestItem.AddressD); + Transaction tx5 = SubmitTxToPool(5, TestItem.PrivateKeyE, TestItem.AddressE); + + // address censorship: false + Block block1 = Build.A.Block.WithNumber(1).WithBaseFeePerGas(0).WithTransactions([tx3, tx4, tx5]).WithParentHash(TestItem.KeccakA).TestObject; + ValueHash256 blockHash1 = block1.Hash!; + BlockProcessingWorkflow(block1); + + Transaction tx6 = SubmitTxToPool(6, TestItem.PrivateKeyC, TestItem.AddressC); + Transaction tx7 = SubmitTxToPool(7, TestItem.PrivateKeyD, TestItem.AddressD); + Transaction tx8 = SubmitTxToPool(8, TestItem.PrivateKeyE, TestItem.AddressE); + + // address censorship: false + Block block2 = Build.A.Block.WithNumber(2).WithBaseFeePerGas(0).WithTransactions([tx7, tx8]).WithParentHash(blockHash1).TestObject; + ValueHash256 blockHash2 = block2.Hash!; + BlockProcessingWorkflow(block2); + + Transaction tx9 = SubmitTxToPool(9, TestItem.PrivateKeyD, TestItem.AddressD); + Transaction tx10 = SubmitTxToPool(10, TestItem.PrivateKeyE, TestItem.AddressE); + + // address censorship: true + Block block3 = Build.A.Block.WithNumber(3).WithBaseFeePerGas(0).WithTransactions([tx1, tx10]).WithParentHash(blockHash2).TestObject; + ValueHash256 blockHash3 = block3.Hash!; + BlockProcessingWorkflow(block3); + + // address censorship: false + Block block4 = Build.A.Block.WithNumber(4).WithBaseFeePerGas(0).WithTransactions([tx2, tx6, tx9]).WithParentHash(blockHash3).TestObject; + BlockProcessingWorkflow(block4); + + Assert.That(() => _censorshipDetector.GetCensoredBlocks().Contains(new BlockNumberHash(block4)), Is.EqualTo(false).After(10, 1)); + } + + private TxPool.TxPool CreatePool(bool eip1559Enabled = true) + { + if (eip1559Enabled) + { + _specProvider = Substitute.For(); + _specProvider.GetSpec(Arg.Any()).IsEip1559Enabled.Returns(true); + } + else + { + _specProvider = MainnetSpecProvider.Instance; + } + + _blockTree = Substitute.For(); + _blockTree.FindBestSuggestedHeader().Returns(Build.A.BlockHeader.WithNumber(1_000_000).TestObject); + _blockTree.Head.Returns(Build.A.Block.WithNumber(1_000_000).TestObject); + _ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId); + _comparer = new TransactionComparerProvider(_specProvider, _blockTree).GetDefaultComparer(); + + return new( + _ethereumEcdsa, + new BlobTxStorage(), + new ChainHeadInfoProvider(_specProvider, _blockTree, _stateProvider), + new TxPoolConfig(), + new TxValidator(_specProvider.ChainId), + _logManager, + _comparer); + } + + private void BlockProcessingWorkflow(Block block) + { + _blockProcessor.BlockProcessing += Raise.EventWith(new BlockEventArgs(block)); + Assert.That(() => _censorshipDetector.BlockPotentiallyCensored(block.Number, block.Hash), Is.EqualTo(true).After(10, 1)); + + foreach (Transaction tx in block.Transactions) + { + _txPool.RemoveTransaction(tx.Hash); + } + } + + private Transaction SubmitTxToPool(int maxPriorityFeePerGas, PrivateKey privateKey, Address address) + { + Transaction tx = Build.A.Transaction. + WithType(TxType.EIP1559). + WithMaxFeePerGas(20.Wei()). + WithMaxPriorityFeePerGas(maxPriorityFeePerGas.Wei()). + WithTo(address). + SignedAndResolved(_ethereumEcdsa, privateKey). + TestObject; + _stateProvider.CreateAccount(tx.SenderAddress, 1_000_000.Wei()); + AcceptTxResult result = _txPool.SubmitTx(tx, TxHandlingOptions.PersistentBroadcast); + result.Should().Be(AcceptTxResult.Accepted); + return tx; + } +} diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs index 7a2b7a6dfa9..53e0fc89a30 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs @@ -102,6 +102,11 @@ the previous head state.*/ if (_logger.IsInfo) _logger.Info($"Processing part of a long blocks branch {i}/{blocksCount}. Block: {suggestedBlock}"); } + if (notReadOnly) + { + BlockProcessing?.Invoke(this, new BlockEventArgs(suggestedBlock)); + } + using CancellationTokenSource cancellationTokenSource = new(); Task? preWarmTask = suggestedBlock.Transactions.Length < 3 ? null @@ -162,6 +167,8 @@ the previous head state.*/ public event EventHandler? BlocksProcessing; + public event EventHandler? BlockProcessing; + // TODO: move to branch processor private void InitBranch(Hash256 branchStateRoot, bool incrementReorgMetric = true) { diff --git a/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs new file mode 100644 index 00000000000..018da79aa26 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetector.cs @@ -0,0 +1,272 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Nethermind.Blockchain; +using Nethermind.Core; +using Nethermind.Core.Caching; +using Nethermind.Core.Crypto; +using Nethermind.Crypto; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.TxPool; + +namespace Nethermind.Consensus.Processing.CensorshipDetector; + +public class CensorshipDetector : IDisposable +{ + private readonly IBlockTree _blockTree; + private readonly ITxPool _txPool; + private readonly IComparer _betterTxComparer; + private readonly IBlockProcessor _blockProcessor; + private readonly ILogger _logger; + private readonly Dictionary? _bestTxPerObservedAddresses; + private readonly LruCache _potentiallyCensoredBlocks; + private readonly WrapAroundArray _censoredBlocks; + private readonly uint _blockCensorshipThreshold; + private readonly int _cacheSize; + + public CensorshipDetector( + IBlockTree blockTree, + ITxPool txPool, + IComparer betterTxComparer, + IBlockProcessor blockProcessor, + ILogManager logManager, + ICensorshipDetectorConfig censorshipDetectorConfig) + { + _blockTree = blockTree; + _txPool = txPool; + _betterTxComparer = betterTxComparer; + _blockProcessor = blockProcessor; + _blockCensorshipThreshold = censorshipDetectorConfig.BlockCensorshipThreshold; + _cacheSize = (int)(4 * _blockCensorshipThreshold); + _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); + + if (censorshipDetectorConfig.AddressesForCensorshipDetection is not null) + { + foreach (string hexString in censorshipDetectorConfig.AddressesForCensorshipDetection) + { + if (Address.TryParse(hexString, out Address address)) + { + _bestTxPerObservedAddresses ??= new Dictionary(); + _bestTxPerObservedAddresses[address!] = null; + } + else + { + if (_logger.IsWarn) _logger.Warn($"Invalid address {hexString} provided for censorship detection."); + } + } + } + + _potentiallyCensoredBlocks = new(_cacheSize, _cacheSize, "potentiallyCensoredBlocks"); + _censoredBlocks = new(_cacheSize); + _blockProcessor.BlockProcessing += OnBlockProcessing; + } + + private bool IsSyncing() + { + long bestSuggestedNumber = _blockTree.FindBestSuggestedHeader()?.Number ?? 0; + if (bestSuggestedNumber == 0) + { + return true; + } + long headNumberOrZero = _blockTree.Head?.Number ?? 0; + return bestSuggestedNumber > headNumberOrZero; + } + + private void OnBlockProcessing(object? sender, BlockEventArgs e) + { + // skip censorship detection if node is not synced yet + if (IsSyncing()) return; + + bool tracksPerAddressCensorship = _bestTxPerObservedAddresses is not null; + if (tracksPerAddressCensorship) + { + UInt256 baseFee = e.Block.BaseFeePerGas; + IEnumerable poolBestTransactions = _txPool.GetBestTxOfEachSender(); + foreach (Transaction tx in poolBestTransactions) + { + // checking tx.GasBottleneck > baseFee ensures only ready transactions are considered. + if (tx.To is not null + && tx.GasBottleneck > baseFee + && _bestTxPerObservedAddresses.TryGetValue(tx.To, out Transaction? bestTx) + && (bestTx is null || _betterTxComparer.Compare(bestTx, tx) > 0)) + { + _bestTxPerObservedAddresses[tx.To] = tx; + } + } + } + + Task.Run(() => Cache(e.Block)); + } + + private void Cache(Block block) + { + bool tracksPerAddressCensorship = _bestTxPerObservedAddresses is not null; + + try + { + if (block.Transactions.Length == 0) + { + BlockCensorshipInfo blockCensorshipInfo = new(false, block.ParentHash); + BlockNumberHash blockNumberHash = new BlockNumberHash(block); + _potentiallyCensoredBlocks.Set(blockNumberHash, blockCensorshipInfo); + } + else + { + // Number of unique addresses specified by the user for censorship detection, to which txs are sent in the block. + long blockTxsOfTrackedAddresses = 0; + + // Number of unique addresses specified by the user for censorship detection, to which includable txs are sent in the pool. + // Includable txs consist of pool transactions better than the worst tx in block. + long poolTxsThatAreBetterThanWorstInBlock = 0; + + Transaction bestTxInBlock = block.Transactions[0]; + Transaction worstTxInBlock = block.Transactions[0]; + HashSet trackedAddressesInBlock = []; + + foreach (Transaction tx in block.Transactions) + { + if (!tx.SupportsBlobs) + { + // Finds best tx in block + if (_betterTxComparer.Compare(bestTxInBlock, tx) > 0) + { + bestTxInBlock = tx; + } + + if (tracksPerAddressCensorship) + { + // Finds worst tx in pool to compare with pool transactions of tracked addresses + if (_betterTxComparer.Compare(worstTxInBlock, tx) < 0) + { + worstTxInBlock = tx; + } + + bool trackAddress = _bestTxPerObservedAddresses.ContainsKey(tx.To!); + if (trackAddress && trackedAddressesInBlock.Add(tx.To!)) + { + blockTxsOfTrackedAddresses++; + } + } + } + } + + if (tracksPerAddressCensorship) + { + foreach (Transaction? bestTx in _bestTxPerObservedAddresses.Values) + { + // if there is no transaction in block or the best tx in the pool is better than the worst tx in the block + if (bestTx is null || _betterTxComparer.Compare(bestTx, worstTxInBlock) < 0) + { + poolTxsThatAreBetterThanWorstInBlock++; + } + } + } + + // Checking to see if the block exhibits high-paying tx censorship or address censorship or both. + // High-paying tx censorship is flagged if the best tx in the pool is not included in the block. + // Address censorship is flagged if txs sent to less than half of the user-specified addresses + // for censorship detection with includable txs in the pool are included in the block. + bool isCensored = _betterTxComparer.Compare(bestTxInBlock, _txPool.GetBestTx()) > 0 + || blockTxsOfTrackedAddresses * 2 < poolTxsThatAreBetterThanWorstInBlock; + + BlockCensorshipInfo blockCensorshipInfo = new(isCensored, block.ParentHash); + BlockNumberHash blockNumberHash = new BlockNumberHash(block); + _potentiallyCensoredBlocks.Set(blockNumberHash, blockCensorshipInfo); + + if (isCensored) + { + Metrics.NumberOfPotentiallyCensoredBlocks++; + Metrics.LastPotentiallyCensoredBlockNumber = block.Number; + DetectMultiBlockCensorship(blockNumberHash, blockCensorshipInfo); + } + } + } + finally + { + if (tracksPerAddressCensorship) + { + foreach (AddressAsKey key in _bestTxPerObservedAddresses.Keys) + { + _bestTxPerObservedAddresses[key] = null; + } + } + } + } + + private void DetectMultiBlockCensorship(BlockNumberHash block, BlockCensorshipInfo blockCensorshipInfo) + { + if (DetectPastBlockCensorship() && !_censoredBlocks.Contains(block)) + { + _censoredBlocks.Add(block); + Metrics.NumberOfCensoredBlocks++; + Metrics.LastCensoredBlockNumber = block.Number; + if (_logger.IsInfo) _logger.Info($"Censorship detected for block {block.Number} with hash {block.Hash!}"); + } + + bool DetectPastBlockCensorship() + { + // Censorship is detected if potential censorship is flagged for the last _blockCensorshipThreshold blocks including the latest. + if (block.Number >= _blockCensorshipThreshold) + { + long blockNumber = block.Number - 1; + ValueHash256 parentHash = blockCensorshipInfo.ParentHash!.Value; + for (int i = 1; i < _blockCensorshipThreshold; i++) + { + BlockCensorshipInfo info = _potentiallyCensoredBlocks.Get(new BlockNumberHash(blockNumber, parentHash)); + + if (!info.IsCensored) + { + return false; + } + + parentHash = info.ParentHash!.Value; + blockNumber--; + } + + return true; + } + + return false; + } + } + + public IEnumerable GetCensoredBlocks() => _censoredBlocks; + + public bool BlockPotentiallyCensored(long blockNumber, ValueHash256 blockHash) => _potentiallyCensoredBlocks.Contains(new BlockNumberHash(blockNumber, blockHash)); + + public void Dispose() + { + _blockProcessor.BlockProcessing -= OnBlockProcessing; + } +} + +public readonly record struct BlockCensorshipInfo(bool IsCensored, ValueHash256? ParentHash); + +public readonly record struct BlockNumberHash(long Number, ValueHash256 Hash) : IEquatable +{ + public BlockNumberHash(Block block) : this(block.Number, block.Hash ?? block.CalculateHash()) { } +} + +public class WrapAroundArray(long maxSize = 1) : IEnumerable +{ + private readonly T[] _items = new T[maxSize]; + private long _counter; + + public void Add(T item) + { + _items[(int)(_counter % maxSize)] = item; + _counter++; + } + + public bool Contains(T item) => _items.Contains(item); + + public IEnumerator GetEnumerator() => ((IEnumerable)_items).GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetectorConfig.cs b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetectorConfig.cs new file mode 100644 index 00000000000..c350c8bf8b4 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/CensorshipDetectorConfig.cs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Consensus.Processing.CensorshipDetector; + +public class CensorshipDetectorConfig : ICensorshipDetectorConfig +{ + public bool Enabled { get; set; } = true; + public uint BlockCensorshipThreshold { get; set; } = 2; + public string[]? AddressesForCensorshipDetection { get; set; } = null; +} diff --git a/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/ICensorshipDetectorConfig.cs b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/ICensorshipDetectorConfig.cs new file mode 100644 index 00000000000..29dec2ddf4d --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/ICensorshipDetectorConfig.cs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Config; + +namespace Nethermind.Consensus.Processing.CensorshipDetector; + +public interface ICensorshipDetectorConfig : IConfig +{ + [ConfigItem(DefaultValue = "true", + Description = "Enabling censorship detection feature")] + bool Enabled { get; set; } + + [ConfigItem(DefaultValue = "2", + Description = "Number of consecutive blocks with detected potential censorship to report censorship attempt")] + uint BlockCensorshipThreshold { get; set; } + + [ConfigItem(DefaultValue = "null", + Description = "The addresses for which censorship is being detected.")] + string[]? AddressesForCensorshipDetection { get; set; } +} diff --git a/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/Metrics.cs b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/Metrics.cs new file mode 100644 index 00000000000..8b1b45758cb --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus/Processing/CensorshipDetector/Metrics.cs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.ComponentModel; +using Nethermind.Core.Attributes; + +namespace Nethermind.Consensus.Processing.CensorshipDetector; + +public static class Metrics +{ + [CounterMetric] + [Description("Total number of censored blocks.")] + public static long NumberOfCensoredBlocks; + + [CounterMetric] + [Description("Total number of potentially censored blocks.")] + public static long NumberOfPotentiallyCensoredBlocks; + + [GaugeMetric] + [Description("Number of last potentially censored block.")] + public static long LastPotentiallyCensoredBlockNumber; + + [GaugeMetric] + [Description("Number of last known censored block.")] + public static long LastCensoredBlockNumber; +} diff --git a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs index 8b2af1574b7..c8dbed52213 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs @@ -32,6 +32,11 @@ Block[] Process( /// event EventHandler BlocksProcessing; + /// + /// Fired when a block is being processed. + /// + event EventHandler BlockProcessing; + /// /// Fired after a block has been processed. /// diff --git a/src/Nethermind/Nethermind.Consensus/Processing/NullBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/NullBlockProcessor.cs index ad47599ff84..6a5814c9b76 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/NullBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/NullBlockProcessor.cs @@ -26,6 +26,12 @@ public event EventHandler BlocksProcessing remove { } } + public event EventHandler? BlockProcessing + { + add { } + remove { } + } + public event EventHandler BlockProcessed { add { } diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs index 5bbdd17de96..b711285e1c0 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; using System.Collections.Generic; -using System.IO.Abstractions; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Nethermind.Api; @@ -12,35 +9,22 @@ using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Filters; -using Nethermind.Blockchain.FullPruning; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Services; -using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Consensus; using Nethermind.Consensus.Comparers; using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Processing.CensorshipDetector; using Nethermind.Consensus.Producers; using Nethermind.Consensus.Scheduler; using Nethermind.Consensus.Validators; using Nethermind.Core; using Nethermind.Core.Attributes; -using Nethermind.Core.Crypto; -using Nethermind.Core.Extensions; -using Nethermind.Db; -using Nethermind.Db.FullPruning; using Nethermind.Evm; using Nethermind.Evm.TransactionProcessing; -using Nethermind.JsonRpc.Converters; -using Nethermind.JsonRpc.Modules.DebugModule; using Nethermind.JsonRpc.Modules.Eth.GasPrice; -using Nethermind.JsonRpc.Modules.Trace; -using Nethermind.Logging; -using Nethermind.Serialization.Json; using Nethermind.State; -using Nethermind.Synchronization.Trie; -using Nethermind.Trie; -using Nethermind.Trie.Pruning; using Nethermind.TxPool; using Nethermind.Wallet; @@ -143,6 +127,21 @@ protected virtual Task InitBlockchain() setApi.BackgroundTaskScheduler = backgroundTaskScheduler; _api.DisposeStack.Push(backgroundTaskScheduler); + ICensorshipDetectorConfig censorshipDetectorConfig = _api.Config(); + if (censorshipDetectorConfig.Enabled) + { + CensorshipDetector censorshipDetector = new( + _api.BlockTree!, + txPool, + CreateTxPoolTxComparer(), + mainBlockProcessor, + _api.LogManager, + censorshipDetectorConfig + ); + setApi.CensorshipDetector = censorshipDetector; + _api.DisposeStack.Push(censorshipDetector); + } + return Task.CompletedTask; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index 0cc6b0a5338..6983e6113ba 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Nethermind.Api; using Nethermind.Blockchain; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; @@ -309,6 +308,12 @@ public event EventHandler? BlocksProcessing remove => _blockProcessorImplementation.BlocksProcessing -= value; } + public event EventHandler? BlockProcessing + { + add => _blockProcessorImplementation.BlockProcessing += value; + remove => _blockProcessorImplementation.BlockProcessing -= value; + } + public event EventHandler? BlockProcessed { add => _blockProcessorImplementation.BlockProcessed += value; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/GetPayloadV3Result.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/GetPayloadV3Result.cs index 492d81ad71e..c12f059b149 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/GetPayloadV3Result.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/GetPayloadV3Result.cs @@ -18,8 +18,7 @@ public GetPayloadV3Result(Block block, UInt256 blockFees, BlobsBundleV1 blobsBun public override ExecutionPayloadV3 ExecutionPayload { get; } - public bool ShouldOverrideBuilder { get; } - + public bool ShouldOverrideBuilder { get; init; } public override string ToString() => $"{{ExecutionPayload: {ExecutionPayload}, Fees: {BlockValue}, BlobsBundle blobs count: {BlobsBundle.Blobs.Length}, ShouldOverrideBuilder {ShouldOverrideBuilder}}}"; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadV3Handler.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadV3Handler.cs index 9555b51f1a9..53f52a3187a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadV3Handler.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/GetPayloadV3Handler.cs @@ -1,10 +1,12 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Linq; using Nethermind.Core.Specs; using Nethermind.Logging; using Nethermind.Merge.Plugin.BlockProduction; using Nethermind.Merge.Plugin.Data; +using Nethermind.Consensus.Processing.CensorshipDetector; namespace Nethermind.Merge.Plugin.Handlers; @@ -14,11 +16,22 @@ namespace Nethermind.Merge.Plugin.Handlers; /// public class GetPayloadV3Handler : GetPayloadHandlerBase { - public GetPayloadV3Handler(IPayloadPreparationService payloadPreparationService, ISpecProvider specProvider, ILogManager logManager) : base( + private readonly CensorshipDetector? _censorshipDetector; + public GetPayloadV3Handler( + IPayloadPreparationService payloadPreparationService, + ISpecProvider specProvider, + ILogManager logManager, + CensorshipDetector? censorshipDetector = null) : base( 3, payloadPreparationService, specProvider, logManager) { + _censorshipDetector = censorshipDetector; } - protected override GetPayloadV3Result GetPayloadResultFromBlock(IBlockProductionContext context) => - new(context.CurrentBestBlock!, context.BlockFees, new BlobsBundleV1(context.CurrentBestBlock!)); + protected override GetPayloadV3Result GetPayloadResultFromBlock(IBlockProductionContext context) + { + return new(context.CurrentBestBlock!, context.BlockFees, new BlobsBundleV1(context.CurrentBestBlock!)) + { + ShouldOverrideBuilder = _censorshipDetector?.GetCensoredBlocks().Contains(new BlockNumberHash(context.CurrentBestBlock!)) ?? false + }; + } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs index 774eebf1d20..2d7ce1edee8 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs @@ -324,7 +324,7 @@ public Task InitRpcModules() IEngineRpcModule engineRpcModule = new EngineRpcModule( new GetPayloadV1Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager), new GetPayloadV2Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager), - new GetPayloadV3Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager), + new GetPayloadV3Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager, _api.CensorshipDetector), new NewPayloadHandler( _api.BlockValidator, _api.BlockTree, diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index 9659aee08c2..c9df512ebe9 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -234,7 +234,7 @@ public async Task InitRpcModules() IEngineRpcModule engineRpcModule = new EngineRpcModule( new GetPayloadV1Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager), new GetPayloadV2Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager), - new GetPayloadV3Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager), + new GetPayloadV3Handler(payloadPreparationService, _api.SpecProvider, _api.LogManager, _api.CensorshipDetector), new NewPayloadHandler( _api.BlockValidator, _api.BlockTree, diff --git a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs index c1771f87338..98a32ce04e3 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs @@ -195,6 +195,14 @@ public EnhancedSortedSet GetFirsts() return sortedValues; } + /// + /// Returns best overall element as per supplied comparer order. + /// + public TValue? GetBest() + { + return GetFirsts().Min; + } + /// /// Gets last element in supplied comparer order. /// diff --git a/src/Nethermind/Nethermind.TxPool/ITxPool.cs b/src/Nethermind/Nethermind.TxPool/ITxPool.cs index 7fbb8102149..2c11c7515af 100644 --- a/src/Nethermind/Nethermind.TxPool/ITxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/ITxPool.cs @@ -38,6 +38,8 @@ public interface ITxPool bool ContainsTx(Hash256 hash, TxType txType); AcceptTxResult SubmitTx(Transaction tx, TxHandlingOptions handlingOptions); bool RemoveTransaction(Hash256? hash); + Transaction? GetBestTx(); + IEnumerable GetBestTxOfEachSender(); bool IsKnown(Hash256 hash); bool TryGetPendingTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? transaction); bool TryGetPendingBlobTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? blobTransaction); diff --git a/src/Nethermind/Nethermind.TxPool/NullTxPool.cs b/src/Nethermind/Nethermind.TxPool/NullTxPool.cs index 57d830e3b52..d0f1587522e 100644 --- a/src/Nethermind/Nethermind.TxPool/NullTxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/NullTxPool.cs @@ -38,6 +38,10 @@ public void RemovePeer(PublicKey nodeId) { } public bool RemoveTransaction(Hash256? hash) => false; + public Transaction? GetBestTx() => null; + + public IEnumerable GetBestTxOfEachSender() => Array.Empty(); + public bool IsKnown(Hash256 hash) => false; public bool TryGetPendingTransaction(Hash256 hash, [NotNullWhen(true)] out Transaction? transaction) diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index 05055748f69..65faf226e95 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -736,6 +736,10 @@ public UInt256 GetLatestPendingNonce(Address address) return maxPendingNonce; } + public Transaction? GetBestTx() => _transactions.GetBest(); + + public IEnumerable GetBestTxOfEachSender() => _transactions.GetFirsts(); + public bool IsKnown(Hash256? hash) => hash is not null ? _hashCache.Get(hash) : false; public event EventHandler? NewDiscovered; From 69e36ddf7edc9c54b87925e3d4d746c6c0b21d36 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel <31224949+emlautarom1@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:11:25 -0300 Subject: [PATCH 015/113] Refactor `TxValidator` (#7386) Co-authored-by: Lukasz Rozmej Co-authored-by: Jorge Mederos <46798594+jmederosalvarado@users.noreply.github.com> --- .../Nethermind.Api/IApiWithBlockchain.cs | 2 +- .../Nethermind.Api/INethermindApi.cs | 16 + .../Nethermind.Api/NethermindApi.cs | 2 +- .../Validators/TestTransactionValidator.cs | 40 -- .../Validators/TxValidatorTests.cs | 42 +- .../Validators/AlwaysValid.cs | 12 +- .../Validators/BlockValidator.cs | 6 +- .../Validators/TxValidator.cs | 451 +++++++++--------- .../Builders/TransactionValidatorBuilder.cs | 11 +- .../Nethermind.Core/TransactionExtensions.cs | 27 +- .../Nethermind.Core/ValidationResult.cs | 13 + .../Steps/StepInitializationException.cs | 4 +- .../InvalidBlockInterceptor.cs | 52 +- .../InitializeBlockchainOptimism.cs | 102 ++-- .../OptimismHeaderValidator.cs | 11 +- .../OptimismTxDecoder.cs | 4 +- .../OptimismTxValidator.cs | 28 -- .../Nethermind.Serialization.Rlp/TxDecoder.cs | 19 +- .../TxDecoders/ITxDecoder.cs | 2 +- .../Nethermind.Specs/ReleaseSpec.cs | 9 +- .../Filters/MalformedTxFilter.cs | 23 +- .../Nethermind.TxPool/ITxValidator.cs | 3 +- 22 files changed, 402 insertions(+), 477 deletions(-) delete mode 100644 src/Nethermind/Nethermind.Blockchain.Test/Validators/TestTransactionValidator.cs create mode 100644 src/Nethermind/Nethermind.Core/ValidationResult.cs rename src/Nethermind/{Nethermind.Serialization.Rlp/TxDecoders => Nethermind.Optimism}/OptimismTxDecoder.cs (96%) delete mode 100644 src/Nethermind/Nethermind.Optimism/OptimismTxValidator.cs diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs index 867deec5a7a..a3a510e7c89 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs @@ -75,7 +75,7 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory IHealthHintService? HealthHintService { get; set; } IRpcCapabilitiesProvider? RpcCapabilitiesProvider { get; set; } ITransactionComparerProvider? TransactionComparerProvider { get; set; } - ITxValidator? TxValidator { get; set; } + TxValidator? TxValidator { get; set; } /// /// Manager of block finalization diff --git a/src/Nethermind/Nethermind.Api/INethermindApi.cs b/src/Nethermind/Nethermind.Api/INethermindApi.cs index 8d864b2e9f8..fff51021393 100644 --- a/src/Nethermind/Nethermind.Api/INethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/INethermindApi.cs @@ -2,7 +2,12 @@ // SPDX-License-Identifier: LGPL-3.0-only #nullable enable +using System; using Nethermind.Config; +using Nethermind.Core; +using Nethermind.Serialization.Rlp; +using Nethermind.Serialization.Rlp.TxDecoders; +using Nethermind.TxPool; namespace Nethermind.Api { @@ -15,4 +20,15 @@ public T Config() where T : IConfig (IApiWithNetwork GetFromApi, INethermindApi SetInApi) ForRpc => (this, this); } + + public static class NethermindApiExtensions + { + public static void RegisterTxType(this INethermindApi api, TxType type, ITxDecoder decoder, ITxValidator validator) + { + ArgumentNullException.ThrowIfNull(api.TxValidator); + + api.TxValidator.RegisterValidator(type, validator); + TxDecoder.Instance.RegisterDecoder(decoder); + } + } } diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 821375276b5..ceee96957d1 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -209,7 +209,7 @@ public ISealEngine SealEngine public ITxPoolInfoProvider? TxPoolInfoProvider { get; set; } public IHealthHintService? HealthHintService { get; set; } public IRpcCapabilitiesProvider? RpcCapabilitiesProvider { get; set; } - public ITxValidator? TxValidator { get; set; } + public TxValidator? TxValidator { get; set; } public IBlockFinalizationManager? FinalizationManager { get; set; } public IGasLimitCalculator? GasLimitCalculator { get; set; } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TestTransactionValidator.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TestTransactionValidator.cs deleted file mode 100644 index 430e5bb2e6e..00000000000 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TestTransactionValidator.cs +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using Nethermind.Core; -using Nethermind.Core.Specs; -using Nethermind.TxPool; - -namespace Nethermind.Blockchain.Test.Validators -{ - public class TestTxValidator : ITxValidator - { - public static TestTxValidator AlwaysValid = new(true); - public static TestTxValidator NeverValid = new(false); - - private readonly Queue _validationResults = new(); - private readonly bool? _alwaysSameResult; - - public TestTxValidator(Queue validationResults) - { - _validationResults = validationResults; - } - - public TestTxValidator(bool validationResult) - { - _alwaysSameResult = validationResult; - } - - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) - { - return _alwaysSameResult ?? _validationResults.Dequeue(); - } - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec, [NotNullWhen(false)] out string? errorMessage) - { - errorMessage = null; - return _alwaysSameResult ?? _validationResults.Dequeue(); - } - } -} diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs index 8e91f13773b..7d3bb9bc00b 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs @@ -56,7 +56,7 @@ public void Zero_r_is_not_valid() Transaction tx = Build.A.Transaction.WithSignature(signature).TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - txValidator.IsWellFormed(tx, MuirGlacier.Instance).Should().BeFalse(); + txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeFalse(); } private static byte CalculateV() => (byte)EthereumEcdsa.CalculateV(TestBlockchainIds.ChainId); @@ -72,7 +72,7 @@ public void Zero_s_is_not_valid() Transaction tx = Build.A.Transaction.WithSignature(signature).TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - txValidator.IsWellFormed(tx, MuirGlacier.Instance).Should().BeFalse(); + txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeFalse(); } [Test, Timeout(Timeout.MaxTestTime)] @@ -86,7 +86,7 @@ public void Bad_chain_id_is_not_valid() Transaction tx = Build.A.Transaction.WithSignature(signature).TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - txValidator.IsWellFormed(tx, MuirGlacier.Instance).Should().BeFalse(); + txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeFalse(); } [Test, Timeout(Timeout.MaxTestTime)] @@ -100,7 +100,7 @@ public void No_chain_id_legacy_tx_is_valid() Transaction tx = Build.A.Transaction.WithSignature(signature).TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - txValidator.IsWellFormed(tx, MuirGlacier.Instance).Should().BeTrue(); + txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeTrue(); } [Test, Timeout(Timeout.MaxTestTime)] @@ -114,7 +114,7 @@ public void Is_valid_with_valid_chain_id() Transaction tx = Build.A.Transaction.WithSignature(signature).TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - txValidator.IsWellFormed(tx, MuirGlacier.Instance).Should().BeTrue(); + txValidator.IsWellFormed(tx, MuirGlacier.Instance).AsBool().Should().BeTrue(); } [Timeout(Timeout.MaxTestTime)] @@ -134,7 +134,7 @@ public void Before_eip_155_has_to_have_valid_chain_id_unless_overridden(bool val releaseSpec.ValidateChainId.Returns(validateChainId); TxValidator txValidator = new(TestBlockchainIds.ChainId); - txValidator.IsWellFormed(tx, releaseSpec).Should().Be(!validateChainId); + txValidator.IsWellFormed(tx, releaseSpec).AsBool().Should().Be(!validateChainId); } [Timeout(Timeout.MaxTestTime)] @@ -274,7 +274,7 @@ public void Transaction_with_init_code_above_max_value_is_rejected_when_eip3860E .WithData(initCode).TestObject; TxValidator txValidator = new(1); - txValidator.IsWellFormed(tx, releaseSpec).Should().Be(expectedResult); + txValidator.IsWellFormed(tx, releaseSpec).AsBool().Should().Be(expectedResult); } //leading zeros in AccessList - expected to pass (real mainnet tx) @@ -345,8 +345,8 @@ public void ShardBlobTransactions_should_have_destination_set() .WithChainId(TestBlockchainIds.ChainId) .SignedAndResolved().TestObject; - Assert.That(txValidator.IsWellFormed(txWithoutTo, Cancun.Instance), Is.False); - Assert.That(txValidator.IsWellFormed(txWithTo, Cancun.Instance)); + Assert.That(txValidator.IsWellFormed(txWithoutTo, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(txWithTo, Cancun.Instance).AsBool()); } [Timeout(Timeout.MaxTestTime)] @@ -404,9 +404,8 @@ public void IsWellFormed_NotBlobTxButMaxFeePerBlobGasIsSet_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -419,9 +418,8 @@ public void IsWellFormed_NotBlobTxButBlobVersionedHashesIsSet_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -437,9 +435,8 @@ public void IsWellFormed_BlobTxToIsNull_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } [Test] public void IsWellFormed_BlobTxHasMoreDataGasThanAllowed_ReturnFalse() @@ -454,9 +451,8 @@ public void IsWellFormed_BlobTxHasMoreDataGasThanAllowed_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -472,9 +468,8 @@ public void IsWellFormed_BlobTxHasNoBlobs_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -490,9 +485,8 @@ public void IsWellFormed_BlobTxHasBlobOverTheSizeLimit_ReturnFalse() Transaction tx = txBuilder.TestObject; ((ShardBlobNetworkWrapper)tx.NetworkWrapper!).Blobs[0] = new byte[Ckzg.Ckzg.BytesPerBlob + 1]; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -508,9 +502,8 @@ public void IsWellFormed_BlobTxHasCommitmentOverTheSizeLimit_ReturnFalse() Transaction tx = txBuilder.TestObject; ((ShardBlobNetworkWrapper)tx.NetworkWrapper!).Commitments[0] = new byte[Ckzg.Ckzg.BytesPerCommitment + 1]; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -526,9 +519,8 @@ public void IsWellFormed_BlobTxHasProofOverTheSizeLimit_ReturnFalse() Transaction tx = txBuilder.TestObject; ((ShardBlobNetworkWrapper)tx.NetworkWrapper!).Proofs[0] = new byte[Ckzg.Ckzg.BytesPerProof + 1]; TxValidator txValidator = new(TestBlockchainIds.ChainId); - string? error; - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance, out error), Is.False); + Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); } private static byte[] MakeArray(int count, params byte[] elements) => diff --git a/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs b/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs index 92ec5b749bf..0550ac08ddb 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs @@ -11,9 +11,11 @@ namespace Nethermind.Consensus.Validators; public class Always : IBlockValidator, ISealValidator, IUnclesValidator, ITxValidator { private readonly bool _result; + private readonly ValidationResult _validationResult; private Always(bool result) { + _validationResult = result ? ValidationResult.Success : "Always invalid."; _result = result; } @@ -79,16 +81,10 @@ public bool Validate(BlockHeader header, BlockHeader[] uncles) return _result; } - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) { - return _result; + return _validationResult; } - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec, out string? errorMessage) - { - errorMessage = null; - return _result; - } - public bool ValidateWithdrawals(Block block, out string? error) { error = null; diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs index 04e0ca08f68..e720c5c44f9 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs @@ -292,9 +292,11 @@ private bool ValidateTransactions(Block block, IReleaseSpec spec, out string? er { Transaction transaction = transactions[txIndex]; - if (!_txValidator.IsWellFormed(transaction, spec, out errorMessage)) + ValidationResult isWellFormed = _txValidator.IsWellFormed(transaction, spec); + if (!isWellFormed) { - if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Invalid transaction: {errorMessage}"); + if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Invalid transaction: {isWellFormed}"); + errorMessage = isWellFormed.Error; return false; } } diff --git a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs index 409f7c32a6d..5207135b109 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs @@ -2,294 +2,283 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Generic; using Nethermind.Consensus.Messages; using Nethermind.Core; -using Nethermind.Core.Crypto; -using Nethermind.Core.Extensions; using Nethermind.Core.Specs; +using Nethermind.TxPool; +using Nethermind.Core.Crypto; using Nethermind.Crypto; using Nethermind.Evm; using Nethermind.Int256; -using Nethermind.TxPool; -namespace Nethermind.Consensus.Validators -{ - public class TxValidator : ITxValidator - { - private readonly ulong _chainIdValue; +namespace Nethermind.Consensus.Validators; - public TxValidator(ulong chainId) - { - _chainIdValue = chainId; - } +public sealed class TxValidator : ITxValidator +{ + private readonly ITxValidator?[] _validators = new ITxValidator?[Transaction.MaxTxType + 1]; - /* Full and correct validation is only possible in the context of a specific block - as we cannot generalize correctness of the transaction without knowing the EIPs implemented - and the world state (account nonce in particular ). - Even without protocol change the tx can become invalid if another tx - from the same account with the same nonce got included on the chain. - As such we can decide whether tx is well formed but we also have to validate nonce - just before the execution of the block / tx. */ - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) - { - return IsWellFormed(transaction, releaseSpec, out _); - } - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec, out string? error) - { - error = null; - - // validate type before calculating intrinsic gas to avoid exception - return ValidateTxType(transaction, releaseSpec, ref error) - // This is unnecessarily calculated twice - at validation and execution times. - && ValidateWithError(transaction.GasLimit >= IntrinsicGasCalculator.Calculate(transaction, releaseSpec), TxErrorMessages.IntrinsicGasTooLow, ref error) - // if it is a call or a transfer then we require the 'To' field to have a value while for an init it will be empty - && ValidateWithError(ValidateSignature(transaction, releaseSpec), TxErrorMessages.InvalidTxSignature, ref error) - && ValidateChainId(transaction, ref error) - && ValidateWithError(Validate1559GasFields(transaction, releaseSpec), TxErrorMessages.InvalidMaxPriorityFeePerGas, ref error) - && ValidateWithError(Validate3860Rules(transaction, releaseSpec), TxErrorMessages.ContractSizeTooBig, ref error) - && Validate4844Fields(transaction, ref error); - } + public TxValidator(ulong chainId) + { + RegisterValidator(TxType.Legacy, new CompositeTxValidator([ + IntrinsicGasTxValidator.Instance, + new LegacySignatureTxValidator(chainId), + ContractSizeTxValidator.Instance, + NonBlobFieldsTxValidator.Instance, + ])); + RegisterValidator(TxType.AccessList, new CompositeTxValidator([ + new ReleaseSpecTxValidator(static spec => spec.IsEip2930Enabled), + IntrinsicGasTxValidator.Instance, + SignatureTxValidator.Instance, + new ExpectedChainIdTxValidator(chainId), + ContractSizeTxValidator.Instance, + NonBlobFieldsTxValidator.Instance, + ])); + RegisterValidator(TxType.EIP1559, new CompositeTxValidator([ + new ReleaseSpecTxValidator(static spec => spec.IsEip1559Enabled), + IntrinsicGasTxValidator.Instance, + SignatureTxValidator.Instance, + new ExpectedChainIdTxValidator(chainId), + GasFieldsTxValidator.Instance, + ContractSizeTxValidator.Instance, + NonBlobFieldsTxValidator.Instance, + ])); + RegisterValidator(TxType.Blob, new CompositeTxValidator([ + new ReleaseSpecTxValidator(static spec => spec.IsEip4844Enabled), + IntrinsicGasTxValidator.Instance, + SignatureTxValidator.Instance, + new ExpectedChainIdTxValidator(chainId), + GasFieldsTxValidator.Instance, + ContractSizeTxValidator.Instance, + BlobFieldsTxValidator.Instance, + MempoolBlobTxValidator.Instance + ])); + } - private static bool Validate3860Rules(Transaction transaction, IReleaseSpec releaseSpec) => - !transaction.IsAboveInitCode(releaseSpec); + public void RegisterValidator(TxType type, ITxValidator validator) => _validators[(byte)type] = validator; + + /// + /// Full and correct validation is only possible in the context of a specific block + /// as we cannot generalize correctness of the transaction without knowing the EIPs implemented + /// and the world state(account nonce in particular). + /// Even without protocol change, the tx can become invalid if another tx + /// from the same account with the same nonce got included on the chain. + /// As such, we can decide whether tx is well formed as long as we also validate nonce + /// just before the execution of the block / tx. + /// + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + _validators.TryGetByTxType(transaction.Type, out ITxValidator validator) + ? validator.IsWellFormed(transaction, releaseSpec) + : TxErrorMessages.InvalidTxType(releaseSpec.Name); +} - private static bool ValidateTxType(Transaction transaction, IReleaseSpec releaseSpec, ref string error) +public sealed class CompositeTxValidator(List validators) : ITxValidator +{ + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + { + foreach (ITxValidator validator in validators) { - bool result = transaction.Type switch + ValidationResult isWellFormed = validator.IsWellFormed(transaction, releaseSpec); + if (!isWellFormed) { - TxType.Legacy => true, - TxType.AccessList => releaseSpec.UseTxAccessLists, - TxType.EIP1559 => releaseSpec.IsEip1559Enabled, - TxType.Blob => releaseSpec.IsEip4844Enabled, - _ => false - }; - - if (!result) - { - error = TxErrorMessages.InvalidTxType(releaseSpec.Name); - return false; + return isWellFormed; } - - return true; } + return ValidationResult.Success; + } +} - private static bool Validate1559GasFields(Transaction transaction, IReleaseSpec releaseSpec) - { - if (!releaseSpec.IsEip1559Enabled || !transaction.Supports1559) - return true; - - return transaction.MaxFeePerGas >= transaction.MaxPriorityFeePerGas; - } - - private bool ValidateChainId(Transaction transaction, ref string? error) - { - return transaction.Type switch - { - TxType.Legacy => true, - _ => ValidateChainIdNonLegacy(transaction.ChainId, ref error) - }; - - bool ValidateChainIdNonLegacy(ulong? chainId, ref string? error) - { - bool result = chainId == _chainIdValue; - if (!result) - { - error = TxErrorMessages.InvalidTxChainId(_chainIdValue, transaction.ChainId); - return false; - } +public sealed class IntrinsicGasTxValidator : ITxValidator +{ + public static readonly IntrinsicGasTxValidator Instance = new(); + private IntrinsicGasTxValidator() { } + + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + // This is unnecessarily calculated twice - at validation and execution times. + transaction.GasLimit < IntrinsicGasCalculator.Calculate(transaction, releaseSpec) + ? TxErrorMessages.IntrinsicGasTooLow + : ValidationResult.Success; +} - return true; - } - } +public sealed class ReleaseSpecTxValidator(Func validate) : ITxValidator +{ + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + !validate(releaseSpec) ? TxErrorMessages.InvalidTxType(releaseSpec.Name) : ValidationResult.Success; +} - private bool ValidateWithError(bool validation, string errorMessage, ref string? error) - { - if (!validation) - { - error = errorMessage; - return false; - } +public sealed class ExpectedChainIdTxValidator(ulong chainId) : ITxValidator +{ + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + transaction.ChainId != chainId ? TxErrorMessages.InvalidTxChainId(chainId, transaction.ChainId) : ValidationResult.Success; +} - return true; - } +public sealed class GasFieldsTxValidator : ITxValidator +{ + public static readonly GasFieldsTxValidator Instance = new(); + private GasFieldsTxValidator() { } - private bool ValidateSignature(Transaction tx, IReleaseSpec spec) - { - Signature? signature = tx.Signature; + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + transaction.MaxFeePerGas < transaction.MaxPriorityFeePerGas ? TxErrorMessages.InvalidMaxPriorityFeePerGas : ValidationResult.Success; +} - if (signature is null) - { - return false; - } +public sealed class ContractSizeTxValidator : ITxValidator +{ + public static readonly ContractSizeTxValidator Instance = new(); + private ContractSizeTxValidator() { } - UInt256 sValue = new(signature.SAsSpan, isBigEndian: true); - UInt256 rValue = new(signature.RAsSpan, isBigEndian: true); + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + transaction.IsAboveInitCode(releaseSpec) ? TxErrorMessages.ContractSizeTooBig : ValidationResult.Success; +} - if (sValue.IsZero || sValue >= (spec.IsEip2Enabled ? Secp256K1Curve.HalfNPlusOne : Secp256K1Curve.N)) - { - return false; - } +/// +/// Ensure that non Blob transactions do not contain Blob specific fields. +/// This validator will be deprecated once we have a proper Transaction type hierarchy. +/// +public sealed class NonBlobFieldsTxValidator : ITxValidator +{ + public static readonly NonBlobFieldsTxValidator Instance = new(); + private NonBlobFieldsTxValidator() { } - if (rValue.IsZero || rValue >= Secp256K1Curve.NMinusOne) - { - return false; - } + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => transaction switch + { + // Execution-payload version verification + { MaxFeePerBlobGas: not null } => TxErrorMessages.NotAllowedMaxFeePerBlobGas, + { BlobVersionedHashes: not null } => TxErrorMessages.NotAllowedBlobVersionedHashes, + { NetworkWrapper: ShardBlobNetworkWrapper } => TxErrorMessages.InvalidTransaction, + _ => ValidationResult.Success + }; +} - if (signature.V is 27 or 28) - { - return true; - } +public sealed class BlobFieldsTxValidator : ITxValidator +{ + public static readonly BlobFieldsTxValidator Instance = new(); + private BlobFieldsTxValidator() { } - if (tx.Type == TxType.Legacy && spec.IsEip155Enabled && (signature.V == _chainIdValue * 2 + 35ul || signature.V == _chainIdValue * 2 + 36ul)) - { - return true; - } + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + transaction switch + { + { To: null } => TxErrorMessages.TxMissingTo, + { MaxFeePerBlobGas: null } => TxErrorMessages.BlobTxMissingMaxFeePerBlobGas, + { BlobVersionedHashes: null } => TxErrorMessages.BlobTxMissingBlobVersionedHashes, + _ => ValidateBlobFields(transaction) + }; - return !spec.ValidateChainId; - } + private ValidationResult ValidateBlobFields(Transaction transaction) + { + int blobCount = transaction.BlobVersionedHashes!.Length; + ulong totalDataGas = BlobGasCalculator.CalculateBlobGas(blobCount); + return totalDataGas > Eip4844Constants.MaxBlobGasPerTransaction ? TxErrorMessages.BlobTxGasLimitExceeded + : blobCount < Eip4844Constants.MinBlobsPerTransaction ? TxErrorMessages.BlobTxMissingBlobs + : ValidateBlobVersionedHashes(); - private static bool Validate4844Fields(Transaction transaction, ref string? error) + ValidationResult ValidateBlobVersionedHashes() { - // Execution-payload version verification - if (!transaction.SupportsBlobs) + for (int i = 0; i < blobCount; i++) { - if (transaction.MaxFeePerBlobGas is not null) - { - error = TxErrorMessages.NotAllowedMaxFeePerBlobGas; - return false; - } - - if (transaction.BlobVersionedHashes is not null) - { - error = TxErrorMessages.NotAllowedBlobVersionedHashes; - return false; - } - - if (transaction is { NetworkWrapper: ShardBlobNetworkWrapper }) + switch (transaction.BlobVersionedHashes[i]) { - //This must be an internal issue? - error = TxErrorMessages.InvalidTransaction; - return false; + case null: return TxErrorMessages.MissingBlobVersionedHash; + case { Length: not KzgPolynomialCommitments.BytesPerBlobVersionedHash }: return TxErrorMessages.InvalidBlobVersionedHashSize; + case { Length: KzgPolynomialCommitments.BytesPerBlobVersionedHash } when transaction.BlobVersionedHashes[i][0] != KzgPolynomialCommitments.KzgBlobHashVersionV1: return TxErrorMessages.InvalidBlobVersionedHashVersion; } - - return true; - } - - if (transaction.To is null) - { - error = TxErrorMessages.TxMissingTo; - return false; } - if (transaction.MaxFeePerBlobGas is null) - { - error = TxErrorMessages.BlobTxMissingMaxFeePerBlobGas; - return false; - } - - if (transaction.BlobVersionedHashes is null) - { - error = TxErrorMessages.BlobTxMissingBlobVersionedHashes; - return false; - } - - int blobCount = transaction.BlobVersionedHashes.Length; - ulong totalDataGas = BlobGasCalculator.CalculateBlobGas(blobCount); - if (totalDataGas > Eip4844Constants.MaxBlobGasPerTransaction) - { - error = TxErrorMessages.BlobTxGasLimitExceeded; - return false; - } + return ValidationResult.Success; + } + } +} - if (blobCount < Eip4844Constants.MinBlobsPerTransaction) - { - error = TxErrorMessages.BlobTxMissingBlobs; - return false; - } +/// +/// Validate Blob transactions in mempool version. +/// +public sealed class MempoolBlobTxValidator : ITxValidator +{ + public static readonly MempoolBlobTxValidator Instance = new(); + private MempoolBlobTxValidator() { } + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + { + int blobCount = transaction.BlobVersionedHashes!.Length; + return transaction.NetworkWrapper is not ShardBlobNetworkWrapper wrapper ? ValidationResult.Success + : wrapper.Blobs.Length != blobCount ? TxErrorMessages.InvalidBlobData + : wrapper.Commitments.Length != blobCount ? TxErrorMessages.InvalidBlobData + : wrapper.Proofs.Length != blobCount ? TxErrorMessages.InvalidBlobData + : ValidateBlobs(); + + ValidationResult ValidateBlobs() + { for (int i = 0; i < blobCount; i++) { - if (transaction.BlobVersionedHashes[i] is null) + if (wrapper.Blobs[i].Length != Ckzg.Ckzg.BytesPerBlob) { - error = TxErrorMessages.MissingBlobVersionedHash; - return false; + return TxErrorMessages.ExceededBlobSize; } - if (transaction.BlobVersionedHashes[i].Length != KzgPolynomialCommitments.BytesPerBlobVersionedHash) + if (wrapper.Commitments[i].Length != Ckzg.Ckzg.BytesPerCommitment) { - error = TxErrorMessages.InvalidBlobVersionedHashSize; - return false; + return TxErrorMessages.ExceededBlobCommitmentSize; } - if (transaction.BlobVersionedHashes[i][0] != KzgPolynomialCommitments.KzgBlobHashVersionV1) + if (wrapper.Proofs[i].Length != Ckzg.Ckzg.BytesPerProof) { - error = TxErrorMessages.InvalidBlobVersionedHashVersion; - return false; + return TxErrorMessages.InvalidBlobProofSize; } } - // Mempool version verification if presents - if (transaction.NetworkWrapper is ShardBlobNetworkWrapper wrapper) + Span hash = stackalloc byte[32]; + for (int i = 0; i < blobCount; i++) { - if (wrapper.Blobs.Length != blobCount) - { - error = TxErrorMessages.InvalidBlobData; - return false; - } - - if (wrapper.Commitments.Length != blobCount) + if (!KzgPolynomialCommitments.TryComputeCommitmentHashV1(wrapper.Commitments[i].AsSpan(), hash) || !hash.SequenceEqual(transaction.BlobVersionedHashes[i])) { - error = TxErrorMessages.InvalidBlobData; - return false; + return TxErrorMessages.InvalidBlobCommitmentHash; } + } - if (wrapper.Proofs.Length != blobCount) - { - error = TxErrorMessages.InvalidBlobData; - return false; - } + return !KzgPolynomialCommitments.AreProofsValid(wrapper.Blobs, wrapper.Commitments, wrapper.Proofs) + ? TxErrorMessages.InvalidBlobProof + : ValidationResult.Success; + } + } +} - for (int i = 0; i < blobCount; i++) - { - if (wrapper.Blobs[i].Length != Ckzg.Ckzg.BytesPerBlob) - { - error = TxErrorMessages.ExceededBlobSize; - return false; - } - if (wrapper.Commitments[i].Length != Ckzg.Ckzg.BytesPerCommitment) - { - error = TxErrorMessages.ExceededBlobCommitmentSize; - return false; - } - if (wrapper.Proofs[i].Length != Ckzg.Ckzg.BytesPerProof) - { - error = TxErrorMessages.InvalidBlobProofSize; - return false; - } - } +public abstract class BaseSignatureTxValidator : ITxValidator +{ + protected virtual ValidationResult ValidateChainId(Transaction transaction, IReleaseSpec releaseSpec) => + releaseSpec.ValidateChainId ? TxErrorMessages.InvalidTxSignature : ValidationResult.Success; - Span hash = stackalloc byte[32]; - for (int i = 0; i < blobCount; i++) - { - if (!KzgPolynomialCommitments.TryComputeCommitmentHashV1( - wrapper.Commitments[i].AsSpan(), hash) || - !hash.SequenceEqual(transaction.BlobVersionedHashes[i])) - { - error = TxErrorMessages.InvalidBlobCommitmentHash; - return false; - } - } + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + { + Signature? signature = transaction.Signature; + if (signature is null) + { + return TxErrorMessages.InvalidTxSignature; + } - if (!KzgPolynomialCommitments.AreProofsValid(wrapper.Blobs, wrapper.Commitments, wrapper.Proofs)) - { - error = TxErrorMessages.InvalidBlobProof; - return false; - } + UInt256 sValue = new(signature.SAsSpan, isBigEndian: true); + UInt256 rValue = new(signature.RAsSpan, isBigEndian: true); - } + UInt256 sMax = releaseSpec.IsEip2Enabled ? Secp256K1Curve.HalfNPlusOne : Secp256K1Curve.N; + return sValue.IsZero || sValue >= sMax ? TxErrorMessages.InvalidTxSignature + : rValue.IsZero || rValue >= Secp256K1Curve.NMinusOne ? TxErrorMessages.InvalidTxSignature + : signature.V is 27 or 28 ? ValidationResult.Success + : ValidateChainId(transaction, releaseSpec); + } +} - return true; - } +public sealed class LegacySignatureTxValidator(ulong chainId) : BaseSignatureTxValidator +{ + protected override ValidationResult ValidateChainId(Transaction transaction, IReleaseSpec releaseSpec) + { + ulong v = transaction.Signature!.V; + return releaseSpec.IsEip155Enabled && (v == chainId * 2 + 35ul || v == chainId * 2 + 36ul) + ? ValidationResult.Success + : base.ValidateChainId(transaction, releaseSpec); } } + +public sealed class SignatureTxValidator : BaseSignatureTxValidator +{ + public static readonly SignatureTxValidator Instance = new(); + private SignatureTxValidator() { } +} diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs index f945817a461..fe41081f60e 100644 --- a/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs +++ b/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Consensus.Validators; using Nethermind.Core.Specs; using Nethermind.TxPool; using NSubstitute; @@ -9,7 +10,7 @@ namespace Nethermind.Core.Test.Builders { public class TransactionValidatorBuilder : BuilderBase { - private bool _alwaysTrue; + private ValidationResult _always; public TransactionValidatorBuilder() { @@ -20,7 +21,7 @@ public TransactionValidatorBuilder ThatAlwaysReturnsFalse { get { - _alwaysTrue = false; + _always = "Invalid"; return this; } } @@ -29,15 +30,15 @@ public TransactionValidatorBuilder ThatAlwaysReturnsTrue { get { - _alwaysTrue = true; + _always = ValidationResult.Success; return this; } } protected override void BeforeReturn() { - TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any(), out _).Returns(_alwaysTrue); - TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any(), out _).Returns(_alwaysTrue); + TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any()).Returns(_always); + TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any()).Returns(_always); base.BeforeReturn(); } } diff --git a/src/Nethermind/Nethermind.Core/TransactionExtensions.cs b/src/Nethermind/Nethermind.Core/TransactionExtensions.cs index 412bce0e3c8..7f54a6a18ef 100644 --- a/src/Nethermind/Nethermind.Core/TransactionExtensions.cs +++ b/src/Nethermind/Nethermind.Core/TransactionExtensions.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Diagnostics.CodeAnalysis; using Nethermind.Core.Specs; using Nethermind.Int256; @@ -33,7 +34,9 @@ public static UInt256 CalculateTransactionPotentialCost(this Transaction tx, boo { UInt256 effectiveGasPrice = tx.CalculateEffectiveGasPrice(eip1559Enabled, baseFee); if (tx.IsServiceTransaction) + { effectiveGasPrice = UInt256.Zero; + } return effectiveGasPrice * (ulong)tx.GasLimit + tx.Value; } @@ -57,15 +60,23 @@ public static UInt256 CalculateEffectiveGasPrice(this Transaction tx, bool eip15 return effectiveGasPrice; } - public static UInt256 CalculateMaxPriorityFeePerGas(this Transaction tx, bool eip1559Enabled, in UInt256 baseFee) - { - return eip1559Enabled ? UInt256.Min(tx.MaxPriorityFeePerGas, tx.MaxFeePerGas > baseFee ? tx.MaxFeePerGas - baseFee : 0) : tx.MaxPriorityFeePerGas; - } - public static bool IsAboveInitCode(this Transaction tx, IReleaseSpec spec) - { - return tx.IsContractCreation && spec.IsEip3860Enabled && (tx.DataLength) > spec.MaxInitCodeSize; - } + public static UInt256 CalculateMaxPriorityFeePerGas(this Transaction tx, bool eip1559Enabled, in UInt256 baseFee) => + eip1559Enabled ? UInt256.Min(tx.MaxPriorityFeePerGas, tx.MaxFeePerGas > baseFee ? tx.MaxFeePerGas - baseFee : 0) : tx.MaxPriorityFeePerGas; + public static bool IsAboveInitCode(this Transaction tx, IReleaseSpec spec) => + tx.IsContractCreation && spec.IsEip3860Enabled && tx.DataLength > spec.MaxInitCodeSize; + public static bool TryGetByTxType(this T?[] array, TxType txType, [NotNullWhen(true)] out T? item) + { + var type = (byte)txType; + if (type > Transaction.MaxTxType) + { + item = default; + return false; + } + + item = array[type]; + return item != null; + } } } diff --git a/src/Nethermind/Nethermind.Core/ValidationResult.cs b/src/Nethermind/Nethermind.Core/ValidationResult.cs new file mode 100644 index 00000000000..739d7e5296e --- /dev/null +++ b/src/Nethermind/Nethermind.Core/ValidationResult.cs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Core; + +public record struct ValidationResult(string? Error) +{ + public static ValidationResult Success => new(null); + public static implicit operator bool(ValidationResult result) => result.AsBool(); + public static implicit operator ValidationResult(string error) => new(error); + public override string ToString() => Error ?? "Success"; + public bool AsBool() => Error is null; +} diff --git a/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs b/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs index 8fe0e62a4f3..767a9daf54d 100644 --- a/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs +++ b/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs @@ -20,9 +20,7 @@ public StepDependencyException(string message) public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) { - if (argument is not null) - return; - throw new StepDependencyException(paramName ?? ""); + if (argument is null) throw new StepDependencyException(paramName ?? ""); } } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs b/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs index 87cbb58f650..3b32e476975 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs @@ -8,23 +8,15 @@ namespace Nethermind.Merge.Plugin.InvalidChainTracker; -public class InvalidBlockInterceptor : IBlockValidator +public class InvalidBlockInterceptor( + IBlockValidator headerValidator, + IInvalidChainTracker invalidChainTracker, + ILogManager logManager) + : IBlockValidator { - private readonly IBlockValidator _baseValidator; - private readonly IInvalidChainTracker _invalidChainTracker; - private readonly ILogger _logger; - - public InvalidBlockInterceptor( - IBlockValidator headerValidator, - IInvalidChainTracker invalidChainTracker, - ILogManager logManager) - { - _baseValidator = headerValidator; - _invalidChainTracker = invalidChainTracker; - _logger = logManager.GetClassLogger(typeof(InvalidBlockInterceptor)); - } + private readonly ILogger _logger = logManager.GetClassLogger(typeof(InvalidBlockInterceptor)); - public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) => _baseValidator.ValidateOrphanedBlock(block, out error); + public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) => headerValidator.ValidateOrphanedBlock(block, out error); public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle = false) { @@ -32,7 +24,7 @@ public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle = fal } public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error) { - bool result = _baseValidator.Validate(header, parent, isUncle, out error); + bool result = headerValidator.Validate(header, parent, isUncle, out error); if (!result) { if (_logger.IsTrace) _logger.Trace($"Intercepted a bad header {header}"); @@ -41,9 +33,9 @@ public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [Not if (_logger.IsDebug) _logger.Debug($"Header invalidation should not be tracked"); return result; } - _invalidChainTracker.OnInvalidBlock(header.Hash!, header.ParentHash); + invalidChainTracker.OnInvalidBlock(header.Hash!, header.ParentHash); } - _invalidChainTracker.SetChildParent(header.Hash!, header.ParentHash!); + invalidChainTracker.SetChildParent(header.Hash!, header.ParentHash!); return result; } @@ -54,7 +46,7 @@ public bool Validate(BlockHeader header, bool isUncle = false) public bool Validate(BlockHeader header, bool isUncle, [NotNullWhen(false)] out string? error) { - bool result = _baseValidator.Validate(header, isUncle, out error); + bool result = headerValidator.Validate(header, isUncle, out error); if (!result) { if (_logger.IsTrace) _logger.Trace($"Intercepted a bad header {header}"); @@ -63,15 +55,15 @@ public bool Validate(BlockHeader header, bool isUncle, [NotNullWhen(false)] out if (_logger.IsDebug) _logger.Debug($"Header invalidation should not be tracked"); return result; } - _invalidChainTracker.OnInvalidBlock(header.Hash!, header.ParentHash); + invalidChainTracker.OnInvalidBlock(header.Hash!, header.ParentHash); } - _invalidChainTracker.SetChildParent(header.Hash!, header.ParentHash!); + invalidChainTracker.SetChildParent(header.Hash!, header.ParentHash!); return result; } public bool ValidateSuggestedBlock(Block block, [NotNullWhen(false)] out string? error, bool validateHashes = true) { - bool result = _baseValidator.ValidateSuggestedBlock(block, out error, validateHashes); + bool result = headerValidator.ValidateSuggestedBlock(block, out error, validateHashes); if (!result) { if (_logger.IsTrace) _logger.Trace($"Intercepted a bad block {block}"); @@ -80,9 +72,9 @@ public bool ValidateSuggestedBlock(Block block, [NotNullWhen(false)] out string? if (_logger.IsDebug) _logger.Debug($"Block invalidation should not be tracked"); return result; } - _invalidChainTracker.OnInvalidBlock(block.Hash!, block.ParentHash); + invalidChainTracker.OnInvalidBlock(block.Hash!, block.ParentHash); } - _invalidChainTracker.SetChildParent(block.Hash!, block.ParentHash!); + invalidChainTracker.SetChildParent(block.Hash!, block.ParentHash!); return result; } @@ -92,7 +84,7 @@ public bool ValidateProcessedBlock(Block block, TxReceipt[] receipts, Block sugg } public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, [NotNullWhen(false)] out string? error) { - bool result = _baseValidator.ValidateProcessedBlock(processedBlock, receipts, suggestedBlock, out error); + bool result = headerValidator.ValidateProcessedBlock(processedBlock, receipts, suggestedBlock, out error); if (!result) { if (_logger.IsTrace) _logger.Trace($"Intercepted a bad block {processedBlock}"); @@ -101,9 +93,9 @@ public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, B if (_logger.IsDebug) _logger.Debug($"Block invalidation should not be tracked"); return result; } - _invalidChainTracker.OnInvalidBlock(suggestedBlock.Hash!, suggestedBlock.ParentHash); + invalidChainTracker.OnInvalidBlock(suggestedBlock.Hash!, suggestedBlock.ParentHash); } - _invalidChainTracker.SetChildParent(suggestedBlock.Hash!, suggestedBlock.ParentHash!); + invalidChainTracker.SetChildParent(suggestedBlock.Hash!, suggestedBlock.ParentHash!); return result; } @@ -115,7 +107,7 @@ private static bool ShouldNotTrackInvalidation(BlockHeader header) public bool ValidateWithdrawals(Block block, out string? error) { - bool result = _baseValidator.ValidateWithdrawals(block, out error); + bool result = headerValidator.ValidateWithdrawals(block, out error); if (!result) { @@ -128,10 +120,10 @@ public bool ValidateWithdrawals(Block block, out string? error) return false; } - _invalidChainTracker.OnInvalidBlock(block.Hash!, block.ParentHash); + invalidChainTracker.OnInvalidBlock(block.Hash!, block.ParentHash); } - _invalidChainTracker.SetChildParent(block.Hash!, block.ParentHash!); + invalidChainTracker.SetChildParent(block.Hash!, block.ParentHash!); return result; } diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index 80c7f2d7e98..e1548b52b92 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -11,6 +11,7 @@ using Nethermind.Consensus.Producers; using Nethermind.Consensus.Validators; using Nethermind.Consensus.Withdrawals; +using Nethermind.Core; using Nethermind.Evm; using Nethermind.Evm.TransactionProcessing; using Nethermind.Init.Steps; @@ -19,98 +20,81 @@ namespace Nethermind.Optimism; -public class InitializeBlockchainOptimism : InitializeBlockchain +public class InitializeBlockchainOptimism(OptimismNethermindApi api) : InitializeBlockchain(api) { - private readonly OptimismNethermindApi _api; - private readonly IBlocksConfig _blocksConfig; - - public InitializeBlockchainOptimism(OptimismNethermindApi api) : base(api) - { - _api = api; - _blocksConfig = api.Config(); - } + private readonly IBlocksConfig _blocksConfig = api.Config(); protected override Task InitBlockchain() { - _api.SpecHelper = new(_api.ChainSpec.Optimism); - _api.L1CostHelper = new(_api.SpecHelper, _api.ChainSpec.Optimism.L1BlockAddress); + api.RegisterTxType(TxType.DepositTx, new OptimismTxDecoder(), Always.Valid); + + api.SpecHelper = new(api.ChainSpec.Optimism); + api.L1CostHelper = new(api.SpecHelper, api.ChainSpec.Optimism.L1BlockAddress); return base.InitBlockchain(); } protected override ITransactionProcessor CreateTransactionProcessor(CodeInfoRepository codeInfoRepository, VirtualMachine virtualMachine) { - if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); - if (_api.SpecHelper is null) throw new StepDependencyException(nameof(_api.SpecHelper)); - if (_api.L1CostHelper is null) throw new StepDependencyException(nameof(_api.L1CostHelper)); - if (_api.WorldState is null) throw new StepDependencyException(nameof(_api.WorldState)); + if (api.SpecProvider is null) throw new StepDependencyException(nameof(api.SpecProvider)); + if (api.SpecHelper is null) throw new StepDependencyException(nameof(api.SpecHelper)); + if (api.L1CostHelper is null) throw new StepDependencyException(nameof(api.L1CostHelper)); + if (api.WorldState is null) throw new StepDependencyException(nameof(api.WorldState)); return new OptimismTransactionProcessor( - _api.SpecProvider, - _api.WorldState, + api.SpecProvider, + api.WorldState, virtualMachine, - _api.LogManager, - _api.L1CostHelper, - _api.SpecHelper, + api.LogManager, + api.L1CostHelper, + api.SpecHelper, codeInfoRepository ); } protected override IHeaderValidator CreateHeaderValidator() { - if (_api.InvalidChainTracker is null) throw new StepDependencyException(nameof(_api.InvalidChainTracker)); + if (api.InvalidChainTracker is null) throw new StepDependencyException(nameof(api.InvalidChainTracker)); OptimismHeaderValidator opHeaderValidator = new( - _api.BlockTree, - _api.SealValidator, - _api.SpecProvider, - _api.LogManager); + api.BlockTree, + api.SealValidator, + api.SpecProvider, + api.LogManager); - return new InvalidHeaderInterceptor(opHeaderValidator, _api.InvalidChainTracker, _api.LogManager); + return new InvalidHeaderInterceptor(opHeaderValidator, api.InvalidChainTracker, api.LogManager); } protected override IBlockValidator CreateBlockValidator() { - if (_api.InvalidChainTracker is null) throw new StepDependencyException(nameof(_api.InvalidChainTracker)); - if (_api.TxValidator is null) throw new StepDependencyException(nameof(_api.TxValidator)); - - OptimismTxValidator txValidator = new(_api.TxValidator); - BlockValidator blockValidator = new( - txValidator, - _api.HeaderValidator, - _api.UnclesValidator, - _api.SpecProvider, - _api.LogManager); - - return new InvalidBlockInterceptor(blockValidator, _api.InvalidChainTracker, _api.LogManager); + if (api.InvalidChainTracker is null) throw new StepDependencyException(nameof(api.InvalidChainTracker)); + return new InvalidBlockInterceptor(base.CreateBlockValidator(), api.InvalidChainTracker, api.LogManager); } protected override BlockProcessor CreateBlockProcessor(BlockCachePreWarmer? preWarmer) { - ITransactionProcessor? apiTransactionProcessor = _api.TransactionProcessor; - ILogManager? apiLogManager = _api.LogManager; - - if (_api.DbProvider is null) throw new StepDependencyException(nameof(_api.DbProvider)); - if (_api.RewardCalculatorSource is null) throw new StepDependencyException(nameof(_api.RewardCalculatorSource)); - if (apiTransactionProcessor is null) throw new StepDependencyException(nameof(apiTransactionProcessor)); - if (_api.SpecHelper is null) throw new StepDependencyException(nameof(_api.SpecHelper)); - if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); - if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); - if (_api.WorldState is null) throw new StepDependencyException(nameof(_api.WorldState)); + ITransactionProcessor? transactionProcessor = api.TransactionProcessor; + if (api.DbProvider is null) throw new StepDependencyException(nameof(api.DbProvider)); + if (api.RewardCalculatorSource is null) throw new StepDependencyException(nameof(api.RewardCalculatorSource)); + if (transactionProcessor is null) throw new StepDependencyException(nameof(transactionProcessor)); + if (api.SpecHelper is null) throw new StepDependencyException(nameof(api.SpecHelper)); + if (api.SpecProvider is null) throw new StepDependencyException(nameof(api.SpecProvider)); + if (api.BlockTree is null) throw new StepDependencyException(nameof(api.BlockTree)); + if (api.WorldState is null) throw new StepDependencyException(nameof(api.WorldState)); - Create2DeployerContractRewriter contractRewriter = new(_api.SpecHelper, _api.SpecProvider, _api.BlockTree); + Create2DeployerContractRewriter contractRewriter = new(api.SpecHelper, api.SpecProvider, api.BlockTree); return new OptimismBlockProcessor( - _api.SpecProvider, - _api.BlockValidator, - _api.RewardCalculatorSource.Get(apiTransactionProcessor!), - new BlockProcessor.BlockValidationTransactionsExecutor(apiTransactionProcessor, _api.WorldState), - _api.WorldState, - _api.ReceiptStorage, - new BlockhashStore(_api.SpecProvider, _api.WorldState), - new BeaconBlockRootHandler(apiTransactionProcessor), - apiLogManager, - _api.SpecHelper, + api.SpecProvider, + api.BlockValidator, + api.RewardCalculatorSource.Get(transactionProcessor), + new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, api.WorldState), + api.WorldState, + api.ReceiptStorage, + new BlockhashStore(api.SpecProvider, api.WorldState), + new BeaconBlockRootHandler(transactionProcessor), + api.LogManager, + api.SpecHelper, contractRewriter, new BlockProductionWithdrawalProcessor(new NullWithdrawalProcessor()), preWarmer: preWarmer); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs b/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs index e163c84f792..32db335b572 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs @@ -10,11 +10,12 @@ namespace Nethermind.Optimism; -public class OptimismHeaderValidator : HeaderValidator +public class OptimismHeaderValidator( + IBlockTree? blockTree, + ISealValidator? sealValidator, + ISpecProvider? specProvider, + ILogManager? logManager) + : HeaderValidator(blockTree, sealValidator, specProvider, logManager) { - public OptimismHeaderValidator(IBlockTree? blockTree, ISealValidator? sealValidator, ISpecProvider? specProvider, ILogManager? logManager) : base(blockTree, sealValidator, specProvider, logManager) - { - } - protected override bool ValidateGasLimitRange(BlockHeader header, BlockHeader parent, IReleaseSpec spec, ref string? error) => true; } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/OptimismTxDecoder.cs b/src/Nethermind/Nethermind.Optimism/OptimismTxDecoder.cs similarity index 96% rename from src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/OptimismTxDecoder.cs rename to src/Nethermind/Nethermind.Optimism/OptimismTxDecoder.cs index 18173c5094d..9bb2e77fcdd 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/OptimismTxDecoder.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTxDecoder.cs @@ -4,8 +4,10 @@ using System; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Serialization.Rlp; +using Nethermind.Serialization.Rlp.TxDecoders; -namespace Nethermind.Serialization.Rlp.TxDecoders; +namespace Nethermind.Optimism; public sealed class OptimismTxDecoder(Func? transactionFactory = null) : BaseEIP1559TxDecoder(TxType.DepositTx, transactionFactory) where T : Transaction, new() diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTxValidator.cs b/src/Nethermind/Nethermind.Optimism/OptimismTxValidator.cs deleted file mode 100644 index c0653b7aa70..00000000000 --- a/src/Nethermind/Nethermind.Optimism/OptimismTxValidator.cs +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using Nethermind.Core; -using Nethermind.Core.Specs; -using Nethermind.TxPool; -using System.Diagnostics.CodeAnalysis; - -namespace Nethermind.Optimism; - -public class OptimismTxValidator : ITxValidator -{ - private readonly ITxValidator _txValidator; - - public OptimismTxValidator(ITxValidator txValidator) - { - _txValidator = txValidator; - } - - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => - IsWellFormed(transaction, releaseSpec, out _); - public bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec, [NotNullWhen(false)] out string? error) - { - error = null; - return transaction.Type == TxType.DepositTx || _txValidator.IsWellFormed(transaction, releaseSpec, out error); - } - -} diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs index 0ef1eb96806..6e62bb887cc 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs @@ -2,8 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.Extensions.ObjectPool; using Nethermind.Core; @@ -30,20 +28,19 @@ public sealed class GeneratedTxDecoder : TxDecoder; public class TxDecoder : IRlpStreamDecoder, IRlpValueDecoder where T : Transaction, new() { - private readonly Dictionary _decoders; + private readonly ITxDecoder?[] _decoders = new ITxDecoder?[Transaction.MaxTxType + 1]; protected TxDecoder(Func? transactionFactory = null) { Func factory = transactionFactory ?? (() => new T()); - _decoders = new() { - { TxType.Legacy, new LegacyTxDecoder(factory) }, - { TxType.AccessList, new AccessListTxDecoder(factory) }, - { TxType.EIP1559, new EIP1559TxDecoder(factory) }, - { TxType.Blob, new BlobTxDecoder(factory) }, - { TxType.DepositTx, new OptimismTxDecoder(factory) } - }; + RegisterDecoder(new LegacyTxDecoder(factory)); + RegisterDecoder(new AccessListTxDecoder(factory)); + RegisterDecoder(new EIP1559TxDecoder(factory)); + RegisterDecoder(new BlobTxDecoder(factory)); } + public void RegisterDecoder(ITxDecoder decoder) => _decoders[(int)decoder.Type] = decoder; + public T? Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { void ThrowIfLegacy(TxType txType1) @@ -83,7 +80,7 @@ void ThrowIfLegacy(TxType txType1) } private ITxDecoder GetDecoder(TxType txType) => - _decoders.TryGetValue(txType, out ITxDecoder decoder) + _decoders.TryGetByTxType(txType, out ITxDecoder decoder) ? decoder : throw new RlpException($"Unknown transaction type {txType}") { Data = { { "txType", txType } } }; diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs index 30cdcec6a4c..07a16c24951 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs @@ -6,7 +6,7 @@ namespace Nethermind.Serialization.Rlp.TxDecoders; -interface ITxDecoder +public interface ITxDecoder { public TxType Type { get; } diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index 7db782213af..1725f2f0e56 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -55,7 +55,12 @@ public class ReleaseSpec : IReleaseSpec // used only in testing public ReleaseSpec Clone() => (ReleaseSpec)MemberwiseClone(); - public bool IsEip1559Enabled { get; set; } + public bool IsEip1559Enabled + { + get => _isEip1559Enabled || IsEip4844Enabled; + set => _isEip1559Enabled = value; + } + public bool IsEip3198Enabled { get; set; } public bool IsEip3529Enabled { get; set; } public bool IsEip3607Enabled { get; set; } @@ -92,6 +97,8 @@ public Address Eip4788ContractAddress public bool IsEip7709Enabled { get; set; } private Address _eip2935ContractAddress; + private bool _isEip1559Enabled; + public Address Eip2935ContractAddress { get => IsEip2935Enabled ? _eip2935ContractAddress : null; diff --git a/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs index 2de0143dd37..52f0753471d 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs @@ -10,27 +10,20 @@ namespace Nethermind.TxPool.Filters /// /// Filters out transactions that are not well formed (not conforming with the yellowpaper and EIPs) /// - internal sealed class MalformedTxFilter : IIncomingTxFilter + internal sealed class MalformedTxFilter( + IChainHeadSpecProvider specProvider, + ITxValidator txValidator, + ILogger logger) + : IIncomingTxFilter { - private readonly ITxValidator _txValidator; - private readonly IChainHeadSpecProvider _specProvider; - private readonly ILogger _logger; - - public MalformedTxFilter(IChainHeadSpecProvider specProvider, ITxValidator txValidator, ILogger logger) - { - _txValidator = txValidator; - _specProvider = specProvider; - _logger = logger; - } - public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandlingOptions txHandlingOptions) { - IReleaseSpec spec = _specProvider.GetCurrentHeadSpec(); - if (!_txValidator.IsWellFormed(tx, spec, out _)) + IReleaseSpec spec = specProvider.GetCurrentHeadSpec(); + if (!txValidator.IsWellFormed(tx, spec)) { Metrics.PendingTransactionsMalformed++; // It may happen that other nodes send us transactions that were signed for another chain or don't have enough gas. - if (_logger.IsTrace) _logger.Trace($"Skipped adding transaction {tx.ToString(" ")}, invalid transaction."); + if (logger.IsTrace) logger.Trace($"Skipped adding transaction {tx.ToString(" ")}, invalid transaction."); return AcceptTxResult.Invalid; } diff --git a/src/Nethermind/Nethermind.TxPool/ITxValidator.cs b/src/Nethermind/Nethermind.TxPool/ITxValidator.cs index 1510c9a165a..64c2075715f 100644 --- a/src/Nethermind/Nethermind.TxPool/ITxValidator.cs +++ b/src/Nethermind/Nethermind.TxPool/ITxValidator.cs @@ -3,12 +3,11 @@ using Nethermind.Core; using Nethermind.Core.Specs; -using System.Diagnostics.CodeAnalysis; namespace Nethermind.TxPool { public interface ITxValidator { - bool IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec, [NotNullWhen(false)] out string? error); + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec); } } From 17533eb1a92feca85fc57c201924c0046155bb06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Moraczy=C5=84ski?= Date: Tue, 10 Sep 2024 19:26:08 +0200 Subject: [PATCH 016/113] Moved BlockProductionTimeout to config, increased BlockProductionTimeout (#7378) --- src/Nethermind/Nethermind.Config/BlocksConfig.cs | 2 ++ src/Nethermind/Nethermind.Config/IBlocksConfig.cs | 3 +++ .../Nethermind.Consensus/Producers/BlockProducerBase.cs | 6 ++++-- .../BlockProduction/PostMergeBlockProducer.cs | 2 +- .../Nethermind.Optimism/OptimismPostMergeBlockProducer.cs | 2 +- src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs | 8 +++++--- src/Nethermind/Nethermind.Runner/configs/chiado.cfg | 3 ++- .../Nethermind.Runner/configs/chiado_archive.cfg | 1 + src/Nethermind/Nethermind.Runner/configs/gnosis.cfg | 1 + .../Nethermind.Runner/configs/gnosis_archive.cfg | 1 + 10 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Config/BlocksConfig.cs b/src/Nethermind/Nethermind.Config/BlocksConfig.cs index 9a12edfb5d4..7b9ab72f2c7 100644 --- a/src/Nethermind/Nethermind.Config/BlocksConfig.cs +++ b/src/Nethermind/Nethermind.Config/BlocksConfig.cs @@ -26,6 +26,8 @@ public class BlocksConfig : IBlocksConfig public bool PreWarmStateOnBlockProcessing { get; set; } = true; + public int BlockProductionTimeoutMs { get; set; } = 4000; + public string ExtraData { get diff --git a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs index 8f232cf2b02..54a72405b79 100644 --- a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs +++ b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs @@ -37,5 +37,8 @@ public interface IBlocksConfig : IConfig [ConfigItem(Description = "Try to pre-warm the state when processing blocks. Can lead to 2x speedup in main loop block processing.", DefaultValue = "True")] bool PreWarmStateOnBlockProcessing { get; set; } + [ConfigItem(Description = "Block Production timeout, in milliseconds.", DefaultValue = "4000")] + int BlockProductionTimeoutMs { get; set; } + byte[] GetExtraDataBytes(); } diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs index 94ae0ee38f0..d11d0190576 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs @@ -41,7 +41,7 @@ public abstract class BlockProducerBase : IBlockProducer private readonly IDifficultyCalculator _difficultyCalculator; protected readonly ISpecProvider _specProvider; private readonly ITxSource _txSource; - protected const int BlockProductionTimeout = 2000; + protected readonly int BlockProductionTimeoutMs; protected readonly SemaphoreSlim _producingBlockLock = new(1); protected ILogger Logger { get; } protected readonly IBlocksConfig _blocksConfig; @@ -70,6 +70,8 @@ protected BlockProducerBase( _difficultyCalculator = difficultyCalculator ?? throw new ArgumentNullException(nameof(difficultyCalculator)); Logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); _blocksConfig = blocksConfig ?? throw new ArgumentNullException(nameof(blocksConfig)); + + BlockProductionTimeoutMs = _blocksConfig.BlockProductionTimeoutMs; } public async Task BuildBlock(BlockHeader? parentHeader = null, IBlockTracer? blockTracer = null, @@ -77,7 +79,7 @@ protected BlockProducerBase( { token ??= default; Block? block = null; - if (await _producingBlockLock.WaitAsync(BlockProductionTimeout, token.Value)) + if (await _producingBlockLock.WaitAsync(BlockProductionTimeoutMs, token.Value)) { try { diff --git a/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/PostMergeBlockProducer.cs b/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/PostMergeBlockProducer.cs index 16b69b24a1f..3c3e401de4d 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/PostMergeBlockProducer.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/BlockProduction/PostMergeBlockProducer.cs @@ -54,7 +54,7 @@ public virtual Block PrepareEmptyBlock(BlockHeader parent, PayloadAttributes? pa blockHeader.Bloom = Bloom.Empty; var block = new Block(blockHeader, Array.Empty(), Array.Empty(), payloadAttributes?.Withdrawals); - if (_producingBlockLock.Wait(BlockProductionTimeout)) + if (_producingBlockLock.Wait(BlockProductionTimeoutMs)) { try { diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs b/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs index 93df8a49f9c..3da889a982b 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs @@ -60,7 +60,7 @@ public override Block PrepareEmptyBlock(BlockHeader parent, PayloadAttributes? p Block block = new(blockHeader, txs, Array.Empty(), payloadAttributes?.Withdrawals); - if (_producingBlockLock.Wait(BlockProductionTimeout)) + if (_producingBlockLock.Wait(BlockProductionTimeoutMs)) { try { diff --git a/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs b/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs index f29cfabcf44..4034ab660c9 100644 --- a/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/ConfigFilesTests.cs @@ -361,16 +361,18 @@ public void Arena_order_is_default(string configWildcard) Test(configWildcard, c => c.NettyArenaOrder, -1); } - [TestCase("chiado", 17_000_000L, 5UL)] - [TestCase("gnosis", 17_000_000L, 5UL)] + [TestCase("chiado", 17_000_000L, 5UL, 3000)] + [TestCase("gnosis", 17_000_000L, 5UL, 3000)] [TestCase("mainnet", 30_000_000L)] [TestCase("sepolia", 30_000_000L)] [TestCase("holesky", 30_000_000L)] [TestCase("^chiado ^gnosis ^mainnet ^sepolia ^holesky")] - public void Blocks_defaults_are_correct(string configWildcard, long? targetBlockGasLimit = null, ulong secondsPerSlot = 12) + public void Blocks_defaults_are_correct(string configWildcard, long? targetBlockGasLimit = null, ulong secondsPerSlot = 12, int blockProductionTimeout = 4000) { Test(configWildcard, c => c.TargetBlockGasLimit, targetBlockGasLimit); Test(configWildcard, c => c.SecondsPerSlot, secondsPerSlot); + Test(configWildcard, c => c.BlockProductionTimeoutMs, blockProductionTimeout); + } [Test] diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg index 063329376f5..944d6513cd3 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg @@ -24,6 +24,7 @@ }, "Blocks": { "SecondsPerSlot": 5, + "BlockProductionTimeoutMs": 3000, "TargetBlockGasLimit": 17000000 }, "Aura": { @@ -43,4 +44,4 @@ 16 ] } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado_archive.cfg b/src/Nethermind/Nethermind.Runner/configs/chiado_archive.cfg index 888f9d039f8..9d50f585634 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado_archive.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/chiado_archive.cfg @@ -22,6 +22,7 @@ }, "Blocks": { "SecondsPerSlot": 5, + "BlockProductionTimeoutMs": 3000, "TargetBlockGasLimit": 17000000 }, "Receipt": { diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg b/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg index b828d7affd2..ef098f08e7b 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg @@ -21,6 +21,7 @@ }, "Blocks": { "SecondsPerSlot": 5, + "BlockProductionTimeoutMs": 3000, "TargetBlockGasLimit": 17000000 }, "Mining": { diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.cfg b/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.cfg index f07093b3804..a963524e08b 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.cfg @@ -15,6 +15,7 @@ }, "Blocks": { "SecondsPerSlot": 5, + "BlockProductionTimeoutMs": 3000, "TargetBlockGasLimit": 17000000 }, "Receipt": { From c1f94552025cf93896910e14f9487b44b36a28fb Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 11 Sep 2024 10:36:30 +0100 Subject: [PATCH 017/113] Reduce memory use during Archive Sync (#7407) --- .../Receipts/PersistentReceiptStorageTests.cs | 6 + .../Processing/BlockchainProcessor.cs | 34 ++++- .../Blockchain/TestBlockchain.cs | 2 + .../Nethermind.Core.Test/TestMemColumnDb.cs | 1 + .../Nethermind.Db.Rpc/RpcColumnsDb.cs | 1 + src/Nethermind/Nethermind.Db/IColumnsDb.cs | 2 +- src/Nethermind/Nethermind.Db/MemColumnsDb.cs | 1 + .../PartialStorageProviderBase.cs | 19 ++- .../PersistentStorageProvider.cs | 13 +- .../Nethermind.State/StateProvider.cs | 23 +-- .../Nethermind.Trie/PreCachedTrieStore.cs | 6 +- .../Nethermind.Trie/Pruning/TrieStore.cs | 142 +++++++++++------- 12 files changed, 167 insertions(+), 83 deletions(-) diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs index e09182ba04e..5fc64104e58 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs @@ -58,6 +58,12 @@ public void SetUp() CreateStorage(); } + [TearDown] + public void TearDown() + { + _receiptsDb.Dispose(); + } + private void CreateStorage() { _decoder = new ReceiptArrayStorageDecoder(_useCompactReceipts); diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs index c3cfb0b7234..1af54a33465 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs @@ -6,15 +6,16 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime; using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; using Nethermind.Blockchain.Find; -using Nethermind.Config; using Nethermind.Core; using Nethermind.Core.Attributes; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Core.Memory; using Nethermind.Evm.Tracing; using Nethermind.Evm.Tracing.GethStyle; using Nethermind.Evm.Tracing.ParityStyle; @@ -295,12 +296,25 @@ private Task RunProcessing() private void RunProcessingLoop() { + const int BlocksBacklogTriggeringManualGC = 20; + const int MaxBlocksWithoutGC = 100; + if (_logger.IsDebug) _logger.Debug($"Starting block processor - {_blockQueue.Count} blocks waiting in the queue."); FireProcessingQueueEmpty(); + var fireGC = false; + var countToGC = 0; foreach (BlockRef blockRef in _blockQueue.GetConsumingEnumerable(_loopCancellationSource.Token)) { + if (!fireGC && _blockQueue.Count > BlocksBacklogTriggeringManualGC) + { + // Long chains in archive sync don't force GC and don't call MallocTrim; + // so we trigger it manually + fireGC = true; + countToGC = MaxBlocksWithoutGC; + } + try { if (blockRef.IsInDb || blockRef.Block is null) @@ -338,11 +352,29 @@ private void RunProcessingLoop() if (_logger.IsTrace) _logger.Trace($"Now {_blockQueue.Count} blocks waiting in the queue."); FireProcessingQueueEmpty(); + + if (fireGC) + { + countToGC--; + if (countToGC <= 0) + { + fireGC = false; + PerformFullGC(); + } + } } if (_logger.IsInfo) _logger.Info("Block processor queue stopped."); } + private void PerformFullGC() + { + if (_logger.IsDebug) _logger.Debug($"Performing Full GC"); + GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; + System.GC.Collect(2, GCCollectionMode.Aggressive, blocking: true, compacting: true); + MallocHelper.Instance.MallocTrim((uint)1.MiB()); + } + private void FireProcessingQueueEmpty() { if (((IBlockProcessingQueue)this).IsEmpty) diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index f93aa06571f..d051818758f 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -442,6 +442,8 @@ public virtual void Dispose() { CodeDb?.Dispose(); StateDb?.Dispose(); + DbProvider.BlobTransactionsDb?.Dispose(); + DbProvider.ReceiptsDb?.Dispose(); } _trieStoreWatcher?.Dispose(); diff --git a/src/Nethermind/Nethermind.Core.Test/TestMemColumnDb.cs b/src/Nethermind/Nethermind.Core.Test/TestMemColumnDb.cs index 9f30feee683..bcb48306915 100644 --- a/src/Nethermind/Nethermind.Core.Test/TestMemColumnDb.cs +++ b/src/Nethermind/Nethermind.Core.Test/TestMemColumnDb.cs @@ -30,4 +30,5 @@ public IColumnsWriteBatch StartWriteBatch() { return new InMemoryColumnWriteBatch(this); } + public void Dispose() { } } diff --git a/src/Nethermind/Nethermind.Db.Rpc/RpcColumnsDb.cs b/src/Nethermind/Nethermind.Db.Rpc/RpcColumnsDb.cs index 1dd84a1fdac..8a458965589 100644 --- a/src/Nethermind/Nethermind.Db.Rpc/RpcColumnsDb.cs +++ b/src/Nethermind/Nethermind.Db.Rpc/RpcColumnsDb.cs @@ -45,5 +45,6 @@ public IColumnsWriteBatch StartWriteBatch() { return new InMemoryColumnWriteBatch(this); } + public void Dispose() { } } } diff --git a/src/Nethermind/Nethermind.Db/IColumnsDb.cs b/src/Nethermind/Nethermind.Db/IColumnsDb.cs index d7531872a6d..4f1eddcbd44 100644 --- a/src/Nethermind/Nethermind.Db/IColumnsDb.cs +++ b/src/Nethermind/Nethermind.Db/IColumnsDb.cs @@ -7,7 +7,7 @@ namespace Nethermind.Db { - public interface IColumnsDb : IDbMeta + public interface IColumnsDb : IDbMeta, IDisposable { IDb GetColumnDb(TKey key); IEnumerable ColumnKeys { get; } diff --git a/src/Nethermind/Nethermind.Db/MemColumnsDb.cs b/src/Nethermind/Nethermind.Db/MemColumnsDb.cs index eecb1d3233b..55168313bee 100644 --- a/src/Nethermind/Nethermind.Db/MemColumnsDb.cs +++ b/src/Nethermind/Nethermind.Db/MemColumnsDb.cs @@ -35,5 +35,6 @@ public IColumnsWriteBatch StartWriteBatch() { return new InMemoryColumnWriteBatch(this); } + public void Dispose() { } } } diff --git a/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs b/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs index 69a3c2fa433..24103a999a1 100644 --- a/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs +++ b/src/Nethermind/Nethermind.State/PartialStorageProviderBase.cs @@ -19,7 +19,7 @@ internal abstract class PartialStorageProviderBase { protected readonly Dictionary> _intraBlockCache = new(); protected readonly ILogger _logger; - protected readonly List _changes = new(Resettable.StartCapacity); + protected readonly List _changes = new(Resettable.StartCapacity); private readonly List _keptInCache = new(); // stack of snapshot indexes on changes for start of each transaction @@ -105,7 +105,7 @@ public void Restore(int snapshot) } _keptInCache.Add(change); - _changes[actualPosition] = null; + _changes[actualPosition] = default; continue; } } @@ -116,7 +116,7 @@ public void Restore(int snapshot) throw new InvalidOperationException($"Expected checked value {forAssertion} to be equal to {currentPosition} - {i}"); } - _changes[currentPosition - i] = null; + _changes[currentPosition - i] = default; if (stack.Count == 0) { @@ -230,7 +230,7 @@ protected bool TryGetCachedValue(in StorageCell storageCell, out byte[]? bytes) { int lastChangeIndex = stack.Peek(); { - bytes = _changes[lastChangeIndex]!.Value; + bytes = _changes[lastChangeIndex].Value; return true; } } @@ -293,7 +293,7 @@ public virtual void ClearStorage(Address address) /// /// Used for tracking each change to storage /// - protected class Change + protected readonly struct Change { public Change(ChangeType changeType, StorageCell storageCell, byte[] value) { @@ -302,9 +302,11 @@ public Change(ChangeType changeType, StorageCell storageCell, byte[] value) ChangeType = changeType; } - public ChangeType ChangeType { get; } - public StorageCell StorageCell { get; } - public byte[] Value { get; } + public readonly ChangeType ChangeType; + public readonly StorageCell StorageCell; + public readonly byte[] Value; + + public bool IsNull => ChangeType == ChangeType.Null; } /// @@ -312,6 +314,7 @@ public Change(ChangeType changeType, StorageCell storageCell, byte[] value) /// protected enum ChangeType { + Null = 0, JustCache, Update, Destroy, diff --git a/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs b/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs index 2e154a6074c..d7ec47050df 100644 --- a/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs +++ b/src/Nethermind/Nethermind.State/PersistentStorageProvider.cs @@ -104,7 +104,7 @@ public byte[] GetOriginal(in StorageCell storageCell) { if (stack.TryGetSearchedItem(snapshot, out int lastChangeIndexBeforeOriginalSnapshot)) { - return _changes[lastChangeIndexBeforeOriginalSnapshot]!.Value; + return _changes[lastChangeIndexBeforeOriginalSnapshot].Value; } } } @@ -112,7 +112,7 @@ public byte[] GetOriginal(in StorageCell storageCell) return value; } - + private HashSet? _tempToUpdateRoots; /// /// Called by Commit /// Used for persistent storage specific logic @@ -127,12 +127,12 @@ protected override void CommitCore(IStorageTracer tracer) { return; } - if (_changes[currentPosition] is null) + if (_changes[currentPosition].IsNull) { throw new InvalidOperationException($"Change at current position {currentPosition} was null when committing {nameof(PartialStorageProviderBase)}"); } - HashSet
toUpdateRoots = new(); + HashSet toUpdateRoots = (_tempToUpdateRoots ??= new()); bool isTracing = tracer.IsTracingStorage; Dictionary? trace = null; @@ -202,7 +202,7 @@ protected override void CommitCore(IStorageTracer tracer) } } - foreach (Address address in toUpdateRoots) + foreach (AddressAsKey address in toUpdateRoots) { // since the accounts could be empty accounts that are removing (EIP-158) if (_stateProvider.AccountExists(address)) @@ -215,6 +215,7 @@ protected override void CommitCore(IStorageTracer tracer) _storages.Remove(address); } } + toUpdateRoots.Clear(); base.CommitCore(tracer); _originalValues.Clear(); @@ -288,7 +289,7 @@ void UpdateRootHashesMultiThread() } } - private void SaveToTree(HashSet
toUpdateRoots, Change change) + private void SaveToTree(HashSet toUpdateRoots, Change change) { if (_originalValues.TryGetValue(change.StorageCell, out byte[] initialValue) && initialValue.AsSpan().SequenceEqual(change.Value)) diff --git a/src/Nethermind/Nethermind.State/StateProvider.cs b/src/Nethermind/Nethermind.State/StateProvider.cs index abcd0c15021..d8e6aebdf0b 100644 --- a/src/Nethermind/Nethermind.State/StateProvider.cs +++ b/src/Nethermind/Nethermind.State/StateProvider.cs @@ -37,7 +37,7 @@ internal class StateProvider private readonly ILogger _logger; private readonly IKeyValueStore _codeDb; - private List _changes = new(Resettable.StartCapacity); + private List _changes = new(Resettable.StartCapacity); internal readonly StateTree _tree; private readonly Func _getStateFromTrie; @@ -186,7 +186,7 @@ Account GetThroughCacheCheckExists() { // this also works like this in Geth (they don't follow the spec ¯\_(*~*)_/¯) // however we don't do it because of a consensus issue with Geth, just to avoid - // hitting non-existing account when substractin Zero-value from the sender + // hitting non-existing account when subtracting Zero-value from the sender if (releaseSpec.IsEip158Enabled && !isSubtracting) { Account touched = GetThroughCacheCheckExists(); @@ -348,12 +348,12 @@ public void Restore(int snapshot) } _keptInCache.Add(change); - _changes[actualPosition] = null; + _changes[actualPosition] = default; continue; } } - _changes[currentPosition - i] = null; // TODO: temp, ??? + _changes[currentPosition - i] = default; // TODO: temp, ??? int forChecking = stack.Pop(); if (forChecking != currentPosition - i) { @@ -439,7 +439,7 @@ public void Commit(IReleaseSpec releaseSpec, IWorldStateTracer stateTracer, bool } if (_logger.IsTrace) _logger.Trace($"Committing state changes (at {currentPosition})"); - if (_changes[currentPosition] is null) + if (_changes[currentPosition].IsNull) { throw new InvalidOperationException($"Change at current position {currentPosition} was null when committing {nameof(StateProvider)}"); } @@ -735,7 +735,7 @@ private void SetState(Address address, Account? account) { if (_intraTxCache.TryGetValue(address, out Stack value)) { - return _changes[value.Peek()]!.Account; + return _changes[value.Peek()].Account; } Account account = GetAndAddToCache(address); @@ -796,6 +796,7 @@ private Stack SetupCache(Address address) private enum ChangeType { + Null = 0, JustCache, Touch, Update, @@ -803,7 +804,7 @@ private enum ChangeType Delete } - private class Change + private readonly struct Change { public Change(ChangeType type, Address address, Account? account) { @@ -812,9 +813,11 @@ public Change(ChangeType type, Address address, Account? account) Account = account; } - public ChangeType ChangeType { get; } - public Address Address { get; } - public Account? Account { get; } + public readonly ChangeType ChangeType; + public readonly Address Address; + public readonly Account? Account; + + public bool IsNull => ChangeType == ChangeType.Null; } public ArrayPoolList? ChangedAddresses() diff --git a/src/Nethermind/Nethermind.Trie/PreCachedTrieStore.cs b/src/Nethermind/Nethermind.Trie/PreCachedTrieStore.cs index 08d580b1de5..5c425d79f7a 100644 --- a/src/Nethermind/Nethermind.Trie/PreCachedTrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/PreCachedTrieStore.cs @@ -88,7 +88,7 @@ public void Set(Hash256? address, in TreePath path, in ValueHash256 keccak, byte public INodeStorage.KeyScheme Scheme => _inner.Scheme; } -public class NodeKey : IEquatable +public readonly struct NodeKey : IEquatable { public readonly Hash256? Address; public readonly TreePath Path; @@ -108,8 +108,8 @@ public NodeKey(Hash256? address, in TreePath path, Hash256 hash) Hash = hash; } - public bool Equals(NodeKey? other) => - other is not null && Address == other.Address && Path.Equals(in other.Path) && Hash.Equals(other.Hash); + public bool Equals(NodeKey other) => + Address == other.Address && Path.Equals(in other.Path) && Hash.Equals(other.Hash); public override bool Equals(object? obj) => obj is NodeKey key && Equals(key); diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs index 7aecf87dd7d..2b7a1eca32e 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs @@ -34,6 +34,9 @@ internal class DirtyNodesCache { private readonly TrieStore _trieStore; private readonly bool _storeByHash; + private readonly ConcurrentDictionary _byKeyObjectCache; + private readonly ConcurrentDictionary _byHashObjectCache; + public readonly long KeyMemoryUsage; public DirtyNodesCache(TrieStore trieStore) @@ -42,6 +45,15 @@ public DirtyNodesCache(TrieStore trieStore) // If the nodestore indicated that path is not required, // we will use a map with hash as its key instead of the full Key to reduce memory usage. _storeByHash = !trieStore._nodeStorage.RequirePath; + int initialBuckets = HashHelpers.GetPrime(Math.Max(31, Environment.ProcessorCount * 16)); + if (_storeByHash) + { + _byHashObjectCache = new(CollectionExtensions.LockPartitions, initialBuckets); + } + else + { + _byKeyObjectCache = new(CollectionExtensions.LockPartitions, initialBuckets); + } KeyMemoryUsage = _storeByHash ? 0 : Key.MemoryUsage; // 0 because previously it was not counted. } @@ -111,11 +123,6 @@ void Trace(TrieNode trieNode) } } - private static readonly int _initialBuckets = HashHelpers.GetPrime(Math.Max(31, Environment.ProcessorCount * 16)); - - private readonly ConcurrentDictionary _byKeyObjectCache = new(CollectionExtensions.LockPartitions, _initialBuckets); - private readonly ConcurrentDictionary _byHashObjectCache = new(CollectionExtensions.LockPartitions, _initialBuckets); - public bool IsNodeCached(in Key key) { if (_storeByHash) return _byHashObjectCache.ContainsKey(key.Keccak); @@ -278,7 +285,16 @@ public readonly void Dispose() private INodeStorage.WriteBatch? _currentBatch = null; - private readonly DirtyNodesCache _dirtyNodes; + private DirtyNodesCache? _dirtyNodes; + private DirtyNodesCache DirtyNodes => _dirtyNodes ?? CreateCacheAtomic(ref _dirtyNodes); + + [MethodImpl(MethodImplOptions.NoInlining)] + private DirtyNodesCache CreateCacheAtomic(ref DirtyNodesCache val) + { + DirtyNodesCache instance = new(this); + DirtyNodesCache? prior = Interlocked.CompareExchange(ref val, instance, null); + return prior ?? instance; + } // Track some of the persisted path hash. Used to be able to remove keys when it is replaced. // If null, disable removing key. @@ -286,8 +302,9 @@ public readonly void Dispose() // Track ALL of the recently re-committed persisted nodes. This is so that we don't accidentally remove // recommitted persisted nodes (which will not get re-persisted). - private readonly ConcurrentDictionary _persistedLastSeen = new(CollectionExtensions.LockPartitions, 4 * 4096); + private readonly ConcurrentDictionary? _persistedLastSeen; + private ConcurrentDictionary? _wasPersisted; private bool _lastPersistedReachedReorgBoundary; private Task _pruningTask = Task.CompletedTask; private readonly CancellationTokenSource _pruningTaskCancellationTokenSource = new(); @@ -320,16 +337,15 @@ public TrieStore( _nodeStorage = nodeStorage ?? throw new ArgumentNullException(nameof(nodeStorage)); _pruningStrategy = pruningStrategy ?? throw new ArgumentNullException(nameof(pruningStrategy)); _persistenceStrategy = persistenceStrategy ?? throw new ArgumentNullException(nameof(persistenceStrategy)); - _dirtyNodes = new DirtyNodesCache(this); _publicStore = new TrieKeyValueStore(this); - if (pruningStrategy.TrackedPastKeyCount > 0 && nodeStorage.RequirePath) - { - _pastPathHash = new(pruningStrategy.TrackedPastKeyCount); - } - else + if (pruningStrategy.PruningEnabled) { - _pastPathHash = null; + _persistedLastSeen = new(CollectionExtensions.LockPartitions, 4 * 4096); + if (pruningStrategy.TrackedPastKeyCount > 0 && nodeStorage.RequirePath) + { + _pastPathHash = new(pruningStrategy.TrackedPastKeyCount); + } } } @@ -386,8 +402,9 @@ public int CachedNodesCount { get { - Metrics.CachedNodesCount = _dirtyNodes.Count; - return _dirtyNodes.Count; + int count = DirtyNodes.Count; + Metrics.CachedNodesCount = count; + return count; } } @@ -460,7 +477,8 @@ private TrieNode SaveOrReplaceInDirtyNodesCache(Hash256? address, NodeCommitInfo if (_pruningStrategy.PruningEnabled) { DirtyNodesCache.Key key = new DirtyNodesCache.Key(address, nodeCommitInfo.Path, node.Keccak); - if (_dirtyNodes.TryGetValue(in key, out TrieNode cachedNodeCopy)) + DirtyNodesCache cache = DirtyNodes; + if (cache.TryGetValue(in key, out TrieNode cachedNodeCopy)) { Metrics.LoadedFromCacheNodesCount++; if (!ReferenceEquals(cachedNodeCopy, node)) @@ -484,7 +502,7 @@ private TrieNode SaveOrReplaceInDirtyNodesCache(Hash256? address, NodeCommitInfo } else { - _dirtyNodes.SaveInCache(key, node); + cache.SaveInCache(key, node); } } @@ -514,7 +532,7 @@ public void FinishBlockCommit(TrieType trieType, long blockNumber, Hash256? addr { if (trieType == TrieType.State) // storage tries happen before state commits { - if (_logger.IsTrace) _logger.Trace($"Enqueued blocks {_commitSetQueue.Count}"); + if (_logger.IsTrace) _logger.Trace($"Enqueued blocks {_commitSetQueue?.Count ?? 0}"); BlockCommitSet set = CurrentPackage; if (set is not null) { @@ -545,9 +563,10 @@ public void FinishBlockCommit(TrieType trieType, long blockNumber, Hash256? addr } CurrentPackage = null; - if (_pruningStrategy.PruningEnabled && Monitor.IsEntered(_dirtyNodes)) + DirtyNodesCache cache = DirtyNodes; + if (_pruningStrategy.PruningEnabled && Monitor.IsEntered(cache)) { - Monitor.Exit(_dirtyNodes); + Monitor.Exit(cache); } } } @@ -614,7 +633,7 @@ public virtual bool IsPersisted(Hash256? address, in TreePath path, in ValueHash public IReadOnlyTrieStore AsReadOnly(INodeStorage? store) => new ReadOnlyTrieStore(this, store); - public bool IsNodeCached(Hash256? address, in TreePath path, Hash256? hash) => _dirtyNodes.IsNodeCached(new DirtyNodesCache.Key(address, path, hash)); + public bool IsNodeCached(Hash256? address, in TreePath path, Hash256? hash) => DirtyNodes.IsNodeCached(new DirtyNodesCache.Key(address, path, hash)); public virtual TrieNode FindCachedOrUnknown(Hash256? address, in TreePath path, Hash256? hash) => FindCachedOrUnknown(address, path, hash, false); @@ -634,10 +653,10 @@ internal TrieNode FindCachedOrUnknown(Hash256? address, in TreePath path, Hash25 private TrieNode FindCachedOrUnknown(DirtyNodesCache.Key key, bool isReadOnly) { - return isReadOnly ? _dirtyNodes.FromCachedRlpOrUnknown(key) : _dirtyNodes.FindCachedOrUnknown(key); + return isReadOnly ? DirtyNodes.FromCachedRlpOrUnknown(key) : DirtyNodes.FindCachedOrUnknown(key); } - public void Dump() => _dirtyNodes.Dump(); + public void Dump() => DirtyNodes.Dump(); public void Prune() { @@ -647,9 +666,10 @@ public void Prune() { try { - lock (_dirtyNodes) + DirtyNodesCache cache = DirtyNodes; + lock (cache) { - using (_dirtyNodes.AcquireMapLock()) + using (cache.AcquireMapLock()) { Stopwatch sw = Stopwatch.StartNew(); if (_logger.IsDebug) _logger.Debug($"Locked {nameof(TrieStore)} for pruning."); @@ -696,8 +716,11 @@ private bool SaveSnapshot() { if (_logger.IsDebug) _logger.Debug("Elevated pruning starting"); - using ArrayPoolList toAddBack = new(_commitSetQueue.Count); - using ArrayPoolList candidateSets = new(_commitSetQueue.Count); + int count = _commitSetQueue?.Count ?? 0; + if (count == 0) return false; + + using ArrayPoolList toAddBack = new(count); + using ArrayPoolList candidateSets = new(count); while (_commitSetQueue.TryDequeue(out BlockCommitSet frontSet)) { if (frontSet!.BlockNumber >= LatestCommittedBlockNumber - _pruningStrategy.MaxDepth) @@ -782,7 +805,7 @@ bool CanRemove(in ValueHash256 address, TinyTreePath path, in TreePath fullPath, if (currentlyPersistingKeccak == keccak) return false; // We have it in cache and it is still needed. - if (_dirtyNodes.TryGetValue(new DirtyNodesCache.Key(address, fullPath, keccak.ToCommitment()), out TrieNode node) && + if (DirtyNodes.TryGetValue(new DirtyNodesCache.Key(address, fullPath, keccak.ToCommitment()), out TrieNode node) && !IsNoLongerNeeded(node)) return false; // We don't have it in cache, but we know it was re-committed, so if it is still needed, don't remove @@ -872,14 +895,15 @@ private void PruneCache(bool skipRecalculateMemory = false, KeyValuePair pruneAndRecalculateAction = new ActionBlock(node => { node.PrunePersistedRecursively(1); - Interlocked.Add(ref newMemory, node.GetMemorySize(false) + _dirtyNodes.KeyMemoryUsage); + Interlocked.Add(ref newMemory, node.GetMemorySize(false) + cache.KeyMemoryUsage); }); - foreach ((DirtyNodesCache.Key key, TrieNode node) in (allNodes ?? _dirtyNodes.AllNodes)) + foreach ((DirtyNodesCache.Key key, TrieNode node) in (allNodes ?? cache.AllNodes)) { if (node.IsPersisted) { @@ -899,7 +923,7 @@ private void PruneCache(bool skipRecalculateMemory = false, KeyValuePair /// This method is here to support testing. ///
- public void ClearCache() => _dirtyNodes.Clear(); + public void ClearCache() => DirtyNodes.Clear(); public void Dispose() { @@ -971,8 +995,6 @@ public void WaitForPruning() _pruningTask.Wait(); } - #region Private - protected readonly INodeStorage _nodeStorage; private readonly TrieKeyValueStore _publicStore; @@ -983,7 +1005,7 @@ public void WaitForPruning() private readonly ILogger _logger; - private readonly ConcurrentQueue _commitSetQueue = new(); + private ConcurrentQueue _commitSetQueue; private long _memoryUsedByDirtyCache; @@ -1000,6 +1022,14 @@ public void WaitForPruning() private long LatestCommittedBlockNumber { get; set; } public INodeStorage.KeyScheme Scheme => _nodeStorage.Scheme; + [MethodImpl(MethodImplOptions.NoInlining)] + private static ConcurrentQueue CreateQueueAtomic(ref ConcurrentQueue val) + { + ConcurrentQueue instance = new(); + ConcurrentQueue? prior = Interlocked.CompareExchange(ref val, instance, null); + return prior ?? instance; + } + private void CreateCommitSet(long blockNumber) { if (_logger.IsDebug) _logger.Debug($"Beginning new {nameof(BlockCommitSet)} - {blockNumber}"); @@ -1009,7 +1039,7 @@ private void CreateCommitSet(long blockNumber) Debug.Assert(IsCurrentListSealed, "Not sealed when beginning new block"); BlockCommitSet commitSet = new(blockNumber); - _commitSetQueue.Enqueue(commitSet); + (_commitSetQueue ?? CreateQueueAtomic(ref _commitSetQueue)).Enqueue(commitSet); LatestCommittedBlockNumber = Math.Max(blockNumber, LatestCommittedBlockNumber); AnnounceReorgBoundaries(); DequeueOldCommitSets(); @@ -1109,6 +1139,8 @@ private bool IsNoLongerNeeded(long lastSeen) private void DequeueOldCommitSets() { + if (_commitSetQueue?.IsEmpty ?? true) return; + while (_commitSetQueue.TryPeek(out BlockCommitSet blockCommitSet)) { if (blockCommitSet.BlockNumber < LatestCommittedBlockNumber - _pruningStrategy.MaxDepth - 1) @@ -1127,9 +1159,10 @@ private void EnsureCommitSetExistsForBlock(long blockNumber) { if (CurrentPackage is null) { - if (_pruningStrategy.PruningEnabled && !Monitor.IsEntered(_dirtyNodes)) + DirtyNodesCache cache = DirtyNodes; + if (_pruningStrategy.PruningEnabled && !Monitor.IsEntered(cache)) { - Monitor.Enter(_dirtyNodes); + Monitor.Enter(cache); } CreateCommitSet(blockNumber); @@ -1180,6 +1213,7 @@ private void PersistOnShutdown() // If we are in archive mode, we don't need to change reorg boundaries. if (_pruningStrategy.PruningEnabled) { + if (_commitSetQueue?.IsEmpty ?? true) return; // here we try to shorten the number of blocks recalculated when restarting (so we force persist) // and we need to speed up the standard announcement procedure so we persists a block @@ -1218,12 +1252,8 @@ private void PersistOnShutdown() } } - #endregion - - ConcurrentDictionary? _wasPersisted; public void PersistCache(CancellationToken cancellationToken) { - if (_logger.IsInfo) _logger.Info($"Full Pruning Persist Cache started."); int commitSetCount = 0; @@ -1249,23 +1279,27 @@ void ClearCommitSetQueue() PruneCurrentSet(); } - // We persist outside of lock first. - ClearCommitSetQueue(); + if (!(_commitSetQueue?.IsEmpty ?? true)) + { + // We persist outside of lock first. + ClearCommitSetQueue(); + } if (_logger.IsInfo) _logger.Info($"Saving all commit set took {stopwatch.Elapsed} for {commitSetCount} commit sets."); stopwatch.Restart(); ConcurrentDictionary wasPersisted; - lock (_dirtyNodes) + DirtyNodesCache cache = DirtyNodes; + lock (cache) { - using (_dirtyNodes.AcquireMapLock()) + using (cache.AcquireMapLock()) { // Double check ClearCommitSetQueue(); // This should clear most nodes. For some reason, not all. PruneCache(skipRecalculateMemory: true); - KeyValuePair[] nodesCopy = _dirtyNodes.AllNodes.ToArray(); + KeyValuePair[] nodesCopy = cache.AllNodes.ToArray(); wasPersisted = Interlocked.Exchange(ref _wasPersisted, null) ?? new(CollectionExtensions.LockPartitions, nodesCopy.Length); @@ -1290,9 +1324,9 @@ void PersistNode(TrieNode n, Hash256? address, TreePath path) }); PruneCache(allNodes: nodesCopy); - if (_dirtyNodes.Count != 0) + if (cache.Count != 0) { - if (_logger.IsWarn) _logger.Warn($"{_dirtyNodes.Count} cache entry remains."); + if (_logger.IsWarn) _logger.Warn($"{cache.Count} cache entry remains."); } } } @@ -1318,7 +1352,7 @@ void PersistNode(TrieNode n, Hash256? address, TreePath path) { Hash256 asHash = new Hash256(key); return _pruningStrategy.PruningEnabled - && _dirtyNodes.TryGetValue(new DirtyNodesCache.Key(null, TreePath.Empty, asHash), out TrieNode? trieNode) + && DirtyNodes.TryGetValue(new DirtyNodesCache.Key(null, TreePath.Empty, asHash), out TrieNode? trieNode) && trieNode is not null && trieNode.NodeType != NodeType.Unknown && trieNode.FullRlp.IsNotNull From 5aebe9b0914369a51383a26ed6a235230d527b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Moraczy=C5=84ski?= Date: Wed, 11 Sep 2024 12:35:37 +0200 Subject: [PATCH 018/113] Update Supported Networks in Readme (#7412) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8827f3e6ac1..cf753b02f87 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Nethermind documentation is available at [docs.nethermind.io](https://docs.nethe ### Supported networks -**`Mainnet`** **`Goerli`** **`Sepolia`** **`Holesky`** **`Gnosis (xDai)`** **`Chiado`** **`Energy Web`** **`Volta`** +**`Mainnet`** **`Goerli`** **`Sepolia`** **`Holesky`** **`Gnosis (xDai)`** **`Chiado`** **`OP Mainnet`** **`OP Sepolia`** **`Base Mainnet`** **`Base Sepolia`** **`Energy Web`** **`Volta`** ## Download and run From 37b9fb47de99df5da4ce9e9211152a8b1d9d0451 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 11 Sep 2024 19:18:10 +0100 Subject: [PATCH 019/113] Change Windows native Allocator (#7418) --- src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj | 1 + src/Nethermind/Nethermind.Runner/app.manifest | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 src/Nethermind/Nethermind.Runner/app.manifest diff --git a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj index 15d6f745f56..e83ea3d08a3 100644 --- a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj +++ b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj @@ -17,6 +17,7 @@ Linux -v $(OutDir)/.data:/data -p 8545:8545 -p 8551:8551 -p 30303:30303 03db39d0-4200-473e-9ff8-4a48d496381f + app.manifest diff --git a/src/Nethermind/Nethermind.Runner/app.manifest b/src/Nethermind/Nethermind.Runner/app.manifest new file mode 100644 index 00000000000..d4c1cebc654 --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/app.manifest @@ -0,0 +1,8 @@ + + + + true + SegmentHeap + + + From 4a17264651e3c6326a18ab7e6764047dbd6d4cae Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 11 Sep 2024 19:18:57 +0100 Subject: [PATCH 020/113] Fast address equals (#7417) --- src/Nethermind/Nethermind.Core/Address.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Address.cs b/src/Nethermind/Nethermind.Core/Address.cs index 3cdab2947f8..ff233e8dd50 100644 --- a/src/Nethermind/Nethermind.Core/Address.cs +++ b/src/Nethermind/Nethermind.Core/Address.cs @@ -7,6 +7,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using System.Text.Json.Serialization; using Nethermind.Core.Crypto; @@ -153,7 +154,15 @@ public bool Equals(Address? other) return true; } - return Nethermind.Core.Extensions.Bytes.AreEqual(Bytes, other.Bytes); + // Address must be 20 bytes long Vector128 + uint + ref byte bytes0 = ref MemoryMarshal.GetArrayDataReference(Bytes); + ref byte bytes1 = ref MemoryMarshal.GetArrayDataReference(other.Bytes); + // Compare first 16 bytes with Vector128 and last 4 bytes with uint + return + Unsafe.As>(ref bytes0) == + Unsafe.As>(ref bytes1) && + Unsafe.As(ref Unsafe.Add(ref bytes0, Vector128.Count)) == + Unsafe.As(ref Unsafe.Add(ref bytes1, Vector128.Count)); } public static Address FromNumber(in UInt256 number) From 413a5b325806882a8b8c165d2d28852afafbcf15 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 11 Sep 2024 19:19:26 +0100 Subject: [PATCH 021/113] Reduce backlog threshold for GC (#7415) --- .../Nethermind.Consensus/Processing/BlockchainProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs index 1af54a33465..ef0cd3600b6 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs @@ -296,7 +296,7 @@ private Task RunProcessing() private void RunProcessingLoop() { - const int BlocksBacklogTriggeringManualGC = 20; + const int BlocksBacklogTriggeringManualGC = 4; const int MaxBlocksWithoutGC = 100; if (_logger.IsDebug) _logger.Debug($"Starting block processor - {_blockQueue.Count} blocks waiting in the queue."); From bb3753d959673b8a00668e9a7a4d77902a5dd9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Chodo=C5=82a?= <43241881+kamilchodola@users.noreply.github.com> Date: Wed, 11 Sep 2024 21:49:57 +0200 Subject: [PATCH 022/113] Bump unstable to 1.29.0 (#7416) --- src/Nethermind/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Directory.Build.props b/src/Nethermind/Directory.Build.props index 4d4af59cbec..86fb341f764 100644 --- a/src/Nethermind/Directory.Build.props +++ b/src/Nethermind/Directory.Build.props @@ -14,7 +14,7 @@ Demerzel Solutions Limited Nethermind $(Commit) - 1.28.0 + 1.29.0 unstable From 4373e5a46648ba65c072a672e9d6293a6713a1fd Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 12 Sep 2024 22:02:57 +0530 Subject: [PATCH 023/113] enable flashBots module --- .../Nethermind.BlockValidation/BlockValidation.cs | 5 +++++ .../Nethermind.BlockValidation/BlockValidationConfig.cs | 1 + .../Handlers/ValidateBuilderSubmissionHandler.cs | 8 +++++--- .../Nethermind.BlockValidation/IBlockValidationConfig.cs | 3 +++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs index 62a004ea45c..2610b3f758c 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Linq; using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Api.Extensions; @@ -52,6 +53,10 @@ public Task Init(INethermindApi api) _api = api; _blockValidationConfig = api.Config(); _jsonRpcConfig = api.Config(); + if(_blockValidationConfig.Enabled) + { + _jsonRpcConfig.EnabledModules = _jsonRpcConfig.EnabledModules.Append(ModuleType.Flashbots).ToArray(); + } return Task.CompletedTask; } diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs index b4c49ec3fc9..90e9cdf310b 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs @@ -7,6 +7,7 @@ namespace Nethermind.BlockValidation; public class BlockValidationConfig : IBlockValidationConfig { + public bool Enabled { get; set; } public bool UseBalanceDiffProfit { get; set; } = false; public bool ExcludeWithdrawals { get; set; } = false; diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs index c590aa346b2..78e1279495d 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.BlockValidation.Data; @@ -362,9 +363,10 @@ private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransact stateProvider, _receiptStorage, new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), - _txProcessingEnv.LogManager, - new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), - new ReceiptsRootCalculator() + beaconBlockRootHandler: new BeaconBlockRootHandler(transactionProcessor), + logManager: _txProcessingEnv.LogManager, + withdrawalProcessor: new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), + receiptsRootCalculator: new ReceiptsRootCalculator() ); } diff --git a/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs b/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs index 65106d17aa6..6afec733197 100644 --- a/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs +++ b/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs @@ -7,6 +7,9 @@ namespace Nethermind.BlockValidation; public interface IBlockValidationConfig : IConfig { + [ConfigItem(Description = "Whether to enable the Flashbots endpoints.", DefaultValue = "false")] + bool Enabled { get; set; } + [ConfigItem(Description = "If set to true, proposer payment is calculated as a balance difference of the fee recipient", DefaultValue = "false")] public bool UseBalanceDiffProfit { get; set; } From a73b41ae911e0fdb035152855b5c4472f670adf2 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 12 Sep 2024 22:08:36 +0530 Subject: [PATCH 024/113] format files --- src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs | 4 ++-- .../Modules/Flashbots/FlashbotsRpcModuleFactory.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs index 2610b3f758c..c925ba74fb8 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs +++ b/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs @@ -38,7 +38,7 @@ public Task InitRpcModules() readOnlyTxProcessingEnv, _blockValidationConfig ); - + ModuleFactoryBase flashbotsRpcModule = new FlashbotsRpcModuleFactory(validateSubmissionHandler); ArgumentNullException.ThrowIfNull(_api.RpcModuleProvider); @@ -53,7 +53,7 @@ public Task Init(INethermindApi api) _api = api; _blockValidationConfig = api.Config(); _jsonRpcConfig = api.Config(); - if(_blockValidationConfig.Enabled) + if (_blockValidationConfig.Enabled) { _jsonRpcConfig.EnabledModules = _jsonRpcConfig.EnabledModules.Append(ModuleType.Flashbots).ToArray(); } diff --git a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs index 9ccdc70a731..ad1b9338302 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs +++ b/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs @@ -9,7 +9,7 @@ namespace Nethermind.BlockValidation.Modules.Flashbots { public class FlashbotsRpcModuleFactory( ValidateSubmissionHandler validateSubmissionHandler - ): ModuleFactoryBase + ) : ModuleFactoryBase { private readonly ValidateSubmissionHandler _validateSubmissionHandler = validateSubmissionHandler ?? throw new ArgumentNullException(nameof(validateSubmissionHandler)); From 71e03ebaef26ed7233b953ed92ea9fec207a629f Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 13 Sep 2024 12:52:59 +0530 Subject: [PATCH 025/113] rename blockValidation -> flashbots --- .../Nethermind.Api/Extensions/PluginConfig.cs | 2 +- .../Data/BidTrace.cs | 2 +- .../Data/BlockValidationResult.cs | 22 +++++++++---------- .../Data/BlockValidationStatus.cs | 4 ++-- .../Data/BuilderBlockValidationRequest.cs | 4 ++-- .../Data/SubmitBlockRequest.cs | 2 +- .../Flashbots.cs} | 20 ++++++++--------- .../FlashbotsConfig.cs} | 4 ++-- .../ValidateBuilderSubmissionHandler.cs | 22 +++++++++---------- .../IFlashbotsConfig.cs} | 4 ++-- .../Modules/Flashbots/FlashbotsRpcModule.cs | 8 +++---- .../Flashbots/FlashbotsRpcModuleFactory.cs | 4 ++-- .../Modules/Flashbots/IFlashbotsRpcModule.cs | 6 ++--- .../Nethermind.Flashbots.csproj} | 2 +- .../Nethermind.Runner.csproj | 10 ++++----- .../Nethermind.Runner/configs/holesky.cfg | 5 ++++- src/Nethermind/Nethermind.sln | 2 +- 17 files changed, 63 insertions(+), 60 deletions(-) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Data/BidTrace.cs (92%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Data/BlockValidationResult.cs (51%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Data/BlockValidationStatus.cs (80%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Data/BuilderBlockValidationRequest.cs (86%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Data/SubmitBlockRequest.cs (94%) rename src/Nethermind/{Nethermind.BlockValidation/BlockValidation.cs => Nethermind.Flashbots/Flashbots.cs} (78%) rename src/Nethermind/{Nethermind.BlockValidation/BlockValidationConfig.cs => Nethermind.Flashbots/FlashbotsConfig.cs} (74%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Handlers/ValidateBuilderSubmissionHandler.cs (94%) rename src/Nethermind/{Nethermind.BlockValidation/IBlockValidationConfig.cs => Nethermind.Flashbots/IFlashbotsConfig.cs} (88%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Modules/Flashbots/FlashbotsRpcModule.cs (64%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Modules/Flashbots/FlashbotsRpcModuleFactory.cs (86%) rename src/Nethermind/{Nethermind.BlockValidation => Nethermind.Flashbots}/Modules/Flashbots/IFlashbotsRpcModule.cs (66%) rename src/Nethermind/{Nethermind.BlockValidation/Nethermind.BlockValidation.csproj => Nethermind.Flashbots/Nethermind.Flashbots.csproj} (79%) diff --git a/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs b/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs index 7e00a7f8f6f..d5812a3adba 100644 --- a/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs +++ b/src/Nethermind/Nethermind.Api/Extensions/PluginConfig.cs @@ -5,5 +5,5 @@ namespace Nethermind.Api.Extensions; public class PluginConfig : IPluginConfig { - public string[] PluginOrder { get; set; } = { "Clique", "Aura", "Ethash", "Optimism", "AuRaMerge", "Merge", "BlockValidation", "MEV", "HealthChecks", "Hive" }; + public string[] PluginOrder { get; set; } = { "Clique", "Aura", "Ethash", "Optimism", "AuRaMerge", "Merge", "Flashbots", "MEV", "HealthChecks", "Hive" }; } diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs similarity index 92% rename from src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs rename to src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs index 37f38520119..25e44f13ef1 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BidTrace.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs @@ -5,7 +5,7 @@ using Nethermind.Core.Crypto; using Nethermind.Int256; -namespace Nethermind.BlockValidation.Data; +namespace Nethermind.Flashbots.Data; public readonly struct BidTrace { diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationResult.cs b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs similarity index 51% rename from src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationResult.cs rename to src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs index cb30aef279e..1a0eae8d723 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationResult.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs @@ -4,40 +4,40 @@ using System.Text.Json.Serialization; using Nethermind.JsonRpc; -namespace Nethermind.BlockValidation.Data; +namespace Nethermind.Flashbots.Data; /// /// Represents the result of a block validation. /// -public class BlockValidationResult +public class FlashbotsResult { - public static ResultWrapper Invalid(string error) + public static ResultWrapper Invalid(string error) { - return ResultWrapper.Success(new BlockValidationResult + return ResultWrapper.Success(new FlashbotsResult { - Status = BlockValidationStatus.Invalid, + Status = FlashbotsStatus.Invalid, ValidationError = error }); } - public static ResultWrapper Valid() + public static ResultWrapper Valid() { - return ResultWrapper.Success(new BlockValidationResult + return ResultWrapper.Success(new FlashbotsResult { - Status = BlockValidationStatus.Valid + Status = FlashbotsStatus.Valid }); } - public static ResultWrapper Error(string error) + public static ResultWrapper Error(string error) { - return ResultWrapper.Fail(error); + return ResultWrapper.Fail(error); } /// /// The status of the validation of the builder submissions /// - public string Status { get; set; } = BlockValidationStatus.Invalid; + public string Status { get; set; } = FlashbotsStatus.Invalid; /// /// Message providing additional details on the validation error if the payload is classified as . diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationStatus.cs similarity index 80% rename from src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs rename to src/Nethermind/Nethermind.Flashbots/Data/BlockValidationStatus.cs index 1788c2991b3..bb74faebb00 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BlockValidationStatus.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationStatus.cs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -namespace Nethermind.BlockValidation.Data; +namespace Nethermind.Flashbots.Data; -public static class BlockValidationStatus +public static class FlashbotsStatus { /// /// The submissions are invalid. diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs similarity index 86% rename from src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs rename to src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index c4bb08457e5..99a15095908 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -3,9 +3,9 @@ using Nethermind.Core.Crypto; -namespace Nethermind.BlockValidation.Data; +namespace Nethermind.Flashbots.Data; -public class BuilderBlockValidationRequest +public class BuilderFlashbotsRequest { /// /// The block hash of the parent beacon block. diff --git a/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs similarity index 94% rename from src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs rename to src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs index e22e5696933..b0426ab7a30 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Data/SubmitBlockRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs @@ -4,7 +4,7 @@ using Nethermind.Core.Crypto; using Nethermind.Merge.Plugin.Data; -namespace Nethermind.BlockValidation.Data; +namespace Nethermind.Flashbots.Data; public readonly struct SubmitBlockRequest { diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs similarity index 78% rename from src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs rename to src/Nethermind/Nethermind.Flashbots/Flashbots.cs index c925ba74fb8..958e0161256 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidation.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -6,24 +6,24 @@ using System.Threading.Tasks; using Nethermind.Api; using Nethermind.Api.Extensions; -using Nethermind.BlockValidation.Handlers; -using Nethermind.BlockValidation.Modules.Flashbots; +using Nethermind.Flashbots.Handlers; +using Nethermind.Flashbots.Modules.Flashbots; using Nethermind.Consensus.Processing; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; -namespace Nethermind.BlockValidation; +namespace Nethermind.Flashbots; -public class BlockValidation : INethermindPlugin +public class Flashbots : INethermindPlugin { private INethermindApi _api = null!; - private IBlockValidationConfig _blockValidationConfig = null!; + private IFlashbotsConfig _flashbotsConfig = null!; private IJsonRpcConfig _jsonRpcConfig = null!; - public virtual string Name => "BlockValidation"; - public virtual string Description => "BlockValidation"; + public virtual string Name => "Flashbots"; + public virtual string Description => "Flashbots"; public string Author => "Nethermind"; public Task InitRpcModules() { @@ -36,7 +36,7 @@ public Task InitRpcModules() ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), readOnlyTxProcessingEnv, - _blockValidationConfig + _flashbotsConfig ); ModuleFactoryBase flashbotsRpcModule = new FlashbotsRpcModuleFactory(validateSubmissionHandler); @@ -51,9 +51,9 @@ public Task InitRpcModules() public Task Init(INethermindApi api) { _api = api; - _blockValidationConfig = api.Config(); + _flashbotsConfig = api.Config(); _jsonRpcConfig = api.Config(); - if (_blockValidationConfig.Enabled) + if (_flashbotsConfig.Enabled) { _jsonRpcConfig.EnabledModules = _jsonRpcConfig.EnabledModules.Append(ModuleType.Flashbots).ToArray(); } diff --git a/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs similarity index 74% rename from src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs rename to src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs index 90e9cdf310b..be96b14b53b 100644 --- a/src/Nethermind/Nethermind.BlockValidation/BlockValidationConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs @@ -3,9 +3,9 @@ using Nethermind.Config; -namespace Nethermind.BlockValidation; +namespace Nethermind.Flashbots; -public class BlockValidationConfig : IBlockValidationConfig +public class FlashbotsConfig : IFlashbotsConfig { public bool Enabled { get; set; } public bool UseBalanceDiffProfit { get; set; } = false; diff --git a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs similarity index 94% rename from src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs rename to src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 78e1279495d..a57b31b1baa 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -9,7 +9,7 @@ using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; -using Nethermind.BlockValidation.Data; +using Nethermind.Flashbots.Data; using Nethermind.Consensus; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Validators; @@ -26,7 +26,7 @@ using Nethermind.Merge.Plugin.Data; using Nethermind.State; -namespace Nethermind.BlockValidation.Handlers; +namespace Nethermind.Flashbots.Handlers; public class ValidateSubmissionHandler { @@ -39,23 +39,23 @@ public class ValidateSubmissionHandler private readonly IBlockValidator _blockValidator; private readonly ILogger _logger; - private readonly IBlockValidationConfig _blockValidationConfig; + private readonly IFlashbotsConfig _flashbotsConfig; private readonly IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); public ValidateSubmissionHandler( IBlockValidator blockValidator, ReadOnlyTxProcessingEnv txProcessingEnv, - IBlockValidationConfig blockValidationConfig) + IFlashbotsConfig flashbotsConfig) { _blockValidator = blockValidator; _txProcessingEnv = txProcessingEnv; _blockTree = _txProcessingEnv.BlockTree; _logger = txProcessingEnv.LogManager!.GetClassLogger(); - _blockValidationConfig = blockValidationConfig; + _flashbotsConfig = flashbotsConfig; } - public Task> ValidateSubmission(BuilderBlockValidationRequest request) + public Task> ValidateSubmission(BuilderFlashbotsRequest request) { ExecutionPayload payload = request.BlockRequest.ExecutionPayload; BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; @@ -67,23 +67,23 @@ public Task> ValidateSubmission(BuilderBloc if (!payload.TryGetBlock(out Block? block)) { if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}."); - return BlockValidationResult.Invalid($"Block {payload} coud not be parsed as a block"); + return FlashbotsResult.Invalid($"Block {payload} coud not be parsed as a block"); } if (block is not null && !ValidateBlock(block, request.BlockRequest.Message, request.RegisterGasLimit, out string? error)) { if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}. Error: {error}"); - return BlockValidationResult.Invalid(error ?? "Block validation failed"); + return FlashbotsResult.Invalid(error ?? "Block validation failed"); } if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) { if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); - return BlockValidationResult.Invalid(blobsError ?? "Blobs bundle validation failed"); + return FlashbotsResult.Invalid(blobsError ?? "Blobs bundle validation failed"); } - return BlockValidationResult.Valid(); + return FlashbotsResult.Valid(); } private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, out string? error) @@ -117,7 +117,7 @@ private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, Address feeRecipient = message.ProposerFeeRecipient; UInt256 expectedProfit = message.Value; - if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, _blockValidationConfig.UseBalanceDiffProfit, _blockValidationConfig.ExcludeWithdrawals, out error)) + if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, _flashbotsConfig.UseBalanceDiffProfit, _flashbotsConfig.ExcludeWithdrawals, out error)) { return false; } diff --git a/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs similarity index 88% rename from src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs rename to src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs index 6afec733197..35fc68cd00c 100644 --- a/src/Nethermind/Nethermind.BlockValidation/IBlockValidationConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs @@ -3,9 +3,9 @@ using Nethermind.Config; -namespace Nethermind.BlockValidation; +namespace Nethermind.Flashbots; -public interface IBlockValidationConfig : IConfig +public interface IFlashbotsConfig : IConfig { [ConfigItem(Description = "Whether to enable the Flashbots endpoints.", DefaultValue = "false")] bool Enabled { get; set; } diff --git a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs similarity index 64% rename from src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModule.cs rename to src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs index 9f2b58b36ea..ba6a711e157 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs @@ -2,11 +2,11 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; -using Nethermind.BlockValidation.Data; -using Nethermind.BlockValidation.Handlers; +using Nethermind.Flashbots.Data; +using Nethermind.Flashbots.Handlers; using Nethermind.JsonRpc; -namespace Nethermind.BlockValidation.Modules.Flashbots; +namespace Nethermind.Flashbots.Modules.Flashbots; public class FlashbotsRpcModule : IFlashbotsRpcModule { @@ -17,7 +17,7 @@ public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) _validateSubmissionHandler = validateSubmissionHandler; } - Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => + Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderFlashbotsRequest @params) => _validateSubmissionHandler.ValidateSubmission(@params); } diff --git a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModuleFactory.cs similarity index 86% rename from src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs rename to src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModuleFactory.cs index ad1b9338302..5f9b9d918c5 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/FlashbotsRpcModuleFactory.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModuleFactory.cs @@ -2,10 +2,10 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using Nethermind.BlockValidation.Handlers; +using Nethermind.Flashbots.Handlers; using Nethermind.JsonRpc.Modules; -namespace Nethermind.BlockValidation.Modules.Flashbots +namespace Nethermind.Flashbots.Modules.Flashbots { public class FlashbotsRpcModuleFactory( ValidateSubmissionHandler validateSubmissionHandler diff --git a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs similarity index 66% rename from src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/IFlashbotsRpcModule.cs rename to src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs index 6abe67edbcf..6eed82a8293 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Modules/Flashbots/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -2,11 +2,11 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; -using Nethermind.BlockValidation.Data; +using Nethermind.Flashbots.Data; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; -namespace Nethermind.BlockValidation.Modules.Flashbots; +namespace Nethermind.Flashbots.Modules.Flashbots; [RpcModule(ModuleType.Flashbots)] public interface IFlashbotsRpcModule : IRpcModule @@ -15,5 +15,5 @@ public interface IFlashbotsRpcModule : IRpcModule Description = " validate the builder submissions as received by a relay", IsSharable = false, IsImplemented = true)] - Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); + Task> flashbots_validateBuilderSubmissionV3(BuilderFlashbotsRequest @params); } diff --git a/src/Nethermind/Nethermind.BlockValidation/Nethermind.BlockValidation.csproj b/src/Nethermind/Nethermind.Flashbots/Nethermind.Flashbots.csproj similarity index 79% rename from src/Nethermind/Nethermind.BlockValidation/Nethermind.BlockValidation.csproj rename to src/Nethermind/Nethermind.Flashbots/Nethermind.Flashbots.csproj index 11efa636a6d..22a6d0fedd8 100644 --- a/src/Nethermind/Nethermind.BlockValidation/Nethermind.BlockValidation.csproj +++ b/src/Nethermind/Nethermind.Flashbots/Nethermind.Flashbots.csproj @@ -1,7 +1,7 @@ - Nethermind.BlockValidation + Nethermind.Flashbots enable diff --git a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj index e83ea3d08a3..f180a1aae50 100644 --- a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj +++ b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj @@ -34,7 +34,7 @@ - + @@ -91,11 +91,11 @@ - - + + - - + + diff --git a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg index c662bd62c59..36e42c361eb 100644 --- a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg @@ -26,9 +26,12 @@ "Port": 8545, "EngineHost": "127.0.0.1", "EnginePort": 8551, - "EngineEnabledModules": "net,eth,subscribe,engine,web3,client" + "EngineEnabledModules": "net,eth,subscribe,engine,web3,client,flashbots" }, "Merge": { "Enabled": true + }, + "BlockValidation": { + "Enabled": true } } diff --git a/src/Nethermind/Nethermind.sln b/src/Nethermind/Nethermind.sln index bd3a5c58c8f..368dcb71d4b 100644 --- a/src/Nethermind/Nethermind.sln +++ b/src/Nethermind/Nethermind.sln @@ -218,7 +218,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Signer", "Signer", "{89311B EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.ExternalSigner.Plugin", "Nethermind.ExternalSigner.Plugin\Nethermind.ExternalSigner.Plugin.csproj", "{6528010D-7DCE-4935-9785-5270FF515F3E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.BlockValidation", "Nethermind.BlockValidation\Nethermind.BlockValidation.csproj", "{580DB104-AE89-444F-BD99-7FE0C84C615C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flashbots", "Nethermind.Flashbots\Nethermind.Flashbots.csproj", "{580DB104-AE89-444F-BD99-7FE0C84C615C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 9f1bf8549799bb11c4aa8e93284505f99826ccc0 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 13 Sep 2024 13:03:10 +0530 Subject: [PATCH 026/113] rename params --- .../Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs | 2 +- .../Handlers/ValidateBuilderSubmissionHandler.cs | 2 +- .../Modules/Flashbots/FlashbotsRpcModule.cs | 2 +- .../Modules/Flashbots/IFlashbotsRpcModule.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 99a15095908..836226b232f 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -5,7 +5,7 @@ namespace Nethermind.Flashbots.Data; -public class BuilderFlashbotsRequest +public class BuilderBlockValidationRequest { /// /// The block hash of the parent beacon block. diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index a57b31b1baa..fe74935cca9 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -55,7 +55,7 @@ public ValidateSubmissionHandler( _flashbotsConfig = flashbotsConfig; } - public Task> ValidateSubmission(BuilderFlashbotsRequest request) + public Task> ValidateSubmission(BuilderBlockValidationRequest request) { ExecutionPayload payload = request.BlockRequest.ExecutionPayload; BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs index ba6a711e157..066bf8fd642 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs @@ -17,7 +17,7 @@ public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) _validateSubmissionHandler = validateSubmissionHandler; } - Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderFlashbotsRequest @params) => + Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => _validateSubmissionHandler.ValidateSubmission(@params); } diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs index 6eed82a8293..b81da13fb39 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -15,5 +15,5 @@ public interface IFlashbotsRpcModule : IRpcModule Description = " validate the builder submissions as received by a relay", IsSharable = false, IsImplemented = true)] - Task> flashbots_validateBuilderSubmissionV3(BuilderFlashbotsRequest @params); + Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); } From d203d5e1dc41d47c572e48665f9f9e52a57e6f8a Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 13 Sep 2024 13:05:59 +0530 Subject: [PATCH 027/113] revert holesky.cfg --- src/Nethermind/Nethermind.Runner/configs/holesky.cfg | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg index 36e42c361eb..c662bd62c59 100644 --- a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg @@ -26,12 +26,9 @@ "Port": 8545, "EngineHost": "127.0.0.1", "EnginePort": 8551, - "EngineEnabledModules": "net,eth,subscribe,engine,web3,client,flashbots" + "EngineEnabledModules": "net,eth,subscribe,engine,web3,client" }, "Merge": { "Enabled": true - }, - "BlockValidation": { - "Enabled": true } } From 1d7c27260fcbb3cf07d2270dfb75f17c007b0c0a Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 19 Sep 2024 12:20:40 +0530 Subject: [PATCH 028/113] add json required --- .../Data/BuilderBlockValidationRequest.cs | 6 +++++- src/Nethermind/Nethermind.Runner/configs/holesky.cfg | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 836226b232f..428c9689f9d 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Text.Json.Serialization; using Nethermind.Core.Crypto; namespace Nethermind.Flashbots.Data; @@ -11,9 +12,12 @@ public class BuilderBlockValidationRequest /// The block hash of the parent beacon block. /// /// - public Hash256 ParentBeaconBlockRoot { get; set; } = Keccak.Zero; + [JsonRequired] + public required Hash256 ParentBeaconBlockRoot { get; set; } + [JsonRequired] public long RegisterGasLimit { get; set; } + [JsonRequired] public SubmitBlockRequest BlockRequest { get; set; } } diff --git a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg index c662bd62c59..36e42c361eb 100644 --- a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg @@ -26,9 +26,12 @@ "Port": 8545, "EngineHost": "127.0.0.1", "EnginePort": 8551, - "EngineEnabledModules": "net,eth,subscribe,engine,web3,client" + "EngineEnabledModules": "net,eth,subscribe,engine,web3,client,flashbots" }, "Merge": { "Enabled": true + }, + "BlockValidation": { + "Enabled": true } } From 0c15eea5111818a6c7b0f30825ea7ee66335ce88 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 23 Sep 2024 17:18:55 +0530 Subject: [PATCH 029/113] fix parameter serialization --- .../Nethermind.Flashbots/Data/BidTrace.cs | 28 ++++++++++++------- .../Data/BuilderBlockValidationRequest.cs | 3 +- .../Data/SubmitBlockRequest.cs | 6 ++-- .../Data/BlobsBundleV1.cs | 9 ++++++ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs index 25e44f13ef1..8fddcb0d205 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs @@ -7,15 +7,23 @@ namespace Nethermind.Flashbots.Data; -public readonly struct BidTrace +public class BidTrace( + ulong slot, + Hash256 blockHash, + PublicKey builderPublicKey, + PublicKey proposerPublicKey, + Address proposerFeeRecipient, + long gasLimit, + long gasUsed, + UInt256 value) { - public ulong Slot { get; } - public Hash256 ParentHash { get; } - public Hash256 BlockHash { get; } - public PublicKey BuilderPublicKey { get; } - public PublicKey ProposerPublicKey { get; } - public Address ProposerFeeRecipient { get; } - public long GasLimit { get; } - public long GasUsed { get; } - public UInt256 Value { get; } + public ulong Slot { get; } = slot; + public required Hash256 ParentHash { get; set; } + public Hash256 BlockHash { get; } = blockHash; + public PublicKey BuilderPublicKey { get; } = builderPublicKey; + public PublicKey ProposerPublicKey { get; } = proposerPublicKey; + public Address ProposerFeeRecipient { get; } = proposerFeeRecipient; + public long GasLimit { get; } = gasLimit; + public long GasUsed { get; } = gasUsed; + public UInt256 Value { get; } = value; } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 428c9689f9d..c0b904693ea 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -3,6 +3,7 @@ using System.Text.Json.Serialization; using Nethermind.Core.Crypto; +using Nethermind.JsonRpc; namespace Nethermind.Flashbots.Data; @@ -19,5 +20,5 @@ public class BuilderBlockValidationRequest public long RegisterGasLimit { get; set; } [JsonRequired] - public SubmitBlockRequest BlockRequest { get; set; } + public required SubmitBlockRequest BlockRequest { get; set; } } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs index b0426ab7a30..60863f294c3 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs @@ -6,7 +6,7 @@ namespace Nethermind.Flashbots.Data; -public readonly struct SubmitBlockRequest +public class SubmitBlockRequest { private readonly ExecutionPayload _executionPayload; private readonly BlobsBundleV1 _blobsBundle; @@ -17,7 +17,7 @@ public SubmitBlockRequest(ExecutionPayload executionPayload, BlobsBundleV1 blobs _blobsBundle = blobsBundle; Message = message; } - public readonly ExecutionPayload ExecutionPayload => _executionPayload; - public readonly BlobsBundleV1 BlobsBundle => _blobsBundle; + public ExecutionPayload ExecutionPayload => _executionPayload; + public BlobsBundleV1 BlobsBundle => _blobsBundle; public BidTrace Message { get; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/BlobsBundleV1.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/BlobsBundleV1.cs index 8d350a98e04..4aeefd3d845 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/BlobsBundleV1.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/BlobsBundleV1.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Text.Json.Serialization; using Nethermind.Core; namespace Nethermind.Merge.Plugin.Data; @@ -49,6 +50,14 @@ public BlobsBundleV1(Block block) } } + [JsonConstructor] + public BlobsBundleV1(byte[][] commitments, byte[][] blobs, byte[][] proofs) + { + Commitments = commitments; + Blobs = blobs; + Proofs = proofs; + } + public byte[][] Commitments { get; } public byte[][] Blobs { get; } public byte[][] Proofs { get; } From 4eeeb9fce2a66ab3e8f16ccc2f6b18d02fb9478d Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 26 Sep 2024 18:55:40 +0530 Subject: [PATCH 030/113] Add initial tests --- .github/workflows/nethermind-tests.yml | 1 + .../FlashbotsModuleTests.Setup.cs | 170 ++++++++++++++++++ .../FlashbotsModuleTests.cs | 32 ++++ .../Nethermind.Flasbots.Test.csproj | 31 ++++ .../Nethermind.Flashbots/Flashbots.cs | 1 + .../ValidateBuilderSubmissionHandler.cs | 8 +- src/Nethermind/Nethermind.sln | 6 + 7 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs create mode 100644 src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs create mode 100644 src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj diff --git a/.github/workflows/nethermind-tests.yml b/.github/workflows/nethermind-tests.yml index b95d724b9ed..78daa78bb44 100644 --- a/.github/workflows/nethermind-tests.yml +++ b/.github/workflows/nethermind-tests.yml @@ -46,6 +46,7 @@ jobs: - Nethermind.EthStats.Test - Nethermind.Evm.Test - Nethermind.Facade.Test + - Nethermind.Flashbots.Test - Nethermind.HealthChecks.Test - Nethermind.Hive.Test - Nethermind.JsonRpc.Test diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs new file mode 100644 index 00000000000..6e7cb834b31 --- /dev/null +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -0,0 +1,170 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Threading.Tasks; +using Nethermind.Blockchain.BeaconBlockRoot; +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Synchronization; +using Nethermind.Consensus; +using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Rewards; +using Nethermind.Consensus.Validators; +using Nethermind.Consensus.Withdrawals; +using Nethermind.Core; +using Nethermind.Core.Extensions; +using Nethermind.Core.Specs; +using Nethermind.Core.Test.Blockchain; +using Nethermind.Crypto; +using Nethermind.Db; +using Nethermind.Flashbots; +using Nethermind.Flashbots.Handlers; +using Nethermind.Flashbots.Modules.Flashbots; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.Merge.Plugin; +using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Specs.Forks; +using NUnit.Framework; + +namespace Nethermind.Flasbots.Test; + +public partial class FlashbotsModuleTests +{ + TestKeyAndAddress? TestKeysAndAddress; + + [SetUp] + public void SetUp(){ + TestKeysAndAddress = new TestKeyAndAddress(); + } + + internal class TestKeyAndAddress + { + public PrivateKey privateKey = new PrivateKey("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"); + public Address TestAddr; + + public PrivateKey TestValidatorKey = new PrivateKey("28c3cd61b687fdd03488e167a5d84f50269df2a4c29a2cfb1390903aa775c5d0"); + public Address TestValidatorAddr; + + public PrivateKey TestBuilderKey = new PrivateKey("0bfbbbc68fefd990e61ba645efb84e0a62e94d5fff02c9b1da8eb45fea32b4e0"); + public Address TestBuilderAddr; + + public UInt256 TestBalance = UInt256.Parse("2000000000000000000"); + public byte[] logCode = Bytes.FromHexString("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00"); + public TestKeyAndAddress() + { + TestAddr = privateKey.Address; + TestValidatorAddr = TestValidatorKey.Address; + TestBuilderAddr = TestBuilderKey.Address; + } + } + + protected virtual MergeTestBlockChain CreateBaseBlockChain( + IFlashbotsConfig flashbotsConfig, + ILogManager? logManager = null) + { + return new MergeTestBlockChain(flashbotsConfig, logManager); + } + + protected async Task CreateBlockChain( + IReleaseSpec? releaseSpec = null, + IFlashbotsConfig? flashbotsConfig = null, + ILogManager? logManager = null) + => await CreateBaseBlockChain(flashbotsConfig ?? new FlashbotsConfig(), logManager).Build(new TestSingleReleaseSpecProvider(releaseSpec ?? London.Instance)); + + private IFlashbotsRpcModule CreateFlashbotsModule(MergeTestBlockChain chain, ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv) + { + return new FlashbotsRpcModule( + new ValidateSubmissionHandler( + chain.HeaderValidator, + chain.BlockValidator, + readOnlyTxProcessingEnv, + chain.FlashbotsConfig + ) + ); + } + + public class MergeTestBlockChain : TestBlockchain + { + public IFlashbotsConfig FlashbotsConfig; + + public IMergeConfig MergeConfig; + + public IWithdrawalProcessor? WithdrawalProcessor { get; set; } + + public ReadOnlyTxProcessingEnv ReadOnlyTxProcessingEnv { get; set; } + + public MergeTestBlockChain(IFlashbotsConfig flashbotsConfig, ILogManager? logManager = null) + { + FlashbotsConfig = flashbotsConfig; + MergeConfig = new MergeConfig() { TerminalTotalDifficulty = "0" }; + LogManager = logManager ?? LogManager; + } + + public sealed override ILogManager LogManager { get; set; } = LimboLogs.Instance; + + public ReadOnlyTxProcessingEnv CreateReadOnlyTxProcessingEnv() + { + ReadOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv( + WorldStateManager, + BlockTree, + SpecProvider, + LogManager + ); + return ReadOnlyTxProcessingEnv; + } + + protected override IBlockProcessor CreateBlockProcessor() + { + BlockValidator = CreateBlockValidator(); + WithdrawalProcessor = new WithdrawalProcessor(State, LogManager); + IBlockProcessor prcessor = new BlockProcessor( + SpecProvider, + BlockValidator, + NoBlockRewards.Instance, + new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State), + State, + ReceiptStorage, + TxProcessor, + new BeaconBlockRootHandler(TxProcessor), + new BlockhashStore(SpecProvider, State), + LogManager, + WithdrawalProcessor + ); + + return prcessor; + } + + protected IBlockValidator CreateBlockValidator() + { + PoSSwitcher = new PoSSwitcher(MergeConfig, SyncConfig.Default, new MemDb(), BlockTree, SpecProvider, new ChainSpec() { Genesis = Core.Test.Builders.Build.A.Block.WithDifficulty(0).TestObject }, LogManager); + ISealValidator SealValidator = new MergeSealValidator(PoSSwitcher, Always.Valid); + HeaderValidator = new MergeHeaderValidator( + PoSSwitcher, + new HeaderValidator(BlockTree, SealValidator, SpecProvider, LogManager), + BlockTree, + SpecProvider, + SealValidator, + LogManager + ); + + return new BlockValidator( + new TxValidator(SpecProvider.ChainId), + HeaderValidator, + Always.Valid, + SpecProvider, + LogManager + ); + } + + protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) + { + TestBlockchain chain = await base.Build(specProvider, initialValues); + return chain; + } + + public async Task Build(ISpecProvider? specProvider = null) => + (MergeTestBlockChain)await Build(specProvider, null); + + } +} diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs new file mode 100644 index 00000000000..d216de14bcd --- /dev/null +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Threading.Tasks; +using Nethermind.Consensus.Processing; +using Nethermind.Core; +using Nethermind.Core.Extensions; +using Nethermind.Crypto; +using Nethermind.Flashbots.Modules.Flashbots; +using Nethermind.Int256; +using Nethermind.State; + +namespace Nethermind.Flasbots.Test; + +public partial class FlashbotsModuleTests +{ + + public async Task TestValidateBuilderSubmissionV3 () + { + using MergeTestBlockChain chain = await CreateBlockChain(); + ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = chain.CreateReadOnlyTxProcessingEnv(); + IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnv); + BlockHeader currentHeader = chain.BlockTree.Head.Header; + IWorldState State = chain.State; + + UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); + + Transaction tx1 = new Transaction( + + ); + } +} diff --git a/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj b/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj new file mode 100644 index 00000000000..038d62c896f --- /dev/null +++ b/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj @@ -0,0 +1,31 @@ + + + + annotations + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index 958e0161256..0e48060c718 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -34,6 +34,7 @@ public Task InitRpcModules() _api.LogManager ); ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( + _api.HeaderValidator?? throw new ArgumentNullException(nameof(_api.HeaderValidator)), _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), readOnlyTxProcessingEnv, _flashbotsConfig diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index fe74935cca9..1b6846c5e6c 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -36,6 +36,7 @@ public class ValidateSubmissionHandler private readonly ReadOnlyTxProcessingEnv _txProcessingEnv; private readonly IBlockTree _blockTree; + private readonly IHeaderValidator _headerValidator; private readonly IBlockValidator _blockValidator; private readonly ILogger _logger; @@ -44,10 +45,12 @@ public class ValidateSubmissionHandler private readonly IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); public ValidateSubmissionHandler( + IHeaderValidator headerValidator, IBlockValidator blockValidator, ReadOnlyTxProcessingEnv txProcessingEnv, IFlashbotsConfig flashbotsConfig) { + _headerValidator = headerValidator; _blockValidator = blockValidator; _txProcessingEnv = txProcessingEnv; _blockTree = _txProcessingEnv.BlockTree; @@ -234,7 +237,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHeader parentHeader, out string? error) { - if (!HeaderValidator.ValidateHash(block.Header)) + if (!_headerValidator.Validate(block.Header)) { error = $"Invalid block header hash {block.Header.Hash}"; return false; @@ -362,8 +365,9 @@ private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransact new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), stateProvider, _receiptStorage, + transactionProcessor, + new BeaconBlockRootHandler(transactionProcessor), new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), - beaconBlockRootHandler: new BeaconBlockRootHandler(transactionProcessor), logManager: _txProcessingEnv.LogManager, withdrawalProcessor: new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), receiptsRootCalculator: new ReceiptsRootCalculator() diff --git a/src/Nethermind/Nethermind.sln b/src/Nethermind/Nethermind.sln index 368dcb71d4b..a39a33f3156 100644 --- a/src/Nethermind/Nethermind.sln +++ b/src/Nethermind/Nethermind.sln @@ -220,6 +220,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.ExternalSigner.P EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flashbots", "Nethermind.Flashbots\Nethermind.Flashbots.csproj", "{580DB104-AE89-444F-BD99-7FE0C84C615C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flasbots.Test", "Nethermind.Flashbots.Test\Nethermind.Flasbots.Test.csproj", "{370C4088-0DB9-401A-872F-E72E3272AB54}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -606,6 +608,10 @@ Global {580DB104-AE89-444F-BD99-7FE0C84C615C}.Debug|Any CPU.Build.0 = Debug|Any CPU {580DB104-AE89-444F-BD99-7FE0C84C615C}.Release|Any CPU.ActiveCfg = Release|Any CPU {580DB104-AE89-444F-BD99-7FE0C84C615C}.Release|Any CPU.Build.0 = Release|Any CPU + {370C4088-0DB9-401A-872F-E72E3272AB54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {370C4088-0DB9-401A-872F-E72E3272AB54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {370C4088-0DB9-401A-872F-E72E3272AB54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {370C4088-0DB9-401A-872F-E72E3272AB54}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 3bbce1fcbfeeeca8c3beb5e7faab18b496198d3d Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 10 Oct 2024 15:21:15 +0530 Subject: [PATCH 031/113] format files --- .../FlashbotsModuleTests.Setup.cs | 9 +++++---- .../Nethermind.Flashbots.Test/FlashbotsModuleTests.cs | 6 +++--- src/Nethermind/Nethermind.Flashbots/Flashbots.cs | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs index 6e7cb834b31..54a02f7a087 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -32,9 +32,10 @@ namespace Nethermind.Flasbots.Test; public partial class FlashbotsModuleTests { TestKeyAndAddress? TestKeysAndAddress; - + [SetUp] - public void SetUp(){ + public void SetUp() + { TestKeysAndAddress = new TestKeyAndAddress(); } @@ -49,7 +50,7 @@ internal class TestKeyAndAddress public PrivateKey TestBuilderKey = new PrivateKey("0bfbbbc68fefd990e61ba645efb84e0a62e94d5fff02c9b1da8eb45fea32b4e0"); public Address TestBuilderAddr; - public UInt256 TestBalance = UInt256.Parse("2000000000000000000"); + public UInt256 TestBalance = UInt256.Parse("2000000000000000000"); public byte[] logCode = Bytes.FromHexString("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00"); public TestKeyAndAddress() { @@ -140,7 +141,7 @@ protected IBlockValidator CreateBlockValidator() PoSSwitcher = new PoSSwitcher(MergeConfig, SyncConfig.Default, new MemDb(), BlockTree, SpecProvider, new ChainSpec() { Genesis = Core.Test.Builders.Build.A.Block.WithDifficulty(0).TestObject }, LogManager); ISealValidator SealValidator = new MergeSealValidator(PoSSwitcher, Always.Valid); HeaderValidator = new MergeHeaderValidator( - PoSSwitcher, + PoSSwitcher, new HeaderValidator(BlockTree, SealValidator, SpecProvider, LogManager), BlockTree, SpecProvider, diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index d216de14bcd..f47b81f79b5 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -14,8 +14,8 @@ namespace Nethermind.Flasbots.Test; public partial class FlashbotsModuleTests { - - public async Task TestValidateBuilderSubmissionV3 () + + public async Task TestValidateBuilderSubmissionV3() { using MergeTestBlockChain chain = await CreateBlockChain(); ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = chain.CreateReadOnlyTxProcessingEnv(); @@ -26,7 +26,7 @@ public async Task TestValidateBuilderSubmissionV3 () UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); Transaction tx1 = new Transaction( - + ); } } diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index 0e48060c718..077b50ac98f 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -34,7 +34,7 @@ public Task InitRpcModules() _api.LogManager ); ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( - _api.HeaderValidator?? throw new ArgumentNullException(nameof(_api.HeaderValidator)), + _api.HeaderValidator ?? throw new ArgumentNullException(nameof(_api.HeaderValidator)), _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), readOnlyTxProcessingEnv, _flashbotsConfig From b9b200842fab3d615734cb006219f03c89cf6aec Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 24 Oct 2024 15:03:11 +0530 Subject: [PATCH 032/113] dummy --- .../Data/SubmitBlockRequest.cs | 6 +- .../Nethermind.Flashbots/Flashbots.cs | 3 +- .../ValidateBuilderSubmissionHandler.cs | 57 +++++++++++++------ .../Modules/Eth/EthRpcModule.cs | 5 +- .../Data/ExecutionPayloadV3.cs | 1 - .../MergeHeaderValidator.cs | 5 ++ .../Nethermind.Runner/configs/holesky.cfg | 2 +- 7 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs index 60863f294c3..7cc851b6ac7 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs @@ -8,16 +8,16 @@ namespace Nethermind.Flashbots.Data; public class SubmitBlockRequest { - private readonly ExecutionPayload _executionPayload; + private readonly ExecutionPayloadV3 _executionPayload; private readonly BlobsBundleV1 _blobsBundle; - public SubmitBlockRequest(ExecutionPayload executionPayload, BlobsBundleV1 blobsBundle, BidTrace message) + public SubmitBlockRequest(ExecutionPayloadV3 executionPayload, BlobsBundleV1 blobsBundle, BidTrace message) { _executionPayload = executionPayload; _blobsBundle = blobsBundle; Message = message; } - public ExecutionPayload ExecutionPayload => _executionPayload; + public ExecutionPayloadV3 ExecutionPayload => _executionPayload; public BlobsBundleV1 BlobsBundle => _blobsBundle; public BidTrace Message { get; } } diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index 077b50ac98f..ddb1e638b4f 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -31,7 +31,8 @@ public Task InitRpcModules() _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), _api.SpecProvider, - _api.LogManager + _api.LogManager, + _api.WorldState ); ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( _api.HeaderValidator ?? throw new ArgumentNullException(nameof(_api.HeaderValidator)), diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 1b6846c5e6c..4a7456978b5 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -25,6 +25,7 @@ using Nethermind.Logging; using Nethermind.Merge.Plugin.Data; using Nethermind.State; +using Nethermind.Core.Crypto; namespace Nethermind.Flashbots.Handlers; @@ -60,7 +61,16 @@ public ValidateSubmissionHandler( public Task> ValidateSubmission(BuilderBlockValidationRequest request) { - ExecutionPayload payload = request.BlockRequest.ExecutionPayload; + ExecutionPayloadV3 payload = request.BlockRequest.ExecutionPayload; + + if (request.ParentBeaconBlockRoot is null) + { + return FlashbotsResult.Invalid("Parent beacon block root must be set in the request"); + } + + payload.ParentBeaconBlockRoot = new Hash256(request.ParentBeaconBlockRoot); + + BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; string payloadStr = $"BuilderBlock: {payload}"; @@ -186,17 +196,30 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected IWorldState currentState = processingScope.WorldState; ITransactionProcessor transactionProcessor = processingScope.TransactionProcessor; - UInt256 feeRecipientBalanceBefore = currentState.GetBalance(feeRecipient); + UInt256 feeRecipientBalanceBefore; + try + { + feeRecipientBalanceBefore = currentState.GetBalance(feeRecipient); + } + catch (Exception ex) + { + error = $"Failed to get balance for fee recipient: {ex.Message}"; + return false; + } BlockProcessor blockProcessor = CreateBlockProcessor(currentState, transactionProcessor); + EthereumEcdsa ecdsa = new EthereumEcdsa(_txProcessingEnv.SpecProvider.ChainId); + IReleaseSpec spec = _txProcessingEnv.SpecProvider.GetSpec(parentHeader); + + RecoverSenderAddress(block, ecdsa, spec); + List suggestedBlocks = [block]; BlockReceiptsTracer blockReceiptsTracer = new(); try { Block processedBlock = blockProcessor.Process(currentState.StateRoot, suggestedBlocks, ValidateSubmissionProcessingOptions, blockReceiptsTracer)[0]; - FinalizeStateAndBlock(currentState, processedBlock, _txProcessingEnv.SpecProvider.GetSpec(parentHeader), block, _blockTree); } catch (Exception e) { @@ -235,6 +258,15 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return true; } + private void RecoverSenderAddress(Block block, EthereumEcdsa ecdsa, IReleaseSpec spec){ + foreach (Transaction tx in block.Transactions) + { + if(tx.SenderAddress is null){ + tx.SenderAddress = ecdsa.RecoverAddress(tx, !spec.ValidateChainId); + } + } + } + private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHeader parentHeader, out string? error) { if (!_headerValidator.Validate(block.Header)) @@ -243,11 +275,11 @@ private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHead return false; } - if (!_blockTree.IsBetterThanHead(block.Header)) - { - error = $"Block {block.Header.Hash} is not better than head"; - return false; - } + // if (!_blockTree.IsBetterThanHead(block.Header)) + // { + // error = $"Block {block.Header.Hash} is not better than head"; + // return false; + // } long calculatedGasLimit = GetGasLimit(parentHeader, registerGasLimit); @@ -373,13 +405,4 @@ private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransact receiptsRootCalculator: new ReceiptsRootCalculator() ); } - - private static void FinalizeStateAndBlock(IWorldState stateProvider, Block processedBlock, IReleaseSpec currentSpec, Block currentBlock, IBlockTree blockTree) - { - stateProvider.StateRoot = processedBlock.StateRoot!; - stateProvider.Commit(currentSpec); - stateProvider.CommitTree(currentBlock.Number); - blockTree.SuggestBlock(processedBlock, BlockTreeSuggestOptions.ForceSetAsMain); - blockTree.UpdateHeadBlock(processedBlock.Hash!); - } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index 2a56b3ce014..b9fa3d8a9d7 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -390,9 +390,10 @@ public ResultWrapper eth_getBlockByNumber(BlockParameter blockParam return ResultWrapper.Success(null); } - IByteBuffer buffer = PooledByteBufferAllocator.Default.Buffer(TxDecoder.Instance.GetLength(transaction, RlpBehaviors.None)); + IByteBuffer buffer = PooledByteBufferAllocator.Default.Buffer(TxDecoder.Instance.GetLength(transaction, RlpBehaviors.SkipTypedWrapping)); using NettyRlpStream stream = new(buffer); - TxDecoder.Instance.Encode(stream, transaction); + TxDecoder.Instance.Encode(stream, transaction, rlpBehaviors: RlpBehaviors.SkipTypedWrapping); + return ResultWrapper.Success(buffer.AsSpan().ToHexString(false)); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs index f05e355b183..32828dfbfbd 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV3.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using Nethermind.Core; -using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Int256; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs index aac51366839..b83e7aa3ece 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs @@ -45,6 +45,11 @@ public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUn } public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) { + BlockHeader? currentHeader; + if(header.Hash != null){ + currentHeader = _blockTree.FindHeader(header.Hash, BlockTreeLookupOptions.None); + } + error = null; return _poSSwitcher.IsPostMerge(header) ? ValidateTheMergeChecks(header) && base.Validate(header, parent, isUncle, out error) diff --git a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg index 36e42c361eb..74901241f07 100644 --- a/src/Nethermind/Nethermind.Runner/configs/holesky.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/holesky.cfg @@ -31,7 +31,7 @@ "Merge": { "Enabled": true }, - "BlockValidation": { + "Flashbots": { "Enabled": true } } From 214b5f0f5a37737820960a6807323971590da392 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 24 Oct 2024 16:39:32 +0530 Subject: [PATCH 033/113] dummy --- .../ValidateBuilderSubmissionHandler.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 4a7456978b5..4a6aaa7acec 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -33,8 +33,10 @@ public class ValidateSubmissionHandler { private const ProcessingOptions ValidateSubmissionProcessingOptions = ProcessingOptions.ReadOnlyChain | ProcessingOptions.IgnoreParentNotOnMainChain - | ProcessingOptions.ForceProcessing; - + | ProcessingOptions.ForceProcessing + | ProcessingOptions.StoreReceipts + | ProcessingOptions.NoValidation + | ProcessingOptions.DoNotVerifyNonce; private readonly ReadOnlyTxProcessingEnv _txProcessingEnv; private readonly IBlockTree _blockTree; private readonly IHeaderValidator _headerValidator; @@ -192,20 +194,11 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected } - IReadOnlyTxProcessingScope processingScope = _txProcessingEnv.Build(parentHeader.StateRoot!); + using IReadOnlyTxProcessingScope processingScope = _txProcessingEnv.Build(parentHeader.StateRoot!); IWorldState currentState = processingScope.WorldState; ITransactionProcessor transactionProcessor = processingScope.TransactionProcessor; - UInt256 feeRecipientBalanceBefore; - try - { - feeRecipientBalanceBefore = currentState.GetBalance(feeRecipient); - } - catch (Exception ex) - { - error = $"Failed to get balance for fee recipient: {ex.Message}"; - return false; - } + UInt256 feeRecipientBalanceBefore = currentState.AccountExists(feeRecipient) ? currentState.GetBalance(feeRecipient) : UInt256.Zero; BlockProcessor blockProcessor = CreateBlockProcessor(currentState, transactionProcessor); From a3b0550fb3151fefe4c72b260ea449c78bcef6c2 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Wed, 30 Oct 2024 23:53:35 +0530 Subject: [PATCH 034/113] fix balance check --- .../Handlers/ValidateBuilderSubmissionHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 4a6aaa7acec..a0cc7598f5c 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -198,7 +198,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected IWorldState currentState = processingScope.WorldState; ITransactionProcessor transactionProcessor = processingScope.TransactionProcessor; - UInt256 feeRecipientBalanceBefore = currentState.AccountExists(feeRecipient) ? currentState.GetBalance(feeRecipient) : UInt256.Zero; + UInt256 feeRecipientBalanceBefore = currentState.HasStateForRoot(currentState.StateRoot) ? ( currentState.AccountExists(feeRecipient) ? currentState.GetBalance(feeRecipient) : UInt256.Zero): UInt256.Zero; BlockProcessor blockProcessor = CreateBlockProcessor(currentState, transactionProcessor); @@ -391,7 +391,7 @@ private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransact stateProvider, _receiptStorage, transactionProcessor, - new BeaconBlockRootHandler(transactionProcessor), + new BeaconBlockRootHandler(transactionProcessor, stateProvider), new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), logManager: _txProcessingEnv.LogManager, withdrawalProcessor: new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), From a0361cfd0a3908aab0d4a38a197318a1f42d5bef Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 11 Nov 2024 19:46:56 +0530 Subject: [PATCH 035/113] fix small errors --- .../FlashbotsModuleTests.Setup.cs | 8 +++--- .../FlashbotsModuleTests.cs | 25 +++++++++++++++---- .../Nethermind.Flashbots/Flashbots.cs | 3 +-- .../ValidateBuilderSubmissionHandler.cs | 18 ++++++++++--- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs index 54a02f7a087..b35d9ffb7e0 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -41,7 +41,7 @@ public void SetUp() internal class TestKeyAndAddress { - public PrivateKey privateKey = new PrivateKey("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"); + public PrivateKey PrivateKey = new PrivateKey("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"); public Address TestAddr; public PrivateKey TestValidatorKey = new PrivateKey("28c3cd61b687fdd03488e167a5d84f50269df2a4c29a2cfb1390903aa775c5d0"); @@ -52,9 +52,11 @@ internal class TestKeyAndAddress public UInt256 TestBalance = UInt256.Parse("2000000000000000000"); public byte[] logCode = Bytes.FromHexString("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00"); + + public UInt256 BaseInitialFee = 1000000000; public TestKeyAndAddress() { - TestAddr = privateKey.Address; + TestAddr = PrivateKey.Address; TestValidatorAddr = TestValidatorKey.Address; TestBuilderAddr = TestBuilderKey.Address; } @@ -127,7 +129,7 @@ protected override IBlockProcessor CreateBlockProcessor() State, ReceiptStorage, TxProcessor, - new BeaconBlockRootHandler(TxProcessor), + new BeaconBlockRootHandler(TxProcessor, State), new BlockhashStore(SpecProvider, State), LogManager, WithdrawalProcessor diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index f47b81f79b5..c07dc970932 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -4,10 +4,11 @@ using System.Threading.Tasks; using Nethermind.Consensus.Processing; using Nethermind.Core; -using Nethermind.Core.Extensions; -using Nethermind.Crypto; +using Nethermind.Core.Specs; +using Nethermind.Core.Test.Builders; using Nethermind.Flashbots.Modules.Flashbots; using Nethermind.Int256; +using Nethermind.Specs.Forks; using Nethermind.State; namespace Nethermind.Flasbots.Test; @@ -17,7 +18,7 @@ public partial class FlashbotsModuleTests public async Task TestValidateBuilderSubmissionV3() { - using MergeTestBlockChain chain = await CreateBlockChain(); + using MergeTestBlockChain chain = await CreateBlockChain(Cancun.Instance); ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = chain.CreateReadOnlyTxProcessingEnv(); IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnv); BlockHeader currentHeader = chain.BlockTree.Head.Header; @@ -25,8 +26,22 @@ public async Task TestValidateBuilderSubmissionV3() UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); - Transaction tx1 = new Transaction( + Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(new Address("0x16")).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + chain.TxPool.SubmitTx(tx1, TxPool.TxHandlingOptions.None); - ); + Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2*TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + chain.TxPool.SubmitTx(tx2, TxPool.TxHandlingOptions.None); + + UInt256 baseFee = BaseFeeCalculator.Calculate(currentHeader, chain.SpecProvider.GetFinalSpec()); + + Transaction tx3 = Build.A.Transaction.WithNonce(nonce + 2).WithValue(10).WithGasLimit(21000).WithValue(baseFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + chain.TxPool.SubmitTx(tx3, TxPool.TxHandlingOptions.None); + + Withdrawal[] withdrawals = [ + Build.A.Withdrawal.WithIndex(0).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject, + Build.A.Withdrawal.WithIndex(1).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject + ]; + + } } diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index ddb1e638b4f..077b50ac98f 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -31,8 +31,7 @@ public Task InitRpcModules() _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), _api.SpecProvider, - _api.LogManager, - _api.WorldState + _api.LogManager ); ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( _api.HeaderValidator ?? throw new ArgumentNullException(nameof(_api.HeaderValidator)), diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index a0cc7598f5c..66c28f1542a 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -35,8 +35,7 @@ public class ValidateSubmissionHandler | ProcessingOptions.IgnoreParentNotOnMainChain | ProcessingOptions.ForceProcessing | ProcessingOptions.StoreReceipts - | ProcessingOptions.NoValidation - | ProcessingOptions.DoNotVerifyNonce; + | ProcessingOptions.NoValidation; private readonly ReadOnlyTxProcessingEnv _txProcessingEnv; private readonly IBlockTree _blockTree; private readonly IHeaderValidator _headerValidator; @@ -145,7 +144,7 @@ private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobsBundle, out string? error) { // get sum of length of blobs of each transaction - int totalBlobsLength = transactions.Sum(t => t.BlobVersionedHashes!.Length); + int totalBlobsLength = transactions.Sum(t => t.BlobVersionedHashes is not null ? t.BlobVersionedHashes.Length : 0); if (totalBlobsLength != blobsBundle.Blobs.Length) { @@ -377,6 +376,19 @@ private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, error = "Malformed proposer payment, gas price not equal to base fee"; return false; } + + if (paymentTx.MaxPriorityFeePerGas != processedBlock.BaseFeePerGas && paymentTx.MaxPriorityFeePerGas != 0) + { + error = "Malformed proposer payment, max priority fee per gas not equal to block max priority fee per gas"; + return false; + } + + if (paymentTx.MaxFeePerGas != processedBlock.BaseFeePerGas) + { + error = "Malformed proposer payment, max fee per gas not equal to block base fee per gas"; + return false; + } + error = null; return true; } From 2e75139f055fcd25a061688d066e84748ce4d01a Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 11 Nov 2024 19:47:14 +0530 Subject: [PATCH 036/113] format files --- .../FlashbotsModuleTests.Setup.cs | 2 +- .../FlashbotsModuleTests.cs | 4 ++-- .../Handlers/ValidateBuilderSubmissionHandler.cs | 14 ++++++++------ .../MergeHeaderValidator.cs | 3 ++- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs index b35d9ffb7e0..9669157bd7c 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -53,7 +53,7 @@ internal class TestKeyAndAddress public UInt256 TestBalance = UInt256.Parse("2000000000000000000"); public byte[] logCode = Bytes.FromHexString("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00"); - public UInt256 BaseInitialFee = 1000000000; + public UInt256 BaseInitialFee = 1000000000; public TestKeyAndAddress() { TestAddr = PrivateKey.Address; diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index c07dc970932..030572b33d4 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -29,7 +29,7 @@ public async Task TestValidateBuilderSubmissionV3() Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(new Address("0x16")).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; chain.TxPool.SubmitTx(tx1, TxPool.TxHandlingOptions.None); - Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2*TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2 * TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; chain.TxPool.SubmitTx(tx2, TxPool.TxHandlingOptions.None); UInt256 baseFee = BaseFeeCalculator.Calculate(currentHeader, chain.SpecProvider.GetFinalSpec()); @@ -42,6 +42,6 @@ public async Task TestValidateBuilderSubmissionV3() Build.A.Withdrawal.WithIndex(1).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject ]; - + } } diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 66c28f1542a..8efad5fabab 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -68,9 +68,9 @@ public Task> ValidateSubmission(BuilderBlockValid { return FlashbotsResult.Invalid("Parent beacon block root must be set in the request"); } - + payload.ParentBeaconBlockRoot = new Hash256(request.ParentBeaconBlockRoot); - + BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; @@ -144,7 +144,7 @@ private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, private bool ValidateBlobsBundle(Transaction[] transactions, BlobsBundleV1 blobsBundle, out string? error) { // get sum of length of blobs of each transaction - int totalBlobsLength = transactions.Sum(t => t.BlobVersionedHashes is not null ? t.BlobVersionedHashes.Length : 0); + int totalBlobsLength = transactions.Sum(t => t.BlobVersionedHashes is not null ? t.BlobVersionedHashes.Length : 0); if (totalBlobsLength != blobsBundle.Blobs.Length) { @@ -197,7 +197,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected IWorldState currentState = processingScope.WorldState; ITransactionProcessor transactionProcessor = processingScope.TransactionProcessor; - UInt256 feeRecipientBalanceBefore = currentState.HasStateForRoot(currentState.StateRoot) ? ( currentState.AccountExists(feeRecipient) ? currentState.GetBalance(feeRecipient) : UInt256.Zero): UInt256.Zero; + UInt256 feeRecipientBalanceBefore = currentState.HasStateForRoot(currentState.StateRoot) ? (currentState.AccountExists(feeRecipient) ? currentState.GetBalance(feeRecipient) : UInt256.Zero) : UInt256.Zero; BlockProcessor blockProcessor = CreateBlockProcessor(currentState, transactionProcessor); @@ -250,10 +250,12 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return true; } - private void RecoverSenderAddress(Block block, EthereumEcdsa ecdsa, IReleaseSpec spec){ + private void RecoverSenderAddress(Block block, EthereumEcdsa ecdsa, IReleaseSpec spec) + { foreach (Transaction tx in block.Transactions) { - if(tx.SenderAddress is null){ + if (tx.SenderAddress is null) + { tx.SenderAddress = ecdsa.RecoverAddress(tx, !spec.ValidateChainId); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs index dd96e338ef0..d5ea85dcbfd 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs @@ -46,7 +46,8 @@ public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUn public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) { BlockHeader? currentHeader; - if(header.Hash != null){ + if (header.Hash != null) + { currentHeader = _blockTree.FindHeader(header.Hash, BlockTreeLookupOptions.None); } From 14850e5de0c84027c771a946a26bc1f0ff7d8737 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 21 Nov 2024 18:37:15 +0530 Subject: [PATCH 037/113] dummy --- src/Nethermind/Chains/holesky.json | 3 + .../FlashbotsModuleTests.cs | 97 ++++++++++++++++++- .../Nethermind.Flasbots.Test.csproj | 2 +- .../Data/BuilderBlockValidationRequest.cs | 1 - .../Data/SubmitBlockRequest.cs | 1 - .../Nethermind.Flashbots/FlashbotsConfig.cs | 4 +- .../ValidateBuilderSubmissionHandler.cs | 10 +- 7 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/Nethermind/Chains/holesky.json b/src/Nethermind/Chains/holesky.json index 5ca2e40da40..403640d06fa 100644 --- a/src/Nethermind/Chains/holesky.json +++ b/src/Nethermind/Chains/holesky.json @@ -1057,6 +1057,9 @@ }, "0x4BC656B34De23896fa6069C9862F355b740401aF": { "balance": "0x084595161401484a000000" + }, + "0x0225343cbAD89626095B4B9cCFB51fC569F88d8B": { + "balance": "0x084595161401484a000000" } } } diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index 030572b33d4..654ebb5d1b7 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -1,24 +1,35 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Threading.Tasks; +using FluentAssertions; using Nethermind.Consensus.Processing; using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Flashbots.Modules.Flashbots; using Nethermind.Int256; +using Nethermind.JsonRpc; +using Nethermind.JsonRpc.Test; +using Nethermind.Merge.Plugin.Data; using Nethermind.Specs.Forks; using Nethermind.State; +using NUnit.Framework; namespace Nethermind.Flasbots.Test; public partial class FlashbotsModuleTests { + private static readonly DateTime Timestamp = DateTimeOffset.FromUnixTimeSeconds(1000).UtcDateTime; + private ITimestamper Timestamper { get; } = new ManualTimestamper(Timestamp); - public async Task TestValidateBuilderSubmissionV3() + [Test] + public virtual async Task TestValidateBuilderSubmissionV3() { - using MergeTestBlockChain chain = await CreateBlockChain(Cancun.Instance); + using MergeTestBlockChain chain = await CreateBlockChain(releaseSpec: Cancun.Instance); ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = chain.CreateReadOnlyTxProcessingEnv(); IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnv); BlockHeader currentHeader = chain.BlockTree.Head.Header; @@ -42,6 +53,88 @@ public async Task TestValidateBuilderSubmissionV3() Build.A.Withdrawal.WithIndex(1).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject ]; + ulong timestamp = Timestamper.UnixTime.Seconds; + Hash256 prevRandao = Keccak.Zero; + var payloadAttrs = new + { + timestamp = timestamp.ToHexString(true), + prevRandao, + suggestedFeeRecipient = TestKeysAndAddress.TestAddr.ToString(), + withdrawals, + parentBeaconBLockRoot = Keccak.Zero + }; + + string?[] @params = new string?[] + { + chain.JsonSerializer.Serialize(new { + headBlockHash = currentHeader.Hash.ToString(), + safeBlockHash = currentHeader.Hash.ToString(), + finalizedBlockHash = currentHeader.Hash.ToString(), + }), chain.JsonSerializer.Serialize(payloadAttrs) + }; + string expectedPayloadId = "0x774c6aff527bbc68"; + + string response = await RpcTest.TestSerializedRequest(rpc, "engine_forkchoiceUpdatedV3", @params!); + JsonRpcSuccessResponse? successResponse = chain.JsonSerializer.Deserialize(response); + + successResponse.Should().NotBeNull(); + response.Should().Be(chain.JsonSerializer.Serialize(new JsonRpcSuccessResponse + { + Id = successResponse.Id, + Result = new ForkchoiceUpdatedV1Result + { + PayloadId = expectedPayloadId, + PayloadStatus = new PayloadStatusV1 + { + LatestValidHash = new("0xd7e58364f16b4a329b959b166f9c32323cb135669335db5dadd0344568f8dc9a"), + Status = PayloadStatus.Valid, + ValidationError = null + } + } + })); + + Hash256 expectedBlockHash = new("0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26"); + string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; + + Block block = new( + new( + currentHeader.Hash, + Keccak.OfAnEmptySequenceRlp, + TestKeysAndAddress.TestAddr, + UInt256.Zero, + 1, + chain.BlockTree.Head!.GasLimit, + timestamp, + Bytes.FromHexString("0x4e65746865726d696e64") // Nethermind + ) + { + BlobGasUsed = 0, + ExcessBlobGas = 0, + BaseFeePerGas = 0, + Bloom = Bloom.Empty, + GasUsed = 0, + Hash = expectedBlockHash, + MixHash = prevRandao, + ParentBeaconBlockRoot = Keccak.Zero, + ReceiptsRoot = chain.BlockTree.Head!.ReceiptsRoot!, + StateRoot = new(stateRoot), + }, + Array.Empty(), + Array.Empty(), + withdrawals + ); + + GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block)); + + response = await RpcTest.TestSerializedRequest(rpc, "engine_getPayloadV3", expectedPayloadId); + successResponse = chain.JsonSerializer.Deserialize(response); + + successResponse.Should().NotBeNull(); + response.Should().Be(chain.JsonSerializer.Serialize(new JsonRpcSuccessResponse + { + Id = successResponse.Id, + Result = expectedPayload + })); } } diff --git a/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj b/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj index 038d62c896f..dd095ad9bff 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj +++ b/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index c0b904693ea..66463d74ffc 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -3,7 +3,6 @@ using System.Text.Json.Serialization; using Nethermind.Core.Crypto; -using Nethermind.JsonRpc; namespace Nethermind.Flashbots.Data; diff --git a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs index 7cc851b6ac7..6e7cc6d783c 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Core.Crypto; using Nethermind.Merge.Plugin.Data; namespace Nethermind.Flashbots.Data; diff --git a/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs index be96b14b53b..d7197fb25c7 100644 --- a/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs @@ -1,13 +1,11 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Config; - namespace Nethermind.Flashbots; public class FlashbotsConfig : IFlashbotsConfig { - public bool Enabled { get; set; } + public bool Enabled { get; set; } = true; public bool UseBalanceDiffProfit { get; set; } = false; public bool ExcludeWithdrawals { get; set; } = false; diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 8efad5fabab..21a22afc861 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -269,11 +269,11 @@ private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHead return false; } - // if (!_blockTree.IsBetterThanHead(block.Header)) - // { - // error = $"Block {block.Header.Hash} is not better than head"; - // return false; - // } + if (!_blockTree.IsBetterThanHead(block.Header)) + { + error = $"Block {block.Header.Hash} is not better than head"; + return false; + } long calculatedGasLimit = GetGasLimit(parentHeader, registerGasLimit); From 65a969f7fcadd357430ebb9fefd9ed4fc32acbae Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Tue, 17 Dec 2024 14:40:03 +0530 Subject: [PATCH 038/113] remove default account --- src/Nethermind/Chains/holesky.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Nethermind/Chains/holesky.json b/src/Nethermind/Chains/holesky.json index 403640d06fa..5ca2e40da40 100644 --- a/src/Nethermind/Chains/holesky.json +++ b/src/Nethermind/Chains/holesky.json @@ -1057,9 +1057,6 @@ }, "0x4BC656B34De23896fa6069C9862F355b740401aF": { "balance": "0x084595161401484a000000" - }, - "0x0225343cbAD89626095B4B9cCFB51fC569F88d8B": { - "balance": "0x084595161401484a000000" } } } From 3ce68ee5db25523db2144ba1aab1019d3ecc1a2b Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 19 Dec 2024 13:09:53 +0530 Subject: [PATCH 039/113] dummy commit --- .../Data/BlockValidationResult.cs | 14 ++++++ .../Data/BuilderBlockValidationRequest.cs | 14 ++++++ .../ValidateBuilderSubmissionHandler.cs | 45 +++++++++++++------ .../Modules/Flashbots/FlashbotsRpcModule.cs | 4 ++ .../Modules/Flashbots/IFlashbotsRpcModule.cs | 8 ++++ 5 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs index 1a0eae8d723..1e22e51da61 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Text.Json.Serialization; +using Nethermind.Core.Crypto; using Nethermind.JsonRpc; namespace Nethermind.Flashbots.Data; @@ -45,3 +46,16 @@ public static ResultWrapper Error(string error) [JsonIgnore(Condition = JsonIgnoreCondition.Never)] public string? ValidationError { get; set; } } + +public class ResultHash +{ + public Hash256 BlockHash { get; set; } + + public Hash256 TxRoot { get; set; } + + public ResultHash(Hash256 blockHash, Hash256 txRoot) + { + BlockHash = blockHash; + TxRoot = txRoot; + } +} diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 66463d74ffc..0e816b929e8 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -3,6 +3,7 @@ using System.Text.Json.Serialization; using Nethermind.Core.Crypto; +using Nethermind.Merge.Plugin.Data; namespace Nethermind.Flashbots.Data; @@ -21,3 +22,16 @@ public class BuilderBlockValidationRequest [JsonRequired] public required SubmitBlockRequest BlockRequest { get; set; } } + +public class BuilderBlockValidationRequestHash +{ + /// + /// The block hash of the parent beacon block. + /// + /// + [JsonRequired] + public required Hash256 ParentBeaconBlockRoot { get; set; } + + [JsonRequired] + public required ExecutionPayloadV3 ExecutionPayload; +} diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 21a22afc861..88ab8bba046 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -60,6 +60,25 @@ public ValidateSubmissionHandler( _flashbotsConfig = flashbotsConfig; } + public Task> ValidateSubmissionHash(BuilderBlockValidationRequestHash request) + { + ExecutionPayloadV3 payload = request.ExecutionPayload; + payload.ParentBeaconBlockRoot = new Hash256(request.ParentBeaconBlockRoot); + + if (!payload.TryGetBlock(out Block? block)) + { + if (_logger.IsWarn) _logger.Warn($"Invalid block."); + return Task.FromResult(ResultWrapper.Success(new ResultHash(Keccak.Zero, Keccak.Zero))); + } + + BlockHeader header = block.Header; + Transaction[] transactions = block.Transactions; + + Hash256 txRoot = Keccak.Zero; + + return Task.FromResult(ResultWrapper.Success(new ResultHash(header.CalculateHash(), txRoot))); + } + public Task> ValidateSubmission(BuilderBlockValidationRequest request) { ExecutionPayloadV3 payload = request.BlockRequest.ExecutionPayload; @@ -90,11 +109,11 @@ public Task> ValidateSubmission(BuilderBlockValid return FlashbotsResult.Invalid(error ?? "Block validation failed"); } - if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) - { - if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); - return FlashbotsResult.Invalid(blobsError ?? "Blobs bundle validation failed"); - } + // if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) + // { + // if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); + // return FlashbotsResult.Invalid(blobsError ?? "Blobs bundle validation failed"); + // } return FlashbotsResult.Valid(); @@ -241,7 +260,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected if (ValidateProposerPayment(expectedProfit, useBalanceDiffProfit, feeRecipientBalanceAfter, amtBeforeOrWithdrawn)) return true; - if (!ValidateProcessedBlock(block, feeRecipient, expectedProfit, out error)) + if (!ValidateProcessedBlock(block, feeRecipient, expectedProfit, blockReceiptsTracer.TxReceipts.ToArray(), out error)) { return false; } @@ -269,11 +288,11 @@ private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHead return false; } - if (!_blockTree.IsBetterThanHead(block.Header)) - { - error = $"Block {block.Header.Hash} is not better than head"; - return false; - } + // if (!_blockTree.IsBetterThanHead(block.Header)) + // { + // error = $"Block {block.Header.Hash} is not better than head"; + // return false; + // } long calculatedGasLimit = GetGasLimit(parentHeader, registerGasLimit); @@ -327,9 +346,9 @@ private bool ValidateProposerPayment(UInt256 expectedProfit, bool useBalanceDiff return false; } - private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, UInt256 expectedProfit, out string? error) + private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, UInt256 expectedProfit, TxReceipt[] receipts, out string? error) { - TxReceipt[] receipts = processedBlock.Hash != null ? _receiptStorage.Get(processedBlock.Hash) : []; + // TxReceipt[] receipts = processedBlock.Hash != null ? _receiptStorage.Get(processedBlock.Hash) : []; if (receipts.Length == 0) { diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs index 066bf8fd642..bba373a7507 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; +using Nethermind.Core.Crypto; using Nethermind.Flashbots.Data; using Nethermind.Flashbots.Handlers; using Nethermind.JsonRpc; @@ -20,4 +21,7 @@ public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => _validateSubmissionHandler.ValidateSubmission(@params); + Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3Hash(BuilderBlockValidationRequestHash @params) => + _validateSubmissionHandler.ValidateSubmissionHash(@params); + } diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs index b81da13fb39..f26e1906903 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; +using Nethermind.Core.Crypto; using Nethermind.Flashbots.Data; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; @@ -16,4 +17,11 @@ public interface IFlashbotsRpcModule : IRpcModule IsSharable = false, IsImplemented = true)] Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); + + // TODO: remove this method + [JsonRpcMethod( + Description = " calculate hash of the builder submissions as received by a relay", + IsSharable = false, + IsImplemented = true)] + Task> flashbots_validateBuilderSubmissionV3Hash(BuilderBlockValidationRequestHash @params); } From 6a9762d4d47fb692a6b6691e6a62ec4a8728718a Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 23 Dec 2024 13:54:16 +0530 Subject: [PATCH 040/113] add prewarmer --- .../Nethermind.Flashbots/Flashbots.cs | 11 +++++ .../Nethermind.Flashbots/FlashbotsConfig.cs | 3 ++ .../ValidateBuilderSubmissionHandler.cs | 49 +++++++++++++------ .../Nethermind.Flashbots/IFlashbotsConfig.cs | 6 +++ 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index 077b50ac98f..ce8eedc8281 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -27,16 +27,27 @@ public class Flashbots : INethermindPlugin public string Author => "Nethermind"; public Task InitRpcModules() { + ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = new ReadOnlyTxProcessingEnvFactory( + _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), + _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), + _api.SpecProvider, + _api.LogManager + ); + ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv( _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), _api.SpecProvider, _api.LogManager ); + ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( _api.HeaderValidator ?? throw new ArgumentNullException(nameof(_api.HeaderValidator)), _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), readOnlyTxProcessingEnv, + readOnlyTxProcessingEnvFactory, + _api.LogManager ?? throw new ArgumentNullException(nameof(_api.LogManager)), + _api.SpecProvider ?? throw new ArgumentNullException(nameof(_api.SpecProvider)), _flashbotsConfig ); diff --git a/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs index d7197fb25c7..363483a383d 100644 --- a/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs @@ -9,4 +9,7 @@ public class FlashbotsConfig : IFlashbotsConfig public bool UseBalanceDiffProfit { get; set; } = false; public bool ExcludeWithdrawals { get; set; } = false; + + public bool EnablePreWarmer { get; set; } = true; + public bool EnableValidation { get; set; } = false; } diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 88ab8bba046..ff59fbbc990 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -31,12 +31,14 @@ namespace Nethermind.Flashbots.Handlers; public class ValidateSubmissionHandler { - private const ProcessingOptions ValidateSubmissionProcessingOptions = ProcessingOptions.ReadOnlyChain + private ProcessingOptions ValidateSubmissionProcessingOptions = ProcessingOptions.ReadOnlyChain | ProcessingOptions.IgnoreParentNotOnMainChain | ProcessingOptions.ForceProcessing - | ProcessingOptions.StoreReceipts - | ProcessingOptions.NoValidation; + | ProcessingOptions.StoreReceipts; private readonly ReadOnlyTxProcessingEnv _txProcessingEnv; + + private readonly ReadOnlyTxProcessingEnvFactory _readOnlyTxProcessingEnvFactory; + private readonly IBlockTree _blockTree; private readonly IHeaderValidator _headerValidator; private readonly IBlockValidator _blockValidator; @@ -46,15 +48,24 @@ public class ValidateSubmissionHandler private readonly IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); + private readonly ILogManager _logManager; + private readonly ISpecProvider _specProvider; + public ValidateSubmissionHandler( IHeaderValidator headerValidator, IBlockValidator blockValidator, ReadOnlyTxProcessingEnv txProcessingEnv, + ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory, + ILogManager logManager, + ISpecProvider specProvider, IFlashbotsConfig flashbotsConfig) { _headerValidator = headerValidator; _blockValidator = blockValidator; _txProcessingEnv = txProcessingEnv; + _readOnlyTxProcessingEnvFactory = readOnlyTxProcessingEnvFactory; + _specProvider = specProvider; + _logManager = logManager; _blockTree = _txProcessingEnv.BlockTree; _logger = txProcessingEnv.LogManager!.GetClassLogger(); _flashbotsConfig = flashbotsConfig; @@ -211,17 +222,18 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected return false; } - - using IReadOnlyTxProcessingScope processingScope = _txProcessingEnv.Build(parentHeader.StateRoot!); + using IReadOnlyTxProcessingScope processingScope = _readOnlyTxProcessingEnvFactory.Create().Build(parentHeader.StateRoot!); IWorldState currentState = processingScope.WorldState; ITransactionProcessor transactionProcessor = processingScope.TransactionProcessor; UInt256 feeRecipientBalanceBefore = currentState.HasStateForRoot(currentState.StateRoot) ? (currentState.AccountExists(feeRecipient) ? currentState.GetBalance(feeRecipient) : UInt256.Zero) : UInt256.Zero; - BlockProcessor blockProcessor = CreateBlockProcessor(currentState, transactionProcessor); + IBlockCachePreWarmer preWarmer = new BlockCachePreWarmer(_readOnlyTxProcessingEnvFactory, _specProvider, _logManager); - EthereumEcdsa ecdsa = new EthereumEcdsa(_txProcessingEnv.SpecProvider.ChainId); - IReleaseSpec spec = _txProcessingEnv.SpecProvider.GetSpec(parentHeader); + BlockProcessor blockProcessor = CreateBlockProcessor(currentState, transactionProcessor, _flashbotsConfig.EnablePreWarmer ? preWarmer : null); + + EthereumEcdsa ecdsa = new EthereumEcdsa(_specProvider.ChainId); + IReleaseSpec spec = _specProvider.GetSpec(parentHeader); RecoverSenderAddress(block, ecdsa, spec); @@ -230,6 +242,10 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected try { + if (!_flashbotsConfig.EnableValidation) + { + ValidateSubmissionProcessingOptions |= ProcessingOptions.NoValidation; + } Block processedBlock = blockProcessor.Process(currentState.StateRoot, suggestedBlocks, ValidateSubmissionProcessingOptions, blockReceiptsTracer)[0]; } catch (Exception e) @@ -312,7 +328,7 @@ private long GetGasLimit(BlockHeader parentHeader, long desiredGasLimit) long? targetGasLimit = desiredGasLimit; long newBlockNumber = parentHeader.Number + 1; - IReleaseSpec spec = _txProcessingEnv.SpecProvider.GetSpec(newBlockNumber, parentHeader.Timestamp); + IReleaseSpec spec = _specProvider.GetSpec(newBlockNumber, parentHeader.Timestamp); if (targetGasLimit is not null) { long maxGasLimitDifference = Math.Max(0, parentGasLimit / spec.GasLimitBoundDivisor - 1); @@ -414,21 +430,22 @@ private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, return true; } - private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransactionProcessor transactionProcessor) + private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransactionProcessor transactionProcessor, IBlockCachePreWarmer? preWarmer = null) { return new BlockProcessor( - _txProcessingEnv.SpecProvider, + _specProvider, _blockValidator, - new Consensus.Rewards.RewardCalculator(_txProcessingEnv.SpecProvider), + new Consensus.Rewards.RewardCalculator(_specProvider), new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), stateProvider, _receiptStorage, transactionProcessor, new BeaconBlockRootHandler(transactionProcessor, stateProvider), - new BlockhashStore(_txProcessingEnv.SpecProvider, stateProvider), - logManager: _txProcessingEnv.LogManager, - withdrawalProcessor: new WithdrawalProcessor(stateProvider, _txProcessingEnv.LogManager!), - receiptsRootCalculator: new ReceiptsRootCalculator() + new BlockhashStore(_specProvider, stateProvider), + logManager: _logManager, + withdrawalProcessor: new WithdrawalProcessor(stateProvider, _logManager!), + receiptsRootCalculator: new ReceiptsRootCalculator(), + preWarmer: preWarmer ); } } diff --git a/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs index 35fc68cd00c..7142d3f0182 100644 --- a/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs @@ -15,4 +15,10 @@ public interface IFlashbotsConfig : IConfig [ConfigItem(Description = "If set to true, withdrawals to the fee recipient are excluded from the balance delta", DefaultValue = "false")] public bool ExcludeWithdrawals { get; set; } + + [ConfigItem(Description = "If set to true, the pre-warmer will be enabled", DefaultValue = "false")] + public bool EnablePreWarmer { get; set; } + + [ConfigItem(Description = "If set to true, the validation will be enabled", DefaultValue = "false")] + public bool EnableValidation { get; set; } } From 6640acae5779ba8810e4f90ab1a8564192d34a3c Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 23 Dec 2024 13:58:12 +0530 Subject: [PATCH 041/113] revert dummy changes --- .../Data/BlockValidationResult.cs | 14 --------- .../Data/BuilderBlockValidationRequest.cs | 14 --------- .../ValidateBuilderSubmissionHandler.cs | 29 ++++--------------- .../Modules/Flashbots/FlashbotsRpcModule.cs | 3 -- .../Modules/Flashbots/IFlashbotsRpcModule.cs | 7 ----- 5 files changed, 5 insertions(+), 62 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs index 1e22e51da61..1a0eae8d723 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Text.Json.Serialization; -using Nethermind.Core.Crypto; using Nethermind.JsonRpc; namespace Nethermind.Flashbots.Data; @@ -46,16 +45,3 @@ public static ResultWrapper Error(string error) [JsonIgnore(Condition = JsonIgnoreCondition.Never)] public string? ValidationError { get; set; } } - -public class ResultHash -{ - public Hash256 BlockHash { get; set; } - - public Hash256 TxRoot { get; set; } - - public ResultHash(Hash256 blockHash, Hash256 txRoot) - { - BlockHash = blockHash; - TxRoot = txRoot; - } -} diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 0e816b929e8..66463d74ffc 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -3,7 +3,6 @@ using System.Text.Json.Serialization; using Nethermind.Core.Crypto; -using Nethermind.Merge.Plugin.Data; namespace Nethermind.Flashbots.Data; @@ -22,16 +21,3 @@ public class BuilderBlockValidationRequest [JsonRequired] public required SubmitBlockRequest BlockRequest { get; set; } } - -public class BuilderBlockValidationRequestHash -{ - /// - /// The block hash of the parent beacon block. - /// - /// - [JsonRequired] - public required Hash256 ParentBeaconBlockRoot { get; set; } - - [JsonRequired] - public required ExecutionPayloadV3 ExecutionPayload; -} diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index ff59fbbc990..29d6df9958e 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -71,25 +71,6 @@ public ValidateSubmissionHandler( _flashbotsConfig = flashbotsConfig; } - public Task> ValidateSubmissionHash(BuilderBlockValidationRequestHash request) - { - ExecutionPayloadV3 payload = request.ExecutionPayload; - payload.ParentBeaconBlockRoot = new Hash256(request.ParentBeaconBlockRoot); - - if (!payload.TryGetBlock(out Block? block)) - { - if (_logger.IsWarn) _logger.Warn($"Invalid block."); - return Task.FromResult(ResultWrapper.Success(new ResultHash(Keccak.Zero, Keccak.Zero))); - } - - BlockHeader header = block.Header; - Transaction[] transactions = block.Transactions; - - Hash256 txRoot = Keccak.Zero; - - return Task.FromResult(ResultWrapper.Success(new ResultHash(header.CalculateHash(), txRoot))); - } - public Task> ValidateSubmission(BuilderBlockValidationRequest request) { ExecutionPayloadV3 payload = request.BlockRequest.ExecutionPayload; @@ -120,11 +101,11 @@ public Task> ValidateSubmission(BuilderBlockValid return FlashbotsResult.Invalid(error ?? "Block validation failed"); } - // if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) - // { - // if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); - // return FlashbotsResult.Invalid(blobsError ?? "Blobs bundle validation failed"); - // } + if (block is not null && !ValidateBlobsBundle(block.Transactions, blobsBundle, out string? blobsError)) + { + if (_logger.IsWarn) _logger.Warn($"Invalid blobs bundle. Result of {payloadStr}. Error: {blobsError}"); + return FlashbotsResult.Invalid(blobsError ?? "Blobs bundle validation failed"); + } return FlashbotsResult.Valid(); diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs index bba373a7507..8f10a21fd5d 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs @@ -21,7 +21,4 @@ public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => _validateSubmissionHandler.ValidateSubmission(@params); - Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3Hash(BuilderBlockValidationRequestHash @params) => - _validateSubmissionHandler.ValidateSubmissionHash(@params); - } diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs index f26e1906903..9ee13121738 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -17,11 +17,4 @@ public interface IFlashbotsRpcModule : IRpcModule IsSharable = false, IsImplemented = true)] Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); - - // TODO: remove this method - [JsonRpcMethod( - Description = " calculate hash of the builder submissions as received by a relay", - IsSharable = false, - IsImplemented = true)] - Task> flashbots_validateBuilderSubmissionV3Hash(BuilderBlockValidationRequestHash @params); } From b73c96b539c7cd5d5450732af3c4388c388dae56 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 23 Dec 2024 13:58:58 +0530 Subject: [PATCH 042/113] remove using --- .../Modules/Flashbots/IFlashbotsRpcModule.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs index 9ee13121738..b81da13fb39 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; -using Nethermind.Core.Crypto; using Nethermind.Flashbots.Data; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules; From 50414ee94ea03df042b26bddfb52ad9d7462c014 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 30 Dec 2024 16:39:52 +0530 Subject: [PATCH 043/113] change flashbots test --- .../FlashbotsModuleTests.Setup.cs | 15 +++++++++------ src/Nethermind/Nethermind.Flashbots/Flashbots.cs | 9 +-------- .../Handlers/ValidateBuilderSubmissionHandler.cs | 8 +++----- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs index 9669157bd7c..228c76801e0 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -75,13 +75,16 @@ protected async Task CreateBlockChain( ILogManager? logManager = null) => await CreateBaseBlockChain(flashbotsConfig ?? new FlashbotsConfig(), logManager).Build(new TestSingleReleaseSpecProvider(releaseSpec ?? London.Instance)); - private IFlashbotsRpcModule CreateFlashbotsModule(MergeTestBlockChain chain, ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv) + private IFlashbotsRpcModule CreateFlashbotsModule(MergeTestBlockChain chain, ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory) { return new FlashbotsRpcModule( new ValidateSubmissionHandler( chain.HeaderValidator, + chain.BlockTree, chain.BlockValidator, - readOnlyTxProcessingEnv, + readOnlyTxProcessingEnvFactory, + chain.LogManager, + chain.SpecProvider, chain.FlashbotsConfig ) ); @@ -95,7 +98,7 @@ public class MergeTestBlockChain : TestBlockchain public IWithdrawalProcessor? WithdrawalProcessor { get; set; } - public ReadOnlyTxProcessingEnv ReadOnlyTxProcessingEnv { get; set; } + public ReadOnlyTxProcessingEnvFactory ReadOnlyTxProcessingEnvFactory { get; set; } public MergeTestBlockChain(IFlashbotsConfig flashbotsConfig, ILogManager? logManager = null) { @@ -106,15 +109,15 @@ public MergeTestBlockChain(IFlashbotsConfig flashbotsConfig, ILogManager? logMan public sealed override ILogManager LogManager { get; set; } = LimboLogs.Instance; - public ReadOnlyTxProcessingEnv CreateReadOnlyTxProcessingEnv() + public ReadOnlyTxProcessingEnvFactory CreateReadOnlyTxProcessingEnvFactory() { - ReadOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv( + ReadOnlyTxProcessingEnvFactory = new ReadOnlyTxProcessingEnvFactory( WorldStateManager, BlockTree, SpecProvider, LogManager ); - return ReadOnlyTxProcessingEnv; + return ReadOnlyTxProcessingEnvFactory; } protected override IBlockProcessor CreateBlockProcessor() diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index ce8eedc8281..1fdfff9721a 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -34,17 +34,10 @@ public Task InitRpcModules() _api.LogManager ); - ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv( - _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), - _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), - _api.SpecProvider, - _api.LogManager - ); - ValidateSubmissionHandler validateSubmissionHandler = new ValidateSubmissionHandler( _api.HeaderValidator ?? throw new ArgumentNullException(nameof(_api.HeaderValidator)), + _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), _api.BlockValidator ?? throw new ArgumentNullException(nameof(_api.BlockValidator)), - readOnlyTxProcessingEnv, readOnlyTxProcessingEnvFactory, _api.LogManager ?? throw new ArgumentNullException(nameof(_api.LogManager)), _api.SpecProvider ?? throw new ArgumentNullException(nameof(_api.SpecProvider)), diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 29d6df9958e..803ce11c543 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -35,7 +35,6 @@ public class ValidateSubmissionHandler | ProcessingOptions.IgnoreParentNotOnMainChain | ProcessingOptions.ForceProcessing | ProcessingOptions.StoreReceipts; - private readonly ReadOnlyTxProcessingEnv _txProcessingEnv; private readonly ReadOnlyTxProcessingEnvFactory _readOnlyTxProcessingEnvFactory; @@ -53,8 +52,8 @@ public class ValidateSubmissionHandler public ValidateSubmissionHandler( IHeaderValidator headerValidator, + IBlockTree blockTree, IBlockValidator blockValidator, - ReadOnlyTxProcessingEnv txProcessingEnv, ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory, ILogManager logManager, ISpecProvider specProvider, @@ -62,12 +61,11 @@ public ValidateSubmissionHandler( { _headerValidator = headerValidator; _blockValidator = blockValidator; - _txProcessingEnv = txProcessingEnv; _readOnlyTxProcessingEnvFactory = readOnlyTxProcessingEnvFactory; _specProvider = specProvider; _logManager = logManager; - _blockTree = _txProcessingEnv.BlockTree; - _logger = txProcessingEnv.LogManager!.GetClassLogger(); + _blockTree = blockTree; + _logger = logManager!.GetClassLogger(); _flashbotsConfig = flashbotsConfig; } From 71c4aa8c225b385e8f878524b695bc66a207eb77 Mon Sep 17 00:00:00 2001 From: "core-repository-dispatch-app[bot]" <173070810+core-repository-dispatch-app[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 10:10:07 +0100 Subject: [PATCH 044/113] Auto-update fast sync settings (#7957) Co-authored-by: rubo Co-authored-by: Ben Adams --- .../Nethermind.Runner/configs/base-mainnet.json | 4 ++-- .../Nethermind.Runner/configs/base-sepolia.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/chiado.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/energyweb.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/exosama.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/gnosis.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/joc-testnet.json | 6 +++--- .../Nethermind.Runner/configs/linea-mainnet.json | 8 ++++---- .../Nethermind.Runner/configs/linea-sepolia.json | 8 ++++---- src/Nethermind/Nethermind.Runner/configs/mainnet.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/op-mainnet.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/op-sepolia.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/sepolia.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/volta.json | 6 +++--- 15 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json index 10fb652a80d..dcc3aebf279 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 23700000, - "PivotHash": "0xf0688530851d54a7ab48bdada5b0c337c83f4e02c18e154fd28117ee8b24a3c1", + "PivotNumber": 24010000, + "PivotHash": "0x831cdfb4ba46281fafb2c1be0c7ecd0a9ca91316f4f93883ed1328de843c0896", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json index 236df2f2473..b803a1b43fc 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 19210000, - "PivotHash": "0xf7f365a68314983660e68c6811ea7becfc8d4dc2f3bdfc642409965fcb32b18e", + "PivotNumber": 19520000, + "PivotHash": "0x41ebcba59e2a4f6e5e2cc1776ea424ed6784000ba2fd8188ac7c23cb23563005", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.json b/src/Nethermind/Nethermind.Runner/configs/chiado.json index d133b02b9d4..324886412a8 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.json +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.json @@ -16,8 +16,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 13310000, - "PivotHash": "0x82113b3a20a9f9f8ad0f00bd64e6e4b8bc626daff7a17e1203534d51963ba19f", + "PivotNumber": 13420000, + "PivotHash": "0x3f27cab16c8b54df8d749594e437450927fcb2f420c7aa63afa1c920215ffc6c", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", "FastSyncCatchUpHeightDelta": "10000000000", "UseGethLimitsInFastBlocks": false diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb.json b/src/Nethermind/Nethermind.Runner/configs/energyweb.json index 6ddbe7327b3..2d130550054 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.json +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.json @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 33280000, - "PivotHash": "0x5301bc535f88c067b931c54c02af770b626b8c37746a4f66ecded74251ecd5a9", - "PivotTotalDifficulty": "11324597171128832064061106935329246076875696208", + "PivotNumber": 33390000, + "PivotHash": "0xcf4df44a619f42f83caa5c123031355b955b2c56ba7a3b2b68d9766ee76993cd", + "PivotTotalDifficulty": "11362028231490135295042078142146740580135625148", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama.json b/src/Nethermind/Nethermind.Runner/configs/exosama.json index 4261a33e322..3505731c171 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.json +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.json @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 13550000, - "PivotHash": "0xd7dea942bde72cdd9b3864dfb31050bda7efa747b457dec84b8141e621b94cf8", - "PivotTotalDifficulty": "4610826071778716179928725930700459264868553282", + "PivotNumber": 13670000, + "PivotHash": "0xc2ad9b50f13ddc0f96a6f5b308c662eb462e28e3c403e523f2656a8a89aa43b9", + "PivotTotalDifficulty": "4651659955809228795544330883592271450243033281", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.json b/src/Nethermind/Nethermind.Runner/configs/gnosis.json index 594362f75c1..c36335c23e9 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.json +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.json @@ -13,8 +13,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 37520000, - "PivotHash": "0xd51e0136cc8ab3f9fc9267074558e5dcc45b6410a0139b6bfa60bd4e7f51959e", + "PivotNumber": 37630000, + "PivotHash": "0x0946886e7530f480d96aa5288051dacec18fb6edb736193901d890c4b815b4fe", "PivotTotalDifficulty": "8626000110427538733349499292577475819600160930", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json index af3777b9727..5a9ee576b99 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 14920000, - "PivotHash": "0xf8213c658d5f26c6ba729229cfddb3faa9dc887ef577baa316480d4fd81ecaa3", - "PivotTotalDifficulty": "29041327" + "PivotNumber": 15040000, + "PivotHash": "0x5b7130b946ce69918c1eed9c8a231470567f2927cd346be7181fff04d2377eb6", + "PivotTotalDifficulty": "29208629" }, "Metrics": { "NodeName": "JOC-Mainnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json index fc4bb12db9f..89b30eb3e39 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 8520000, - "PivotHash": "0x37534848edaf397d3c7af09154464593eb48f87946a35238ea26d36746670f7b", - "PivotTotalDifficulty": "15205038" + "PivotNumber": 8640000, + "PivotHash": "0xe4cc87261bff1b877ac7086fb6c15606b674c8572d6b1aedd45c0d21f6564996", + "PivotTotalDifficulty": "15378420" }, "Metrics": { "NodeName": "JOC-Testnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json index 482ec5aa48a..6dc4ec6ec79 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json @@ -16,13 +16,13 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 13310000, - "PivotHash": "0x4f899c26f26ac8e85272864201f46e030ffed46372dd052998bee8463255fcff", - "PivotTotalDifficulty": "26620001", + "PivotNumber": 13600000, + "PivotHash": "0xb835bb6b7e37d43eeef5f669daaf18f8f925a58c603b20ed99273afac2d6bc1c", + "PivotTotalDifficulty": "27200001", "HeaderStateDistance": 6 }, "JsonRpc": { "Enabled": true, "Port": 8545 } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json index a34234f9798..756a183b6fb 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json @@ -16,13 +16,13 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 7090000, - "PivotHash": "0xf8e4888bd895671f2290cce1caa4ac326d896df16136476b97a3c3abdb866ada", - "PivotTotalDifficulty": "14180001", + "PivotNumber": 7300000, + "PivotHash": "0xb5be783d3492d6440fd646a4ea3c76b0d91bf31e597c463a0a236fe217ec59ec", + "PivotTotalDifficulty": "14600001", "HeaderStateDistance": 6 }, "JsonRpc": { "Enabled": true, "Port": 8545 } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.json b/src/Nethermind/Nethermind.Runner/configs/mainnet.json index cc529409d06..6da66d8db45 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.json @@ -9,8 +9,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 21403000, - "PivotHash": "0x852d706e7a6062866187e080584924298ef3a0771be4f554a6e4c42135827bbc", + "PivotNumber": 21453000, + "PivotHash": "0x26edc7632b3f2509f4b2b5bc43b2cec38db019004ffdec57a13eb5138897b3c2", "PivotTotalDifficulty": "58750003716598352816469", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json index 582796790fc..aad3991ef58 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json @@ -16,8 +16,8 @@ "AncientBodiesBarrier": 105235063, "AncientReceiptsBarrier": 105235063, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 129300000, - "PivotHash": "0x567bd9814f414b9827af6ae54c902b4bb9f4045bd6f0e2f18cec3c7806735d7c", + "PivotNumber": 129600000, + "PivotHash": "0xd06264ead4bb1a026135affe815b3b817c835f9513358e18991391c19b727eb9", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json index 08c2b45fe6a..a361b2efa53 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 21200000, - "PivotHash": "0x937bdbc55627c2c6515b1828c43a168b0ac66aee90fe9646896e514e265b6462", + "PivotNumber": 21500000, + "PivotHash": "0x4cf34352e99086e20ea35f4b226944439ec33aee26d11195428b1a9acb118a4c", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.json b/src/Nethermind/Nethermind.Runner/configs/sepolia.json index bfdb4a979d0..8dcca161e6f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.json @@ -17,8 +17,8 @@ "FastSync": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 7279000, - "PivotHash": "0x8cdb73d9696a9b066a13195818f1a490b60aa19a8bdde262dc0d8bfd51cece86", + "PivotNumber": 7327000, + "PivotHash": "0xe40a6655fec461e11c519b88a1deb09a72cd281f8891f4bef9e7ed9284aed616", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.json b/src/Nethermind/Nethermind.Runner/configs/volta.json index 4d58b61e9c8..e97f1790683 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.json +++ b/src/Nethermind/Nethermind.Runner/configs/volta.json @@ -15,9 +15,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 30290000, - "PivotHash": "0xb036d5a4e89b4bbed2c81803d8eea2f2c5e416c2ec004ba04b820c54768e37cd", - "PivotTotalDifficulty": "10307152894035226058305616859108259124625257474", + "PivotNumber": 30370000, + "PivotHash": "0x1d4bde4ad082c4fb179e539141e85b06e54ac053acb461a4f2b8983a919aa8e7", + "PivotTotalDifficulty": "10334375483388901135382686827702800581541531379", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, From eb62a450a563256ee7aaa4f7980a4594508a2587 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Mon, 23 Dec 2024 12:18:24 +0000 Subject: [PATCH 045/113] Add GasLimit to NewPayoad log (#7955) --- .../Processing/ProcessingStats.cs | 10 +++++----- .../Handlers/NewPayloadHandler.cs | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs index ce7c15307b8..0fde5c6baa9 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs @@ -214,7 +214,7 @@ void Execute() if (chunkBlocks > 1) { - _logger.Info($"Processed {block.Number - chunkBlocks + 1,10}...{block.Number,9} | {chunkMs,10:N1} ms | slot {runMs,7:N0} ms |{blockGas}"); + _logger.Info($"Processed {block.Number - chunkBlocks + 1,10}...{block.Number,9} | {chunkMs,10:N1} ms | slot {runMs,11:N0} ms |{blockGas}"); } else { @@ -241,7 +241,7 @@ void Execute() < 2000 => orangeText, _ => redText }; - _logger.Info($"Processed {block.Number,10} | {chunkColor}{chunkMs,10:N1}{resetColor} ms | slot {runMs,7:N0} ms |{blockGas}"); + _logger.Info($"Processed {block.Number,10} | {chunkColor}{chunkMs,10:N1}{resetColor} ms | slot {runMs,11:N0} ms |{blockGas}"); } string mgasPerSecondColor = (mgasPerSecond / (block.GasLimit / 1_000_000.0)) switch @@ -285,14 +285,14 @@ void Execute() var recoveryQueue = Metrics.RecoveryQueueSize; var processingQueue = Metrics.ProcessingQueueSize; - _logger.Info($" Block{(chunkBlocks > 1 ? $"s x{chunkBlocks,-9:N0} " : $"{(isMev ? " mev" : " ")} {rewards.ToDecimal(null) / weiToEth,5:N4}{BlocksConfig.GasTokenTicker,4}")}{(chunkBlocks == 1 ? mgasColor : "")} {chunkMGas,7:F2}{resetColor} MGas | {chunkTx,8:N0} txs | calls {callsColor}{chunkCalls,6:N0}{resetColor} {darkGreyText}({chunkEmptyCalls,3:N0}){resetColor} | sload {chunkSload,7:N0} | sstore {sstoreColor}{chunkSstore,6:N0}{resetColor} | create {createsColor}{chunkCreates,3:N0}{resetColor}{(_currentSelfDestructOps - _lastSelfDestructOps > 0 ? $"{darkGreyText}({-(_currentSelfDestructOps - _lastSelfDestructOps),3:N0}){resetColor}" : "")}"); + _logger.Info($" Block{(chunkBlocks > 1 ? $"s x{chunkBlocks,-9:N0} " : $"{(isMev ? " mev" : " ")} {rewards.ToDecimal(null) / weiToEth,5:N4}{BlocksConfig.GasTokenTicker,4}")}{(chunkBlocks == 1 ? mgasColor : "")} {chunkMGas,7:F2}{resetColor} MGas | {chunkTx,8:N0} txs | calls {callsColor}{chunkCalls,10:N0}{resetColor} {darkGreyText}({chunkEmptyCalls,3:N0}){resetColor} | sload {chunkSload,7:N0} | sstore {sstoreColor}{chunkSstore,6:N0}{resetColor} | create {createsColor}{chunkCreates,3:N0}{resetColor}{(_currentSelfDestructOps - _lastSelfDestructOps > 0 ? $"{darkGreyText}({-(_currentSelfDestructOps - _lastSelfDestructOps),3:N0}){resetColor}" : "")}"); if (recoveryQueue > 0 || processingQueue > 0) { - _logger.Info($" Block throughput {mgasPerSecondColor}{mgasPerSecond,11:F2}{resetColor} MGas/s{(mgasPerSecond > 1000 ? "🔥" : " ")}| {txps,10:N1} tps | {bps,7:F2} Blk/s | recover {recoveryQueue,5:N0} | process {processingQueue,5:N0}"); + _logger.Info($" Block throughput {mgasPerSecondColor}{mgasPerSecond,11:F2}{resetColor} MGas/s{(mgasPerSecond > 1000 ? "🔥" : " ")}| {txps,10:N1} tps | {bps,10:F2} Blk/s | recover {recoveryQueue,5:N0} | process {processingQueue,5:N0}"); } else { - _logger.Info($" Block throughput {mgasPerSecondColor}{mgasPerSecond,11:F2}{resetColor} MGas/s{(mgasPerSecond > 1000 ? "🔥" : " ")}| {txps,10:N1} tps | {bps,7:F2} Blk/s | exec code {resetColor} from cache {cachedContractsUsed,7:N0} |{resetColor} new {contractsAnalysed,6:N0}"); + _logger.Info($" Block throughput {mgasPerSecondColor}{mgasPerSecond,11:F2}{resetColor} MGas/s{(mgasPerSecond > 1000 ? "🔥" : " ")}| {txps,10:N1} tps | {bps,10:F2} Blk/s | exec code {resetColor} from cache {cachedContractsUsed,7:N0} |{resetColor} new {contractsAnalysed,6:N0}"); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs index e0202c101b3..895d34a5b54 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/NewPayloadHandler.cs @@ -47,6 +47,9 @@ public class NewPayloadHandler : IAsyncHandler 0 => "👆", + < 0 => "👇", + _ => " " + }; + } + /// /// Processes the execution payload and returns the /// and the hash of the last valid block. @@ -97,7 +110,9 @@ public async Task> HandleAsync(ExecutionPayload r string requestStr = $"New Block: {request}"; if (_logger.IsInfo) { - _logger.Info($"Received {requestStr}, {block.ParsedExtraData()}"); + _logger.Info($"Received {requestStr} | limit {block.Header.GasLimit,13:N0} {GetGasChange(block.Number == _lastBlockNumber + 1 ? block.Header.GasLimit : _lastBlockGasLimit)} | {block.ParsedExtraData()}"); + _lastBlockNumber = block.Number; + _lastBlockGasLimit = block.Header.GasLimit; } if (!HeaderValidator.ValidateHash(block!.Header)) From 31cfaeabdd7a6f111c5c78f9c95ad0acbbe7e384 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Mon, 23 Dec 2024 12:18:46 +0000 Subject: [PATCH 046/113] Reduce guard checks and interface calls when using ArrayPoolList (#7960) --- .../Nethermind.Crypto/KeccakRlpStream.cs | 5 -- .../Eth/FeeHistory/FeeHistoryOracle.cs | 3 +- .../P2P/SerializerTester.cs | 1 + .../Eth/V65/Eth65ProtocolHandlerTests.cs | 3 +- .../Eth/V65/PooledTxsRequestorTests.cs | 60 +++++++++++-------- .../Eth/V68/Eth68ProtocolHandlerTests.cs | 4 +- .../NodeData/GetNodeDataMessageTests.cs | 6 +- .../GetStorageRangesMessageSerializerTests.cs | 4 +- .../GetTrieNodesMessageSerializerTests.cs | 2 +- .../TrieNodesMessageSerializerTests.cs | 4 +- .../Eth/HashesMessageSerializer.cs | 4 +- .../Subprotocols/Eth/IPooledTxsRequestor.cs | 8 +-- .../Subprotocols/Eth/PooledTxsRequestor.cs | 51 +++++++--------- .../Eth/V62/Eth62ProtocolHandler.cs | 6 +- .../Messages/TransactionsMessageSerializer.cs | 4 +- .../Eth/V65/Eth65ProtocolHandler.cs | 4 +- ...ledTransactionHashesMessageSerializer68.cs | 18 +++--- .../Snap/Messages/GetStorageRangeMessage.cs | 2 +- .../GetStorageRangesMessageSerializer.cs | 26 ++++---- .../Subprotocols/Snap/SnapProtocolHandler.cs | 4 +- .../NettyRlpStream.cs | 15 +---- .../Nethermind.Serialization.Rlp/RlpStream.cs | 35 ----------- 22 files changed, 111 insertions(+), 158 deletions(-) diff --git a/src/Nethermind/Nethermind.Crypto/KeccakRlpStream.cs b/src/Nethermind/Nethermind.Crypto/KeccakRlpStream.cs index 3a943a97bed..0d049e54e8b 100644 --- a/src/Nethermind/Nethermind.Crypto/KeccakRlpStream.cs +++ b/src/Nethermind/Nethermind.Crypto/KeccakRlpStream.cs @@ -30,11 +30,6 @@ public override void Write(ReadOnlySpan bytesToWrite) _keccakHash.Update(bytesToWrite); } - public override void Write(IReadOnlyList bytesToWrite) - { - _keccakHash.Update(bytesToWrite.ToArray()); - } - public override void WriteByte(byte byteToWrite) { _keccakHash.Update(MemoryMarshal.CreateSpan(ref byteToWrite, 1)); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/FeeHistory/FeeHistoryOracle.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/FeeHistory/FeeHistoryOracle.cs index cd6a76ceda2..bccfd97e433 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/FeeHistory/FeeHistoryOracle.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/FeeHistory/FeeHistoryOracle.cs @@ -254,10 +254,11 @@ static IEnumerable CalculateGasUsed(TxReceipt[] txReceipts) : txs.Select(static tx => tx.GasLimit)); List rewardInfos = new(txs.Length); + Span gasUsedSpan = gasUsed.AsSpan(); for (int i = 0; i < txs.Length; i++) { txs[i].TryCalculatePremiumPerGas(block.BaseFeePerGas, out UInt256 premiumPerGas); - rewardInfos.Add(new RewardInfo(gasUsed[i], premiumPerGas)); + rewardInfos.Add(new RewardInfo(gasUsedSpan[i], premiumPerGas)); } rewardInfos.Sort(static (i1, i2) => i1.PremiumPerGas.CompareTo(i2.PremiumPerGas)); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs b/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs index ecb452577cc..49af7bc0457 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs @@ -50,6 +50,7 @@ public static void TestZero(IZeroMessageSerializer serializer, T message, { buffer.Release(); buffer2.Release(); + message.TryDispose(); } } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs index 2101315e42a..0da9a95c1b9 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandlerTests.cs @@ -10,6 +10,7 @@ using FluentAssertions; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -196,7 +197,7 @@ public void should_handle_NewPooledTransactionHashesMessage([Values(true, false) HandleIncomingStatusMessage(); HandleZeroMessage(msg, Eth65MessageCode.NewPooledTransactionHashes); - _pooledTxsRequestor.Received(canGossipTransactions ? 1 : 0).RequestTransactions(Arg.Any>(), Arg.Any>()); + _pooledTxsRequestor.Received(canGossipTransactions ? 1 : 0).RequestTransactions(Arg.Any>(), Arg.Any>()); } private void HandleZeroMessage(T msg, int messageCode) where T : MessageBase diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTxsRequestorTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTxsRequestorTests.cs index 6dab74e1b83..bf4b2a8fd4e 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTxsRequestorTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V65/PooledTxsRequestorTests.cs @@ -12,6 +12,9 @@ using Nethermind.TxPool; using NSubstitute; using NUnit.Framework; +using System.Runtime.InteropServices; +using Nethermind.Core.Collections; +using Nethermind.Core.Extensions; namespace Nethermind.Network.Test.P2P.Subprotocols.Eth.V65 { @@ -20,74 +23,79 @@ public class PooledTxsRequestorTests private readonly ITxPool _txPool = Substitute.For(); private readonly Action _doNothing = static msg => msg.Dispose(); private IPooledTxsRequestor _requestor; - private IReadOnlyList _request; - private IList _expected; - private IReadOnlyList _response; + private ArrayPoolList _response; + [TearDown] + public void TearDown() + { + _response?.Dispose(); + } [Test] public void filter_properly_newPooledTxHashes() { - _response = new List(); _requestor = new PooledTxsRequestor(_txPool, new TxPoolConfig()); - _requestor.RequestTransactions(_doNothing, new List { TestItem.KeccakA, TestItem.KeccakD }); + using var skipped = new ArrayPoolList(2) { TestItem.KeccakA, TestItem.KeccakD }; + _requestor.RequestTransactions(_doNothing, skipped); - _request = new List { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; - _expected = new List { TestItem.KeccakB, TestItem.KeccakC }; - _requestor.RequestTransactions(Send, _request); - _response.Should().BeEquivalentTo(_expected); + using var request = new ArrayPoolList(3) { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; + using var expected = new ArrayPoolList(3) { TestItem.KeccakB, TestItem.KeccakC }; + _requestor.RequestTransactions(Send, request); + _response.Should().BeEquivalentTo(expected); } [Test] public void filter_properly_already_pending_hashes() { - _response = new List(); _requestor = new PooledTxsRequestor(_txPool, new TxPoolConfig()); - _requestor.RequestTransactions(_doNothing, new List { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }); + using var skipped = new ArrayPoolList(3) { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; + _requestor.RequestTransactions(_doNothing, skipped); - _request = new List { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; - _requestor.RequestTransactions(Send, _request); + using var request = new ArrayPoolList(3) { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; + _requestor.RequestTransactions(Send, request); _response.Should().BeEmpty(); } [Test] public void filter_properly_discovered_hashes() { - _response = new List(); _requestor = new PooledTxsRequestor(_txPool, new TxPoolConfig()); - _request = new List { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; - _expected = new List { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; - _requestor.RequestTransactions(Send, _request); - _response.Should().BeEquivalentTo(_expected); + using var request = new ArrayPoolList(3) { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; + using var expected = new ArrayPoolList(3) { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC }; + _requestor.RequestTransactions(Send, request); + _response.Should().BeEquivalentTo(expected); } [Test] public void can_handle_empty_argument() { - _response = new List(); _requestor = new PooledTxsRequestor(_txPool, new TxPoolConfig()); - _requestor.RequestTransactions(Send, new List()); + using var skipped = new ArrayPoolList(0); + _requestor.RequestTransactions(Send, skipped); _response.Should().BeEmpty(); } [Test] public void filter_properly_hashes_present_in_hashCache() { - _response = new List(); ITxPool txPool = Substitute.For(); txPool.IsKnown(Arg.Any()).Returns(true); _requestor = new PooledTxsRequestor(txPool, new TxPoolConfig()); - _request = new List { TestItem.KeccakA, TestItem.KeccakB }; - _expected = new List { }; - _requestor.RequestTransactions(Send, _request); - _response.Should().BeEquivalentTo(_expected); + using var request = new ArrayPoolList(2) { TestItem.KeccakA, TestItem.KeccakB }; + using var expected = new ArrayPoolList(0) { }; + _requestor.RequestTransactions(Send, request); + _response.Should().BeEquivalentTo(expected); } private void Send(GetPooledTransactionsMessage msg) { - using (msg) _response = msg.Hashes.ToList(); + _response?.Dispose(); + using (msg) + { + _response = msg.Hashes.ToPooledList(); + } } } } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs index d628e6f2fb8..1e6ff9b22b9 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs @@ -125,7 +125,7 @@ public void Can_handle_NewPooledTransactions_message([Values(0, 1, 2, 100)] int HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes); _pooledTxsRequestor.Received(canGossipTransactions ? 1 : 0).RequestTransactionsEth68(Arg.Any>(), - Arg.Any>(), Arg.Any>(), Arg.Any>()); + Arg.Any>(), Arg.Any>(), Arg.Any>()); } [TestCase(true)] @@ -163,7 +163,7 @@ public void Should_process_huge_transaction() HandleZeroMessage(msg, Eth68MessageCode.NewPooledTransactionHashes); _pooledTxsRequestor.Received(1).RequestTransactionsEth68(Arg.Any>(), - Arg.Any>(), Arg.Any>(), Arg.Any>()); + Arg.Any>(), Arg.Any>(), Arg.Any>()); } [TestCase(1)] diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs index 3338e376b64..a0d1d6b6680 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/NodeData/GetNodeDataMessageTests.cs @@ -21,7 +21,7 @@ public class GetNodeDataMessageTests public void Sets_values_from_constructor_argument() { Hash256[] keys = { TestItem.KeccakA, TestItem.KeccakB }; - GetNodeDataMessage message = new(keys.ToPooledList()); + using GetNodeDataMessage message = new(keys.ToPooledList()); keys.Should().BeEquivalentTo(message.Hashes); } @@ -34,7 +34,7 @@ public void Throws_on_null_argument() [Test] public void To_string() { - GetNodeDataMessage message = new(ArrayPoolList.Empty()); + using GetNodeDataMessage message = new(ArrayPoolList.Empty()); _ = message.ToString(); } @@ -42,7 +42,7 @@ public void To_string() public void Packet_type_and_protocol_are_correct() { Hash256[] keys = { TestItem.KeccakA, TestItem.KeccakB }; - GetNodeDataMessage message = new(keys.ToPooledList()); + using GetNodeDataMessage message = new(keys.ToPooledList()); message.PacketType.Should().Be(NodeDataMessageCode.GetNodeData); message.Protocol.Should().Be(Protocol.NodeData); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs index 2ff36f94ab6..dc18743e1e7 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializerTests.cs @@ -22,7 +22,7 @@ public void Roundtrip_Many() GetStorageRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - StoragetRange = new() + StorageRange = new() { RootHash = TestItem.KeccakA, Accounts = TestItem.Keccaks.Select(static k => new PathWithAccount(k, null)).ToPooledList(TestItem.Keccaks.Length), @@ -43,7 +43,7 @@ public void Roundtrip_Empty() GetStorageRangeMessage msg = new() { RequestId = MessageConstants.Random.NextLong(), - StoragetRange = new() + StorageRange = new() { RootHash = Keccak.OfAnEmptyString, Accounts = ArrayPoolList.Empty(), diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs index 246ec02169f..dfaa9be7109 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializerTests.cs @@ -98,7 +98,7 @@ public void NullPathGroup() GetTrieNodesMessageSerializer serializer = new(); - GetTrieNodesMessage? msg = serializer.Deserialize(data); + using GetTrieNodesMessage? msg = serializer.Deserialize(data); byte[] recode = serializer.Serialize(msg); recode.Should().BeEquivalentTo(data); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs index 8f39b2a721b..7f16e8267e3 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializerTests.cs @@ -15,7 +15,7 @@ public class TrieNodesMessageSerializerTests [Test] public void Roundtrip() { - ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; + using ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; TrieNodesMessage message = new(data); @@ -27,7 +27,7 @@ public void Roundtrip() [Test] public void RoundtripWithCorrectLength() { - ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; + using ArrayPoolList data = new(2) { new byte[] { 0xde, 0xad, 0xc0, 0xde }, new byte[] { 0xfe, 0xed } }; TrieNodesMessage message = new(data); message.RequestId = 1; diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs index b5b34e51ee0..3e19519d884 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/HashesMessageSerializer.cs @@ -40,9 +40,9 @@ public void Serialize(IByteBuffer byteBuffer, T message) RlpStream rlpStream = new NettyRlpStream(byteBuffer); rlpStream.StartSequence(contentLength); - for (int i = 0; i < message.Hashes.Count; i++) + foreach (Hash256 hash in message.Hashes.AsSpan()) { - rlpStream.Encode(message.Hashes[i]); + rlpStream.Encode(hash); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/IPooledTxsRequestor.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/IPooledTxsRequestor.cs index b3018e51e55..26f443961a5 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/IPooledTxsRequestor.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/IPooledTxsRequestor.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Collections.Generic; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Network.P2P.Subprotocols.Eth.V65.Messages; @@ -10,8 +10,8 @@ namespace Nethermind.Network.P2P.Subprotocols.Eth { public interface IPooledTxsRequestor { - void RequestTransactions(Action send, IReadOnlyList hashes); - void RequestTransactionsEth66(Action send, IReadOnlyList hashes); - void RequestTransactionsEth68(Action send, IReadOnlyList hashes, IReadOnlyList sizes, IReadOnlyList types); + void RequestTransactions(Action send, IOwnedReadOnlyList hashes); + void RequestTransactionsEth66(Action send, IOwnedReadOnlyList hashes); + void RequestTransactionsEth68(Action send, IOwnedReadOnlyList hashes, IOwnedReadOnlyList sizes, IOwnedReadOnlyList types); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs index 796b5c89d79..f0d77bf2694 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs @@ -27,15 +27,15 @@ public PooledTxsRequestor(ITxPool txPool, ITxPoolConfig txPoolConfig) _blobSupportEnabled = txPoolConfig.BlobsSupport.IsEnabled(); } - public void RequestTransactions(Action send, IReadOnlyList hashes) + public void RequestTransactions(Action send, IOwnedReadOnlyList hashes) { - ArrayPoolList discoveredTxHashes = AddMarkUnknownHashes(hashes); + ArrayPoolList discoveredTxHashes = AddMarkUnknownHashes(hashes.AsSpan()); RequestPooledTransactions(send, discoveredTxHashes); } - public void RequestTransactionsEth66(Action send, IReadOnlyList hashes) + public void RequestTransactionsEth66(Action send, IOwnedReadOnlyList hashes) { - ArrayPoolList discoveredTxHashes = AddMarkUnknownHashes(hashes); + ArrayPoolList discoveredTxHashes = AddMarkUnknownHashes(hashes.AsSpan()); if (discoveredTxHashes.Count <= MaxNumberOfTxsInOneMsg) { @@ -56,41 +56,44 @@ public void RequestTransactionsEth66(Action send, IReadOnlyList hashes, IReadOnlyList sizes, IReadOnlyList types) + public void RequestTransactionsEth68(Action send, IOwnedReadOnlyList hashes, IOwnedReadOnlyList sizes, IOwnedReadOnlyList types) { - using ArrayPoolList<(Hash256 Hash, byte Type, int Size)> discoveredTxHashesAndSizes = AddMarkUnknownHashesEth68(hashes, sizes, types); + using ArrayPoolList<(Hash256 Hash, byte Type, int Size)> discoveredTxHashesAndSizes = AddMarkUnknownHashesEth68(hashes.AsSpan(), sizes.AsSpan(), types.AsSpan()); if (discoveredTxHashesAndSizes.Count == 0) return; int packetSizeLeft = TransactionsMessage.MaxPacketSize; ArrayPoolList hashesToRequest = new(discoveredTxHashesAndSizes.Count); - for (int i = 0; i < discoveredTxHashesAndSizes.Count; i++) + var discoveredCount = discoveredTxHashesAndSizes.Count; + var toRequestCount = 0; + foreach ((Hash256 hash, byte type, int size) in discoveredTxHashesAndSizes.AsSpan()) { - int txSize = discoveredTxHashesAndSizes[i].Size; - TxType txType = (TxType)discoveredTxHashesAndSizes[i].Type; + int txSize = size; + TxType txType = (TxType)type; - if (txSize > packetSizeLeft && hashesToRequest.Count > 0) + if (txSize > packetSizeLeft && toRequestCount > 0) { RequestPooledTransactionsEth66(send, hashesToRequest); - hashesToRequest = new ArrayPoolList(discoveredTxHashesAndSizes.Count); + hashesToRequest = new ArrayPoolList(discoveredCount); packetSizeLeft = TransactionsMessage.MaxPacketSize; + toRequestCount = 0; } if (_blobSupportEnabled || txType != TxType.Blob) { - hashesToRequest.Add(discoveredTxHashesAndSizes[i].Hash); + hashesToRequest.Add(hash); packetSizeLeft -= txSize; + toRequestCount++; } } RequestPooledTransactionsEth66(send, hashesToRequest); } - private ArrayPoolList AddMarkUnknownHashes(IReadOnlyList hashes) + private ArrayPoolList AddMarkUnknownHashes(ReadOnlySpan hashes) { - int count = hashes.Count; - ArrayPoolList discoveredTxHashes = new ArrayPoolList(count); - for (int i = 0; i < count; i++) + ArrayPoolList discoveredTxHashes = new ArrayPoolList(hashes.Length); + for (int i = 0; i < hashes.Length; i++) { Hash256 hash = hashes[i]; if (!_txPool.IsKnown(hash) && _pendingHashes.Set(hash)) @@ -102,11 +105,10 @@ private ArrayPoolList AddMarkUnknownHashes(IReadOnlyList hashe return discoveredTxHashes; } - private ArrayPoolList<(Hash256, byte, int)> AddMarkUnknownHashesEth68(IReadOnlyList hashes, IReadOnlyList sizes, IReadOnlyList types) + private ArrayPoolList<(Hash256, byte, int)> AddMarkUnknownHashesEth68(ReadOnlySpan hashes, ReadOnlySpan sizes, ReadOnlySpan types) { - int count = hashes.Count; - ArrayPoolList<(Hash256, byte, int)> discoveredTxHashesAndSizes = new(count); - for (int i = 0; i < count; i++) + ArrayPoolList<(Hash256, byte, int)> discoveredTxHashesAndSizes = new(hashes.Length); + for (int i = 0; i < hashes.Length; i++) { Hash256 hash = hashes[i]; if (!_txPool.IsKnown(hash) && !_txPool.ContainsTx(hash, (TxType)types[i]) && _pendingHashes.Set(hash)) @@ -120,14 +122,7 @@ private ArrayPoolList AddMarkUnknownHashes(IReadOnlyList hashe private static void RequestPooledTransactions(Action send, IOwnedReadOnlyList hashesToRequest) { - if (hashesToRequest.Count > 0) - { - send(new(hashesToRequest)); - } - else - { - hashesToRequest.Dispose(); - } + send(new(hashesToRequest)); } private static void RequestPooledTransactionsEth66(Action send, IOwnedReadOnlyList hashesToRequest) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs index db427262f5f..d14cc6ba3fc 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs @@ -261,12 +261,12 @@ protected void Handle(TransactionsMessage msg) private ValueTask HandleSlow((IOwnedReadOnlyList txs, int startIndex) request, CancellationToken cancellationToken) { IOwnedReadOnlyList transactions = request.txs; + ReadOnlySpan transactionsSpan = transactions.AsSpan(); try { int startIdx = request.startIndex; bool isTrace = Logger.IsTrace; - int count = transactions.Count; - for (int i = startIdx; i < count; i++) + for (int i = startIdx; i < transactionsSpan.Length; i++) { if (cancellationToken.IsCancellationRequested) { @@ -275,7 +275,7 @@ private ValueTask HandleSlow((IOwnedReadOnlyList txs, int startInde return ValueTask.CompletedTask; } - PrepareAndSubmitTransaction(transactions[i], isTrace); + PrepareAndSubmitTransaction(transactionsSpan[i], isTrace); } transactions.Dispose(); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs index 94366d508f7..33c633924d8 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/TransactionsMessageSerializer.cs @@ -19,9 +19,9 @@ public void Serialize(IByteBuffer byteBuffer, TransactionsMessage message) NettyRlpStream nettyRlpStream = new(byteBuffer); nettyRlpStream.StartSequence(contentLength); - for (int i = 0; i < message.Transactions.Count; i++) + foreach (Transaction tx in message.Transactions.AsSpan()) { - nettyRlpStream.Encode(message.Transactions[i], RlpBehaviors.InMempoolForm); + nettyRlpStream.Encode(tx, RlpBehaviors.InMempoolForm); } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs index 919b817e5c2..64bba16adee 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V65/Eth65ProtocolHandler.cs @@ -130,11 +130,11 @@ internal Task FulfillPooledTransactionsRequest(GetPoo ArrayPoolList txsToSend = new(msg.Hashes.Count); int packetSizeLeft = TransactionsMessage.MaxPacketSize; - for (int i = 0; i < msg.Hashes.Count; i++) + foreach (Hash256 hash in msg.Hashes.AsSpan()) { if (cancellationToken.IsCancellationRequested) break; - if (_txPool.TryGetPendingTransaction(msg.Hashes[i], out Transaction tx)) + if (_txPool.TryGetPendingTransaction(hash, out Transaction tx)) { int txSize = tx.GetLength(); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs index e74239a702f..64e80a7bd69 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V68/Messages/NewPooledTransactionHashesMessageSerializer68.cs @@ -24,15 +24,15 @@ public NewPooledTransactionHashesMessage68 Deserialize(IByteBuffer byteBuffer) public void Serialize(IByteBuffer byteBuffer, NewPooledTransactionHashesMessage68 message) { int sizesLength = 0; - for (int i = 0; i < message.Sizes.Count; i++) + foreach (int size in message.Sizes.AsSpan()) { - sizesLength += Rlp.LengthOf(message.Sizes[i]); + sizesLength += Rlp.LengthOf(size); } int hashesLength = 0; - for (int i = 0; i < message.Hashes.Count; i++) + foreach (Hash256 hash in message.Hashes.AsSpan()) { - hashesLength += Rlp.LengthOf(message.Hashes[i]); + hashesLength += Rlp.LengthOf(hash); } int totalSize = Rlp.LengthOf(message.Types) + Rlp.LengthOfSequence(sizesLength) + Rlp.LengthOfSequence(hashesLength); @@ -42,18 +42,18 @@ public void Serialize(IByteBuffer byteBuffer, NewPooledTransactionHashesMessage6 RlpStream rlpStream = new NettyRlpStream(byteBuffer); rlpStream.StartSequence(totalSize); - rlpStream.Encode(message.Types); + rlpStream.Encode(message.Types.AsSpan()); rlpStream.StartSequence(sizesLength); - for (int i = 0; i < message.Sizes.Count; ++i) + foreach (int size in message.Sizes.AsSpan()) { - rlpStream.Encode(message.Sizes[i]); + rlpStream.Encode(size); } rlpStream.StartSequence(hashesLength); - for (int i = 0; i < message.Hashes.Count; ++i) + foreach (Hash256 hash in message.Hashes.AsSpan()) { - rlpStream.Encode(message.Hashes[i]); + rlpStream.Encode(hash); } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangeMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangeMessage.cs index a03b4f4015e..093f18cae0a 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangeMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangeMessage.cs @@ -9,7 +9,7 @@ public class GetStorageRangeMessage : SnapMessageBase { public override int PacketType => SnapMessageCode.GetStorageRanges; - public StorageRange StoragetRange { get; set; } + public StorageRange StorageRange { get; set; } /// /// Soft limit at which to stop returning data diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs index 85742375261..238adab58c3 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetStorageRangesMessageSerializer.cs @@ -16,10 +16,10 @@ public override void Serialize(IByteBuffer byteBuffer, GetStorageRangeMessage me NettyRlpStream rlpStream = GetRlpStreamAndStartSequence(byteBuffer, message); rlpStream.Encode(message.RequestId); - rlpStream.Encode(message.StoragetRange.RootHash); - rlpStream.Encode(message.StoragetRange.Accounts.Select(static a => a.Path).ToArray()); // TODO: optimize this - rlpStream.Encode(message.StoragetRange.StartingHash); - rlpStream.Encode(message.StoragetRange.LimitHash); + rlpStream.Encode(message.StorageRange.RootHash); + rlpStream.Encode(message.StorageRange.Accounts.Select(static a => a.Path).ToArray()); // TODO: optimize this + rlpStream.Encode(message.StorageRange.StartingHash); + rlpStream.Encode(message.StorageRange.LimitHash); rlpStream.Encode(message.ResponseBytes); } @@ -30,11 +30,11 @@ protected override GetStorageRangeMessage Deserialize(RlpStream rlpStream) message.RequestId = rlpStream.DecodeLong(); - message.StoragetRange = new(); - message.StoragetRange.RootHash = rlpStream.DecodeKeccak(); - message.StoragetRange.Accounts = rlpStream.DecodeArrayPoolList(DecodePathWithRlpData); - message.StoragetRange.StartingHash = rlpStream.DecodeKeccak(); - message.StoragetRange.LimitHash = rlpStream.DecodeKeccak(); + message.StorageRange = new(); + message.StorageRange.RootHash = rlpStream.DecodeKeccak(); + message.StorageRange.Accounts = rlpStream.DecodeArrayPoolList(DecodePathWithRlpData); + message.StorageRange.StartingHash = rlpStream.DecodeKeccak(); + message.StorageRange.LimitHash = rlpStream.DecodeKeccak(); message.ResponseBytes = rlpStream.DecodeLong(); return message; @@ -48,10 +48,10 @@ private PathWithAccount DecodePathWithRlpData(RlpStream stream) public override int GetLength(GetStorageRangeMessage message, out int contentLength) { contentLength = Rlp.LengthOf(message.RequestId); - contentLength += Rlp.LengthOf(message.StoragetRange.RootHash); - contentLength += Rlp.LengthOf(message.StoragetRange.Accounts.Select(static a => a.Path).ToArray(), true); // TODO: optimize this - contentLength += Rlp.LengthOf(message.StoragetRange.StartingHash); - contentLength += Rlp.LengthOf(message.StoragetRange.LimitHash); + contentLength += Rlp.LengthOf(message.StorageRange.RootHash); + contentLength += Rlp.LengthOf(message.StorageRange.Accounts.Select(static a => a.Path).ToArray(), true); // TODO: optimize this + contentLength += Rlp.LengthOf(message.StorageRange.StartingHash); + contentLength += Rlp.LengthOf(message.StorageRange.LimitHash); contentLength += Rlp.LengthOf(message.ResponseBytes); return Rlp.LengthOfSequence(contentLength); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs index 112bcd1ab82..bf5c53388a7 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs @@ -255,7 +255,7 @@ private StorageRangeMessage FulfillStorageRangeMessage(GetStorageRangeMessage ge Proofs = ArrayPoolList.Empty(), Slots = ArrayPoolList>.Empty(), }; - StorageRange? storageRange = getStorageRangeMessage.StoragetRange; + StorageRange? storageRange = getStorageRangeMessage.StorageRange; (IOwnedReadOnlyList>? ranges, IOwnedReadOnlyList proofs) = SyncServer.GetStorageRanges(storageRange.RootHash, storageRange.Accounts, storageRange.StartingHash, storageRange.LimitHash, getStorageRangeMessage.ResponseBytes, cancellationToken); StorageRangeMessage? response = new() { Proofs = proofs, Slots = ranges }; @@ -286,7 +286,7 @@ public async Task GetStorageRange(StorageRange range, Cancellati StorageRangeMessage response = await _requestSizer.MeasureLatency(bytesLimit => SendRequest(new GetStorageRangeMessage() { - StoragetRange = range, + StorageRange = range, ResponseBytes = bytesLimit }, _getStorageRangeRequests, token)); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs index 652a3dded3b..e7aed1c2846 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using DotNetty.Buffers; using DotNetty.Common.Utilities; +using Nethermind.Core.Collections; namespace Nethermind.Serialization.Rlp { @@ -32,20 +33,6 @@ public override void Write(ReadOnlySpan bytesToWrite) _buffer.SetWriterIndex(newWriterIndex); } - public override void Write(IReadOnlyList bytesToWrite) - { - _buffer.EnsureWritable(bytesToWrite.Count); - Span target = - _buffer.Array.AsSpan(_buffer.ArrayOffset + _buffer.WriterIndex, bytesToWrite.Count); - for (int i = 0; i < bytesToWrite.Count; ++i) - { - target[i] = bytesToWrite[i]; - } - - int newWriterIndex = _buffer.WriterIndex + bytesToWrite.Count; - _buffer.SetWriterIndex(newWriterIndex); - } - public override void WriteByte(byte byteToWrite) { _buffer.EnsureWritable(1); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs index c7300497dac..052abf998d2 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs @@ -183,15 +183,6 @@ public virtual void Write(ReadOnlySpan bytesToWrite) _position += bytesToWrite.Length; } - public virtual void Write(IReadOnlyList bytesToWrite) - { - for (int i = 0; i < bytesToWrite.Count; ++i) - { - Data[_position + i] = bytesToWrite[i]; - } - Position += bytesToWrite.Count; - } - protected virtual string Description => Data.AsSpan(0, Math.Min(Rlp.DebugMessageContentLength, Length)).ToHexString() ?? "0x"; @@ -594,32 +585,6 @@ public void Encode(ReadOnlySpan input) } } - public void Encode(IReadOnlyList input) - { - if (input.Count == 0) - { - WriteByte(EmptyArrayByte); - } - else if (input.Count == 1 && input[0] < 128) - { - WriteByte(input[0]); - } - else if (input.Count < 56) - { - byte smallPrefix = (byte)(input.Count + 128); - WriteByte(smallPrefix); - Write(input); - } - else - { - int lengthOfLength = Rlp.LengthOfLength(input.Count); - byte prefix = (byte)(183 + lengthOfLength); - WriteByte(prefix); - WriteEncodedLength(input.Count); - Write(input); - } - } - public void Encode(byte[][] arrays) { int itemsLength = 0; From e9655659b61211ddd87afd42e68a7506e66e1838 Mon Sep 17 00:00:00 2001 From: Ruben Buniatyan Date: Tue, 24 Dec 2024 00:33:41 +0100 Subject: [PATCH 047/113] Update Nethermind.Numerics.Int256 package (#7965) --- src/Nethermind/Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props index f3cb0784482..8a9ba749697 100644 --- a/src/Nethermind/Directory.Packages.props +++ b/src/Nethermind/Directory.Packages.props @@ -54,7 +54,7 @@ - + From cd000fec3a76bd492b5bc5d09edb9962ca476f7d Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 24 Dec 2024 07:58:26 +0800 Subject: [PATCH 048/113] Refactor/move prewarm out of tx env base (#7963) --- .../Processing/OverridableTxProcessingEnv.cs | 7 ++--- .../Processing/ReadOnlyTxProcessingEnv.cs | 31 +++++++++++++------ .../Processing/ReadOnlyTxProcessingEnvBase.cs | 18 +++++------ .../ReadOnlyTxProcessingEnvFactory.cs | 30 +++++++++++++++--- .../SimulateReadOnlyBlocksProcessingEnv.cs | 2 +- .../OptimismOverridableTxProcessingEnv.cs | 5 ++- .../OptimismReadOnlyTxProcessingEnv.cs | 6 ++-- .../TaikoReadOnlyTxProcessingEnv.cs | 8 ++--- .../TaikoReadOnlyTxProcessingEnvFactory.cs | 5 ++- 9 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs index da0f252c160..91bebb95d24 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs @@ -28,13 +28,12 @@ public OverridableTxProcessingEnv( OverridableWorldStateManager worldStateManager, IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, - ILogManager? logManager, - IWorldState? worldStateToWarmUp = null - ) : base(worldStateManager, readOnlyBlockTree, specProvider, logManager, worldStateToWarmUp) + ILogManager? logManager + ) : base(worldStateManager.GlobalStateReader, worldStateManager.CreateResettableWorldState(), readOnlyBlockTree, specProvider, logManager) { WorldStateManager = worldStateManager; StateProvider = (OverridableWorldState)base.StateProvider; - CodeInfoRepository = new(new CodeInfoRepository((worldStateToWarmUp as IPreBlockCaches)?.Caches.PrecompileCache)); + CodeInfoRepository = new(new CodeInfoRepository()); Machine = new VirtualMachine(BlockhashProvider, specProvider, CodeInfoRepository, logManager); _transactionProcessorLazy = new(CreateTransactionProcessor); } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index 5e7d4ea28da..0edf4a1f249 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -30,25 +30,36 @@ protected ITransactionProcessor TransactionProcessor public IVirtualMachine Machine { get; } public ICodeInfoRepository CodeInfoRepository { get; } + public ReadOnlyTxProcessingEnv( IWorldStateManager worldStateManager, - IBlockTree blockTree, - ISpecProvider? specProvider, - ILogManager? logManager, - IWorldState? worldStateToWarmUp = null) - : this(worldStateManager, blockTree.AsReadOnly(), specProvider, logManager, worldStateToWarmUp) + IReadOnlyBlockTree readOnlyBlockTree, + ISpecProvider specProvider, + ILogManager logManager, + IWorldState worldStateToWarmUp + ) : this(worldStateManager.GlobalStateReader, worldStateManager.CreateResettableWorldState(worldStateToWarmUp), new CodeInfoRepository((worldStateToWarmUp as IPreBlockCaches)?.Caches.PrecompileCache), readOnlyBlockTree, specProvider, logManager) { } public ReadOnlyTxProcessingEnv( IWorldStateManager worldStateManager, IReadOnlyBlockTree readOnlyBlockTree, - ISpecProvider? specProvider, - ILogManager? logManager, - IWorldState? worldStateToWarmUp = null - ) : base(worldStateManager, readOnlyBlockTree, specProvider, logManager, worldStateToWarmUp) + ISpecProvider specProvider, + ILogManager logManager + ) : this(worldStateManager.GlobalStateReader, worldStateManager.CreateResettableWorldState(), new CodeInfoRepository(), readOnlyBlockTree, specProvider, logManager) + { + } + + private ReadOnlyTxProcessingEnv( + IStateReader stateReader, + IWorldState stateProvider, + ICodeInfoRepository codeInfoRepository, + IReadOnlyBlockTree readOnlyBlockTree, + ISpecProvider specProvider, + ILogManager logManager + ) : base(stateReader, stateProvider, readOnlyBlockTree, specProvider, logManager) { - CodeInfoRepository = new CodeInfoRepository((worldStateToWarmUp as IPreBlockCaches)?.Caches.PrecompileCache); + CodeInfoRepository = codeInfoRepository; Machine = new VirtualMachine(BlockhashProvider, specProvider, CodeInfoRepository, logManager); BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree)); BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs index 058aca9f9c2..bcda8d98798 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs @@ -18,22 +18,20 @@ public class ReadOnlyTxProcessingEnvBase public IBlockhashProvider BlockhashProvider { get; protected set; } public ISpecProvider SpecProvider { get; } - public ILogManager? LogManager { get; set; } + protected ILogManager LogManager { get; } protected ReadOnlyTxProcessingEnvBase( - IWorldStateManager worldStateManager, + IStateReader stateReader, + IWorldState stateProvider, IBlockTree readOnlyBlockTree, - ISpecProvider? specProvider, - ILogManager? logManager, - IWorldState? worldStateToWarmUp = null + ISpecProvider specProvider, + ILogManager logManager ) { - ArgumentNullException.ThrowIfNull(specProvider); - ArgumentNullException.ThrowIfNull(worldStateManager); SpecProvider = specProvider; - StateReader = worldStateManager.GlobalStateReader; - StateProvider = worldStateManager.CreateResettableWorldState(worldStateToWarmUp); - BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree)); + StateReader = stateReader; + StateProvider = stateProvider; + BlockTree = readOnlyBlockTree; BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); LogManager = logManager; } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs index 4ec2703d6b1..95dd55645de 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvFactory.cs @@ -3,6 +3,7 @@ using Nethermind.Blockchain; using Nethermind.Core.Specs; +using Nethermind.Evm; using Nethermind.Evm.TransactionProcessing; using Nethermind.Logging; using Nethermind.State; @@ -12,19 +13,38 @@ namespace Nethermind.Consensus.Processing; public class ReadOnlyTxProcessingEnvFactory( IWorldStateManager worldStateManager, IReadOnlyBlockTree readOnlyBlockTree, - ISpecProvider? specProvider, - ILogManager? logManager, + ISpecProvider specProvider, + ILogManager logManager, IWorldState? worldStateToWarmUp = null) : IReadOnlyTxProcessingEnvFactory { public ReadOnlyTxProcessingEnvFactory( IWorldStateManager worldStateManager, IBlockTree blockTree, - ISpecProvider? specProvider, - ILogManager? logManager, + ISpecProvider specProvider, + ILogManager logManager, IWorldState? worldStateToWarmUp = null) : this(worldStateManager, blockTree.AsReadOnly(), specProvider, logManager, worldStateToWarmUp) { } - public IReadOnlyTxProcessorSource Create() => new ReadOnlyTxProcessingEnv(worldStateManager, readOnlyBlockTree, specProvider, logManager, worldStateToWarmUp); + public IReadOnlyTxProcessorSource Create() + { + if (worldStateToWarmUp is null) + { + return new ReadOnlyTxProcessingEnv( + worldStateManager, + readOnlyBlockTree, + specProvider, + logManager); + } + else + { + return new ReadOnlyTxProcessingEnv( + worldStateManager, + readOnlyBlockTree, + specProvider, + logManager, + worldStateToWarmUp); + } + } } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs index 151f64efb11..8a5b31657b7 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs @@ -58,7 +58,7 @@ public SimulateReadOnlyBlocksProcessingEnv( ISpecProvider specProvider, ILogManager? logManager = null, bool validate = false) - : base(worldStateManager, blockTree, specProvider, logManager) + : base(worldStateManager.GlobalStateReader, worldStateManager.CreateResettableWorldState(), blockTree, specProvider, logManager) { ReadOnlyBlockTree = baseBlockTree; DbProvider = readOnlyDbProvider; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs b/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs index 9e06be1ddcd..76ff5c8e5c2 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs @@ -18,9 +18,8 @@ public class OptimismOverridableTxProcessingEnv( ISpecProvider specProvider, ILogManager logManager, IL1CostHelper l1CostHelper, - IOptimismSpecHelper opSpecHelper, - IWorldState? worldStateToWarmUp = null) - : OverridableTxProcessingEnv(worldStateManager, readOnlyBlockTree, specProvider, logManager, worldStateToWarmUp) + IOptimismSpecHelper opSpecHelper) + : OverridableTxProcessingEnv(worldStateManager, readOnlyBlockTree, specProvider, logManager) { protected override ITransactionProcessor CreateTransactionProcessor() { diff --git a/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs index b374b105bed..78d5b9a08a5 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs @@ -18,13 +18,11 @@ public class OptimismReadOnlyTxProcessingEnv( ISpecProvider specProvider, ILogManager logManager, IL1CostHelper l1CostHelper, - IOptimismSpecHelper opSpecHelper, - IWorldState? worldStateToWarmUp = null) : ReadOnlyTxProcessingEnv( + IOptimismSpecHelper opSpecHelper) : ReadOnlyTxProcessingEnv( worldStateManager, readOnlyBlockTree, specProvider, - logManager, - worldStateToWarmUp + logManager ) { protected override ITransactionProcessor CreateTransactionProcessor() diff --git a/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs index 51ec8c5cde2..faf0a5242dd 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs @@ -14,14 +14,12 @@ public class TaikoReadOnlyTxProcessingEnv( OverridableWorldStateManager worldStateManager, IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, - ILogManager logManager, - IWorldState? worldStateToWarmUp = null) : OverridableTxProcessingEnv( + ILogManager logManager) : OverridableTxProcessingEnv( worldStateManager, readOnlyBlockTree, specProvider, - logManager, - worldStateToWarmUp - ) + logManager +) { protected override ITransactionProcessor CreateTransactionProcessor() => new TaikoTransactionProcessor(SpecProvider, StateProvider, Machine, CodeInfoRepository, LogManager); diff --git a/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnvFactory.cs b/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnvFactory.cs index 48c15a34936..73bbeefa235 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnvFactory.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnvFactory.cs @@ -12,8 +12,7 @@ public class TaikoReadOnlyTxProcessingEnvFactory( OverridableWorldStateManager worldStateManager, IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, - ILogManager logManager, - IWorldState? worldStateToWarmUp = null) + ILogManager logManager) { - public TaikoReadOnlyTxProcessingEnv Create() => new(worldStateManager, readOnlyBlockTree, specProvider, logManager, worldStateToWarmUp); + public TaikoReadOnlyTxProcessingEnv Create() => new(worldStateManager, readOnlyBlockTree, specProvider, logManager); } From f8ed4278d3d59a494140864d7e00a531178613f7 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 24 Dec 2024 14:17:49 +0800 Subject: [PATCH 049/113] Set minimum state pivot to be at least the block after (#7949) Co-authored-by: Ben Adams --- .../IContainerSynchronizerTestExtensions.cs | 2 +- .../SnapSync/ProgressTrackerTests.cs | 6 +++--- .../SnapSync/StateSyncPivotTest.cs | 17 ++++++++++------- .../FastSync/StateSyncPivot.cs | 8 +++++++- .../ParallelSync/SyncFeed.cs | 5 +++++ .../SnapSync/ProgressTracker.cs | 6 ++++++ 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs b/src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs index 5622a96675f..9eb5af8a2a9 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/IContainerSynchronizerTestExtensions.cs @@ -15,7 +15,7 @@ public static class IContainerSynchronizerTestExtensions public static ContainerBuilder WithSuggestedHeaderOfStateRoot(this ContainerBuilder builder, Hash256 stateRoot) { IBlockTree blockTree = Substitute.For(); - BlockHeader header = Build.A.BlockHeader.WithStateRoot(stateRoot).TestObject; + BlockHeader header = Build.A.BlockHeader.WithStateRoot(stateRoot).WithNumber(1).TestObject; blockTree.FindHeader(Arg.Any()).Returns(header); blockTree.BestSuggestedHeader.Returns(header); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs index bbb039b8402..d7d4642918c 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs @@ -142,9 +142,9 @@ public void Will_deque_storage_request_if_high() [Test] public void Will_mark_progress_and_flush_when_finished() { - BlockTree blockTree = Build.A.BlockTree().WithBlocks(Build.A.Block + BlockTree blockTree = Build.A.BlockTree() .WithStateRoot(Keccak.EmptyTreeHash) - .TestObject).TestObject; + .OfChainLength(2).TestObject; TestMemDb memDb = new(); SyncConfig syncConfig = new TestSyncConfig() { SnapSyncAccountRangePartitionCount = 1 }; using ProgressTracker progressTracker = new(memDb, syncConfig, new StateSyncPivot(blockTree, syncConfig, LimboLogs.Instance), LimboLogs.Instance); @@ -163,7 +163,7 @@ public void Will_mark_progress_and_flush_when_finished() private ProgressTracker CreateProgressTracker(int accountRangePartition = 1) { - BlockTree blockTree = Build.A.BlockTree().WithBlocks(Build.A.Block.WithStateRoot(Keccak.EmptyTreeHash).TestObject).TestObject; + BlockTree blockTree = Build.A.BlockTree().WithStateRoot(Keccak.EmptyTreeHash).OfChainLength(2).TestObject; SyncConfig syncConfig = new TestSyncConfig() { SnapSyncAccountRangePartitionCount = accountRangePartition }; return new(new MemDb(), syncConfig, new StateSyncPivot(blockTree, syncConfig, LimboLogs.Instance), LimboLogs.Instance); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs index 08879df8b2f..1e2e6e187e7 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs @@ -3,7 +3,6 @@ using FluentAssertions; using Nethermind.Blockchain; -using Nethermind.Blockchain.Synchronization; using Nethermind.Core.Test.Builders; using Nethermind.Logging; using NSubstitute; @@ -13,16 +12,18 @@ namespace Nethermind.Synchronization.Test.SnapSync; public class StateSyncPivotTest { - [TestCase(1000, 1000, 10, 100, 1022)] - [TestCase(900, 1000, 10, 50, 1022)] - [TestCase(900, 1000, 10, 100, 1022)] - [TestCase(900, 900, 32, 100, 900)] + [TestCase(1000, 1000, 10, 100, 1022, 0)] + [TestCase(900, 1000, 10, 50, 1022, 0)] + [TestCase(900, 1000, 10, 100, 1022, 0)] + [TestCase(900, 900, 32, 100, 900, 0)] + [TestCase(0, 300, 32, 100, 301, 300)] public void Will_set_new_best_header_some_distance_from_best_suggested( int originalBestSuggested, int newBestSuggested, int minDistance, int maxDistance, - int newBestHeader + int newPivotHeader, + int syncPivot ) { IBlockTree blockTree = Substitute.For(); @@ -32,6 +33,8 @@ int newBestHeader Synchronization.FastSync.StateSyncPivot stateSyncPivot = new Synchronization.FastSync.StateSyncPivot(blockTree, new TestSyncConfig() { + PivotNumber = syncPivot.ToString(), + FastSync = true, StateMinDistanceFromHead = minDistance, StateMaxDistanceFromHead = maxDistance, }, LimboLogs.Instance); @@ -40,6 +43,6 @@ int newBestHeader stateSyncPivot.GetPivotHeader().Should().NotBeNull(); blockTree.BestSuggestedHeader.Returns(Build.A.BlockHeader.WithNumber(newBestSuggested).TestObject); - stateSyncPivot.GetPivotHeader().Number.Should().Be(newBestHeader); + stateSyncPivot.GetPivotHeader().Number.Should().Be(newPivotHeader); } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs index 80a3e322511..7d33bfb71ef 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs @@ -68,7 +68,13 @@ public void UpdateHeaderForcefully() private void TrySetNewBestHeader(string msg) { BlockHeader bestSuggestedHeader = _blockTree.BestSuggestedHeader; - long targetBlockNumber = Math.Max(bestSuggestedHeader.Number + MultiSyncModeSelector.FastSyncLag - _syncConfig.StateMinDistanceFromHead, 0); + long targetBlockNumber = bestSuggestedHeader.Number + MultiSyncModeSelector.FastSyncLag - _syncConfig.StateMinDistanceFromHead; + targetBlockNumber = Math.Max(targetBlockNumber, 0); + // The new pivot must be at least one block after the sync pivot as the forward downloader does not + // download the block at the sync pivot which may cause state not found error if state was downloaded + // at exactly sync pivot. + targetBlockNumber = Math.Max(targetBlockNumber, _syncConfig.PivotNumberParsed + 1); + BlockHeader bestHeader = _blockTree.FindHeader(targetBlockNumber); if (bestHeader is not null) { diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncFeed.cs index 802cd5530be..7af89a0ccf8 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncFeed.cs @@ -25,6 +25,11 @@ private void ChangeState(SyncFeedState newState) _taskCompletionSource ??= new TaskCompletionSource(); } + if (CurrentState == SyncFeedState.Finished && newState == SyncFeedState.Finished) + { + return; + } + if (CurrentState == SyncFeedState.Finished) { return; diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index 18d98823a07..253ac4b8bd1 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -137,6 +137,12 @@ public void UpdatePivot() public bool IsFinished(out SnapSyncBatch? nextBatch) { + if (!CanSync()) + { + nextBatch = null; + return false; + } + Interlocked.Increment(ref _reqCount); BlockHeader? pivotHeader = _pivot.GetPivotHeader(); From 1a81d766d84fc0581e09300fe0b6c951e0142f68 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Fri, 27 Dec 2024 19:31:59 +0800 Subject: [PATCH 050/113] Refactor/remove tx processing env base (#7967) --- .../Processing/OverridableTxProcessingEnv.cs | 25 ++++++++---- .../Processing/ReadOnlyTxProcessingEnv.cs | 21 +++++++--- .../Processing/ReadOnlyTxProcessingEnvBase.cs | 38 ------------------- .../SimulateReadOnlyBlocksProcessingEnv.cs | 28 +++++++------- ...ulateReadOnlyBlocksProcessingEnvFactory.cs | 3 +- 5 files changed, 48 insertions(+), 67 deletions(-) delete mode 100644 src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs diff --git a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs index 91bebb95d24..4b520f42ab5 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs @@ -14,12 +14,15 @@ namespace Nethermind.Consensus.Processing; -public class OverridableTxProcessingEnv : ReadOnlyTxProcessingEnvBase, IOverridableTxProcessorSource +public class OverridableTxProcessingEnv : IOverridableTxProcessorSource { - private readonly Lazy _transactionProcessorLazy; + public IStateReader StateReader { get; } + public IBlockTree BlockTree { get; } + protected ISpecProvider SpecProvider { get; } + protected ILogManager LogManager { get; } - protected new OverridableWorldState StateProvider { get; } - protected OverridableWorldStateManager WorldStateManager { get; } + private readonly Lazy _transactionProcessorLazy; + protected OverridableWorldState StateProvider { get; } protected OverridableCodeInfoRepository CodeInfoRepository { get; } protected IVirtualMachine Machine { get; } protected ITransactionProcessor TransactionProcessor => _transactionProcessorLazy.Value; @@ -29,12 +32,18 @@ public OverridableTxProcessingEnv( IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, ILogManager? logManager - ) : base(worldStateManager.GlobalStateReader, worldStateManager.CreateResettableWorldState(), readOnlyBlockTree, specProvider, logManager) + ) { - WorldStateManager = worldStateManager; - StateProvider = (OverridableWorldState)base.StateProvider; + SpecProvider = specProvider; + StateReader = worldStateManager.GlobalStateReader; + BlockTree = readOnlyBlockTree; + IBlockhashProvider blockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); + LogManager = logManager; + + StateProvider = (OverridableWorldState)worldStateManager.CreateResettableWorldState(); + CodeInfoRepository = new(new CodeInfoRepository()); - Machine = new VirtualMachine(BlockhashProvider, specProvider, CodeInfoRepository, logManager); + Machine = new VirtualMachine(blockhashProvider, specProvider, CodeInfoRepository, logManager); _transactionProcessorLazy = new(CreateTransactionProcessor); } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index 0edf4a1f249..3aef55f3647 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -14,9 +14,14 @@ // ReSharper disable UnusedAutoPropertyAccessor.Global namespace Nethermind.Consensus.Processing { - public class ReadOnlyTxProcessingEnv : ReadOnlyTxProcessingEnvBase, IReadOnlyTxProcessorSource + public class ReadOnlyTxProcessingEnv : IReadOnlyTxProcessorSource { - protected readonly ILogManager _logManager; + public IStateReader StateReader { get; } + protected IWorldState StateProvider { get; } + protected IBlockTree BlockTree { get; } + public IBlockhashProvider BlockhashProvider { get; } + protected ISpecProvider SpecProvider { get; } + protected ILogManager LogManager { get; } protected ITransactionProcessor? _transactionProcessor; protected ITransactionProcessor TransactionProcessor @@ -57,18 +62,24 @@ private ReadOnlyTxProcessingEnv( IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, ILogManager logManager - ) : base(stateReader, stateProvider, readOnlyBlockTree, specProvider, logManager) + ) { + SpecProvider = specProvider; + StateReader = stateReader; + StateProvider = stateProvider; + BlockTree = readOnlyBlockTree; + BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); + CodeInfoRepository = codeInfoRepository; Machine = new VirtualMachine(BlockhashProvider, specProvider, CodeInfoRepository, logManager); BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree)); BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); - _logManager = logManager; + LogManager = logManager; } protected virtual ITransactionProcessor CreateTransactionProcessor() => - new TransactionProcessor(SpecProvider, StateProvider, Machine, CodeInfoRepository, _logManager); + new TransactionProcessor(SpecProvider, StateProvider, Machine, CodeInfoRepository, LogManager); public IReadOnlyTxProcessingScope Build(Hash256 stateRoot) { diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs deleted file mode 100644 index bcda8d98798..00000000000 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnvBase.cs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using Nethermind.Blockchain; -using Nethermind.Core.Specs; -using Nethermind.Evm; -using Nethermind.Logging; -using Nethermind.State; - -namespace Nethermind.Consensus.Processing; - -public class ReadOnlyTxProcessingEnvBase -{ - public IStateReader StateReader { get; protected set; } - protected IWorldState StateProvider { get; set; } - public IBlockTree BlockTree { get; protected set; } - public IBlockhashProvider BlockhashProvider { get; protected set; } - - public ISpecProvider SpecProvider { get; } - protected ILogManager LogManager { get; } - - protected ReadOnlyTxProcessingEnvBase( - IStateReader stateReader, - IWorldState stateProvider, - IBlockTree readOnlyBlockTree, - ISpecProvider specProvider, - ILogManager logManager - ) - { - SpecProvider = specProvider; - StateReader = stateReader; - StateProvider = stateProvider; - BlockTree = readOnlyBlockTree; - BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); - LogManager = logManager; - } -} diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs index 8a5b31657b7..47a4a1cd193 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs @@ -43,43 +43,41 @@ protected override void ProcessTransaction(in BlockExecutionContext blkCtx, Tran } } -public class SimulateReadOnlyBlocksProcessingEnv : ReadOnlyTxProcessingEnvBase, IDisposable +public class SimulateReadOnlyBlocksProcessingEnv : IDisposable { + private IWorldState StateProvider { get; } + public IBlockTree BlockTree { get; } + public ISpecProvider SpecProvider { get; } + private readonly IBlockValidator _blockValidator; private readonly ILogManager? _logManager; private readonly ITransactionProcessor _transactionProcessor; public IWorldState WorldState => StateProvider; public SimulateReadOnlyBlocksProcessingEnv( - IWorldStateManager worldStateManager, + IWorldState worldState, IReadOnlyBlockTree baseBlockTree, IReadOnlyDbProvider readOnlyDbProvider, IBlockTree blockTree, ISpecProvider specProvider, ILogManager? logManager = null, bool validate = false) - : base(worldStateManager.GlobalStateReader, worldStateManager.CreateResettableWorldState(), blockTree, specProvider, logManager) { - ReadOnlyBlockTree = baseBlockTree; + SpecProvider = specProvider; DbProvider = readOnlyDbProvider; - WorldStateManager = worldStateManager; _logManager = logManager; - BlockTree = new BlockTreeOverlay(ReadOnlyBlockTree, blockTree); - BlockhashProvider = new SimulateBlockhashProvider(new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager), BlockTree); - StateProvider = WorldStateManager.GlobalWorldState; - StateReader = WorldStateManager.GlobalStateReader; + BlockTree = new BlockTreeOverlay(baseBlockTree, blockTree); + StateProvider = worldState; + SimulateBlockhashProvider blockhashProvider = new SimulateBlockhashProvider(new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager), BlockTree); CodeInfoRepository = new OverridableCodeInfoRepository(new CodeInfoRepository()); - VirtualMachine = new SimulateVirtualMachine(new VirtualMachine(BlockhashProvider, specProvider, CodeInfoRepository, logManager)); - _transactionProcessor = new SimulateTransactionProcessor(SpecProvider, StateProvider, VirtualMachine, CodeInfoRepository, _logManager, validate); + SimulateVirtualMachine virtualMachine = new SimulateVirtualMachine(new VirtualMachine(blockhashProvider, specProvider, CodeInfoRepository, logManager)); + _transactionProcessor = new SimulateTransactionProcessor(SpecProvider, StateProvider, virtualMachine, CodeInfoRepository, _logManager, validate); _blockValidator = CreateValidator(); BlockTransactionPicker = new BlockProductionTransactionPicker(specProvider, true); } - public IWorldStateManager WorldStateManager { get; } - public IVirtualMachine VirtualMachine { get; } - public IReadOnlyDbProvider DbProvider { get; } - public IReadOnlyBlockTree ReadOnlyBlockTree { get; set; } + private IReadOnlyDbProvider DbProvider { get; } public OverridableCodeInfoRepository CodeInfoRepository { get; } public BlockProductionTransactionPicker BlockTransactionPicker { get; } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs index 077d5ca67fa..f54e75c53c9 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs @@ -27,10 +27,11 @@ public SimulateReadOnlyBlocksProcessingEnv Create(bool validate) IReadOnlyDbProvider editableDbProvider = new ReadOnlyDbProvider(dbProvider, true); OverlayTrieStore overlayTrieStore = new(editableDbProvider.StateDb, worldStateManager.TrieStore, logManager); OverlayWorldStateManager overlayWorldStateManager = new(editableDbProvider, overlayTrieStore, logManager); + IWorldState worldState = overlayWorldStateManager.GlobalWorldState; BlockTree tempBlockTree = CreateTempBlockTree(editableDbProvider, specProvider, logManager, editableDbProvider); return new SimulateReadOnlyBlocksProcessingEnv( - overlayWorldStateManager, + worldState, baseBlockTree, editableDbProvider, tempBlockTree, From cba9d1d274ba432b78090b1b21c42de2001d6a54 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Sat, 28 Dec 2024 11:17:59 +0800 Subject: [PATCH 051/113] Make clique test a bit more resilient (#7969) --- .../Nethermind.Clique.Test/CliqueBlockProducerTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs index 595c46d44a5..d462ff3461b 100644 --- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs +++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs @@ -380,8 +380,8 @@ public On AssertVote(PrivateKey nodeKey, long number, Address address, bool vote { WaitForNumber(nodeKey, number); if (_logger.IsInfo) _logger.Info($"ASSERTING {vote} VOTE ON {address} AT BLOCK {number}"); - Assert.That(_blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Header.Nonce, Is.EqualTo(vote ? Consensus.Clique.Clique.NonceAuthVote : Consensus.Clique.Clique.NonceDropVote), nodeKey + " vote nonce"); - Assert.That(_blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None).Beneficiary, Is.EqualTo(address), nodeKey.Address + " vote nonce"); + Assert.That(() => _blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None)?.Header.Nonce, Is.EqualTo(vote ? Consensus.Clique.Clique.NonceAuthVote : Consensus.Clique.Clique.NonceDropVote).After(_timeout, 100), nodeKey + " vote nonce"); + Assert.That(() => _blockTrees[nodeKey].FindBlock(number, BlockTreeLookupOptions.None)?.Beneficiary, Is.EqualTo(address).After(_timeout, 100), nodeKey.Address + " vote nonce"); return this; } @@ -561,7 +561,7 @@ public On Wait(int i) } } - private static readonly int _timeout = 2000; // this has to cover block period of second + wiggle of up to 500ms * (signers - 1) + 100ms delay of the block readiness check + private static readonly int _timeout = 5000; // this has to cover block period of second + wiggle of up to 500ms * (signers - 1) + 100ms delay of the block readiness check [Test] public async Task Can_produce_block_with_transactions() From 3b170fe9f615fba01694f0e0731981e68a08828e Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Sat, 28 Dec 2024 12:12:05 +0800 Subject: [PATCH 052/113] Refactor/isolate overrideable world state (#7968) --- .../Nethermind.Api/NethermindApi.cs | 3 +- .../RegisterAuRaRpcModules.cs | 18 ++++---- .../Processing/OverridableTxProcessingEnv.cs | 9 ++-- .../OverridableTxProcessingScope.cs | 2 +- .../BlockchainBridgeTests.cs | 16 +++---- ...ulateReadOnlyBlocksProcessingEnvFactory.cs | 5 +-- .../Steps/RegisterRpcModules.cs | 5 +-- .../EthModuleBenchmarks.cs | 5 ++- .../Modules/DebugRpcModuleTests.cs | 2 +- .../Modules/TestRpcBlockchain.cs | 6 +-- .../Modules/TraceRpcModuleTests.cs | 3 +- .../Modules/DebugModule/DebugModuleFactory.cs | 10 ++--- .../Modules/Trace/TraceModuleFactory.cs | 20 ++++----- .../OptimismOverridableTxProcessingEnv.cs | 2 +- .../Rpc/OptimismTraceModuleFactory.cs | 12 ++--- .../Rpc/RegisterOptimismRpcModules.cs | 3 +- .../Nethermind.State/IWorldStateManager.cs | 18 +++++++- .../OverlayWorldStateManager.cs | 45 ------------------- .../Nethermind.State/OverridableWorldState.cs | 2 +- .../OverridableWorldStateManager.cs | 36 +++------------ .../ReadOnlyWorldStateManager.cs | 15 ++++++- .../Nethermind.State/WorldStateManager.cs | 8 ++++ .../Rpc/RegisterTaikoRpcModules.cs | 3 +- .../Rpc/TaikoTraceModuleFactory.cs | 9 ++-- .../Nethermind.Taiko/TaikoPlugin.cs | 4 +- .../TaikoReadOnlyTxProcessingEnv.cs | 2 +- 26 files changed, 104 insertions(+), 159 deletions(-) delete mode 100644 src/Nethermind/Nethermind.State/OverlayWorldStateManager.cs diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 5e9e0618b91..1e7ad8cfdd4 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -76,11 +76,10 @@ public NethermindApi(IConfigProvider configProvider, IJsonSerializer jsonSeriali public IBlockchainBridge CreateBlockchainBridge() { ReadOnlyBlockTree readOnlyTree = BlockTree!.AsReadOnly(); - OverridableWorldStateManager overridableWorldStateManager = new(DbProvider!, WorldStateManager!.TrieStore, LogManager); // TODO: reuse the same trie cache here OverridableTxProcessingEnv txProcessingEnv = new( - overridableWorldStateManager, + WorldStateManager!.CreateOverridableWorldScope(), readOnlyTree, SpecProvider!, LogManager); diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/RegisterAuRaRpcModules.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/RegisterAuRaRpcModules.cs index a227a5a25ad..18022b96fe3 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/RegisterAuRaRpcModules.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/RegisterAuRaRpcModules.cs @@ -66,8 +66,7 @@ protected override void RegisterTraceRpcModule(IRpcModuleProvider rpcModuleProvi StepDependencyException.ThrowIfNull(_api.SpecProvider); AuRaTraceModuleFactory traceModuleFactory = new( - _api.WorldStateManager.TrieStore, - _api.DbProvider, + _api.WorldStateManager, _api.BlockTree, _jsonRpcConfig, _api.BlockPreprocessor, @@ -82,8 +81,7 @@ protected override void RegisterTraceRpcModule(IRpcModuleProvider rpcModuleProvi } protected class AuRaTraceModuleFactory( - IReadOnlyTrieStore trieStore, - IDbProvider dbProvider, + IWorldStateManager worldStateManager, IBlockTree blockTree, IJsonRpcConfig jsonRpcConfig, IBlockPreprocessorStep recoveryStep, @@ -93,10 +91,10 @@ protected class AuRaTraceModuleFactory( IPoSSwitcher poSSwitcher, ILogManager logManager, IAuRaBlockProcessorFactory factory) - : TraceModuleFactory(trieStore, dbProvider, blockTree, jsonRpcConfig, recoveryStep, rewardCalculatorSource, + : TraceModuleFactory(worldStateManager, blockTree, jsonRpcConfig, recoveryStep, rewardCalculatorSource, receiptFinder, specProvider, poSSwitcher, logManager) { - protected override ReadOnlyChainProcessingEnv CreateChainProcessingEnv(OverridableWorldStateManager worldStateManager, + protected override ReadOnlyChainProcessingEnv CreateChainProcessingEnv(IOverridableWorldScope worldStateManager, IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor, IReadOnlyTxProcessingScope scope, IRewardCalculator rewardCalculator) { @@ -202,7 +200,7 @@ protected override void RegisterDebugRpcModule(IRpcModuleProvider rpcModuleProvi StepDependencyException.ThrowIfNull(_api.SpecProvider); AuRaDebugModuleFactory debugModuleFactory = new( - _api.WorldStateManager.TrieStore, + _api.WorldStateManager, _api.DbProvider, _api.BlockTree, _jsonRpcConfig, @@ -223,7 +221,7 @@ protected override void RegisterDebugRpcModule(IRpcModuleProvider rpcModuleProvi } protected class AuRaDebugModuleFactory( - IReadOnlyTrieStore trieStore, + IWorldStateManager worldStateManager, IDbProvider dbProvider, IBlockTree blockTree, IJsonRpcConfig jsonRpcConfig, @@ -239,12 +237,12 @@ protected class AuRaDebugModuleFactory( IFileSystem fileSystem, ILogManager logManager, IAuRaBlockProcessorFactory factory) - : DebugModuleFactory(trieStore, dbProvider, blockTree, jsonRpcConfig, blockValidator, recoveryStep, + : DebugModuleFactory(worldStateManager, dbProvider, blockTree, jsonRpcConfig, blockValidator, recoveryStep, rewardCalculator, receiptStorage, receiptsMigration, configProvider, specProvider, syncModeSelector, badBlockStore, fileSystem, logManager) { protected override ReadOnlyChainProcessingEnv CreateReadOnlyChainProcessingEnv(IReadOnlyTxProcessingScope scope, - OverridableWorldStateManager worldStateManager, BlockProcessor.BlockValidationTransactionsExecutor transactionsExecutor) + IOverridableWorldScope worldStateManager, BlockProcessor.BlockValidationTransactionsExecutor transactionsExecutor) { return new AuRaReadOnlyChainProcessingEnv( scope, diff --git a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs index 4b520f42ab5..eed81454245 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingEnv.cs @@ -22,25 +22,24 @@ public class OverridableTxProcessingEnv : IOverridableTxProcessorSource protected ILogManager LogManager { get; } private readonly Lazy _transactionProcessorLazy; - protected OverridableWorldState StateProvider { get; } + protected IOverridableWorldState StateProvider { get; } protected OverridableCodeInfoRepository CodeInfoRepository { get; } protected IVirtualMachine Machine { get; } protected ITransactionProcessor TransactionProcessor => _transactionProcessorLazy.Value; public OverridableTxProcessingEnv( - OverridableWorldStateManager worldStateManager, + IOverridableWorldScope overridableScope, IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, ILogManager? logManager ) { SpecProvider = specProvider; - StateReader = worldStateManager.GlobalStateReader; + StateReader = overridableScope.GlobalStateReader; BlockTree = readOnlyBlockTree; IBlockhashProvider blockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); LogManager = logManager; - - StateProvider = (OverridableWorldState)worldStateManager.CreateResettableWorldState(); + StateProvider = overridableScope.WorldState; CodeInfoRepository = new(new CodeInfoRepository()); Machine = new VirtualMachine(blockhashProvider, specProvider, CodeInfoRepository, logManager); diff --git a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingScope.cs b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingScope.cs index b168b1c1e93..057f75e92c3 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingScope.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/OverridableTxProcessingScope.cs @@ -11,7 +11,7 @@ namespace Nethermind.Consensus.Processing; public class OverridableTxProcessingScope( IOverridableCodeInfoRepository codeInfoRepository, ITransactionProcessor transactionProcessor, - OverridableWorldState worldState, + IOverridableWorldState worldState, Hash256 originalStateRoot ) : IOverridableTxProcessingScope { diff --git a/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs b/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs index beb29a04702..078b924abcf 100644 --- a/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs +++ b/src/Nethermind/Nethermind.Facade.Test/BlockchainBridgeTests.cs @@ -48,7 +48,7 @@ public class BlockchainBridgeTests private IDbProvider _dbProvider; private class TestReadOnlyTxProcessingEnv( - OverridableWorldStateManager worldStateManager, + IOverridableWorldScope worldStateManager, IReadOnlyBlockTree blockTree, ISpecProvider specProvider, ILogManager logManager, @@ -72,13 +72,12 @@ public async Task SetUp() _ethereumEcdsa = Substitute.For(); _specProvider = MainnetSpecProvider.Instance; - IReadOnlyTrieStore trieStore = new TrieStore(_dbProvider.StateDb, LimboLogs.Instance).AsReadOnly(); - - OverridableWorldStateManager worldStateManager = new(_dbProvider, trieStore, LimboLogs.Instance); + WorldStateManager worldStateManager = WorldStateManager.CreateForTest(_dbProvider, LimboLogs.Instance); + IOverridableWorldScope overridableWorldScope = worldStateManager.CreateOverridableWorldScope(); IReadOnlyBlockTree readOnlyBlockTree = _blockTree.AsReadOnly(); TestReadOnlyTxProcessingEnv processingEnv = new( - worldStateManager, + overridableWorldScope, readOnlyBlockTree, _specProvider, LimboLogs.Instance, @@ -207,13 +206,10 @@ public void Call_uses_valid_beneficiary() [TestCase(0)] public void Bridge_head_is_correct(long headNumber) { - IReadOnlyTrieStore trieStore = new TrieStore(_dbProvider.StateDb, LimboLogs.Instance).AsReadOnly(); - - OverridableWorldStateManager worldStateManager = - new(_dbProvider, trieStore, LimboLogs.Instance); + WorldStateManager worldStateManager = WorldStateManager.CreateForTest(_dbProvider, LimboLogs.Instance); IReadOnlyBlockTree roBlockTree = _blockTree.AsReadOnly(); OverridableTxProcessingEnv processingEnv = new( - worldStateManager, + worldStateManager.CreateOverridableWorldScope(), roBlockTree, _specProvider, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs index f54e75c53c9..cfbb63bee82 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnvFactory.cs @@ -11,7 +11,6 @@ using Nethermind.Logging; using Nethermind.State; using Nethermind.State.Repositories; -using Nethermind.Trie.Pruning; namespace Nethermind.Facade.Simulate; @@ -25,9 +24,7 @@ public class SimulateReadOnlyBlocksProcessingEnvFactory( public SimulateReadOnlyBlocksProcessingEnv Create(bool validate) { IReadOnlyDbProvider editableDbProvider = new ReadOnlyDbProvider(dbProvider, true); - OverlayTrieStore overlayTrieStore = new(editableDbProvider.StateDb, worldStateManager.TrieStore, logManager); - OverlayWorldStateManager overlayWorldStateManager = new(editableDbProvider, overlayTrieStore, logManager); - IWorldState worldState = overlayWorldStateManager.GlobalWorldState; + IWorldState worldState = worldStateManager.CreateOverlayWorldState(editableDbProvider.StateDb, editableDbProvider.CodeDb); BlockTree tempBlockTree = CreateTempBlockTree(editableDbProvider, specProvider, logManager, editableDbProvider); return new SimulateReadOnlyBlocksProcessingEnv( diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index 6bfc89b87e6..daa7ce6fc7d 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -214,7 +214,7 @@ protected virtual void RegisterDebugRpcModule(IRpcModuleProvider rpcModuleProvid StepDependencyException.ThrowIfNull(_api.SpecProvider); DebugModuleFactory debugModuleFactory = new( - _api.WorldStateManager.TrieStore, + _api.WorldStateManager, _api.DbProvider, _api.BlockTree, _jsonRpcConfig, @@ -285,8 +285,7 @@ protected ModuleFactoryBase CreateTraceModuleFactory() StepDependencyException.ThrowIfNull(_api.SpecProvider); return new TraceModuleFactory( - _api.WorldStateManager.TrieStore, - _api.DbProvider, + _api.WorldStateManager, _api.BlockTree, _jsonRpcConfig, _api.BlockPreprocessor, diff --git a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs index 997a4107c2a..86f446d973d 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs @@ -68,7 +68,8 @@ public void GlobalSetup() stateProvider.Commit(spec); stateProvider.CommitTree(0); - OverridableWorldStateManager stateManager = new(dbProvider, trieStore.AsReadOnly(), LimboLogs.Instance); + WorldStateManager stateManager = new(stateProvider, trieStore, dbProvider, LimboLogs.Instance); + OverridableWorldStateManager overridableScope = new(dbProvider, trieStore.AsReadOnly(), LimboLogs.Instance); StateReader stateReader = new(trieStore, codeDb, LimboLogs.Instance); @@ -138,7 +139,7 @@ TransactionProcessor transactionProcessor BlockchainBridge bridge = new( new OverridableTxProcessingEnv( - stateManager, + overridableScope, new ReadOnlyBlockTree(blockTree), specProvider, LimboLogs.Instance), diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugRpcModuleTests.cs index 2c78136b61b..e7da233ff0f 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugRpcModuleTests.cs @@ -49,7 +49,7 @@ public static async Task Create(ISpecProvider? specProvider = null, boo IReceiptsMigration receiptsMigration = Substitute.For(); ISyncModeSelector syncModeSelector = Substitute.For(); var factory = new DebugModuleFactory( - blockchain.WorldStateManager.TrieStore, + blockchain.WorldStateManager, blockchain.DbProvider, blockchain.BlockTree, blockchain.RpcConfig, diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs index d5d9aaf4e6a..f0ada6657ee 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcBlockchain.cs @@ -48,7 +48,7 @@ public class TestRpcBlockchain : TestBlockchain public ITxSender TxSender { get; private set; } = null!; public IReceiptFinder ReceiptFinder { get; private set; } = null!; public IGasPriceOracle GasPriceOracle { get; private set; } = null!; - public OverridableWorldStateManager OverridableWorldStateManager { get; private set; } = null!; + public IOverridableWorldScope OverridableWorldStateManager { get; private set; } = null!; public IKeyStore KeyStore { get; } = new MemKeyStore(TestItem.PrivateKeys, Path.Combine("testKeyStoreDir", Path.GetRandomFileName())); public IWallet TestWallet { get; } = @@ -150,9 +150,9 @@ protected override async Task Build( IFilterManager filterManager = new FilterManager(filterStore, BlockProcessor, TxPool, LimboLogs.Instance); var dbProvider = new ReadOnlyDbProvider(DbProvider, false); IReadOnlyBlockTree? roBlockTree = BlockTree!.AsReadOnly(); - OverridableWorldStateManager overridableWorldStateManager = new(DbProvider, WorldStateManager.TrieStore, LogManager); + IOverridableWorldScope overridableWorldStateManager = WorldStateManager.CreateOverridableWorldScope(); OverridableTxProcessingEnv processingEnv = new( - overridableWorldStateManager, + WorldStateManager.CreateOverridableWorldScope(), roBlockTree, SpecProvider, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index 446c7743efe..25e6c76a10f 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -63,8 +63,7 @@ public async Task Build(ISpecProvider? specProvider = null, bool isAura = false) } Factory = new( - Blockchain.OverridableWorldStateManager.TrieStore, - Blockchain.DbProvider, + Blockchain.WorldStateManager, Blockchain.BlockTree, JsonRpcConfig, Blockchain.BlockPreprocessorStep, diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs index 953b5c4be1d..bf3ec5d4ff6 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs @@ -24,7 +24,6 @@ namespace Nethermind.JsonRpc.Modules.DebugModule; public class DebugModuleFactory : ModuleFactoryBase { - private readonly IReadOnlyTrieStore _trieStore; private readonly IJsonRpcConfig _jsonRpcConfig; private readonly IBlockValidator _blockValidator; protected readonly IRewardCalculatorSource _rewardCalculatorSource; @@ -39,9 +38,10 @@ public class DebugModuleFactory : ModuleFactoryBase private readonly ISyncModeSelector _syncModeSelector; private readonly IBadBlockStore _badBlockStore; private readonly IFileSystem _fileSystem; + private readonly IWorldStateManager _worldStateManager; public DebugModuleFactory( - IReadOnlyTrieStore trieStore, + IWorldStateManager worldStateManager, IDbProvider dbProvider, IBlockTree blockTree, IJsonRpcConfig jsonRpcConfig, @@ -57,7 +57,7 @@ public DebugModuleFactory( IFileSystem fileSystem, ILogManager logManager) { - _trieStore = trieStore; + _worldStateManager = worldStateManager; _dbProvider = dbProvider.AsReadOnly(false); _blockTree = blockTree.AsReadOnly(); _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); @@ -76,7 +76,7 @@ public DebugModuleFactory( public override IDebugRpcModule Create() { - OverridableWorldStateManager worldStateManager = new(_dbProvider, _trieStore, _logManager); + IOverridableWorldScope worldStateManager = _worldStateManager.CreateOverridableWorldScope(); OverridableTxProcessingEnv txEnv = new(worldStateManager, _blockTree, _specProvider, _logManager); IReadOnlyTxProcessingScope scope = txEnv.Build(Keccak.EmptyTreeHash); @@ -111,7 +111,7 @@ public override IDebugRpcModule Create() } protected virtual ReadOnlyChainProcessingEnv CreateReadOnlyChainProcessingEnv(IReadOnlyTxProcessingScope scope, - OverridableWorldStateManager worldStateManager, BlockProcessor.BlockValidationTransactionsExecutor transactionsExecutor) + IOverridableWorldScope worldStateManager, BlockProcessor.BlockValidationTransactionsExecutor transactionsExecutor) { return new ReadOnlyChainProcessingEnv( scope, diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs index 11a2ce1ba68..166de6fb581 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs @@ -11,17 +11,14 @@ using Nethermind.Consensus.Validators; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; -using Nethermind.Db; using Nethermind.Evm.TransactionProcessing; using Nethermind.Logging; using Nethermind.State; -using Nethermind.Trie.Pruning; namespace Nethermind.JsonRpc.Modules.Trace; public class TraceModuleFactory( - IReadOnlyTrieStore trieStore, - IDbProvider dbProvider, + IWorldStateManager worldStateManager, IBlockTree blockTree, IJsonRpcConfig jsonRpcConfig, IBlockPreprocessorStep recoveryStep, @@ -31,7 +28,6 @@ public class TraceModuleFactory( IPoSSwitcher poSSwitcher, ILogManager logManager) : ModuleFactoryBase { - protected readonly IReadOnlyTrieStore _trieStore = trieStore; protected readonly IReadOnlyBlockTree _blockTree = blockTree.AsReadOnly(); protected readonly IJsonRpcConfig _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); protected readonly IReceiptStorage _receiptStorage = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); @@ -41,9 +37,9 @@ public class TraceModuleFactory( protected readonly IRewardCalculatorSource _rewardCalculatorSource = rewardCalculatorSource ?? throw new ArgumentNullException(nameof(rewardCalculatorSource)); protected readonly IPoSSwitcher _poSSwitcher = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher)); - protected virtual OverridableTxProcessingEnv CreateTxProcessingEnv(OverridableWorldStateManager worldStateManager) => new(worldStateManager, _blockTree, _specProvider, _logManager); + protected virtual OverridableTxProcessingEnv CreateTxProcessingEnv(IOverridableWorldScope worldScope) => new(worldScope, _blockTree, _specProvider, _logManager); - protected virtual ReadOnlyChainProcessingEnv CreateChainProcessingEnv(OverridableWorldStateManager worldStateManager, IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor, IReadOnlyTxProcessingScope scope, IRewardCalculator rewardCalculator) => new( + protected virtual ReadOnlyChainProcessingEnv CreateChainProcessingEnv(IOverridableWorldScope worldScope, IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor, IReadOnlyTxProcessingScope scope, IRewardCalculator rewardCalculator) => new( scope, Always.Valid, _recoveryStep, @@ -51,14 +47,14 @@ public class TraceModuleFactory( _receiptStorage, _specProvider, _blockTree, - worldStateManager.GlobalStateReader, + worldScope.GlobalStateReader, _logManager, transactionsExecutor); public override ITraceRpcModule Create() { - OverridableWorldStateManager worldStateManager = new(dbProvider, _trieStore, logManager); - OverridableTxProcessingEnv txProcessingEnv = CreateTxProcessingEnv(worldStateManager); + IOverridableWorldScope overridableScope = worldStateManager.CreateOverridableWorldScope(); + OverridableTxProcessingEnv txProcessingEnv = CreateTxProcessingEnv(overridableScope); IReadOnlyTxProcessingScope scope = txProcessingEnv.Build(Keccak.EmptyTreeHash); IRewardCalculator rewardCalculator = @@ -68,8 +64,8 @@ public override ITraceRpcModule Create() RpcBlockTransactionsExecutor rpcBlockTransactionsExecutor = new(scope.TransactionProcessor, scope.WorldState); BlockProcessor.BlockValidationTransactionsExecutor executeBlockTransactionsExecutor = new(scope.TransactionProcessor, scope.WorldState); - ReadOnlyChainProcessingEnv traceProcessingEnv = CreateChainProcessingEnv(worldStateManager, rpcBlockTransactionsExecutor, scope, rewardCalculator); - ReadOnlyChainProcessingEnv executeProcessingEnv = CreateChainProcessingEnv(worldStateManager, executeBlockTransactionsExecutor, scope, rewardCalculator); + ReadOnlyChainProcessingEnv traceProcessingEnv = CreateChainProcessingEnv(overridableScope, rpcBlockTransactionsExecutor, scope, rewardCalculator); + ReadOnlyChainProcessingEnv executeProcessingEnv = CreateChainProcessingEnv(overridableScope, executeBlockTransactionsExecutor, scope, rewardCalculator); Tracer tracer = new(scope.WorldState, traceProcessingEnv.ChainProcessor, executeProcessingEnv.ChainProcessor, traceOptions: ProcessingOptions.TraceTransactions); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs b/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs index 76ff5c8e5c2..d6ce36e8290 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismOverridableTxProcessingEnv.cs @@ -13,7 +13,7 @@ namespace Nethermind.Optimism; public class OptimismOverridableTxProcessingEnv( - OverridableWorldStateManager worldStateManager, + IOverridableWorldScope worldStateManager, IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, ILogManager logManager, diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTraceModuleFactory.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTraceModuleFactory.cs index bf5b837c883..d2658eb974d 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTraceModuleFactory.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTraceModuleFactory.cs @@ -9,19 +9,16 @@ using Nethermind.Consensus.Validators; using Nethermind.Consensus.Withdrawals; using Nethermind.Core.Specs; -using Nethermind.Db; using Nethermind.Evm.TransactionProcessing; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules.Trace; using Nethermind.Logging; using Nethermind.State; -using Nethermind.Trie.Pruning; namespace Nethermind.Optimism.Rpc; public class OptimismTraceModuleFactory( - IReadOnlyTrieStore trieStore, - IDbProvider dbProvider, + IWorldStateManager worldStateManager, IBlockTree blockTree, IJsonRpcConfig jsonRpcConfig, IBlockPreprocessorStep recoveryStep, @@ -34,8 +31,7 @@ public class OptimismTraceModuleFactory( IOptimismSpecHelper opSpecHelper, Create2DeployerContractRewriter contractRewriter, IWithdrawalProcessor withdrawalProcessor) : TraceModuleFactory( - trieStore, - dbProvider, + worldStateManager, blockTree, jsonRpcConfig, recoveryStep, @@ -45,10 +41,10 @@ public class OptimismTraceModuleFactory( poSSwitcher, logManager) { - protected override OverridableTxProcessingEnv CreateTxProcessingEnv(OverridableWorldStateManager worldStateManager) => + protected override OverridableTxProcessingEnv CreateTxProcessingEnv(IOverridableWorldScope worldStateManager) => new OptimismOverridableTxProcessingEnv(worldStateManager, _blockTree, _specProvider, _logManager, l1CostHelper, opSpecHelper); - protected override ReadOnlyChainProcessingEnv CreateChainProcessingEnv(OverridableWorldStateManager worldStateManager, IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor, IReadOnlyTxProcessingScope scope, IRewardCalculator rewardCalculator) => new OptimismReadOnlyChainProcessingEnv( + protected override ReadOnlyChainProcessingEnv CreateChainProcessingEnv(IOverridableWorldScope worldStateManager, IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor, IReadOnlyTxProcessingScope scope, IRewardCalculator rewardCalculator) => new OptimismReadOnlyChainProcessingEnv( scope, Always.Valid, _recoveryStep, diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs b/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs index 80dac97f0a2..bb034599ee5 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs @@ -100,8 +100,7 @@ protected override void RegisterTraceRpcModule(IRpcModuleProvider rpcModuleProvi StepDependencyException.ThrowIfNull(_api.SpecHelper); OptimismTraceModuleFactory traceModuleFactory = new( - _api.WorldStateManager.TrieStore, - _api.DbProvider, + _api.WorldStateManager, _api.BlockTree, _jsonRpcConfig, _api.BlockPreprocessor, diff --git a/src/Nethermind/Nethermind.State/IWorldStateManager.cs b/src/Nethermind/Nethermind.State/IWorldStateManager.cs index 79f9f0c3279..bb7817f8893 100644 --- a/src/Nethermind/Nethermind.State/IWorldStateManager.cs +++ b/src/Nethermind/Nethermind.State/IWorldStateManager.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core; using Nethermind.Trie.Pruning; namespace Nethermind.State; @@ -10,7 +11,6 @@ public interface IWorldStateManager { IWorldState GlobalWorldState { get; } IStateReader GlobalStateReader { get; } - IReadOnlyTrieStore TrieStore { get; } bool SupportHashLookup { get; } /// @@ -21,4 +21,20 @@ public interface IWorldStateManager IWorldState CreateResettableWorldState(IWorldState? forWarmup = null); event EventHandler? ReorgBoundaryReached; + + // TODO: These two method can be combined + IOverridableWorldScope CreateOverridableWorldScope(); + + IWorldState CreateOverlayWorldState(IKeyValueStoreWithBatching overlayState, IKeyValueStore overlayCode); +} + +public interface IOverridableWorldScope +{ + IOverridableWorldState WorldState { get; } + IStateReader GlobalStateReader { get; } +} + +public interface IOverridableWorldState : IWorldState +{ + void ResetOverrides(); } diff --git a/src/Nethermind/Nethermind.State/OverlayWorldStateManager.cs b/src/Nethermind/Nethermind.State/OverlayWorldStateManager.cs deleted file mode 100644 index 852cccd716f..00000000000 --- a/src/Nethermind/Nethermind.State/OverlayWorldStateManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using Nethermind.Db; -using Nethermind.Logging; -using Nethermind.Trie; -using Nethermind.Trie.Pruning; - -namespace Nethermind.State; - -public class OverlayWorldStateManager( - IReadOnlyDbProvider dbProvider, - OverlayTrieStore overlayTrieStore, - ILogManager? logManager) - : IWorldStateManager -{ - private readonly IDb _codeDb = dbProvider.GetDb(DbNames.Code); - - private readonly StateReader _reader = new(overlayTrieStore, dbProvider.GetDb(DbNames.Code), logManager); - - private readonly WorldState _state = new(overlayTrieStore, dbProvider.GetDb(DbNames.Code), logManager); - - public IWorldState GlobalWorldState => _state; - - public IStateReader GlobalStateReader => _reader; - - public IReadOnlyTrieStore TrieStore { get; } = overlayTrieStore.AsReadOnly(); - public bool SupportHashLookup => overlayTrieStore.Scheme == INodeStorage.KeyScheme.Hash; - - public IWorldState CreateResettableWorldState(IWorldState? forWarmup = null) - { - ITrieStore trieStore = forWarmup is IPreBlockCaches { Caches: { } preBlockCaches } - ? new PreCachedTrieStore(overlayTrieStore, preBlockCaches.RlpCache) - : overlayTrieStore; - - return new WorldState(trieStore, _codeDb, logManager); - } - - public event EventHandler? ReorgBoundaryReached - { - add => overlayTrieStore.ReorgBoundaryReached += value; - remove => overlayTrieStore.ReorgBoundaryReached -= value; - } -} diff --git a/src/Nethermind/Nethermind.State/OverridableWorldState.cs b/src/Nethermind/Nethermind.State/OverridableWorldState.cs index 70a1bfc0afb..6fab49ccfc6 100644 --- a/src/Nethermind/Nethermind.State/OverridableWorldState.cs +++ b/src/Nethermind/Nethermind.State/OverridableWorldState.cs @@ -13,7 +13,7 @@ public class OverridableWorldState( ILogManager? logManager, PreBlockCaches? preBlockCaches = null, bool populatePreBlockCache = true) - : WorldState(trieStore, dbProvider.GetDb(DbNames.Code), logManager, preBlockCaches, populatePreBlockCache) + : WorldState(trieStore, dbProvider.GetDb(DbNames.Code), logManager, preBlockCaches, populatePreBlockCache), IOverridableWorldState { /// diff --git a/src/Nethermind/Nethermind.State/OverridableWorldStateManager.cs b/src/Nethermind/Nethermind.State/OverridableWorldStateManager.cs index d88525f856f..b4a5c631d25 100644 --- a/src/Nethermind/Nethermind.State/OverridableWorldStateManager.cs +++ b/src/Nethermind/Nethermind.State/OverridableWorldStateManager.cs @@ -8,42 +8,20 @@ namespace Nethermind.State; -public class OverridableWorldStateManager : IWorldStateManager +public class OverridableWorldStateManager : IOverridableWorldScope { - private readonly ReadOnlyDbProvider _readOnlyDbProvider; private readonly StateReader _reader; - private readonly WorldState _state; - - private readonly OverlayTrieStore _overlayTrieStore; - private readonly ILogManager? _logManager; public OverridableWorldStateManager(IDbProvider dbProvider, IReadOnlyTrieStore trieStore, ILogManager? logManager) { - dbProvider = _readOnlyDbProvider = new(dbProvider, true); - OverlayTrieStore overlayTrieStore = new(dbProvider.StateDb, trieStore, logManager); + IReadOnlyDbProvider readOnlyDbProvider = new ReadOnlyDbProvider(dbProvider, true); + OverlayTrieStore overlayTrieStore = new(readOnlyDbProvider.StateDb, trieStore, logManager); - _logManager = logManager; - _reader = new(overlayTrieStore, dbProvider.GetDb(DbNames.Code), logManager); - _state = new(overlayTrieStore, dbProvider.GetDb(DbNames.Code), logManager); - _overlayTrieStore = overlayTrieStore; - } + _reader = new(overlayTrieStore, readOnlyDbProvider.CodeDb, logManager); - public IWorldState GlobalWorldState => _state; - public IStateReader GlobalStateReader => _reader; - public IReadOnlyTrieStore TrieStore => _overlayTrieStore.AsReadOnly(); - public bool SupportHashLookup => _overlayTrieStore.Scheme == INodeStorage.KeyScheme.Hash; - - public IWorldState CreateResettableWorldState(IWorldState? forWarmup = null) - { - if (forWarmup is not null) - throw new NotSupportedException("Overridable world state with warm up is not supported."); - - return new OverridableWorldState(_overlayTrieStore, _readOnlyDbProvider, _logManager); + WorldState = new OverridableWorldState(overlayTrieStore, readOnlyDbProvider, logManager); } - public event EventHandler? ReorgBoundaryReached - { - add => _overlayTrieStore.ReorgBoundaryReached += value; - remove => _overlayTrieStore.ReorgBoundaryReached -= value; - } + public IOverridableWorldState WorldState { get; } + public IStateReader GlobalStateReader => _reader; } diff --git a/src/Nethermind/Nethermind.State/ReadOnlyWorldStateManager.cs b/src/Nethermind/Nethermind.State/ReadOnlyWorldStateManager.cs index e2c139b9914..5cd51dc6d75 100644 --- a/src/Nethermind/Nethermind.State/ReadOnlyWorldStateManager.cs +++ b/src/Nethermind/Nethermind.State/ReadOnlyWorldStateManager.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core; using Nethermind.Db; using Nethermind.Logging; using Nethermind.Trie; @@ -17,6 +18,7 @@ public class ReadOnlyWorldStateManager : IWorldStateManager private readonly IReadOnlyTrieStore _readOnlyTrieStore; private readonly ILogManager _logManager; private readonly ReadOnlyDb _codeDb; + private readonly IDbProvider _dbProvider; public ReadOnlyWorldStateManager( IDbProvider dbProvider, @@ -24,6 +26,7 @@ public ReadOnlyWorldStateManager( ILogManager logManager ) { + _dbProvider = dbProvider; _readOnlyTrieStore = readOnlyTrieStore; _logManager = logManager; @@ -36,7 +39,6 @@ ILogManager logManager public IStateReader GlobalStateReader { get; } - public IReadOnlyTrieStore TrieStore => _readOnlyTrieStore; public bool SupportHashLookup => _readOnlyTrieStore.Scheme == INodeStorage.KeyScheme.Hash; public IWorldState CreateResettableWorldState(IWorldState? forWarmup = null) @@ -59,4 +61,15 @@ public virtual event EventHandler? ReorgBoundaryReached add => throw new InvalidOperationException("Unsupported operation"); remove => throw new InvalidOperationException("Unsupported operation"); } + + public IOverridableWorldScope CreateOverridableWorldScope() + { + return new OverridableWorldStateManager(_dbProvider, _readOnlyTrieStore, _logManager); + } + + public IWorldState CreateOverlayWorldState(IKeyValueStoreWithBatching overlayState, IKeyValueStore overlayCode) + { + OverlayTrieStore overlayTrieStore = new(overlayState, _readOnlyTrieStore, _logManager); + return new WorldState(overlayTrieStore, overlayCode, _logManager); + } } diff --git a/src/Nethermind/Nethermind.State/WorldStateManager.cs b/src/Nethermind/Nethermind.State/WorldStateManager.cs index 807db3ab54f..d40aad09c5a 100644 --- a/src/Nethermind/Nethermind.State/WorldStateManager.cs +++ b/src/Nethermind/Nethermind.State/WorldStateManager.cs @@ -15,6 +15,14 @@ public class WorldStateManager( ILogManager logManager) : ReadOnlyWorldStateManager(dbProvider, trieStore.AsReadOnly(), logManager) { + public static WorldStateManager CreateForTest(IDbProvider dbProvider, ILogManager logManager) + { + ITrieStore trieStore = new TrieStore(dbProvider.StateDb, logManager); + IWorldState worldState = new WorldState(trieStore, dbProvider.CodeDb, logManager); + + return new WorldStateManager(worldState, trieStore, dbProvider, logManager); + } + public override IWorldState GlobalWorldState => worldState; public override event EventHandler? ReorgBoundaryReached diff --git a/src/Nethermind/Nethermind.Taiko/Rpc/RegisterTaikoRpcModules.cs b/src/Nethermind/Nethermind.Taiko/Rpc/RegisterTaikoRpcModules.cs index 4166d0e4cdc..b17c1ebe526 100644 --- a/src/Nethermind/Nethermind.Taiko/Rpc/RegisterTaikoRpcModules.cs +++ b/src/Nethermind/Nethermind.Taiko/Rpc/RegisterTaikoRpcModules.cs @@ -83,8 +83,7 @@ protected override void RegisterTraceRpcModule(IRpcModuleProvider rpcModuleProvi StepDependencyException.ThrowIfNull(_api.WorldState); TaikoTraceModuleFactory traceModuleFactory = new( - _api.WorldStateManager.TrieStore, - _api.DbProvider, + _api.WorldStateManager, _api.BlockTree, _jsonRpcConfig, _api.BlockPreprocessor, diff --git a/src/Nethermind/Nethermind.Taiko/Rpc/TaikoTraceModuleFactory.cs b/src/Nethermind/Nethermind.Taiko/Rpc/TaikoTraceModuleFactory.cs index e7045d4e609..f5d50f57c78 100644 --- a/src/Nethermind/Nethermind.Taiko/Rpc/TaikoTraceModuleFactory.cs +++ b/src/Nethermind/Nethermind.Taiko/Rpc/TaikoTraceModuleFactory.cs @@ -7,20 +7,19 @@ using Nethermind.Consensus.Processing; using Nethermind.Consensus.Rewards; using Nethermind.Core.Specs; -using Nethermind.Db; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules.Trace; using Nethermind.Logging; using Nethermind.State; -using Nethermind.Trie.Pruning; namespace Nethermind.Taiko.Rpc; class TaikoTraceModuleFactory( - IReadOnlyTrieStore trieStore, IDbProvider dbProvider, IBlockTree blockTree, IJsonRpcConfig jsonRpcConfig, + IWorldStateManager worldStateManager, + IBlockTree blockTree, IJsonRpcConfig jsonRpcConfig, IBlockPreprocessorStep recoveryStep, IRewardCalculatorSource rewardCalculatorSource, IReceiptStorage receiptFinder, ISpecProvider specProvider, IPoSSwitcher poSSwitcher, ILogManager logManager) : - TraceModuleFactory(trieStore, dbProvider, blockTree, jsonRpcConfig, recoveryStep, rewardCalculatorSource, receiptFinder, specProvider, poSSwitcher, logManager) + TraceModuleFactory(worldStateManager, blockTree, jsonRpcConfig, recoveryStep, rewardCalculatorSource, receiptFinder, specProvider, poSSwitcher, logManager) { - protected override OverridableTxProcessingEnv CreateTxProcessingEnv(OverridableWorldStateManager worldStateManager) => new TaikoReadOnlyTxProcessingEnv(worldStateManager, _blockTree, _specProvider, _logManager); + protected override OverridableTxProcessingEnv CreateTxProcessingEnv(IOverridableWorldScope worldStateManager) => new TaikoReadOnlyTxProcessingEnv(worldStateManager, _blockTree, _specProvider, _logManager); } diff --git a/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs b/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs index cb9fb700e37..6dcf7db3c65 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoPlugin.cs @@ -155,10 +155,8 @@ public async Task InitRpcModules() ReadOnlyBlockTree readonlyBlockTree = _api.BlockTree.AsReadOnly(); - OverridableWorldStateManager overridableWorldStateManager = new(_api.DbProvider!, _api.WorldStateManager!.TrieStore, _api.LogManager); - TaikoReadOnlyTxProcessingEnv txProcessingEnv = - new(overridableWorldStateManager, readonlyBlockTree, _api.SpecProvider, _api.LogManager); + new(_api.WorldStateManager!.CreateOverridableWorldScope(), readonlyBlockTree, _api.SpecProvider, _api.LogManager); IReadOnlyTxProcessingScope scope = txProcessingEnv.Build(Keccak.EmptyTreeHash); diff --git a/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs index faf0a5242dd..883ee47a18f 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoReadOnlyTxProcessingEnv.cs @@ -11,7 +11,7 @@ namespace Nethermind.Taiko; public class TaikoReadOnlyTxProcessingEnv( - OverridableWorldStateManager worldStateManager, + IOverridableWorldScope worldStateManager, IReadOnlyBlockTree readOnlyBlockTree, ISpecProvider specProvider, ILogManager logManager) : OverridableTxProcessingEnv( From 67fd2bc0f87fd050d584bede039ca4f8d4ba0258 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Mon, 30 Dec 2024 00:47:04 +0000 Subject: [PATCH 053/113] Share stack pool between threads (#7972) --- src/Nethermind/Nethermind.Evm/EvmState.cs | 66 +++------------------- src/Nethermind/Nethermind.Evm/StackPool.cs | 48 ++++++++++++++++ 2 files changed, 55 insertions(+), 59 deletions(-) create mode 100644 src/Nethermind/Nethermind.Evm/StackPool.cs diff --git a/src/Nethermind/Nethermind.Evm/EvmState.cs b/src/Nethermind/Nethermind.Evm/EvmState.cs index 743b7e0102e..feb1abdbc87 100644 --- a/src/Nethermind/Nethermind.Evm/EvmState.cs +++ b/src/Nethermind/Nethermind.Evm/EvmState.cs @@ -2,9 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Threading; using Nethermind.Core; using Nethermind.State; @@ -16,57 +14,7 @@ namespace Nethermind.Evm [DebuggerDisplay("{ExecutionType} to {Env.ExecutingAccount}, G {GasAvailable} R {Refund} PC {ProgramCounter} OUT {OutputDestination}:{OutputLength}")] public class EvmState : IDisposable // TODO: rename to CallState { - private class StackPool - { - private readonly int _maxCallStackDepth; - private readonly struct StackItem(byte[] dataStack, int[] returnStack) - { - public readonly byte[] DataStack = dataStack; - public readonly int[] ReturnStack = returnStack; - } - - // TODO: we have wrong call depth calculation somewhere - public StackPool(int maxCallStackDepth = VirtualMachine.MaxCallDepth * 2) - { - _maxCallStackDepth = maxCallStackDepth; - } - - private readonly Stack _stackPool = new(32); - - private int _stackPoolDepth; - - /// - /// The word 'return' acts here once as a verb 'to return stack to the pool' and once as a part of the - /// compound noun 'return stack' which is a stack of subroutine return values. - /// - /// - /// - public void ReturnStacks(byte[] dataStack, int[] returnStack) - { - _stackPool.Push(new(dataStack, returnStack)); - } - - public (byte[], int[]) RentStacks() - { - if (_stackPool.TryPop(out StackItem result)) - { - return (result.DataStack, result.ReturnStack); - } - - _stackPoolDepth++; - if (_stackPoolDepth > _maxCallStackDepth) - { - EvmStack.ThrowEvmStackOverflowException(); - } - - return - ( - new byte[(EvmStack.MaxStackSize + EvmStack.RegisterLength) * 32], - new int[EvmStack.ReturnStackSize] - ); - } - } - private static readonly ThreadLocal _stackPool = new(static () => new StackPool()); + private static readonly StackPool _stackPool = new(); public byte[]? DataStack; @@ -81,7 +29,7 @@ public void ReturnStacks(byte[] dataStack, int[] returnStack) public int ReturnStackHead = 0; private bool _canRestore = true; /// - /// Contructor for a top level . + /// Constructor for a top level . /// public EvmState( long gasAvailable, @@ -101,7 +49,7 @@ public EvmState( { } /// - /// Contructor for a top level . + /// Constructor for a top level . /// public EvmState( long gasAvailable, @@ -120,7 +68,7 @@ public EvmState( { } /// - /// Contructor for a frame beneath top level. + /// Constructor for a frame beneath top level. /// internal EvmState( long gasAvailable, @@ -215,7 +163,7 @@ public void Dispose() if (DataStack is not null) { // Only Dispose once - _stackPool.Value.ReturnStacks(DataStack, ReturnStack!); + _stackPool.ReturnStacks(DataStack, ReturnStack!); DataStack = null; ReturnStack = null; } @@ -228,14 +176,14 @@ public void InitStacks() { if (DataStack is null) { - (DataStack, ReturnStack) = _stackPool.Value.RentStacks(); + (DataStack, ReturnStack) = _stackPool.RentStacks(); } } public void CommitToParent(EvmState parentState) { parentState.Refund += Refund; - _canRestore = false; // we can't restore if we commited + _canRestore = false; // we can't restore if we committed } private void Restore() diff --git a/src/Nethermind/Nethermind.Evm/StackPool.cs b/src/Nethermind/Nethermind.Evm/StackPool.cs new file mode 100644 index 00000000000..5564fbe045c --- /dev/null +++ b/src/Nethermind/Nethermind.Evm/StackPool.cs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Concurrent; + +namespace Nethermind.Evm; + +internal class StackPool +{ + // Also have parallel prewarming and Rpc calls + private const int MaxStacksPooled = VirtualMachine.MaxCallDepth * 2; + private readonly struct StackItem(byte[] dataStack, int[] returnStack) + { + public readonly byte[] DataStack = dataStack; + public readonly int[] ReturnStack = returnStack; + } + + private readonly ConcurrentQueue _stackPool = new(); + + /// + /// The word 'return' acts here once as a verb 'to return stack to the pool' and once as a part of the + /// compound noun 'return stack' which is a stack of subroutine return values. + /// + /// + /// + public void ReturnStacks(byte[] dataStack, int[] returnStack) + { + if (_stackPool.Count <= MaxStacksPooled) + { + _stackPool.Enqueue(new(dataStack, returnStack)); + } + } + + public (byte[], int[]) RentStacks() + { + if (_stackPool.TryDequeue(out StackItem result)) + { + return (result.DataStack, result.ReturnStack); + } + + return + ( + new byte[(EvmStack.MaxStackSize + EvmStack.RegisterLength) * 32], + new int[EvmStack.ReturnStackSize] + ); + } +} + From bbfc2cd354034fee416b2889c65dd71ed532632c Mon Sep 17 00:00:00 2001 From: "core-repository-dispatch-app[bot]" <173070810+core-repository-dispatch-app[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 10:46:43 +0100 Subject: [PATCH 054/113] Auto-update fast sync settings (#7979) Co-authored-by: rubo Co-authored-by: Lukasz Rozmej --- src/Nethermind/Nethermind.Runner/configs/base-mainnet.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/base-sepolia.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/chiado.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/energyweb.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/exosama.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/gnosis.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/joc-testnet.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/mainnet.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/op-mainnet.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/op-sepolia.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/sepolia.json | 4 ++-- src/Nethermind/Nethermind.Runner/configs/volta.json | 6 +++--- 15 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json index dcc3aebf279..30d6a0649d4 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 24010000, - "PivotHash": "0x831cdfb4ba46281fafb2c1be0c7ecd0a9ca91316f4f93883ed1328de843c0896", + "PivotNumber": 24310000, + "PivotHash": "0x417f11e9ecf84f33722b817548441a596006fe41923ef283eaf142c0b09057df", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json index b803a1b43fc..864deaada97 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 19520000, - "PivotHash": "0x41ebcba59e2a4f6e5e2cc1776ea424ed6784000ba2fd8188ac7c23cb23563005", + "PivotNumber": 19820000, + "PivotHash": "0x1866ba44cc6f250f1127c401ab3f91e02bc5310d8717f49f2b5c304c5d364ea6", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.json b/src/Nethermind/Nethermind.Runner/configs/chiado.json index 324886412a8..a0855106549 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.json +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.json @@ -16,8 +16,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 13420000, - "PivotHash": "0x3f27cab16c8b54df8d749594e437450927fcb2f420c7aa63afa1c920215ffc6c", + "PivotNumber": 13540000, + "PivotHash": "0x9caa530d8ecba3d2ae14ede428b6814ee98861d272db473f5a0ffeb7bb57ccf0", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", "FastSyncCatchUpHeightDelta": "10000000000", "UseGethLimitsInFastBlocks": false diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb.json b/src/Nethermind/Nethermind.Runner/configs/energyweb.json index 2d130550054..2bb7a8373cf 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.json +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.json @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 33390000, - "PivotHash": "0xcf4df44a619f42f83caa5c123031355b955b2c56ba7a3b2b68d9766ee76993cd", - "PivotTotalDifficulty": "11362028231490135295042078142146740580135625148", + "PivotNumber": 33500000, + "PivotHash": "0x9889c00d49a47aa28aecee906bf6ff1009ae4aad28987a1fc7765e00f7257095", + "PivotTotalDifficulty": "11399459291851438526023049348964235083395554979", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama.json b/src/Nethermind/Nethermind.Runner/configs/exosama.json index 3505731c171..093cfaca31e 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.json +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.json @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 13670000, - "PivotHash": "0xc2ad9b50f13ddc0f96a6f5b308c662eb462e28e3c403e523f2656a8a89aa43b9", - "PivotTotalDifficulty": "4651659955809228795544330883592271450243033281", + "PivotNumber": 13800000, + "PivotHash": "0x09481e05ba5ea79fbf3d0ad65f85746e510d9a58e5cc3c4ec8bf4dbcf21cc751", + "PivotTotalDifficulty": "4695896663508950795794569582558401317732053281", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.json b/src/Nethermind/Nethermind.Runner/configs/gnosis.json index c36335c23e9..20bad1be9c5 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.json +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.json @@ -13,8 +13,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 37630000, - "PivotHash": "0x0946886e7530f480d96aa5288051dacec18fb6edb736193901d890c4b815b4fe", + "PivotNumber": 37750000, + "PivotHash": "0x7ed0ac3f5d0032c4c794c363f5073aba604416fae8b117e472f5fe824c8600a6", "PivotTotalDifficulty": "8626000110427538733349499292577475819600160930", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json index 5a9ee576b99..100fe99c13f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 15040000, - "PivotHash": "0x5b7130b946ce69918c1eed9c8a231470567f2927cd346be7181fff04d2377eb6", - "PivotTotalDifficulty": "29208629" + "PivotNumber": 15160000, + "PivotHash": "0x76f2b33e4a63cac3fe1f230c42f578a3728d55b743b257f97edcbe725601b915", + "PivotTotalDifficulty": "29376308" }, "Metrics": { "NodeName": "JOC-Mainnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json index 89b30eb3e39..b7752df4a8c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 8640000, - "PivotHash": "0xe4cc87261bff1b877ac7086fb6c15606b674c8572d6b1aedd45c0d21f6564996", - "PivotTotalDifficulty": "15378420" + "PivotNumber": 8760000, + "PivotHash": "0x7e7b570759ae5dbe167ef5afdf34d38a4f5113d5cf66192f43e59a0aa4109c07", + "PivotTotalDifficulty": "15552727" }, "Metrics": { "NodeName": "JOC-Testnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json index 6dc4ec6ec79..e001014f985 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json @@ -16,9 +16,9 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 13600000, - "PivotHash": "0xb835bb6b7e37d43eeef5f669daaf18f8f925a58c603b20ed99273afac2d6bc1c", - "PivotTotalDifficulty": "27200001", + "PivotNumber": 13890000, + "PivotHash": "0xd8769b604da37c0873f54c3ff2b1cb34a158c5ec61c8183a3fe9d7cbc71f2176", + "PivotTotalDifficulty": "27780001", "HeaderStateDistance": 6 }, "JsonRpc": { diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json index 756a183b6fb..ca57ec0b7f0 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json @@ -16,9 +16,9 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 7300000, - "PivotHash": "0xb5be783d3492d6440fd646a4ea3c76b0d91bf31e597c463a0a236fe217ec59ec", - "PivotTotalDifficulty": "14600001", + "PivotNumber": 7540000, + "PivotHash": "0x0a13ca1767c2f037f5fe806f43c63934b7d1af6c75736916074d52c5a09d1305", + "PivotTotalDifficulty": "15080001", "HeaderStateDistance": 6 }, "JsonRpc": { diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.json b/src/Nethermind/Nethermind.Runner/configs/mainnet.json index 6da66d8db45..6988055fd64 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.json @@ -9,8 +9,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 21453000, - "PivotHash": "0x26edc7632b3f2509f4b2b5bc43b2cec38db019004ffdec57a13eb5138897b3c2", + "PivotNumber": 21503000, + "PivotHash": "0xa90c674e7137bfb87cce458b18b5391ff615944060128ef9c9d5b7b1f4d09cb1", "PivotTotalDifficulty": "58750003716598352816469", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json index aad3991ef58..11e5703214c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json @@ -16,8 +16,8 @@ "AncientBodiesBarrier": 105235063, "AncientReceiptsBarrier": 105235063, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 129600000, - "PivotHash": "0xd06264ead4bb1a026135affe815b3b817c835f9513358e18991391c19b727eb9", + "PivotNumber": 129900000, + "PivotHash": "0x6ed7a63e1752a64fa777d1f07974b50bd43270c9d9333c88535cea0cf7e7cbbb", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json index a361b2efa53..1cf0917d14f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 21500000, - "PivotHash": "0x4cf34352e99086e20ea35f4b226944439ec33aee26d11195428b1a9acb118a4c", + "PivotNumber": 21800000, + "PivotHash": "0x2785448281eaa9cd8b1f828ec54cc090df5bb6075110df31217a9d6651a9f4e0", "PivotTotalDifficulty": "0" }, "Discovery": { diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.json b/src/Nethermind/Nethermind.Runner/configs/sepolia.json index 8dcca161e6f..bddfdf17321 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.json @@ -17,8 +17,8 @@ "FastSync": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 7327000, - "PivotHash": "0xe40a6655fec461e11c519b88a1deb09a72cd281f8891f4bef9e7ed9284aed616", + "PivotNumber": 7374000, + "PivotHash": "0x089a3035ba78279275bbd907a09d6c401f1ff305d8cd1dacba207f3127940e47", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.json b/src/Nethermind/Nethermind.Runner/configs/volta.json index e97f1790683..effc9617664 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.json +++ b/src/Nethermind/Nethermind.Runner/configs/volta.json @@ -15,9 +15,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 30370000, - "PivotHash": "0x1d4bde4ad082c4fb179e539141e85b06e54ac053acb461a4f2b8983a919aa8e7", - "PivotTotalDifficulty": "10334375483388901135382686827702800581541531379", + "PivotNumber": 30460000, + "PivotHash": "0x03df63df628a75b21087556f0178a84ee610a2007ce700e8bd2e923bb6c1b3b9", + "PivotTotalDifficulty": "10365000896411785597094390542371659720572358821", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, From 8eba3acecb17043cb45d1b902d9edd68756431b4 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 30 Dec 2024 18:04:53 +0800 Subject: [PATCH 055/113] Fix spammy log during snap sync (#7977) --- .../SnapSync/StateSyncPivotTest.cs | 2 +- .../Nethermind.Synchronization/FastSync/StateSyncPivot.cs | 4 ++-- .../Nethermind.Synchronization/SnapSync/ProgressTracker.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs index 1e2e6e187e7..6e5e7b1ab8a 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/StateSyncPivotTest.cs @@ -43,6 +43,6 @@ int syncPivot stateSyncPivot.GetPivotHeader().Should().NotBeNull(); blockTree.BestSuggestedHeader.Returns(Build.A.BlockHeader.WithNumber(newBestSuggested).TestObject); - stateSyncPivot.GetPivotHeader().Number.Should().Be(newPivotHeader); + stateSyncPivot.GetPivotHeader()?.Number.Should().Be(newPivotHeader); } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs index 7d33bfb71ef..f9174805406 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/StateSyncPivot.cs @@ -16,7 +16,7 @@ namespace Nethermind.Synchronization.FastSync public class StateSyncPivot { private readonly IBlockTree _blockTree; - private BlockHeader _bestHeader; + private BlockHeader? _bestHeader; private readonly ILogger _logger; private readonly ISyncConfig _syncConfig; @@ -35,7 +35,7 @@ public StateSyncPivot(IBlockTree blockTree, ISyncConfig syncConfig, ILogManager _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); } - public BlockHeader GetPivotHeader() + public BlockHeader? GetPivotHeader() { if (_bestHeader is null || (_blockTree.BestSuggestedHeader?.Number + MultiSyncModeSelector.FastSyncLag) - _bestHeader.Number >= _syncConfig.StateMaxDistanceFromHead) { diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index 253ac4b8bd1..0f6be8f9a67 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -137,7 +137,7 @@ public void UpdatePivot() public bool IsFinished(out SnapSyncBatch? nextBatch) { - if (!CanSync()) + if (_pivot.GetPivotHeader() is null) { nextBatch = null; return false; From 8e6388b89bb8fa61183b76551b2fa63fd757d3cd Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 30 Dec 2024 15:50:37 +0100 Subject: [PATCH 056/113] Change for 7702 in devnet 5 (#7980) --- .../Encoding/AuthorizationTupleDecoderTests.cs | 14 +++++++------- .../Nethermind.Core/AuthorizationTuple.cs | 6 +++--- .../Eip7702/AuthorizationTupleDecoder.cs | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs index 590012bd66d..be7ef4c4be4 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs @@ -53,7 +53,7 @@ public static IEnumerable WrongSizeFieldsEncodedCases() { yield return TupleRlpStream( //Wrong chain size - Enumerable.Range(0, 9).Select(static i => (byte)0xFF).ToArray(), + Enumerable.Range(0, 33).Select(static i => (byte)0xFF).ToArray(), Address.Zero.Bytes, Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 1).Select(static i => (byte)0xFF).ToArray(), @@ -63,7 +63,7 @@ public static IEnumerable WrongSizeFieldsEncodedCases() yield return TupleRlpStream( //Wrong address size - Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), + Enumerable.Range(0, 32).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 19).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 1).Select(static i => (byte)0xFF).ToArray(), @@ -73,7 +73,7 @@ public static IEnumerable WrongSizeFieldsEncodedCases() yield return TupleRlpStream( //Wrong address size - Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), + Enumerable.Range(0, 32).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 21).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 1).Select(static i => (byte)0xFF).ToArray(), @@ -83,7 +83,7 @@ public static IEnumerable WrongSizeFieldsEncodedCases() yield return TupleRlpStream( //Wrong nonce size - Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), + Enumerable.Range(0, 32).Select(static i => (byte)0xFF).ToArray(), Address.Zero.Bytes, Enumerable.Range(0, 9).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 1).Select(static i => (byte)0xFF).ToArray(), @@ -93,7 +93,7 @@ public static IEnumerable WrongSizeFieldsEncodedCases() yield return TupleRlpStream( //Wrong yParity size - Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), + Enumerable.Range(0, 32).Select(static i => (byte)0xFF).ToArray(), Address.Zero.Bytes, Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 2).Select(static i => (byte)0xFF).ToArray(), @@ -103,7 +103,7 @@ public static IEnumerable WrongSizeFieldsEncodedCases() yield return TupleRlpStream( //Wrong R size - Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), + Enumerable.Range(0, 32).Select(static i => (byte)0xFF).ToArray(), Address.Zero.Bytes, Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 1).Select(static i => (byte)0xFF).ToArray(), @@ -113,7 +113,7 @@ public static IEnumerable WrongSizeFieldsEncodedCases() yield return TupleRlpStream( //Wrong S size - Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), + Enumerable.Range(0, 32).Select(static i => (byte)0xFF).ToArray(), Address.Zero.Bytes, Enumerable.Range(0, 8).Select(static i => (byte)0xFF).ToArray(), Enumerable.Range(0, 1).Select(static i => (byte)0xFF).ToArray(), diff --git a/src/Nethermind/Nethermind.Core/AuthorizationTuple.cs b/src/Nethermind/Nethermind.Core/AuthorizationTuple.cs index c49e374a2c4..c5f91203b69 100644 --- a/src/Nethermind/Nethermind.Core/AuthorizationTuple.cs +++ b/src/Nethermind/Nethermind.Core/AuthorizationTuple.cs @@ -6,14 +6,14 @@ namespace Nethermind.Core; public class AuthorizationTuple( - ulong chainId, + UInt256 chainId, Address codeAddress, ulong nonce, Signature sig, Address? authority = null) { public AuthorizationTuple( - ulong chainId, + UInt256 chainId, Address codeAddress, ulong nonce, byte yParity, @@ -22,7 +22,7 @@ public AuthorizationTuple( Address? authority = null) : this(chainId, codeAddress, nonce, new Signature(r, s, (ulong)yParity + Signature.VOffset), authority) { } - public ulong ChainId { get; } = chainId; + public UInt256 ChainId { get; } = chainId; public Address CodeAddress { get; protected set; } = codeAddress; public ulong Nonce { get; } = nonce; public Signature AuthoritySignature { get; protected set; } = sig; diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs index 46bbc1cf887..192f4a64e49 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs @@ -19,7 +19,7 @@ public AuthorizationTuple Decode(RlpStream stream, RlpBehaviors rlpBehaviors = R { int length = stream.ReadSequenceLength(); int check = length + stream.Position; - ulong chainId = stream.DecodeULong(); + UInt256 chainId = stream.DecodeUInt256(); Address? codeAddress = stream.DecodeAddress(); ulong nonce = stream.DecodeULong(); byte yParity = stream.DecodeByte(); @@ -43,7 +43,7 @@ public AuthorizationTuple Decode(ref Rlp.ValueDecoderContext decoderContext, Rlp { int length = decoderContext.ReadSequenceLength(); int check = length + decoderContext.Position; - ulong chainId = decoderContext.DecodeULong(); + UInt256 chainId = decoderContext.DecodeUInt256(); Address? codeAddress = decoderContext.DecodeAddress(); ulong nonce = decoderContext.DecodeULong(); byte yParity = decoderContext.DecodeByte(); @@ -82,7 +82,7 @@ public void Encode(RlpStream stream, AuthorizationTuple item, RlpBehaviors rlpBe stream.Encode(new UInt256(item.AuthoritySignature.S, true)); } - public NettyRlpStream EncodeWithoutSignature(ulong chainId, Address codeAddress, ulong nonce) + public NettyRlpStream EncodeWithoutSignature(UInt256 chainId, Address codeAddress, ulong nonce) { int contentLength = GetContentLengthWithoutSig(chainId, codeAddress, nonce); var totalLength = Rlp.LengthOfSequence(contentLength); @@ -92,7 +92,7 @@ public NettyRlpStream EncodeWithoutSignature(ulong chainId, Address codeAddress, return stream; } - public void EncodeWithoutSignature(RlpStream stream, ulong chainId, Address codeAddress, ulong nonce) + public void EncodeWithoutSignature(RlpStream stream, UInt256 chainId, Address codeAddress, ulong nonce) { int contentLength = GetContentLengthWithoutSig(chainId, codeAddress, nonce); stream.StartSequence(contentLength); @@ -109,7 +109,7 @@ private static int GetContentLength(AuthorizationTuple tuple) => + Rlp.LengthOf(new UInt256(tuple.AuthoritySignature.R.AsSpan(), true)) + Rlp.LengthOf(new UInt256(tuple.AuthoritySignature.S.AsSpan(), true)); - private static int GetContentLengthWithoutSig(ulong chainId, Address codeAddress, ulong nonce) => + private static int GetContentLengthWithoutSig(UInt256 chainId, Address codeAddress, ulong nonce) => Rlp.LengthOf(chainId) + Rlp.LengthOf(codeAddress) + Rlp.LengthOf(nonce); From 5c6299f01ee5275029a6ba899b587fe31513ec06 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Tue, 31 Dec 2024 11:29:20 +0000 Subject: [PATCH 057/113] Reduce parallel prewarming overwork (#7983) --- .../Processing/BlockCachePreWarmer.cs | 17 +++++------ .../SystemTransactionProcessor.cs | 4 +-- .../TransactionProcessor.cs | 30 +++++++++---------- .../Nethermind.Evm/VirtualMachine.cs | 2 +- .../Simulate/SimulateTransactionProcessor.cs | 2 +- .../OptimismTransactionProcessor.cs | 2 +- .../TaikoTransactionProcessor.cs | 6 ++-- 7 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs index 032015356a4..0e22e03213e 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs @@ -24,7 +24,6 @@ namespace Nethermind.Consensus.Processing; public sealed class BlockCachePreWarmer(ReadOnlyTxProcessingEnvFactory envFactory, ISpecProvider specProvider, ILogManager logManager, PreBlockCaches? preBlockCaches = null) : IBlockCachePreWarmer { private readonly ObjectPool _envPool = new DefaultObjectPool(new ReadOnlyTxProcessingEnvPooledObjectPolicy(envFactory), Environment.ProcessorCount * 4); - private readonly ObjectPool _systemTransactionPool = new DefaultObjectPool(new DefaultPooledObjectPolicy(), Environment.ProcessorCount * 4); private readonly ILogger _logger = logManager.GetClassLogger(); public Task PreWarmCaches(Block suggestedBlock, Hash256? parentStateRoot, IReleaseSpec spec, CancellationToken cancellationToken = default, params ReadOnlySpan systemAccessLists) @@ -135,7 +134,6 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp ParallelUnbalancedWork.For(0, block.Transactions.Length, parallelOptions, new(this, block, stateRoot, spec), static (i, state) => { IReadOnlyTxProcessorSource env = state.PreWarmer._envPool.Get(); - SystemTransaction systemTransaction = state.PreWarmer._systemTransactionPool.Get(); Transaction? tx = null; try { @@ -143,7 +141,6 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp if (state.Block.TransactionProcessed > i) return state; tx = state.Block.Transactions[i]; - tx.CopyTo(systemTransaction); using IReadOnlyTxProcessingScope scope = env.Build(state.StateRoot); Address senderAddress = tx.SenderAddress!; @@ -170,7 +167,7 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp { scope.WorldState.WarmUp(tx.AccessList); // eip-2930 } - TransactionResult result = scope.TransactionProcessor.Warmup(systemTransaction, new BlockExecutionContext(state.Block.Header.Clone()), NullTxTracer.Instance); + TransactionResult result = scope.TransactionProcessor.Warmup(tx, new BlockExecutionContext(state.BlockHeader), NullTxTracer.Instance); if (state.PreWarmer._logger.IsTrace) state.PreWarmer._logger.Trace($"Finished pre-warming cache for tx[{i}] {tx.Hash} with {result}"); } catch (Exception ex) when (ex is EvmException or OverflowException) @@ -183,7 +180,6 @@ private void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec sp } finally { - state.PreWarmer._systemTransactionPool.Return(systemTransaction); state.PreWarmer._envPool.Return(env); } @@ -308,12 +304,13 @@ private class ReadOnlyTxProcessingEnvPooledObjectPolicy(ReadOnlyTxProcessingEnvF public bool Return(IReadOnlyTxProcessorSource obj) => true; } - private struct BlockState(BlockCachePreWarmer preWarmer, Block block, Hash256 stateRoot, IReleaseSpec spec) + private readonly struct BlockState(BlockCachePreWarmer preWarmer, Block block, Hash256 stateRoot, IReleaseSpec spec) { - public BlockCachePreWarmer PreWarmer = preWarmer; - public Block Block = block; - public Hash256 StateRoot = stateRoot; - public IReleaseSpec Spec = spec; + public readonly BlockCachePreWarmer PreWarmer = preWarmer; + public readonly Block Block = block; + public readonly Hash256 StateRoot = stateRoot; + public readonly IReleaseSpec Spec = spec; + public readonly BlockHeader BlockHeader => Block.Header; } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs index 9eaab2cd442..dfcc817703e 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs @@ -38,8 +38,8 @@ protected override TransactionResult Execute(Transaction tx, in BlockExecutionCo WorldState.CreateAccountIfNotExists(Address.SystemUser, UInt256.Zero, UInt256.Zero); } - return base.Execute(tx, in blCtx, tracer, (opts != ExecutionOptions.Warmup && !opts.HasFlag(ExecutionOptions.NoValidation)) - ? opts | (ExecutionOptions)OriginalValidate | ExecutionOptions.NoValidation + return base.Execute(tx, in blCtx, tracer, (opts != ExecutionOptions.SkipValidation && !opts.HasFlag(ExecutionOptions.SkipValidationAndCommit)) + ? opts | (ExecutionOptions)OriginalValidate | ExecutionOptions.SkipValidationAndCommit : opts); } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 83ac64d7a68..ce3038cf504 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -64,17 +64,17 @@ protected enum ExecutionOptions /// /// Skip potential fail checks /// - Warmup = 4, + SkipValidation = 4, /// /// Skip potential fail checks and commit state after execution /// - NoValidation = Commit | Warmup, + SkipValidationAndCommit = Commit | SkipValidation, /// /// Commit and later restore state also skip validation, use for CallAndRestore /// - CommitAndRestore = Commit | Restore | NoValidation + CommitAndRestore = Commit | Restore | SkipValidation } protected TransactionProcessorBase( @@ -115,10 +115,10 @@ public TransactionResult Execute(Transaction transaction, in BlockExecutionConte ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.Commit); public TransactionResult Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => - ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.NoValidation); + ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.SkipValidationAndCommit); public TransactionResult Warmup(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => - ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.Warmup); + ExecuteCore(transaction, in blCtx, txTracer, ExecutionOptions.SkipValidation); private TransactionResult ExecuteCore(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { @@ -141,7 +141,7 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon // commit - is for standard execute, we will commit thee state after execution // !commit - is for build up during block production, we won't commit state after each transaction to support rollbacks // we commit only after all block is constructed - bool commit = opts.HasFlag(ExecutionOptions.Commit) || (!opts.HasFlag(ExecutionOptions.Warmup) && !spec.IsEip658Enabled); + bool commit = opts.HasFlag(ExecutionOptions.Commit) || (!opts.HasFlag(ExecutionOptions.SkipValidation) && !spec.IsEip658Enabled); TransactionResult result; if (!(result = ValidateStatic(tx, header, spec, opts, out long intrinsicGas))) return result; @@ -177,7 +177,7 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon } else { - if (!opts.HasFlag(ExecutionOptions.NoValidation)) + if (!opts.HasFlag(ExecutionOptions.SkipValidation)) WorldState.AddToBalance(tx.SenderAddress!, senderReservedGasPayment, spec); DecrementNonce(tx); @@ -347,7 +347,7 @@ protected virtual TransactionResult ValidateStatic( { intrinsicGas = IntrinsicGasCalculator.Calculate(tx, spec); - bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); + bool validate = !opts.HasFlag(ExecutionOptions.SkipValidation); if (tx.SenderAddress is null) { @@ -401,7 +401,7 @@ protected virtual bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, { bool commit = opts.HasFlag(ExecutionOptions.Commit) || !spec.IsEip658Enabled; bool restore = opts.HasFlag(ExecutionOptions.Restore); - bool noValidation = opts.HasFlag(ExecutionOptions.NoValidation); + bool noValidation = opts.HasFlag(ExecutionOptions.SkipValidation); if (Logger.IsDebug) Logger.Debug($"TX sender account does not exist {sender} - trying to recover it"); @@ -436,7 +436,7 @@ protected virtual bool RecoverSenderIfNeeded(Transaction tx, IReleaseSpec spec, protected virtual TransactionResult ValidateSender(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) { - bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); + bool validate = !opts.HasFlag(ExecutionOptions.SkipValidation); if (validate && WorldState.IsInvalidContractSender(spec, tx.SenderAddress!)) { @@ -453,7 +453,7 @@ protected virtual TransactionResult BuyGas(Transaction tx, BlockHeader header, I premiumPerGas = UInt256.Zero; senderReservedGasPayment = UInt256.Zero; blobBaseFee = UInt256.Zero; - bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); + bool validate = !opts.HasFlag(ExecutionOptions.SkipValidation); if (validate) { @@ -579,7 +579,7 @@ private ExecutionEnvironment BuildExecutionEnvironment( ); } - protected virtual bool ShouldValidate(ExecutionOptions opts) => !opts.HasFlag(ExecutionOptions.NoValidation); + protected virtual bool ShouldValidate(ExecutionOptions opts) => !opts.HasFlag(ExecutionOptions.SkipValidation); protected virtual void ExecuteEvmCall( Transaction tx, @@ -696,7 +696,7 @@ protected virtual void ExecuteEvmCall( WorldState.Restore(snapshot); Complete: - if (!opts.HasFlag(ExecutionOptions.NoValidation)) + if (!opts.HasFlag(ExecutionOptions.SkipValidation)) header.GasUsed += spentGas; } @@ -765,7 +765,7 @@ protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec s if (Logger.IsTrace) Logger.Trace("Refunding unused gas of " + unspentGas + " and refund of " + actualRefund); // If noValidation we didn't charge for gas, so do not refund - if (!opts.HasFlag(ExecutionOptions.NoValidation)) + if (!opts.HasFlag(ExecutionOptions.SkipValidation)) WorldState.AddToBalance(tx.SenderAddress!, (ulong)(unspentGas + actualRefund) * gasPrice, spec); spentGas -= actualRefund; } @@ -776,7 +776,7 @@ protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec s if (Logger.IsTrace) Logger.Trace("Refunding delegations only: " + refund); // If noValidation we didn't charge for gas, so do not refund - if (!opts.HasFlag(ExecutionOptions.NoValidation)) + if (!opts.HasFlag(ExecutionOptions.SkipValidation)) WorldState.AddToBalance(tx.SenderAddress!, (ulong)refund * gasPrice, spec); spentGas -= refund; } diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index c7c32b01ded..88525f10b84 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -2496,7 +2496,7 @@ private EvmExceptionType InstructionLog(EvmState vmState, ref EvmStack ReadOnlyMemory data = vmState.Memory.Load(in position, length); Hash256[] topics = new Hash256[topicsCount]; - for (int i = 0; i < topicsCount; i++) + for (int i = 0; i < topics.Length; i++) { topics[i] = new Hash256(stack.PopWord256()); } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs index 60d4c6df049..2e50055564f 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs @@ -26,7 +26,7 @@ protected override TransactionResult Execute(Transaction tx, in BlockExecutionCo { if (!validate) { - opts |= ExecutionOptions.NoValidation; + opts |= ExecutionOptions.SkipValidation; } return base.Execute(tx, in blCtx, tracer, opts); diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs index 716b22bd539..b13b19502cc 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs @@ -70,7 +70,7 @@ protected override TransactionResult BuyGas(Transaction tx, BlockHeader header, senderReservedGasPayment = UInt256.Zero; blobBaseFee = UInt256.Zero; - bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); + bool validate = !opts.HasFlag(ExecutionOptions.SkipValidation); UInt256 senderBalance = WorldState.GetBalance(tx.SenderAddress!); diff --git a/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs b/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs index 595230ade5c..4bd8f8965b2 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs @@ -23,15 +23,15 @@ public class TaikoTransactionProcessor( { protected override TransactionResult ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, out long intrinsicGas) - => base.ValidateStatic(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.NoValidation : opts, out intrinsicGas); + => base.ValidateStatic(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, out intrinsicGas); protected override TransactionResult BuyGas(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, in UInt256 effectiveGasPrice, out UInt256 premiumPerGas, out UInt256 senderReservedGasPayment, out UInt256 blobBaseFee) - => base.BuyGas(tx, header, spec, tracer, tx.IsAnchorTx ? opts | ExecutionOptions.NoValidation : opts, in effectiveGasPrice, out premiumPerGas, out senderReservedGasPayment, out blobBaseFee); + => base.BuyGas(tx, header, spec, tracer, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, in effectiveGasPrice, out premiumPerGas, out senderReservedGasPayment, out blobBaseFee); protected override long Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, in TransactionSubstate substate, in long unspentGas, in UInt256 gasPrice, int codeInsertRefunds) - => base.Refund(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.NoValidation : opts, substate, unspentGas, gasPrice, codeInsertRefunds); + => base.Refund(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, substate, unspentGas, gasPrice, codeInsertRefunds); protected override void PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in UInt256 blobBaseFee, in byte statusCode) { From 14cfa0e71eadce40a436dc1f0a955c3672215392 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Tue, 31 Dec 2024 11:32:43 +0000 Subject: [PATCH 058/113] Reuse thread state when prewarming addresses in parallel (#7984) --- .../Processing/BlockCachePreWarmer.cs | 74 +++++++++++++------ .../Threading/ParallelUnbalancedWork.cs | 67 ++++++++++------- 2 files changed, 94 insertions(+), 47 deletions(-) diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs index 0e22e03213e..4659441e62c 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs @@ -97,10 +97,10 @@ private void WarmupWithdrawals(ParallelOptions parallelOptions, IReleaseSpec spe { if (spec.WithdrawalsEnabled && block.Withdrawals is not null) { - ParallelUnbalancedWork.For(0, block.Withdrawals.Length, parallelOptions, (preWarmer: this, block, stateRoot), + ParallelUnbalancedWork.For(0, block.Withdrawals.Length, parallelOptions, (envPool: _envPool, block, stateRoot), static (i, state) => { - IReadOnlyTxProcessorSource env = state.preWarmer._envPool.Get(); + IReadOnlyTxProcessorSource env = state.envPool.Get(); try { using IReadOnlyTxProcessingScope scope = env.Build(state.stateRoot); @@ -108,7 +108,7 @@ private void WarmupWithdrawals(ParallelOptions parallelOptions, IReleaseSpec spe } finally { - state.preWarmer._envPool.Return(env); + state.envPool.Return(env); } return state; @@ -242,11 +242,12 @@ private void WarmupAddresses(ParallelOptions parallelOptions, Block block) { if (parallelOptions.CancellationToken.IsCancellationRequested) return; + ObjectPool envPool = PreWarmer._envPool; try { if (SystemTxAccessLists is not null) { - var env = PreWarmer._envPool.Get(); + var env = envPool.Get(); try { using IReadOnlyTxProcessingScope scope = env.Build(StateRoot); @@ -258,38 +259,36 @@ private void WarmupAddresses(ParallelOptions parallelOptions, Block block) } finally { - PreWarmer._envPool.Return(env); + envPool.Return(env); SystemTxAccessLists.Dispose(); } } - ParallelUnbalancedWork.For(0, block.Transactions.Length, parallelOptions, (preWarmer: PreWarmer, block, StateRoot), + AddressWarmingState baseState = new(envPool, block, StateRoot); + + ParallelUnbalancedWork.For( + 0, + block.Transactions.Length, + parallelOptions, + baseState.InitThreadState, static (i, state) => { - Transaction tx = state.block.Transactions[i]; + Transaction tx = state.Block.Transactions[i]; Address? sender = tx.SenderAddress; - var env = state.preWarmer._envPool.Get(); - try + if (sender is not null) { - using IReadOnlyTxProcessingScope scope = env.Build(state.StateRoot); - if (sender is not null) - { - scope.WorldState.WarmUp(sender); - } - Address to = tx.To; - if (to is not null) - { - scope.WorldState.WarmUp(to); - } + state.Scope.WorldState.WarmUp(sender); } - finally + Address to = tx.To; + if (to is not null) { - state.preWarmer._envPool.Return(env); + state.Scope.WorldState.WarmUp(to); } return state; - }); + }, + AddressWarmingState.FinallyAction); } catch (OperationCanceledException) { @@ -298,6 +297,37 @@ private void WarmupAddresses(ParallelOptions parallelOptions, Block block) } } + private readonly struct AddressWarmingState(ObjectPool envPool, Block block, Hash256 stateRoot) : IDisposable + { + public static Action FinallyAction { get; } = DisposeThreadState; + + public readonly ObjectPool EnvPool = envPool; + public readonly Block Block = block; + public readonly Hash256 StateRoot = stateRoot; + public readonly IReadOnlyTxProcessorSource? Env; + public readonly IReadOnlyTxProcessingScope? Scope; + + public AddressWarmingState(ObjectPool envPool, Block block, Hash256 stateRoot, IReadOnlyTxProcessorSource env, IReadOnlyTxProcessingScope scope) : this(envPool, block, stateRoot) + { + Env = env; + Scope = scope; + } + + public AddressWarmingState InitThreadState() + { + IReadOnlyTxProcessorSource env = EnvPool.Get(); + return new(EnvPool, Block, StateRoot, env, scope: env.Build(StateRoot)); + } + + public void Dispose() + { + Scope.Dispose(); + EnvPool.Return(Env); + } + + private static void DisposeThreadState(AddressWarmingState state) => state.Dispose(); + } + private class ReadOnlyTxProcessingEnvPooledObjectPolicy(ReadOnlyTxProcessingEnvFactory envFactory) : IPooledObjectPolicy { public IReadOnlyTxProcessorSource Create() => envFactory.Create(); diff --git a/src/Nethermind/Nethermind.Core/Threading/ParallelUnbalancedWork.cs b/src/Nethermind/Nethermind.Core/Threading/ParallelUnbalancedWork.cs index c54d39cc255..1b0d691c091 100644 --- a/src/Nethermind/Nethermind.Core/Threading/ParallelUnbalancedWork.cs +++ b/src/Nethermind/Nethermind.Core/Threading/ParallelUnbalancedWork.cs @@ -41,7 +41,7 @@ public static void For(int fromInclusive, int toExclusive, ParallelOptions paral { int threads = parallelOptions.MaxDegreeOfParallelism > 0 ? parallelOptions.MaxDegreeOfParallelism : Environment.ProcessorCount; - Data data = new(threads, fromInclusive, toExclusive, action); + Data data = new(threads, fromInclusive, toExclusive, action, parallelOptions.CancellationToken); for (int i = 0; i < threads - 1; i++) { @@ -55,6 +55,8 @@ public static void For(int fromInclusive, int toExclusive, ParallelOptions paral { data.Event.Wait(); } + + parallelOptions.CancellationToken.ThrowIfCancellationRequested(); } /// @@ -137,16 +139,22 @@ private ParallelUnbalancedWork(Data data) /// public void Execute() { - int i = _data.Index.GetNext(); - while (i < _data.ToExclusive) + try + { + int i = _data.Index.GetNext(); + while (i < _data.ToExclusive) + { + if (_data.CancellationToken.IsCancellationRequested) return; + _data.Action(i); + // Get the next index + i = _data.Index.GetNext(); + } + } + finally { - _data.Action(i); - // Get the next index - i = _data.Index.GetNext(); + // Signal that this thread has completed its work + _data.MarkThreadCompleted(); } - - // Signal that this thread has completed its work - _data.MarkThreadCompleted(); } /// @@ -173,7 +181,7 @@ private struct PaddedValue(int value) /// /// Represents the base data shared among threads during parallel execution. /// - private class BaseData(int threads, int fromInclusive, int toExclusive) + private class BaseData(int threads, int fromInclusive, int toExclusive, CancellationToken token) { /// /// Gets the shared counter for indices. @@ -181,6 +189,7 @@ private class BaseData(int threads, int fromInclusive, int toExclusive) public SharedCounter Index { get; } = new SharedCounter(fromInclusive); public SemaphoreSlim Event { get; } = new(initialCount: 0); private int _activeThreads = threads; + public CancellationToken CancellationToken { get; } = token; /// /// Gets the exclusive upper bound of the range. @@ -212,8 +221,8 @@ public int MarkThreadCompleted() /// /// Represents the data shared among threads for the parallel action. /// - private class Data(int threads, int fromInclusive, int toExclusive, Action action) : - BaseData(threads, fromInclusive, toExclusive) + private class Data(int threads, int fromInclusive, int toExclusive, Action action, CancellationToken token) : + BaseData(threads, fromInclusive, toExclusive, token) { /// /// Gets the action to be executed for each iteration. @@ -254,7 +263,7 @@ public static void For( : Environment.ProcessorCount; // Create shared data with thread-local initializers and finalizers - var data = new Data(threads, fromInclusive, toExclusive, action, init, initValue, @finally); + var data = new Data(threads, fromInclusive, toExclusive, action, init, initValue, @finally, parallelOptions.CancellationToken); // Queue work items to the thread pool for all threads except the current one for (int i = 0; i < threads - 1; i++) @@ -270,6 +279,8 @@ public static void For( { data.Event.Wait(); } + + parallelOptions.CancellationToken.ThrowIfCancellationRequested(); } /// @@ -284,16 +295,21 @@ public static void For( public void Execute() { TLocal? value = _data.Init(); - int i = _data.Index.GetNext(); - while (i < _data.ToExclusive) + try { - value = _data.Action(i, value); - i = _data.Index.GetNext(); + int i = _data.Index.GetNext(); + while (i < _data.ToExclusive) + { + if (_data.CancellationToken.IsCancellationRequested) return; + value = _data.Action(i, value); + i = _data.Index.GetNext(); + } + } + finally + { + _data.Finally(value); + _data.MarkThreadCompleted(); } - - _data.Finally(value); - - _data.MarkThreadCompleted(); } /// @@ -304,9 +320,10 @@ private class Data(int threads, int fromInclusive, int toExclusive, Func action, - Func? init = null, - TValue? initValue = default, - Action? @finally = null) : BaseData(threads, fromInclusive, toExclusive) + Func? init, + TValue? initValue, + Action? @finally, + CancellationToken token) : BaseData(threads, fromInclusive, toExclusive, token) { /// /// Gets the action to be executed for each iteration. @@ -317,7 +334,7 @@ private class Data(int threads, /// Initializes the thread-local data. /// /// The initialized thread-local data. - public TValue Init() => initValue ?? (init is not null ? init.Invoke() : default)!; + public TValue Init() => init is not null ? init.Invoke() : initValue!; /// /// Finalizes the thread-local data. From a437a69b5bcd27255ad89e6d613a264cbc5772a0 Mon Sep 17 00:00:00 2001 From: Ruben Buniatyan Date: Tue, 31 Dec 2024 23:30:23 +0100 Subject: [PATCH 059/113] Update CodeQL actions to v3 (#7966) --- .github/workflows/codeql.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7f4f0753374..54cc1f179b8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -20,25 +20,20 @@ jobs: matrix: language: ['csharp'] steps: - - name: Free up disk space - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be #v1.3.1 - with: - large-packages: false - tool-cache: false - name: Check out repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 #v4.2.0 - with: - submodules: true + uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@5618c9fc1e675841ca52c1c6b1304f5255a905a0 #v2.19.0 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} + queries: security-and-quality + packs: githubsecuritylab/codeql-${{ matrix.language }}-queries - name: Set up .NET - uses: actions/setup-dotnet@6bd8b7f7774af54e05809fcc5431931b3eb1ddee #v4.0.1 + uses: actions/setup-dotnet@v4 - name: Build Nethermind working-directory: src/Nethermind run: dotnet build Nethermind.sln -c release - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@5618c9fc1e675841ca52c1c6b1304f5255a905a0 #v2.19.0 + uses: github/codeql-action/analyze@v3 with: category: '/language:${{ matrix.language }}' From 4aa70aa6d58bed343a878edd796d47b021bb7683 Mon Sep 17 00:00:00 2001 From: Ruben Buniatyan Date: Wed, 1 Jan 2025 12:38:06 +0100 Subject: [PATCH 060/113] Update file header (#7988) --- .editorconfig | 2 +- CONTRIBUTING.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 7740e59ebc8..b1c662982f6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -file_header_template = SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited\nSPDX-License-Identifier: LGPL-3.0-only +file_header_template = SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited\nSPDX-License-Identifier: LGPL-3.0-only [*.cs] indent_size = 4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e3f03b3fe7a..27a6e7b0451 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,7 +59,7 @@ Branch names must follow the `kebab-case` or `snake_case` pattern and be all low The following notice must be included as a header in all source files if possible. ``` -// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only ``` From 85e4c3bf1ffb397e6ee3fbce4e3a13c6b782cfcb Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 1 Jan 2025 20:14:40 +0300 Subject: [PATCH 061/113] Add schema to configs (#7493) --- .../Nethermind.Config/JsonConfigSource.cs | 6 +- .../Nethermind.Runner/configs/AuraTest.json | 1 + .../configs/base-mainnet.json | 3 +- .../configs/base-mainnet_archive.json | 1 + .../configs/base-sepolia.json | 3 +- .../configs/base-sepolia_archive.json | 1 + .../Nethermind.Runner/configs/chiado.json | 5 +- .../configs/chiado_archive.json | 1 + .../Nethermind.Runner/configs/energyweb.json | 3 +- .../configs/energyweb_archive.json | 1 + .../Nethermind.Runner/configs/exosama.json | 3 +- .../configs/exosama_archive.json | 1 + .../Nethermind.Runner/configs/gnosis.json | 3 +- .../configs/gnosis_archive.json | 8 +- .../Nethermind.Runner/configs/hive.json | 1 + .../Nethermind.Runner/configs/holesky.json | 68 +++-- .../configs/holesky_archive.json | 67 ++--- .../configs/joc-mainnet.json | 3 +- .../configs/joc-mainnet_archive.json | 1 + .../configs/joc-testnet.json | 3 +- .../configs/joc-testnet_archive.json | 1 + .../configs/linea-mainnet.json | 3 +- .../configs/linea-mainnet_archive.json | 1 + .../configs/linea-sepolia.json | 3 +- .../configs/linea-sepolia_archive.json | 1 + .../Nethermind.Runner/configs/mainnet.json | 3 +- .../configs/mainnet_archive.json | 1 + .../Nethermind.Runner/configs/mekong.json | 1 + .../configs/mekong_archive.json | 1 + .../Nethermind.Runner/configs/op-mainnet.json | 3 +- .../configs/op-mainnet_archive.json | 1 + .../Nethermind.Runner/configs/op-sepolia.json | 3 +- .../configs/op-sepolia_archive.json | 1 + .../Nethermind.Runner/configs/poacore.json | 1 + .../configs/poacore_archive.json | 2 + .../configs/poacore_validator.json | 1 + .../Nethermind.Runner/configs/sepolia.json | 5 +- .../configs/sepolia_archive.json | 1 + .../Nethermind.Runner/configs/spaceneth.json | 23 +- .../configs/spaceneth_persistent.json | 22 +- .../configs/taiko-hekla.json | 3 +- .../configs/taiko-mainnet.json | 1 + .../Nethermind.Runner/configs/volta.json | 3 +- .../configs/volta_archive.json | 1 + tools/SchemaGenerator/Program.cs | 79 ++++++ .../Properties/launchSettings.json | 7 + tools/SchemaGenerator/README.md | 11 + tools/SchemaGenerator/SchemaGenerator.csproj | 27 ++ tools/SchemaGenerator/SchemaGenerator.sln | 235 ++++++++++++++++++ tools/SchemaGenerator/update.ps1 | 8 + 50 files changed, 540 insertions(+), 96 deletions(-) create mode 100644 tools/SchemaGenerator/Program.cs create mode 100644 tools/SchemaGenerator/Properties/launchSettings.json create mode 100644 tools/SchemaGenerator/README.md create mode 100644 tools/SchemaGenerator/SchemaGenerator.csproj create mode 100644 tools/SchemaGenerator/SchemaGenerator.sln create mode 100644 tools/SchemaGenerator/update.ps1 diff --git a/src/Nethermind/Nethermind.Config/JsonConfigSource.cs b/src/Nethermind/Nethermind.Config/JsonConfigSource.cs index 2f647f104f1..c2b983c1d64 100644 --- a/src/Nethermind/Nethermind.Config/JsonConfigSource.cs +++ b/src/Nethermind/Nethermind.Config/JsonConfigSource.cs @@ -12,6 +12,8 @@ namespace Nethermind.Config; public class JsonConfigSource : IConfigSource { + private const string SchemaKey = "$schema"; + public JsonConfigSource(string configFilePath) { LoadJsonConfig(configFilePath); @@ -22,7 +24,7 @@ private void ApplyJsonConfig(string jsonContent) try { using var json = JsonDocument.Parse(jsonContent); - foreach (var moduleEntry in json.RootElement.EnumerateObject()) + foreach (var moduleEntry in json.RootElement.EnumerateObject().Where(o => o.Name != SchemaKey)) { LoadModule(moduleEntry.Name, moduleEntry.Value); } @@ -72,7 +74,7 @@ private void LoadModule(string moduleName, JsonElement configItems) { var itemsDict = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (var configItem in configItems.EnumerateObject()) + foreach (var configItem in configItems.EnumerateObject().Where(o => o.Name != SchemaKey)) { var key = configItem.Name; if (!itemsDict.ContainsKey(key)) diff --git a/src/Nethermind/Nethermind.Runner/configs/AuraTest.json b/src/Nethermind/Nethermind.Runner/configs/AuraTest.json index 98626cc6c9f..02521f62516 100644 --- a/src/Nethermind/Nethermind.Runner/configs/AuraTest.json +++ b/src/Nethermind/Nethermind.Runner/configs/AuraTest.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/AuRaTest.json", "GenesisHash": "0xa13552e2290059c2736d101e945071a5f3768bc3338c73724184b0606eb8df1d", diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json index 30d6a0649d4..692be680acc 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/base-mainnet.json", "GenesisHash": "0xf712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd", @@ -38,4 +39,4 @@ "Optimism": { "SequencerUrl": "https://mainnet-sequencer.base.org" } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json index 58b9efe0ef3..fc76030b98e 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/base-mainnet.json", "GenesisHash": "0xf712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd", diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json index 864deaada97..0034b4b6715 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/base-sepolia.json", "GenesisHash": "0x0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4", @@ -38,4 +39,4 @@ "Optimism": { "SequencerUrl": "https://sepolia-sequencer.base.org" } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json index 3ad61c1df3f..16b69d12124 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/base-sepolia.json", "GenesisHash": "0x0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4", diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.json b/src/Nethermind/Nethermind.Runner/configs/chiado.json index a0855106549..0fc475a3b89 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.json +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "MemoryHint": 768000000, "ChainSpecPath": "chainspec/chiado.json", @@ -19,7 +20,7 @@ "PivotNumber": 13540000, "PivotHash": "0x9caa530d8ecba3d2ae14ede428b6814ee98861d272db473f5a0ffeb7bb57ccf0", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", - "FastSyncCatchUpHeightDelta": "10000000000", + "FastSyncCatchUpHeightDelta": 10000000000, "UseGethLimitsInFastBlocks": false }, "Blocks": { @@ -56,4 +57,4 @@ 16 ] } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado_archive.json b/src/Nethermind/Nethermind.Runner/configs/chiado_archive.json index 413820f824b..dde4077b24f 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/chiado_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "MemoryHint": 768000000, "ChainSpecPath": "chainspec/chiado.json", diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb.json b/src/Nethermind/Nethermind.Runner/configs/energyweb.json index 2bb7a8373cf..0db75c48f17 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.json +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/energyweb.json", "GenesisHash": "0x0b6d3e680af2fc525392c720666cce58e3d8e6fe75ba4b48cb36bcc69039229b", @@ -32,4 +33,4 @@ "Merge": { "Enabled": false } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json b/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json index 8a8727f4719..9c997527266 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/energyweb.json", "GenesisHash": "0x0b6d3e680af2fc525392c720666cce58e3d8e6fe75ba4b48cb36bcc69039229b", diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama.json b/src/Nethermind/Nethermind.Runner/configs/exosama.json index 093cfaca31e..4b1028670e2 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.json +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/exosama.json", "GenesisHash": "0x46b22ad9d580f08e8c7cf3a4433c8f913b354c43e267512efa19f21dfd234c74", @@ -32,4 +33,4 @@ "Merge": { "Enabled": false } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama_archive.json b/src/Nethermind/Nethermind.Runner/configs/exosama_archive.json index 9e69483aa40..2f249d7dd03 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/exosama_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/exosama.json", "GenesisHash": "0x46b22ad9d580f08e8c7cf3a4433c8f913b354c43e267512efa19f21dfd234c74", diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.json b/src/Nethermind/Nethermind.Runner/configs/gnosis.json index 20bad1be9c5..ea7742c1a59 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.json +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/gnosis.json", "GenesisHash": "0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756", @@ -49,4 +50,4 @@ 16 ] } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.json b/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.json index e25fa600e47..967fe965820 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/gnosis.json", "GenesisHash": "0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756", @@ -28,14 +29,13 @@ "Metrics": { "NodeName": "Gnosis Archive" }, - "Bloom": - { - "IndexLevelBucketSizes" : [16, 16, 16] + "Bloom": { + "IndexLevelBucketSizes": [ 16, 16, 16 ] }, "Pruning": { "Mode": "None" }, "Merge": { - "FinalTotalDifficulty": "8626000110427538733349499292577475819600160930" + "FinalTotalDifficulty": "8626000110427538733349499292577475819600160930" } } diff --git a/src/Nethermind/Nethermind.Runner/configs/hive.json b/src/Nethermind/Nethermind.Runner/configs/hive.json index d0d51c733ce..7cfe35d9f9d 100644 --- a/src/Nethermind/Nethermind.Runner/configs/hive.json +++ b/src/Nethermind/Nethermind.Runner/configs/hive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "PubSubEnabled": true, "WebSocketsEnabled": true, diff --git a/src/Nethermind/Nethermind.Runner/configs/holesky.json b/src/Nethermind/Nethermind.Runner/configs/holesky.json index 0898fa2b7c2..27101434088 100644 --- a/src/Nethermind/Nethermind.Runner/configs/holesky.json +++ b/src/Nethermind/Nethermind.Runner/configs/holesky.json @@ -1,37 +1,35 @@ { - "Init": { - "ChainSpecPath": "chainspec/holesky.json", - "GenesisHash": "0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4", - "BaseDbPath": "nethermind_db/holesky", - "LogFileName": "holesky.logs.txt" - }, - "TxPool": { - "Size": 1024 - }, - "Sync": { - "FastSync": true, - "SnapSync": true, - "FastSyncCatchUpHeightDelta": "10000000000" - }, - "Metrics": { - "NodeName": "Holesky" - }, - "Blocks": { - "TargetBlockGasLimit": 36000000 - }, - "JsonRpc": { - "Enabled": true, - "Timeout": 20000, - "Host": "127.0.0.1", - "Port": 8545, - "EngineHost": "127.0.0.1", - "EnginePort": 8551, - "EngineEnabledModules": "net,eth,subscribe,engine,web3,client,flashbots" - }, - "Merge": { - "Enabled": true - }, - "Flashbots": { - "Enabled": true - } + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", + "Init": { + "ChainSpecPath": "chainspec/holesky.json", + "GenesisHash": "0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4", + "BaseDbPath": "nethermind_db/holesky", + "LogFileName": "holesky.logs.txt" + }, + "TxPool": { + "Size": 1024 + }, + "Sync": { + "FastSync": true, + "SnapSync": true, + "FastSyncCatchUpHeightDelta": "10000000000" + }, + "Metrics": { + "NodeName": "Holesky" + }, + "Blocks": { + "TargetBlockGasLimit": 36000000 + }, + "JsonRpc": { + "Enabled": true, + "Timeout": 20000, + "Host": "127.0.0.1", + "Port": 8545, + "EngineHost": "127.0.0.1", + "EnginePort": 8551, + "EngineEnabledModules": "net,eth,subscribe,engine,web3,client" + }, + "Merge": { + "Enabled": true + } } diff --git a/src/Nethermind/Nethermind.Runner/configs/holesky_archive.json b/src/Nethermind/Nethermind.Runner/configs/holesky_archive.json index 50f3c4e26ab..019d50b9140 100644 --- a/src/Nethermind/Nethermind.Runner/configs/holesky_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/holesky_archive.json @@ -1,35 +1,36 @@ { - "Init": { - "ChainSpecPath": "chainspec/holesky.json", - "GenesisHash": "0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4", - "BaseDbPath": "nethermind_db/holesky_archive", - "LogFileName": "holesky_archive.logs.txt" - }, - "TxPool": { - "Size": 1024 - }, - "Metrics": { - "NodeName": "Holesky Archive" - }, - "Blocks": { - "TargetBlockGasLimit": 36000000 - }, - "Receipt": { - "TxLookupLimit": 0 - }, - "Pruning": { - "Mode": "None" - }, - "JsonRpc": { - "Enabled": true, - "Timeout": 20000, - "Host": "127.0.0.1", - "Port": 8545, - "EngineHost": "127.0.0.1", - "EnginePort": 8551, - "EngineEnabledModules": "net,eth,subscribe,engine,web3,client" - }, - "Merge": { - "Enabled": true - } + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", + "Init": { + "ChainSpecPath": "chainspec/holesky.json", + "GenesisHash": "0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4", + "BaseDbPath": "nethermind_db/holesky_archive", + "LogFileName": "holesky_archive.logs.txt" + }, + "TxPool": { + "Size": 1024 + }, + "Metrics": { + "NodeName": "Holesky Archive" + }, + "Blocks": { + "TargetBlockGasLimit": 36000000 + }, + "Receipt": { + "TxLookupLimit": 0 + }, + "Pruning": { + "Mode": "None" + }, + "JsonRpc": { + "Enabled": true, + "Timeout": 20000, + "Host": "127.0.0.1", + "Port": 8545, + "EngineHost": "127.0.0.1", + "EnginePort": 8551, + "EngineEnabledModules": "net,eth,subscribe,engine,web3,client" + }, + "Merge": { + "Enabled": true + } } diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json index 100fe99c13f..29eec0cff2d 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/joc-mainnet.json", "GenesisHash": "0x1b54bfa6846a13aacc57066840ec10d1b74b06870539bbc8a3d1b19bdc566733", @@ -28,4 +29,4 @@ "Merge": { "Enabled": false } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json index 7a5816be536..fa99f295699 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/joc-mainnet.json", "GenesisHash": "0x1b54bfa6846a13aacc57066840ec10d1b74b06870539bbc8a3d1b19bdc566733", diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json index b7752df4a8c..f15fc3d7b21 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/joc-testnet.json", "GenesisHash": "0x0fb7b4779aae36dc557227283f182bc9a3b232c07fae4a2553734c5817df1d06", @@ -28,4 +29,4 @@ "Merge": { "Enabled": false } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json index f4be5e23cbe..88bae2152c4 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/joc-testnet.json", "GenesisHash": "0x0fb7b4779aae36dc557227283f182bc9a3b232c07fae4a2553734c5817df1d06", diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json index e001014f985..6117826b3a4 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/linea-mainnet.json", "GenesisHash": "0xb6762a65689107b2326364aefc18f94cda413209fab35c00d4af51eaa20ffbc6", @@ -25,4 +26,4 @@ "Enabled": true, "Port": 8545 } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json index 775ee7ac150..e78a635b82d 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/linea-mainnet.json", "GenesisHash": "0xb6762a65689107b2326364aefc18f94cda413209fab35c00d4af51eaa20ffbc6", diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json index ca57ec0b7f0..22e1a456c94 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/linea-sepolia.json", "GenesisHash": "0x65a64c825d7c13ce1bf077801d0b6b2a89853e19e4a89a5433d7d85d2102a20b", @@ -25,4 +26,4 @@ "Enabled": true, "Port": 8545 } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json index ecca09dde1b..183a68a68aa 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/linea-sepolia.json", "GenesisHash": "0x65a64c825d7c13ce1bf077801d0b6b2a89853e19e4a89a5433d7d85d2102a20b", diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.json b/src/Nethermind/Nethermind.Runner/configs/mainnet.json index 6988055fd64..9c809222ae3 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/foundation.json", "GenesisHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", @@ -35,4 +36,4 @@ "Merge": { "Enabled": true } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/mainnet_archive.json index d11c95a89a9..4f0cc4f60de 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/foundation.json", "GenesisHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", diff --git a/src/Nethermind/Nethermind.Runner/configs/mekong.json b/src/Nethermind/Nethermind.Runner/configs/mekong.json index 95790d7858e..a10ca84bb00 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mekong.json +++ b/src/Nethermind/Nethermind.Runner/configs/mekong.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/mekong.json", "GenesisHash": "0x13613aa073d32a70ebd3c9f952da2c0f956978b64c1b37c25641c6fecb024ade", diff --git a/src/Nethermind/Nethermind.Runner/configs/mekong_archive.json b/src/Nethermind/Nethermind.Runner/configs/mekong_archive.json index ece457408ab..56d77d4e672 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mekong_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/mekong_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/mekong.json", "GenesisHash": "0x13613aa073d32a70ebd3c9f952da2c0f956978b64c1b37c25641c6fecb024ade", diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json index 11e5703214c..bd98ba39bd7 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/op-mainnet.json", "GenesisHash": "0x7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b", @@ -41,4 +42,4 @@ "Optimism": { "SequencerUrl": "https://mainnet-sequencer.optimism.io" } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json index 4aab65ad766..98ab3b32baf 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/op-mainnet.json", "GenesisHash": "0x7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b", diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json index 1cf0917d14f..c99d06eaea9 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/op-sepolia.json", "GenesisHash": "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", @@ -38,4 +39,4 @@ "Optimism": { "SequencerUrl": "https://sepolia-sequencer.optimism.io" } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json index 07d38c0fa89..0723d0fe554 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/op-sepolia.json", "GenesisHash": "0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d", diff --git a/src/Nethermind/Nethermind.Runner/configs/poacore.json b/src/Nethermind/Nethermind.Runner/configs/poacore.json index 94ed3102b2b..28907bcb0fc 100644 --- a/src/Nethermind/Nethermind.Runner/configs/poacore.json +++ b/src/Nethermind/Nethermind.Runner/configs/poacore.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/poacore.json", "GenesisHash": "0x39f02c003dde5b073b3f6e1700fc0b84b4877f6839bb23edadd3d2d82a488634", diff --git a/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json b/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json index 51525125360..eb54c50b673 100644 --- a/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/poacore.json", "GenesisHash": "0x39f02c003dde5b073b3f6e1700fc0b84b4877f6839bb23edadd3d2d82a488634", @@ -17,6 +18,7 @@ }, "Receipt": { "TxLookupLimit": 0 + }, "Bloom": { "IndexLevelBucketSizes": [ 16, 16, 16, 16 ] diff --git a/src/Nethermind/Nethermind.Runner/configs/poacore_validator.json b/src/Nethermind/Nethermind.Runner/configs/poacore_validator.json index 1838192982d..e40f6b0ca82 100644 --- a/src/Nethermind/Nethermind.Runner/configs/poacore_validator.json +++ b/src/Nethermind/Nethermind.Runner/configs/poacore_validator.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "StoreReceipts": false, "IsMining": true, diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.json b/src/Nethermind/Nethermind.Runner/configs/sepolia.json index bddfdf17321..c98f63a3863 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/sepolia.json", "GenesisHash": "0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9", @@ -20,7 +21,7 @@ "PivotNumber": 7374000, "PivotHash": "0x089a3035ba78279275bbd907a09d6c401f1ff305d8cd1dacba207f3127940e47", "PivotTotalDifficulty": "17000018015853232", - "FastSyncCatchUpHeightDelta": "10000000000" + "FastSyncCatchUpHeightDelta": 10000000000 }, "Blocks": { "TargetBlockGasLimit": 36000000 @@ -37,4 +38,4 @@ "Merge": { "Enabled": true } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia_archive.json b/src/Nethermind/Nethermind.Runner/configs/sepolia_archive.json index 7d99df7dbff..6a9c1802434 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/sepolia.json", "GenesisHash": "0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9", diff --git a/src/Nethermind/Nethermind.Runner/configs/spaceneth.json b/src/Nethermind/Nethermind.Runner/configs/spaceneth.json index c927342ee6f..2b265d54a52 100644 --- a/src/Nethermind/Nethermind.Runner/configs/spaceneth.json +++ b/src/Nethermind/Nethermind.Runner/configs/spaceneth.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "EnableUnsecuredDevWallet": true, "KeepDevWalletInMemory": true, @@ -28,8 +29,26 @@ "Host": "127.0.0.1", "Port": 8545, "EnabledModules": [ - "Admin", "Clique", "Consensus", "Db", "Debug", "Deposit", "Erc20", "Eth", "Evm", - "Health", "Net", "Nft", "Parity", "Personal", "Proof", "Subscribe", "Trace", "TxPool", "Vault", "Web3" + "Admin", + "Clique", + "Consensus", + "Db", + "Debug", + "Deposit", + "Erc20", + "Eth", + "Evm", + "Health", + "Net", + "Nft", + "Parity", + "Personal", + "Proof", + "Subscribe", + "Trace", + "TxPool", + "Vault", + "Web3" ] }, "Metrics": { diff --git a/src/Nethermind/Nethermind.Runner/configs/spaceneth_persistent.json b/src/Nethermind/Nethermind.Runner/configs/spaceneth_persistent.json index bd6a812dde0..459d4de4b12 100644 --- a/src/Nethermind/Nethermind.Runner/configs/spaceneth_persistent.json +++ b/src/Nethermind/Nethermind.Runner/configs/spaceneth_persistent.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "EnableUnsecuredDevWallet": true, "KeepDevWalletInMemory": true, @@ -24,8 +25,25 @@ "Host": "127.0.0.1", "Port": 8545, "EnabledModules": [ - "Admin", "Clique", "Consensus", "Db", "Debug", "Deposit", "Erc20", "Eth", "Evm", - "Net", "Nft", "Parity", "Personal", "Proof", "Subscribe", "Trace", "TxPool", "Vault", "Web3" + "Admin", + "Clique", + "Consensus", + "Db", + "Debug", + "Deposit", + "Erc20", + "Eth", + "Evm", + "Net", + "Nft", + "Parity", + "Personal", + "Proof", + "Subscribe", + "Trace", + "TxPool", + "Vault", + "Web3" ] }, "TxPool": { diff --git a/src/Nethermind/Nethermind.Runner/configs/taiko-hekla.json b/src/Nethermind/Nethermind.Runner/configs/taiko-hekla.json index 80332d5e39b..7996f69f22c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/taiko-hekla.json +++ b/src/Nethermind/Nethermind.Runner/configs/taiko-hekla.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/taiko-hekla.json", "GenesisHash": "0x1f5554042aa50dc0712936ae234d8803b80b84251f85d074756a2f391896e109", @@ -14,7 +15,7 @@ "SnapSync": true, "PivotNumber": 882786, "PivotHash": "0x76e654042380ab94b86398fdb3515d7e699c7c070ffbbf6a49e581eb2b8f3f00", - "PivotTotalDifficulty": 0 + "PivotTotalDifficulty": 0 }, "JsonRpc": { "Enabled": true, diff --git a/src/Nethermind/Nethermind.Runner/configs/taiko-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/taiko-mainnet.json index 11b376e819e..95b9a88c59d 100644 --- a/src/Nethermind/Nethermind.Runner/configs/taiko-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/taiko-mainnet.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/taiko-mainnet.json", "GenesisHash": "0x90bc60466882de9637e269e87abab53c9108cf9113188bc4f80bcfcb10e489b9", diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.json b/src/Nethermind/Nethermind.Runner/configs/volta.json index effc9617664..1d02eb071f8 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.json +++ b/src/Nethermind/Nethermind.Runner/configs/volta.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "IsMining": false, "ChainSpecPath": "chainspec/volta.json", @@ -36,4 +37,4 @@ "Merge": { "Enabled": false } -} \ No newline at end of file +} diff --git a/src/Nethermind/Nethermind.Runner/configs/volta_archive.json b/src/Nethermind/Nethermind.Runner/configs/volta_archive.json index c8282d4179b..4fe022caef2 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/volta_archive.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/NethermindEth/core-scripts/refs/heads/main/schemas/config.json", "Init": { "ChainSpecPath": "chainspec/volta.json", "GenesisHash": "0xebd8b413ca7b7f84a8dd20d17519ce2b01954c74d94a0a739a3e416abe0e43e5", diff --git a/tools/SchemaGenerator/Program.cs b/tools/SchemaGenerator/Program.cs new file mode 100644 index 00000000000..9ab99232f09 --- /dev/null +++ b/tools/SchemaGenerator/Program.cs @@ -0,0 +1,79 @@ + +using NJsonSchema; +using System.Reflection; +using System.Reflection.Emit; +using Nethermind.Config; +using Nethermind.Core.Collections; + +Type iConfigType = typeof(IConfig); + +Type[] types = [ + ..Directory.GetFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Nethermind.*.dll").SelectMany(f => GetConfigTypes(Assembly.LoadFrom(f))), + ]; + +var assemblyName = new AssemblyName("Nethermind.Config"); +var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); +ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); + +TypeBuilder typeBuilder = moduleBuilder.DefineType("NethermindConfig", TypeAttributes.Public); + +foreach (Type configInterface in types) +{ + CreateProperty(typeBuilder, configInterface); +} + +Type configType = typeBuilder.CreateType(); + +JsonSchema schema = JsonSchema.FromType(configType); + +foreach (KeyValuePair def in schema.Definitions) +{ + if (def.Value.Enumeration is { Count: > 0 }) + { + def.Value.Type = JsonObjectType.String; + def.Value.Enumeration.Clear(); + def.Value.Enumeration.AddRange(def.Value.EnumerationNames); + } +} + +schema.Properties.Add("$schema", new JsonSchemaProperty { Type = JsonObjectType.String }); + +Console.WriteLine(schema.ToJson()); + +void CreateProperty(TypeBuilder typeBuilder, Type classType) +{ + Type interfaceType = classType.GetInterfaces().First(i => iConfigType.IsAssignableFrom(i) && i != iConfigType); + string propertyName = interfaceType.Name.Substring(1, interfaceType.Name.Length - 7); + FieldBuilder fieldBuilder = typeBuilder.DefineField($"_{propertyName}", interfaceType, FieldAttributes.Private); + PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, interfaceType, null); + MethodBuilder getMethodBuilder = typeBuilder.DefineMethod($"get_{propertyName}", + MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, + interfaceType, + Type.EmptyTypes); + + ILGenerator getIL = getMethodBuilder.GetILGenerator(); + getIL.Emit(OpCodes.Ldarg_0); + getIL.Emit(OpCodes.Ldfld, fieldBuilder); + getIL.Emit(OpCodes.Ret); + + // Define the 'set' accessor method + MethodBuilder setMethodBuilder = typeBuilder.DefineMethod($"set_{propertyName}", + MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, + null, + [interfaceType]); + + ILGenerator setIL = setMethodBuilder.GetILGenerator(); + setIL.Emit(OpCodes.Ldarg_0); + setIL.Emit(OpCodes.Ldarg_1); + setIL.Emit(OpCodes.Stfld, fieldBuilder); + setIL.Emit(OpCodes.Ret); + + // Map the get and set methods to the property + propertyBuilder.SetGetMethod(getMethodBuilder); + propertyBuilder.SetSetMethod(setMethodBuilder); +} + +IEnumerable GetConfigTypes(Assembly assembly) +{ + return assembly.GetTypes().Where(t => iConfigType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract); +} diff --git a/tools/SchemaGenerator/Properties/launchSettings.json b/tools/SchemaGenerator/Properties/launchSettings.json new file mode 100644 index 00000000000..e320d74f14a --- /dev/null +++ b/tools/SchemaGenerator/Properties/launchSettings.json @@ -0,0 +1,7 @@ +{ + "profiles": { + "Generate": { + "commandName": "Project" + } + } +} diff --git a/tools/SchemaGenerator/README.md b/tools/SchemaGenerator/README.md new file mode 100644 index 00000000000..13452cea30f --- /dev/null +++ b/tools/SchemaGenerator/README.md @@ -0,0 +1,11 @@ +# JSON Schema Generator for Nethermind Configs + +Generates schema for all the configs found. Based on NJsonSchema which has better support for enums + +To update the schema, run `./update.ps1` script. For preview: + +``` +dotnet run -v 0 --property WarningLevel=0 > schema.json +``` + +For a new config to appear in the schema, project that contains the config should be included in `SchemaGenerator` solution and in `SchemaGenerator.csproj` as a `ProjectReference`. diff --git a/tools/SchemaGenerator/SchemaGenerator.csproj b/tools/SchemaGenerator/SchemaGenerator.csproj new file mode 100644 index 00000000000..c579436d930 --- /dev/null +++ b/tools/SchemaGenerator/SchemaGenerator.csproj @@ -0,0 +1,27 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + + + + + + + + + diff --git a/tools/SchemaGenerator/SchemaGenerator.sln b/tools/SchemaGenerator/SchemaGenerator.sln new file mode 100644 index 00000000000..48f25eda686 --- /dev/null +++ b/tools/SchemaGenerator/SchemaGenerator.sln @@ -0,0 +1,235 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SchemaGenerator", "SchemaGenerator.csproj", "{3670AA89-2A73-4C09-A13F-F207035D89EA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Api", "..\..\src\Nethermind\Nethermind.Api\Nethermind.Api.csproj", "{B0399199-3C55-4AF3-9A59-5BC1D1616A19}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Blockchain", "..\..\src\Nethermind\Nethermind.Blockchain\Nethermind.Blockchain.csproj", "{F23FB617-5FA1-4C89-A38A-C2DFA7DB5440}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Facade", "..\..\src\Nethermind\Nethermind.Facade\Nethermind.Facade.csproj", "{AA9C67C6-7B46-4A48-818F-2856CE5EF01D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Grpc", "..\..\src\Nethermind\Nethermind.Grpc\Nethermind.Grpc.csproj", "{854CA332-FC2D-4D49-B4D9-BD2AD2A45C89}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.JsonRpc", "..\..\src\Nethermind\Nethermind.JsonRpc\Nethermind.JsonRpc.csproj", "{CFD4097F-01A5-46FF-94D6-05A05EB1C534}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Monitoring", "..\..\src\Nethermind\Nethermind.Monitoring\Nethermind.Monitoring.csproj", "{9A58A4EE-4EEF-4244-B62B-0A784E846397}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Network", "..\..\src\Nethermind\Nethermind.Network\Nethermind.Network.csproj", "{C0E61E05-970E-4DE0-A61F-02F2A98305BB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Sockets", "..\..\src\Nethermind\Nethermind.Sockets\Nethermind.Sockets.csproj", "{FA9E459A-5A17-4C24-BABD-0AD9272AB98E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Abi", "..\..\src\Nethermind\Nethermind.Abi\Nethermind.Abi.csproj", "{1A56D354-D7A1-4CE7-A385-3D48459DF949}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Core", "..\..\src\Nethermind\Nethermind.Core\Nethermind.Core.csproj", "{50BC4631-B36C-4A80-A950-747AA0126751}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Db", "..\..\src\Nethermind\Nethermind.Db\Nethermind.Db.csproj", "{634922FD-45FB-4236-9319-57546C5E9D5D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Evm", "..\..\src\Nethermind\Nethermind.Evm\Nethermind.Evm.csproj", "{1CE18A05-8048-4227-80A7-663EAF120A09}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Network.Stats", "..\..\src\Nethermind\Nethermind.Network.Stats\Nethermind.Network.Stats.csproj", "{96656EF2-848C-4D80-87A1-DB70DC5C280D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Specs", "..\..\src\Nethermind\Nethermind.Specs\Nethermind.Specs.csproj", "{42EA22A8-271B-40B8-A14C-C0B3320F8A53}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.State", "..\..\src\Nethermind\Nethermind.State\Nethermind.State.csproj", "{BE93E6ED-345B-4F84-82FE-B2306DCA12F0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.TxPool", "..\..\src\Nethermind\Nethermind.TxPool\Nethermind.TxPool.csproj", "{2BD3F956-C335-4C64-A517-282012F54A7E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Consensus", "..\..\src\Nethermind\Nethermind.Consensus\Nethermind.Consensus.csproj", "{DC68F63C-407F-444D-A436-EFE423F3B2A8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Crypto", "..\..\src\Nethermind\Nethermind.Crypto\Nethermind.Crypto.csproj", "{6C517105-7845-4A46-AFBD-22431C64461C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Synchronization", "..\..\src\Nethermind\Nethermind.Synchronization\Nethermind.Synchronization.csproj", "{8C618588-0380-408C-89A3-EBD1D98CC521}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Config", "..\..\src\Nethermind\Nethermind.Config\Nethermind.Config.csproj", "{1DE1E47A-7A2E-4E32-8BB1-11281C501D73}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Serialization.Json", "..\..\src\Nethermind\Nethermind.Serialization.Json\Nethermind.Serialization.Json.csproj", "{8D4E493F-2063-49B5-AAC2-458F10FAC073}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Serialization.Rlp", "..\..\src\Nethermind\Nethermind.Serialization.Rlp\Nethermind.Serialization.Rlp.csproj", "{CB2A6251-A878-4F5D-A049-9B3B9891B123}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Trie", "..\..\src\Nethermind\Nethermind.Trie\Nethermind.Trie.csproj", "{F0B78631-1159-4797-8277-1ADB7070DCDC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Optimism", "..\..\src\Nethermind\Nethermind.Optimism\Nethermind.Optimism.csproj", "{3B3380FE-674F-4059-B134-516B848A0749}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Init", "..\..\src\Nethermind\Nethermind.Init\Nethermind.Init.csproj", "{54BBF9B5-6106-4BDB-9ED1-2A1DBA9F6918}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Merge.Plugin", "..\..\src\Nethermind\Nethermind.Merge.Plugin\Nethermind.Merge.Plugin.csproj", "{7D28812C-C6F2-473D-904E-BE2D8CC5F5BE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Db.Rocks", "..\..\src\Nethermind\Nethermind.Db.Rocks\Nethermind.Db.Rocks.csproj", "{981A3E24-AEF7-4F6E-B87F-6249AC10BCD4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Db.Rpc", "..\..\src\Nethermind\Nethermind.Db.Rpc\Nethermind.Db.Rpc.csproj", "{7B16F7F4-CCB9-4DB7-A53A-0FD6ED698AAF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Network.Discovery", "..\..\src\Nethermind\Nethermind.Network.Discovery\Nethermind.Network.Discovery.csproj", "{28638961-FEF8-4334-95BD-E55F2F92D0AF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Network.Dns", "..\..\src\Nethermind\Nethermind.Network.Dns\Nethermind.Network.Dns.csproj", "{EFB9367F-EFB8-4940-97A8-62F3967FC17D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Network.Enr", "..\..\src\Nethermind\Nethermind.Network.Enr\Nethermind.Network.Enr.csproj", "{C1F412BA-FC1F-4701-B947-BA42DA855423}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Init.Snapshot", "..\..\src\Nethermind\Nethermind.Init.Snapshot\Nethermind.Init.Snapshot.csproj", "{90AA7A9D-FC7F-419E-A671-A07FDD02DA10}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.EthStats", "..\..\src\Nethermind\Nethermind.EthStats\Nethermind.EthStats.csproj", "{D005A22C-A3BD-4FCC-A84D-4D4BFCBDADA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.AuRa", "..\..\src\Nethermind\Nethermind.Consensus.AuRa\Nethermind.Consensus.AuRa.csproj", "{C5BDD4A6-55B9-42FB-8D7E-592AA0EBEA59}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter", "..\..\src\Nethermind\Nethermind.Shutter\Nethermind.Shutter.csproj", "{1AFE7CD3-03EE-459C-8C06-C9B580FDF82B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3670AA89-2A73-4C09-A13F-F207035D89EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3670AA89-2A73-4C09-A13F-F207035D89EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3670AA89-2A73-4C09-A13F-F207035D89EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3670AA89-2A73-4C09-A13F-F207035D89EA}.Release|Any CPU.Build.0 = Release|Any CPU + {B0399199-3C55-4AF3-9A59-5BC1D1616A19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0399199-3C55-4AF3-9A59-5BC1D1616A19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0399199-3C55-4AF3-9A59-5BC1D1616A19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0399199-3C55-4AF3-9A59-5BC1D1616A19}.Release|Any CPU.Build.0 = Release|Any CPU + {F23FB617-5FA1-4C89-A38A-C2DFA7DB5440}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F23FB617-5FA1-4C89-A38A-C2DFA7DB5440}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F23FB617-5FA1-4C89-A38A-C2DFA7DB5440}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F23FB617-5FA1-4C89-A38A-C2DFA7DB5440}.Release|Any CPU.Build.0 = Release|Any CPU + {AA9C67C6-7B46-4A48-818F-2856CE5EF01D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA9C67C6-7B46-4A48-818F-2856CE5EF01D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA9C67C6-7B46-4A48-818F-2856CE5EF01D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA9C67C6-7B46-4A48-818F-2856CE5EF01D}.Release|Any CPU.Build.0 = Release|Any CPU + {854CA332-FC2D-4D49-B4D9-BD2AD2A45C89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {854CA332-FC2D-4D49-B4D9-BD2AD2A45C89}.Debug|Any CPU.Build.0 = Debug|Any CPU + {854CA332-FC2D-4D49-B4D9-BD2AD2A45C89}.Release|Any CPU.ActiveCfg = Release|Any CPU + {854CA332-FC2D-4D49-B4D9-BD2AD2A45C89}.Release|Any CPU.Build.0 = Release|Any CPU + {CFD4097F-01A5-46FF-94D6-05A05EB1C534}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFD4097F-01A5-46FF-94D6-05A05EB1C534}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFD4097F-01A5-46FF-94D6-05A05EB1C534}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFD4097F-01A5-46FF-94D6-05A05EB1C534}.Release|Any CPU.Build.0 = Release|Any CPU + {9A58A4EE-4EEF-4244-B62B-0A784E846397}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A58A4EE-4EEF-4244-B62B-0A784E846397}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A58A4EE-4EEF-4244-B62B-0A784E846397}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A58A4EE-4EEF-4244-B62B-0A784E846397}.Release|Any CPU.Build.0 = Release|Any CPU + {C0E61E05-970E-4DE0-A61F-02F2A98305BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C0E61E05-970E-4DE0-A61F-02F2A98305BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C0E61E05-970E-4DE0-A61F-02F2A98305BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C0E61E05-970E-4DE0-A61F-02F2A98305BB}.Release|Any CPU.Build.0 = Release|Any CPU + {FA9E459A-5A17-4C24-BABD-0AD9272AB98E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA9E459A-5A17-4C24-BABD-0AD9272AB98E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA9E459A-5A17-4C24-BABD-0AD9272AB98E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA9E459A-5A17-4C24-BABD-0AD9272AB98E}.Release|Any CPU.Build.0 = Release|Any CPU + {1A56D354-D7A1-4CE7-A385-3D48459DF949}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A56D354-D7A1-4CE7-A385-3D48459DF949}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A56D354-D7A1-4CE7-A385-3D48459DF949}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A56D354-D7A1-4CE7-A385-3D48459DF949}.Release|Any CPU.Build.0 = Release|Any CPU + {50BC4631-B36C-4A80-A950-747AA0126751}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50BC4631-B36C-4A80-A950-747AA0126751}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50BC4631-B36C-4A80-A950-747AA0126751}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50BC4631-B36C-4A80-A950-747AA0126751}.Release|Any CPU.Build.0 = Release|Any CPU + {634922FD-45FB-4236-9319-57546C5E9D5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {634922FD-45FB-4236-9319-57546C5E9D5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {634922FD-45FB-4236-9319-57546C5E9D5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {634922FD-45FB-4236-9319-57546C5E9D5D}.Release|Any CPU.Build.0 = Release|Any CPU + {1CE18A05-8048-4227-80A7-663EAF120A09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1CE18A05-8048-4227-80A7-663EAF120A09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CE18A05-8048-4227-80A7-663EAF120A09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1CE18A05-8048-4227-80A7-663EAF120A09}.Release|Any CPU.Build.0 = Release|Any CPU + {96656EF2-848C-4D80-87A1-DB70DC5C280D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96656EF2-848C-4D80-87A1-DB70DC5C280D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96656EF2-848C-4D80-87A1-DB70DC5C280D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96656EF2-848C-4D80-87A1-DB70DC5C280D}.Release|Any CPU.Build.0 = Release|Any CPU + {42EA22A8-271B-40B8-A14C-C0B3320F8A53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42EA22A8-271B-40B8-A14C-C0B3320F8A53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42EA22A8-271B-40B8-A14C-C0B3320F8A53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42EA22A8-271B-40B8-A14C-C0B3320F8A53}.Release|Any CPU.Build.0 = Release|Any CPU + {BE93E6ED-345B-4F84-82FE-B2306DCA12F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE93E6ED-345B-4F84-82FE-B2306DCA12F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE93E6ED-345B-4F84-82FE-B2306DCA12F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE93E6ED-345B-4F84-82FE-B2306DCA12F0}.Release|Any CPU.Build.0 = Release|Any CPU + {2BD3F956-C335-4C64-A517-282012F54A7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BD3F956-C335-4C64-A517-282012F54A7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BD3F956-C335-4C64-A517-282012F54A7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BD3F956-C335-4C64-A517-282012F54A7E}.Release|Any CPU.Build.0 = Release|Any CPU + {DC68F63C-407F-444D-A436-EFE423F3B2A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC68F63C-407F-444D-A436-EFE423F3B2A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC68F63C-407F-444D-A436-EFE423F3B2A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC68F63C-407F-444D-A436-EFE423F3B2A8}.Release|Any CPU.Build.0 = Release|Any CPU + {6C517105-7845-4A46-AFBD-22431C64461C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C517105-7845-4A46-AFBD-22431C64461C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C517105-7845-4A46-AFBD-22431C64461C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C517105-7845-4A46-AFBD-22431C64461C}.Release|Any CPU.Build.0 = Release|Any CPU + {8C618588-0380-408C-89A3-EBD1D98CC521}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C618588-0380-408C-89A3-EBD1D98CC521}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C618588-0380-408C-89A3-EBD1D98CC521}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C618588-0380-408C-89A3-EBD1D98CC521}.Release|Any CPU.Build.0 = Release|Any CPU + {1DE1E47A-7A2E-4E32-8BB1-11281C501D73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1DE1E47A-7A2E-4E32-8BB1-11281C501D73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1DE1E47A-7A2E-4E32-8BB1-11281C501D73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1DE1E47A-7A2E-4E32-8BB1-11281C501D73}.Release|Any CPU.Build.0 = Release|Any CPU + {8D4E493F-2063-49B5-AAC2-458F10FAC073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D4E493F-2063-49B5-AAC2-458F10FAC073}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D4E493F-2063-49B5-AAC2-458F10FAC073}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D4E493F-2063-49B5-AAC2-458F10FAC073}.Release|Any CPU.Build.0 = Release|Any CPU + {CB2A6251-A878-4F5D-A049-9B3B9891B123}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB2A6251-A878-4F5D-A049-9B3B9891B123}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB2A6251-A878-4F5D-A049-9B3B9891B123}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB2A6251-A878-4F5D-A049-9B3B9891B123}.Release|Any CPU.Build.0 = Release|Any CPU + {F0B78631-1159-4797-8277-1ADB7070DCDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0B78631-1159-4797-8277-1ADB7070DCDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0B78631-1159-4797-8277-1ADB7070DCDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0B78631-1159-4797-8277-1ADB7070DCDC}.Release|Any CPU.Build.0 = Release|Any CPU + {3B3380FE-674F-4059-B134-516B848A0749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B3380FE-674F-4059-B134-516B848A0749}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B3380FE-674F-4059-B134-516B848A0749}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B3380FE-674F-4059-B134-516B848A0749}.Release|Any CPU.Build.0 = Release|Any CPU + {54BBF9B5-6106-4BDB-9ED1-2A1DBA9F6918}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54BBF9B5-6106-4BDB-9ED1-2A1DBA9F6918}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54BBF9B5-6106-4BDB-9ED1-2A1DBA9F6918}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54BBF9B5-6106-4BDB-9ED1-2A1DBA9F6918}.Release|Any CPU.Build.0 = Release|Any CPU + {7D28812C-C6F2-473D-904E-BE2D8CC5F5BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D28812C-C6F2-473D-904E-BE2D8CC5F5BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D28812C-C6F2-473D-904E-BE2D8CC5F5BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D28812C-C6F2-473D-904E-BE2D8CC5F5BE}.Release|Any CPU.Build.0 = Release|Any CPU + {981A3E24-AEF7-4F6E-B87F-6249AC10BCD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {981A3E24-AEF7-4F6E-B87F-6249AC10BCD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {981A3E24-AEF7-4F6E-B87F-6249AC10BCD4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {981A3E24-AEF7-4F6E-B87F-6249AC10BCD4}.Release|Any CPU.Build.0 = Release|Any CPU + {7B16F7F4-CCB9-4DB7-A53A-0FD6ED698AAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B16F7F4-CCB9-4DB7-A53A-0FD6ED698AAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B16F7F4-CCB9-4DB7-A53A-0FD6ED698AAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B16F7F4-CCB9-4DB7-A53A-0FD6ED698AAF}.Release|Any CPU.Build.0 = Release|Any CPU + {28638961-FEF8-4334-95BD-E55F2F92D0AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28638961-FEF8-4334-95BD-E55F2F92D0AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28638961-FEF8-4334-95BD-E55F2F92D0AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28638961-FEF8-4334-95BD-E55F2F92D0AF}.Release|Any CPU.Build.0 = Release|Any CPU + {EFB9367F-EFB8-4940-97A8-62F3967FC17D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFB9367F-EFB8-4940-97A8-62F3967FC17D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFB9367F-EFB8-4940-97A8-62F3967FC17D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFB9367F-EFB8-4940-97A8-62F3967FC17D}.Release|Any CPU.Build.0 = Release|Any CPU + {C1F412BA-FC1F-4701-B947-BA42DA855423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1F412BA-FC1F-4701-B947-BA42DA855423}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1F412BA-FC1F-4701-B947-BA42DA855423}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1F412BA-FC1F-4701-B947-BA42DA855423}.Release|Any CPU.Build.0 = Release|Any CPU + {90AA7A9D-FC7F-419E-A671-A07FDD02DA10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90AA7A9D-FC7F-419E-A671-A07FDD02DA10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90AA7A9D-FC7F-419E-A671-A07FDD02DA10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90AA7A9D-FC7F-419E-A671-A07FDD02DA10}.Release|Any CPU.Build.0 = Release|Any CPU + {D005A22C-A3BD-4FCC-A84D-4D4BFCBDADA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D005A22C-A3BD-4FCC-A84D-4D4BFCBDADA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D005A22C-A3BD-4FCC-A84D-4D4BFCBDADA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D005A22C-A3BD-4FCC-A84D-4D4BFCBDADA2}.Release|Any CPU.Build.0 = Release|Any CPU + {C5BDD4A6-55B9-42FB-8D7E-592AA0EBEA59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5BDD4A6-55B9-42FB-8D7E-592AA0EBEA59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5BDD4A6-55B9-42FB-8D7E-592AA0EBEA59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5BDD4A6-55B9-42FB-8D7E-592AA0EBEA59}.Release|Any CPU.Build.0 = Release|Any CPU + {1AFE7CD3-03EE-459C-8C06-C9B580FDF82B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1AFE7CD3-03EE-459C-8C06-C9B580FDF82B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1AFE7CD3-03EE-459C-8C06-C9B580FDF82B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1AFE7CD3-03EE-459C-8C06-C9B580FDF82B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {80A498BE-33FF-4A03-AEF1-979170084AB3} + EndGlobalSection +EndGlobal diff --git a/tools/SchemaGenerator/update.ps1 b/tools/SchemaGenerator/update.ps1 new file mode 100644 index 00000000000..44d116698ba --- /dev/null +++ b/tools/SchemaGenerator/update.ps1 @@ -0,0 +1,8 @@ +git clone git@github.com:NethermindEth/core-scripts.git +dotnet run -v 0 --property WarningLevel=0 > ./core-scripts/schemas/config.json +cd core-scripts +git add . +git commit -m "Update schema" +git push +cd .. +rm -Recurse -Force ./core-scripts From f6cd53da299f3466ec883620394aeb7805d6d316 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Thu, 2 Jan 2025 11:35:49 +0000 Subject: [PATCH 062/113] Reduce per tx execution allocations (#7990) Co-authored-by: lukasz.rozmej --- .../Nethermind.Evm.Benchmark/EvmBenchmarks.cs | 2 +- .../MultipleUnsignedOperations.cs | 2 +- .../StaticCallBenchmarks.cs | 2 +- .../Nethermind.Evm.Test/EvmStateTests.cs | 19 +- src/Nethermind/Nethermind.Evm/EvmState.cs | 366 ++++++++++-------- .../Nethermind.Evm/StackAccessTracker.cs | 164 ++++---- .../TransactionProcessor.cs | 8 +- .../Nethermind.Evm/VirtualMachine.cs | 26 +- 8 files changed, 329 insertions(+), 260 deletions(-) diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs b/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs index b29fcf00088..ad34320f047 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/EvmBenchmarks.cs @@ -58,7 +58,7 @@ public void GlobalSetup() inputData: default ); - _evmState = new EvmState(long.MaxValue, _environment, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot()); + _evmState = EvmState.RentTopLevel(long.MaxValue, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot(), _environment, new StackAccessTracker()); } [Benchmark] diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs b/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs index 97d0d9e6cf8..942d06a4929 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/MultipleUnsignedOperations.cs @@ -91,7 +91,7 @@ public void GlobalSetup() inputData: default ); - _evmState = new EvmState(100_000_000L, _environment, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot()); + _evmState = EvmState.RentTopLevel(100_000_000L, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot(), _environment, new StackAccessTracker()); } [Benchmark] diff --git a/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs b/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs index b7b8d39945b..c299c991efa 100644 --- a/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs +++ b/src/Nethermind/Nethermind.Evm.Benchmark/StaticCallBenchmarks.cs @@ -102,7 +102,7 @@ public void GlobalSetup() inputData: default ); - _evmState = new EvmState(100_000_000L, _environment, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot()); + _evmState = EvmState.RentTopLevel(100_000_000L, ExecutionType.TRANSACTION, _stateProvider.TakeSnapshot(), _environment, new StackAccessTracker()); } [Benchmark(Baseline = true)] diff --git a/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs b/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs index e462d04c288..2a6c1f8cbf5 100644 --- a/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/EvmStateTests.cs @@ -216,25 +216,26 @@ public void Can_dispose_without_init() public void Can_dispose_after_init() { EvmState evmState = CreateEvmState(); - evmState.InitStacks(); + evmState.InitializeStacks(); evmState.Dispose(); } private static EvmState CreateEvmState(EvmState parentEvmState = null, bool isContinuation = false) => parentEvmState is null - ? new EvmState(10000, - new ExecutionEnvironment(), - ExecutionType.CALL, - Snapshot.Empty) - : new EvmState(10000, - new ExecutionEnvironment(), + ? EvmState.RentTopLevel(10000, ExecutionType.CALL, Snapshot.Empty, + new ExecutionEnvironment(), + new StackAccessTracker()) + : EvmState.RentFrame(10000, 0, 0, + ExecutionType.CALL, + false, false, - parentEvmState.AccessTracker, - false); + Snapshot.Empty, + new ExecutionEnvironment(), + parentEvmState.AccessTracker); public class Context { } } diff --git a/src/Nethermind/Nethermind.Evm/EvmState.cs b/src/Nethermind/Nethermind.Evm/EvmState.cs index feb1abdbc87..ead92e96c8a 100644 --- a/src/Nethermind/Nethermind.Evm/EvmState.cs +++ b/src/Nethermind/Nethermind.Evm/EvmState.cs @@ -2,196 +2,238 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Concurrent; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Nethermind.Core; using Nethermind.State; -namespace Nethermind.Evm +namespace Nethermind.Evm; + +/// +/// State for EVM Calls +/// +[DebuggerDisplay("{ExecutionType} to {Env.ExecutingAccount}, G {GasAvailable} R {Refund} PC {ProgramCounter} OUT {OutputDestination}:{OutputLength}")] +public sealed class EvmState : IDisposable // TODO: rename to CallState { + private static readonly ConcurrentQueue _statePool = new(); + private static readonly StackPool _stackPool = new(); + + public byte[]? DataStack; + public int[]? ReturnStack; + + public long GasAvailable { get; set; } + internal long OutputDestination { get; private set; } // TODO: move to CallEnv + internal long OutputLength { get; private set; } // TODO: move to CallEnv + public long Refund { get; set; } + + public int DataStackHead; + + public int ReturnStackHead; + internal ExecutionType ExecutionType { get; private set; } // TODO: move to CallEnv + public int ProgramCounter { get; set; } + public bool IsTopLevel { get; private set; } // TODO: move to CallEnv + private bool _canRestore; + public bool IsStatic { get; private set; } // TODO: move to CallEnv + public bool IsContinuation { get; set; } // TODO: move to CallEnv + public bool IsCreateOnPreExistingAccount { get; private set; } // TODO: move to CallEnv + + private bool _isDisposed = true; + + private EvmPooledMemory _memory; + private Snapshot _snapshot; + private ExecutionEnvironment _env; + private StackAccessTracker _accessTracker; + +#if DEBUG + private StackTrace? _creationStackTrace; +#endif /// - /// State for EVM Calls + /// Rent a top level . /// - [DebuggerDisplay("{ExecutionType} to {Env.ExecutingAccount}, G {GasAvailable} R {Refund} PC {ProgramCounter} OUT {OutputDestination}:{OutputLength}")] - public class EvmState : IDisposable // TODO: rename to CallState + public static EvmState RentTopLevel( + long gasAvailable, + ExecutionType executionType, + in Snapshot snapshot, + in ExecutionEnvironment env, + in StackAccessTracker accessedItems) { - private static readonly StackPool _stackPool = new(); - - public byte[]? DataStack; - - public int[]? ReturnStack; - - public StackAccessTracker AccessTracker => _accessTracker; - - private readonly StackAccessTracker _accessTracker; - - public int DataStackHead = 0; - - public int ReturnStackHead = 0; - private bool _canRestore = true; - /// - /// Constructor for a top level . - /// - public EvmState( - long gasAvailable, - ExecutionEnvironment env, - ExecutionType executionType, - Snapshot snapshot, - in StackAccessTracker accessedItems) : this(gasAvailable, - env, - executionType, - true, - snapshot, - 0L, - 0L, - false, - accessedItems, - false) - { - } - /// - /// Constructor for a top level . - /// - public EvmState( - long gasAvailable, - ExecutionEnvironment env, - ExecutionType executionType, - Snapshot snapshot) : this(gasAvailable, - env, - executionType, - true, - snapshot, - 0L, - 0L, - false, - new StackAccessTracker(), - false) - { - } - /// - /// Constructor for a frame beneath top level. - /// - internal EvmState( - long gasAvailable, - ExecutionEnvironment env, - ExecutionType executionType, - Snapshot snapshot, - long outputDestination, - long outputLength, - bool isStatic, - in StackAccessTracker stateForAccessLists, - bool isCreateOnPreExistingAccount) : - this( - gasAvailable, - env, - executionType, - false, - snapshot, - outputDestination, - outputLength, - isStatic, - stateForAccessLists, - isCreateOnPreExistingAccount) - { + EvmState state = Rent(); + state.Initialize( + gasAvailable, + outputDestination: 0L, + outputLength: 0L, + executionType: executionType, + isTopLevel: true, + isStatic: false, + isCreateOnPreExistingAccount: false, + snapshot: snapshot, + env: env, + stateForAccessLists: accessedItems); + return state; + } - } - private EvmState( - long gasAvailable, - ExecutionEnvironment env, - ExecutionType executionType, - bool isTopLevel, - Snapshot snapshot, - long outputDestination, - long outputLength, - bool isStatic, - in StackAccessTracker stateForAccessLists, - bool isCreateOnPreExistingAccount) + /// + /// Constructor for a frame beneath top level. + /// + public static EvmState RentFrame( + long gasAvailable, + long outputDestination, + long outputLength, + ExecutionType executionType, + bool isStatic, + bool isCreateOnPreExistingAccount, + in Snapshot snapshot, + in ExecutionEnvironment env, + in StackAccessTracker stateForAccessLists) + { + EvmState state = Rent(); + + state.Initialize( + gasAvailable, + outputDestination, + outputLength, + executionType, + isTopLevel: false, + isStatic: isStatic, + isCreateOnPreExistingAccount: isCreateOnPreExistingAccount, + snapshot: snapshot, + env: env, + stateForAccessLists: stateForAccessLists); + + return state; + } + + private static EvmState Rent() => _statePool.TryDequeue(out EvmState state) ? state : new EvmState(); + + private void Initialize( + long gasAvailable, + long outputDestination, + long outputLength, + ExecutionType executionType, + bool isTopLevel, + bool isStatic, + bool isCreateOnPreExistingAccount, + in Snapshot snapshot, + in ExecutionEnvironment env, + in StackAccessTracker stateForAccessLists) + { + GasAvailable = gasAvailable; + OutputDestination = outputDestination; + OutputLength = outputLength; + Refund = 0; + DataStackHead = 0; + ReturnStackHead = 0; + ExecutionType = executionType; + ProgramCounter = 0; + IsTopLevel = isTopLevel; + _canRestore = !isTopLevel; + IsStatic = isStatic; + IsContinuation = false; + IsCreateOnPreExistingAccount = isCreateOnPreExistingAccount; + _snapshot = snapshot; + _env = env; + _accessTracker = new(stateForAccessLists); + if (executionType.IsAnyCreate()) { - GasAvailable = gasAvailable; - ExecutionType = executionType; - IsTopLevel = isTopLevel; - _canRestore = !isTopLevel; - Snapshot = snapshot; - Env = env; - OutputDestination = outputDestination; - OutputLength = outputLength; - IsStatic = isStatic; - IsContinuation = false; - IsCreateOnPreExistingAccount = isCreateOnPreExistingAccount; - _accessTracker = new(stateForAccessLists); - if (executionType.IsAnyCreate()) - { - _accessTracker.WasCreated(env.ExecutingAccount); - } - _accessTracker.TakeSnapshot(); + _accessTracker.WasCreated(env.ExecutingAccount); } + _accessTracker.TakeSnapshot(); - public Address From + // Should be disposed when being initialized + if (!_isDisposed) { - get - { - return ExecutionType switch - { - ExecutionType.STATICCALL or ExecutionType.CALL or ExecutionType.CALLCODE or ExecutionType.CREATE or ExecutionType.CREATE2 or ExecutionType.TRANSACTION => Env.Caller, - ExecutionType.DELEGATECALL => Env.ExecutingAccount, - _ => throw new ArgumentOutOfRangeException(), - }; - } + ThrowIfNotUninitialized(); } + // Mark revived + _isDisposed = false; - public long GasAvailable { get; set; } - public int ProgramCounter { get; set; } - public long Refund { get; set; } +#if DEBUG + _creationStackTrace = new(); +#endif - public Address To => Env.CodeSource ?? Env.ExecutingAccount; - internal bool IsPrecompile => Env.CodeInfo.IsPrecompile; - public readonly ExecutionEnvironment Env; + [DoesNotReturn] + [StackTraceHidden] + static void ThrowIfNotUninitialized() + { + throw new InvalidOperationException("Already in use"); + } + } - internal ExecutionType ExecutionType { get; } // TODO: move to CallEnv - public bool IsTopLevel { get; } // TODO: move to CallEnv - internal long OutputDestination { get; } // TODO: move to CallEnv - internal long OutputLength { get; } // TODO: move to CallEnv - public bool IsStatic { get; } // TODO: move to CallEnv - public bool IsContinuation { get; set; } // TODO: move to CallEnv - public bool IsCreateOnPreExistingAccount { get; } // TODO: move to CallEnv - public Snapshot Snapshot { get; } // TODO: move to CallEnv + public Address From => ExecutionType switch + { + ExecutionType.STATICCALL or ExecutionType.CALL or ExecutionType.CALLCODE or ExecutionType.CREATE + or ExecutionType.CREATE2 or ExecutionType.TRANSACTION => Env.Caller, + ExecutionType.DELEGATECALL => Env.ExecutingAccount, + _ => throw new ArgumentOutOfRangeException(), + }; + + public Address To => Env.CodeSource ?? Env.ExecutingAccount; + internal bool IsPrecompile => Env.CodeInfo.IsPrecompile; + public ref readonly StackAccessTracker AccessTracker => ref _accessTracker; + public ref readonly ExecutionEnvironment Env => ref _env; + public ref EvmPooledMemory Memory => ref _memory; // TODO: move to CallEnv + public ref readonly Snapshot Snapshot => ref _snapshot; // TODO: move to CallEnv + + public void Dispose() + { + // Shouldn't be called multiple times + Debug.Assert(!_isDisposed); - private EvmPooledMemory _memory; - public ref EvmPooledMemory Memory => ref _memory; // TODO: move to CallEnv + if (_isDisposed) return; - public void Dispose() + _isDisposed = true; + if (DataStack is not null) { - if (DataStack is not null) - { - // Only Dispose once - _stackPool.ReturnStacks(DataStack, ReturnStack!); - DataStack = null; - ReturnStack = null; - } - Restore(); // we are trying to restore when disposing - Memory.Dispose(); - Memory = default; + // Only return if initialized + _stackPool.ReturnStacks(DataStack, ReturnStack!); + DataStack = null; + ReturnStack = null; } - - public void InitStacks() + if (_canRestore) { - if (DataStack is null) - { - (DataStack, ReturnStack) = _stackPool.RentStacks(); - } + // if we didn't commit and we are not top level, then we need to restore and drop the changes done in this call + _accessTracker.Restore(); } + _memory.Dispose(); + // Blank refs to not hold against GC + _memory = default; + _accessTracker = default; + _env = default; + _snapshot = default; + + _statePool.Enqueue(this); + +#if DEBUG + GC.SuppressFinalize(this); +#endif + } - public void CommitToParent(EvmState parentState) +#if DEBUG + ~EvmState() + { + if (!_isDisposed) { - parentState.Refund += Refund; - _canRestore = false; // we can't restore if we committed + throw new InvalidOperationException($"{nameof(EvmState)} hasn't been disposed. Created {_creationStackTrace}"); } + } +#endif + + public void InitializeStacks() + { + ObjectDisposedException.ThrowIf(_isDisposed, this); - private void Restore() + if (DataStack is null) { - if (_canRestore) // if we didn't commit and we are not top level, then we need to restore and drop the changes done in this call - { - _accessTracker.Restore(); - } + (DataStack, ReturnStack) = _stackPool.RentStacks(); } } + + public void CommitToParent(EvmState parentState) + { + ObjectDisposedException.ThrowIf(_isDisposed, this); + + parentState.Refund += Refund; + _canRestore = false; // we can't restore if we committed + } } diff --git a/src/Nethermind/Nethermind.Evm/StackAccessTracker.cs b/src/Nethermind/Nethermind.Evm/StackAccessTracker.cs index 6de077bc191..df941be5596 100644 --- a/src/Nethermind/Nethermind.Evm/StackAccessTracker.cs +++ b/src/Nethermind/Nethermind.Evm/StackAccessTracker.cs @@ -1,102 +1,126 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using Nethermind.Core; using Nethermind.Core.Collections; using Nethermind.Core.Eip2930; using Nethermind.Int256; -namespace Nethermind.Evm +namespace Nethermind.Evm; + +public struct StackAccessTracker : IDisposable { - public struct StackAccessTracker + public readonly IReadOnlySet
AccessedAddresses => _trackingState.AccessedAddresses; + public readonly IReadOnlySet AccessedStorageCells => _trackingState.AccessedStorageCells; + public readonly ICollection Logs => _trackingState.Logs; + public readonly IReadOnlySet
DestroyList => _trackingState.DestroyList; + public readonly IReadOnlySet CreateList => _trackingState.CreateList; + + private TrackingState _trackingState; + + private int _addressesSnapshots; + private int _storageKeysSnapshots; + private int _destroyListSnapshots; + private int _logsSnapshots; + + public StackAccessTracker(in StackAccessTracker accessTracker) { - public readonly IReadOnlySet
AccessedAddresses => _accessedAddresses; - public readonly IReadOnlySet AccessedStorageCells => _accessedStorageCells; - public readonly ICollection Logs => _logs; - public readonly IReadOnlySet
DestroyList => _destroyList; - public readonly IReadOnlySet CreateList => _createList; - private readonly JournalSet
_accessedAddresses; - private readonly JournalSet _accessedStorageCells; - private readonly JournalCollection _logs; - private readonly JournalSet
_destroyList; - private readonly HashSet _createList; - - private int _addressesSnapshots; - private int _storageKeysSnapshots; - private int _destroyListSnapshots; - private int _logsSnapshots; - - public StackAccessTracker(in StackAccessTracker accessTracker) - { - _accessedAddresses = accessTracker._accessedAddresses; - _accessedStorageCells = accessTracker._accessedStorageCells; - _logs = accessTracker._logs; - _destroyList = accessTracker._destroyList; - _createList = accessTracker._createList; - } + _trackingState = accessTracker._trackingState; + } - public StackAccessTracker() - { - _accessedAddresses = new(); - _accessedStorageCells = new(); - _logs = new(); - _destroyList = new(); - _createList = new(); - } - public readonly bool IsCold(Address? address) => !AccessedAddresses.Contains(address); + public StackAccessTracker() + { + _trackingState = TrackingState.RentState(); + } + public readonly bool IsCold(Address? address) => !_trackingState.AccessedAddresses.Contains(address); - public readonly bool IsCold(in StorageCell storageCell) => !_accessedStorageCells.Contains(storageCell); + public readonly bool IsCold(in StorageCell storageCell) => !_trackingState.AccessedStorageCells.Contains(storageCell); - public readonly void WarmUp(Address address) - { - _accessedAddresses.Add(address); - } + public readonly void WarmUp(Address address) + { + _trackingState.AccessedAddresses.Add(address); + } - public readonly void WarmUp(in StorageCell storageCell) - { - _accessedStorageCells.Add(storageCell); - } + public readonly void WarmUp(in StorageCell storageCell) + { + _trackingState.AccessedStorageCells.Add(storageCell); + } - public readonly void WarmUp(AccessList? accessList) + public readonly void WarmUp(AccessList? accessList) + { + if (accessList?.IsEmpty == false) { - if (accessList?.IsEmpty == false) + foreach ((Address address, AccessList.StorageKeysEnumerable storages) in accessList) { - foreach ((Address address, AccessList.StorageKeysEnumerable storages) in accessList) + _trackingState.AccessedAddresses.Add(address); + foreach (UInt256 storage in storages) { - _accessedAddresses.Add(address); - foreach (UInt256 storage in storages) - { - _accessedStorageCells.Add(new StorageCell(address, storage)); - } + _trackingState.AccessedStorageCells.Add(new StorageCell(address, storage)); } } } + } - public readonly void ToBeDestroyed(Address address) - { - _destroyList.Add(address); - } + public readonly void ToBeDestroyed(Address address) + { + _trackingState.DestroyList.Add(address); + } - public readonly void WasCreated(Address address) - { - _createList.Add(address); - } + public readonly void WasCreated(Address address) + { + _trackingState.CreateList.Add(address); + } + + public void TakeSnapshot() + { + _addressesSnapshots = _trackingState.AccessedAddresses.TakeSnapshot(); + _storageKeysSnapshots = _trackingState.AccessedStorageCells.TakeSnapshot(); + _destroyListSnapshots = _trackingState.DestroyList.TakeSnapshot(); + _logsSnapshots = _trackingState.Logs.TakeSnapshot(); + } + + public readonly void Restore() + { + _trackingState.Logs.Restore(_logsSnapshots); + _trackingState.DestroyList.Restore(_destroyListSnapshots); + _trackingState.AccessedAddresses.Restore(_addressesSnapshots); + _trackingState.AccessedStorageCells.Restore(_storageKeysSnapshots); + } + + public void Dispose() + { + TrackingState state = _trackingState; + _trackingState = null; + TrackingState.ResetAndReturn(state); + } - public void TakeSnapshot() + private class TrackingState + { + private static readonly ConcurrentQueue _trackerPool = new(); + public static TrackingState RentState() => _trackerPool.TryDequeue(out TrackingState tracker) ? tracker : new TrackingState(); + + public static void ResetAndReturn(TrackingState state) { - _addressesSnapshots = _accessedAddresses.TakeSnapshot(); - _storageKeysSnapshots = _accessedStorageCells.TakeSnapshot(); - _destroyListSnapshots = _destroyList.TakeSnapshot(); - _logsSnapshots = _logs.TakeSnapshot(); + state.Clear(); + _trackerPool.Enqueue(state); } - public readonly void Restore() + public JournalSet
AccessedAddresses { get; } = new(); + public JournalSet AccessedStorageCells { get; } = new(); + public JournalCollection Logs { get; } = new(); + public JournalSet
DestroyList { get; } = new(); + public HashSet CreateList { get; } = new(); + + private void Clear() { - _logs.Restore(_logsSnapshots); - _destroyList.Restore(_destroyListSnapshots); - _accessedAddresses.Restore(_addressesSnapshots); - _accessedStorageCells.Restore(_storageKeysSnapshots); + AccessedAddresses.Clear(); + AccessedStorageCells.Clear(); + Logs.Clear(); + DestroyList.Clear(); + CreateList.Clear(); } } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index ce3038cf504..9638f58ff7f 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -158,7 +158,9 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon if (commit) WorldState.Commit(spec, tracer.IsTracingState ? tracer : NullTxTracer.Instance, commitStorageRoots: false); - StackAccessTracker accessTracker = new(); + // substate.Logs contains a reference to accessTracker.Logs so we can't Dispose until end of the method + using StackAccessTracker accessTracker = new(); + int delegationRefunds = ProcessDelegations(tx, spec, accessTracker); ExecutionEnvironment env = BuildExecutionEnvironment(tx, in blCtx, spec, effectiveGasPrice, _codeInfoRepository, accessTracker); @@ -618,11 +620,11 @@ protected virtual void ExecuteEvmCall( } } - using (EvmState state = new EvmState( + using (EvmState state = EvmState.RentTopLevel( unspentGas, - env, tx.IsContractCreation ? ExecutionType.CREATE : ExecutionType.TRANSACTION, snapshot, + env, accessedItems)) { diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index 88525f10b84..56149f85a78 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -647,7 +647,7 @@ private CallResult ExecuteCall(EvmState vmState, ReadOnlyM goto Empty; } - vmState.InitStacks(); + vmState.InitializeStacks(); EvmStack stack = new(vmState.DataStackHead, _txTracer, vmState.DataStack.AsSpan()); long gasAvailable = vmState.GasAvailable; @@ -2229,16 +2229,16 @@ private EvmExceptionType InstructionCall( } ExecutionType executionType = GetCallExecutionType(instruction, env.IsPostMerge()); - returnData = new EvmState( + returnData = EvmState.RentFrame( gasLimitUl, - callEnv, - executionType, - snapshot, outputOffset.ToLong(), outputLength.ToLong(), + executionType, instruction == Instruction.STATICCALL || vmState.IsStatic, - vmState.AccessTracker, - isCreateOnPreExistingAccount: false); + isCreateOnPreExistingAccount: false, + snapshot: snapshot, + env: callEnv, + stateForAccessLists: vmState.AccessTracker); return EvmExceptionType.None; @@ -2468,16 +2468,16 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref transferValue: value, value: value ); - EvmState callState = new( + EvmState callState = EvmState.RentFrame( callGas, - callEnv, - instruction == Instruction.CREATE2 ? ExecutionType.CREATE2 : ExecutionType.CREATE, - snapshot, 0L, 0L, + instruction == Instruction.CREATE2 ? ExecutionType.CREATE2 : ExecutionType.CREATE, vmState.IsStatic, - vmState.AccessTracker, - accountExists); + accountExists, + snapshot, + callEnv, + vmState.AccessTracker); return (EvmExceptionType.None, callState); } From 9c720ced8aa2863fc90c9a68c32a548a33f828a3 Mon Sep 17 00:00:00 2001 From: Nikita Mescheryakov Date: Thu, 2 Jan 2025 17:39:50 +0300 Subject: [PATCH 063/113] Optimism CL P2P (#7297) Co-authored-by: lukasz.rozmej --- src/Nethermind/Chains/base-mainnet.json | 6 +- src/Nethermind/Chains/base-sepolia.json | 4 + src/Nethermind/Chains/op-mainnet.json | 4 + src/Nethermind/Chains/op-sepolia.json | 4 + src/Nethermind/Nethermind.Core/Address.cs | 12 + src/Nethermind/Nethermind.Core/Bloom.cs | 5 + .../CL/PayloadDecoderTests.cs | 203 +++++++++++++ .../Nethermind.Optimism/CL/CLConfig.cs | 15 + .../CL/ICLChainSpecEngineParameters.cs | 17 ++ .../Nethermind.Optimism/CL/ICLConfig.cs | 21 ++ .../Nethermind.Optimism/CL/OptimismCL.cs | 44 +++ .../CL/P2P/IP2PBlockValidator.cs | 28 ++ .../CL/P2P/IPayloadDecoder.cs | 13 + .../CL/P2P/OptimismCLP2P.cs | 268 ++++++++++++++++++ .../CL/P2P/P2PBlockValidator.cs | 164 +++++++++++ .../CL/P2P/PayloadDecoder.cs | 91 ++++++ .../Nethermind.Optimism.csproj | 7 + .../Nethermind.Optimism/OptimismPlugin.cs | 17 ++ 18 files changed, 922 insertions(+), 1 deletion(-) create mode 100644 src/Nethermind/Nethermind.Optimism.Test/CL/PayloadDecoderTests.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/CLConfig.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/ICLChainSpecEngineParameters.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/ICLConfig.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/P2P/IP2PBlockValidator.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/P2P/IPayloadDecoder.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/P2P/P2PBlockValidator.cs create mode 100644 src/Nethermind/Nethermind.Optimism/CL/P2P/PayloadDecoder.cs diff --git a/src/Nethermind/Chains/base-mainnet.json b/src/Nethermind/Chains/base-mainnet.json index 3098cc81864..642f5ae56c0 100644 --- a/src/Nethermind/Chains/base-mainnet.json +++ b/src/Nethermind/Chains/base-mainnet.json @@ -16,6 +16,10 @@ "create2DeployerAddress": "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", "create2DeployerCode": "6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033" } + }, + "OptimismCL": { + "sequencerP2PAddress": "0xAf6E19BE0F9cE7f8afd49a1824851023A8249e8a", + "nodes": ["/ip4/150.136.106.181/tcp/9222/p2p/16Uiu2HAkwJ9rhDQHogv1PB6yZtpu6QMZMuA7TjAYhNbVKQGrSkYB", "/ip4/45.42.140.30/tcp/21727/p2p/16Uiu2HAm4KH5k1Qkq2gEk74WhWvfunLJLSE7ptVaX5nGy7mdVR7g", "/ip4/54.198.153.150/tcp/9222/p2p/16Uiu2HAkwSnpTCP4f1ttHa2hKgiwZaa8TFJYWHtNNhYbqKwaYMRu", "/ip4/85.17.108.76/tcp/9222/p2p/16Uiu2HAm9bjq6bjVfQtM9SwGV7W3tC5NUaLJPsSBRn4SoqzCXhLq", "/ip4/35.173.48.199/tcp/9222/p2p/16Uiu2HAmHKzkXepNhPBmUrVNShk26WBvaZB5edjCNCpV5sza8Sgd", "/ip4/184.72.129.189/tcp/9222/p2p/16Uiu2HAm3qwgs4Bvfx1GJ5qnY4LjPbYCc394kvdjpxuJBsP3SQnW", "/ip4/184.73.87.196/tcp/9222/p2p/16Uiu2HAmAocWHkRKPsD4kN8pTEEpCqc576vu5nR19DoAfvKd8o8i", "/ip4/18.208.138.113/tcp/9222/p2p/16Uiu2HAmUcc9SxrGewq68TG4EoYB7noYqQrVr1yzinCVHqg4WRGF", "/ip4/173.231.41.130/tcp/9233/p2p/16Uiu2HAm8XHH6fhCh1hxiwCAMpak1rwnd6M53Pqe3AaUGiUZ5AG1", "/ip4/3.231.11.52/tcp/9222/p2p/16Uiu2HAkvLBTPqfA9HHXgnLUQiEJg7EKPb7gu7qMXfJFS79Goy3b", "/ip4/44.221.43.51/tcp/9333/p2p/16Uiu2HAmEGAgiKjz9MCPoEqU3KK9Xu9ZAhJBRoP6quzNKTMKpee9", "/ip4/3.220.145.177/tcp/9222/p2p/16Uiu2HAm31LCBALXkJfNGmK1tVkgzQDw9QQoNcFznzBBCYUPUhAD"] } }, "params": { @@ -64,7 +68,7 @@ "eip4844TransitionTimestamp": "0x65f23e01", "eip5656TransitionTimestamp": "0x65f23e01", "eip6780TransitionTimestamp": "0x65f23e01", - + "rip7212TransitionTimestamp": "0x668eb001", "opGraniteTransitionTimestamp": "0x66e1be81", diff --git a/src/Nethermind/Chains/base-sepolia.json b/src/Nethermind/Chains/base-sepolia.json index d9ab7c57857..71d3fb265ac 100644 --- a/src/Nethermind/Chains/base-sepolia.json +++ b/src/Nethermind/Chains/base-sepolia.json @@ -17,6 +17,10 @@ "create2DeployerAddress": "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", "create2DeployerCode": "6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033" } + }, + "OptimismCL": { + "sequencerP2PAddress": "0xb830b99c95Ea32300039624Cb567d324D4b1D83C", + "nodes": ["/ip4/18.208.138.113/tcp/9222/p2p/16Uiu2HAmUcc9SxrGewq68TG4EoYB7noYqQrVr1yzinCVHqg4WRGF", "/ip4/44.221.43.51/tcp/9333/p2p/16Uiu2HAmEGAgiKjz9MCPoEqU3KK9Xu9ZAhJBRoP6quzNKTMKpee9", "/ip4/184.73.87.196/tcp/9222/p2p/16Uiu2HAmAocWHkRKPsD4kN8pTEEpCqc576vu5nR19DoAfvKd8o8i", "/ip4/150.136.106.181/tcp/9222/p2p/16Uiu2HAkwJ9rhDQHogv1PB6yZtpu6QMZMuA7TjAYhNbVKQGrSkYB", "/ip4/173.231.41.130/tcp/9233/p2p/16Uiu2HAm8XHH6fhCh1hxiwCAMpak1rwnd6M53Pqe3AaUGiUZ5AG1", "/ip4/45.42.140.30/tcp/21727/p2p/16Uiu2HAm4KH5k1Qkq2gEk74WhWvfunLJLSE7ptVaX5nGy7mdVR7g"] } }, "params": { diff --git a/src/Nethermind/Chains/op-mainnet.json b/src/Nethermind/Chains/op-mainnet.json index 7f6a7765ef3..92b65c15058 100644 --- a/src/Nethermind/Chains/op-mainnet.json +++ b/src/Nethermind/Chains/op-mainnet.json @@ -16,6 +16,10 @@ "create2DeployerAddress": "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", "create2DeployerCode": "6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033" } + }, + "OptimismCL": { + "sequencerP2PAddress": "0xAAAA45d9549EDA09E70937013520214382Ffc4A2", + "nodes": ["/ip4/23.92.177.87/tcp/20254/p2p/16Uiu2HAm4pKiPJoM8ub3jH9chumSpEfX5pCd8sm9njkzaH7mFUN3", "/ip4/144.76.158.143/tcp/30311/p2p/16Uiu2HAmEHh2HSzK3Ff9BYpzXch68guMytNyjKvogFLanaKCcUES", "/ip4/51.91.72.147/tcp/9003/p2p/16Uiu2HAmGXwim6g3kQd3tehvWtqab7JcvT4bWpkCAnhzY56vZubc", "/ip4/45.42.140.30/tcp/21727/p2p/16Uiu2HAm4KH5k1Qkq2gEk74WhWvfunLJLSE7ptVaX5nGy7mdVR7g", "/ip4/35.173.48.199/tcp/9222/p2p/16Uiu2HAmHKzkXepNhPBmUrVNShk26WBvaZB5edjCNCpV5sza8Sgd", "/ip4/5.39.71.166/tcp/9003/p2p/16Uiu2HAkw4vemhwxVdNa5VaudjBRnA4XRKUDZmrxynVHFgMrG84c", "/ip4/3.239.211.184/tcp/9222/p2p/16Uiu2HAkxFNPGjdqZXXTdUr9xHKUJyUZbXqZC1EgDqStG2RxxzZ8", "/ip4/34.71.206.92/tcp/9003/p2p/16Uiu2HAmNRGrco5LGvaGT8Q85eqCxwWeWGsbgw9cL6HFsTbyci7m", "/ip4/15.204.213.68/tcp/9003/p2p/16Uiu2HAmAAP78k6MEFKbZjFvwC2Syr86ePVKJGRa9eXeCqrnXiAq", "/ip4/116.202.215.20/tcp/9222/p2p/16Uiu2HAm6h61WPbW7tySjVqJsF1ArvQ5G2HWSGicNTh31TBdHcVB", "/ip4/142.132.209.114/tcp/21367/p2p/16Uiu2HAmA6ECeJPQGUrcEhF4XFvKkLJvpr2nHbkTL4hZ2777K3d3", "/ip4/85.17.108.76/tcp/9222/p2p/16Uiu2HAm9bjq6bjVfQtM9SwGV7W3tC5NUaLJPsSBRn4SoqzCXhLq", "/ip4/18.208.138.113/tcp/9222/p2p/16Uiu2HAmUcc9SxrGewq68TG4EoYB7noYqQrVr1yzinCVHqg4WRGF"] } }, "params": { diff --git a/src/Nethermind/Chains/op-sepolia.json b/src/Nethermind/Chains/op-sepolia.json index f59bd1f8f34..6dc4494191a 100644 --- a/src/Nethermind/Chains/op-sepolia.json +++ b/src/Nethermind/Chains/op-sepolia.json @@ -17,6 +17,10 @@ "create2DeployerAddress": "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", "create2DeployerCode": "6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033" } + }, + "OptimismCL": { + "sequencerP2PAddress": "0x57CACBB0d30b01eb2462e5dC940c161aff3230D3", + "nodes": ["/ip4/34.27.24.113/tcp/9003/p2p/16Uiu2HAmL7Zmt7uNr8eNJTi3hJVH1gb4eDfcmBN3fP2k9Lu7L5i4","/ip4/87.246.108.92/tcp/31900/p2p/16Uiu2HAkxuB7g9PaV6ekEo2yUCB5ocW4MPBrRtW5eXsAgccBSj1b", "/ip4/141.147.43.140/tcp/9222/p2p/16Uiu2HAmCKPsKd8wAJ993zzFHg2VLRrqQVsfFqG1PYv3NG5kB924", "/ip4/34.170.131.59/tcp/9003/p2p/6Uiu2HAmK7wyBpAEg2b7jXebgmNNtyCywHJKm4YaWYn6PMUoDHmC"] } }, "params": { diff --git a/src/Nethermind/Nethermind.Core/Address.cs b/src/Nethermind/Nethermind.Core/Address.cs index 9b940feba52..11a92cd615b 100644 --- a/src/Nethermind/Nethermind.Core/Address.cs +++ b/src/Nethermind/Nethermind.Core/Address.cs @@ -140,6 +140,18 @@ public Address(byte[] bytes) Bytes = bytes; } + public Address(ReadOnlySpan bytes) + { + if (bytes.Length != Size) + { + throw new ArgumentException( + $"{nameof(Address)} should be {Size} bytes long and is {bytes.Length} bytes long", + nameof(bytes)); + } + + Bytes = bytes.ToArray(); + } + public bool Equals(Address? other) { if (other is null) diff --git a/src/Nethermind/Nethermind.Core/Bloom.cs b/src/Nethermind/Nethermind.Core/Bloom.cs index 1cd212b0606..50673c9ee30 100644 --- a/src/Nethermind/Nethermind.Core/Bloom.cs +++ b/src/Nethermind/Nethermind.Core/Bloom.cs @@ -46,6 +46,11 @@ public Bloom(byte[] bytes) Bytes = bytes; } + public Bloom(ReadOnlySpan bytes) + { + Bytes = bytes.ToArray(); + } + public byte[] Bytes { get; } public void Set(ReadOnlySpan sequence) diff --git a/src/Nethermind/Nethermind.Optimism.Test/CL/PayloadDecoderTests.cs b/src/Nethermind/Nethermind.Optimism.Test/CL/PayloadDecoderTests.cs new file mode 100644 index 00000000000..68d61f34136 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism.Test/CL/PayloadDecoderTests.cs @@ -0,0 +1,203 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using FluentAssertions; +using Nethermind.Core; +using Nethermind.Merge.Plugin.Data; +using Nethermind.Optimism.CL; +using NUnit.Framework; + +namespace Nethermind.Optimism.Test.CL; + +public class PayloadDecoderTests +{ + [TestCaseSource(nameof(RealPayloadsTestCases))] + public void OpMainnetPayloadsTest((string Data, ExecutionPayloadV3 Payload) testCase) + { + byte[] bytes = Convert.FromBase64String(testCase.Data); + ExecutionPayloadV3 decoded = PayloadDecoder.Instance.DecodePayload(bytes); + ComparePayloads(testCase.Payload, decoded); + } + + private void ComparePayloads(ExecutionPayloadV3 expected, ExecutionPayloadV3 actual) + { + expected.BaseFeePerGas.Should().Be(actual.BaseFeePerGas); + expected.BlobGasUsed.Should().Be(actual.BlobGasUsed); + expected.BlockHash.Should().Be(actual.BlockHash); + expected.BlockNumber.Should().Be(actual.BlockNumber); + expected.ExcessBlobGas.Should().Be(actual.ExcessBlobGas); + expected.ExecutionRequests.Should().BeEquivalentTo(actual.ExecutionRequests); + expected.ExtraData.Should().BeEquivalentTo(actual.ExtraData); + expected.FeeRecipient.Should().BeEquivalentTo(actual.FeeRecipient); + expected.GasLimit.Should().Be(actual.GasLimit); + expected.GasUsed.Should().Be(actual.GasUsed); + expected.Timestamp.Should().Be(actual.Timestamp); + expected.ParentHash.Should().Be(actual.ParentHash); + expected.Transactions.Should().BeEquivalentTo(actual.Transactions); + expected.ParentBeaconBlockRoot.Should().Be(actual.ParentBeaconBlockRoot!); + expected.ReceiptsRoot.Should().BeEquivalentTo(actual.ReceiptsRoot); + expected.StateRoot.Should().BeEquivalentTo(actual.StateRoot); + expected.Withdrawals.Should().BeEquivalentTo(actual.Withdrawals); + expected.LogsBloom.Should().Be(actual.LogsBloom); + expected.PrevRandao.Should().Be(actual.PrevRandao); + } + + public static IEnumerable<(string, ExecutionPayloadV3)> RealPayloadsTestCases() + { + // OP-mainnet + yield return ("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", + new ExecutionPayloadV3() + { + BaseFeePerGas = 0x55451, + BlobGasUsed = 0, + BlockHash = new("0xaadc2aff85b5f6704b66e56d3d73ae795209ecd601ec7d4cf2a64750c152988c"), + BlockNumber = 129499858, + ExcessBlobGas = 0, + ExecutionRequests = null, + ExtraData = Array.Empty(), + FeeRecipient = new("0x4200000000000000000000000000000000000011"), + GasLimit = 0x3938700, + GasUsed = 0x7b5d2c, + Timestamp = 0x6763df5d, + ParentHash = new("0x414aba29e9e6c0c137e074f5e19f365fdc5aa59a6b5c9eb6289b4953bc87174c"), + Transactions = new byte[][] + { + Convert.FromBase64String("fvj4oGNZXhCDzUFKDGCZihNWuD1shnHfxHswY5MlznXt6OHzlN6t3q3erd6t3q3erd6t3q3erQABlEIAAAAAAAAAAAAAAAAAAAAAAAAVgICDD0JAgLikRApeIAAAFGsAD3nFAAAAAAAAAAAAAAAAZ2PfDwAAAAABRxRrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAll7R3sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACduiKH0ShqEQ51XF31bU752PooW1nqrpyiPh/NMOZzcrp5s0AAAAAAAAAAAAAAAAaIckZmijuH9U3rO5S6R6b2PzKYU="), + Convert.FromBase64String("+MuCBmeEHc1lAIMBhqCUlWDoJ682yU0qwzo5vOH+eGMQiNuAuGQjuHLdAAAAAAAAAAAAAAAAYlHn+qgjd3pnEBoiTlWGzMPIF6IAAAAAAAAAAAAAAACR3KN4ViQOXhkGIi7HknixZCDckgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADTY7Y/1stsAAOKD5NZFi55RlTQhoFP7lXq2IiyUrcJuvr+s0r5ddmLq8L6ATOKz2cLxw5/QKf9AX4GT0FcLBvFPONHb9cCvdLJBt5g=="), + Convert.FromBase64String("AvkBMwqDBXH6hAQsHYCEBDbGIoMJJ8CUgCtltdkBZiHmYAOu0LFmFQk/MouAuMSgBZegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApFuKEYQ2zAAAAAAAAAAAAAAAAAAAAAAAAAAKZH1F95u7Hxd3dEOUwAAAAAAAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAABNwiWIreBcQDOKnZWm2p3O5ovNYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY+APwICg7MvmjmhDiTxtTzqnrMtw17Ehuf0Krbb0bUkmqy0Z2AGgek8a8El54GSIu5BNo/BdS45bPuL/y6AQQ0Y3pWsUgrg="), + Convert.FromBase64String("AvkBMwqDBGnOhAF9eECEAYgg4oMJJ8CUgCtltdkBZiHmYAOu0LFmFQk/MouAuMSgBZegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHOGC4mDkPgAAAAAAAAAAAAAAAAAAAAAAAAAKZH0tfOMS7112xzjKgAAAAAAAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAD8HzKWRY+bKieguR3XaBxAIOCdBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY+APwICgbHbR/jPBiwz1iQnswruSfWkvvMc25kPEl9z4cO06lfigcgzs9C9CWrxkHE1Lxo6tIw2G1r1Ocnq0ScDV7mrNZQk="), + Convert.FromBase64String("AvhwCoMPDPaDGWxsgyQWMIPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaAo5Tp1XGBAUnsnG/qST9yQ+55WBYH13/hBfz5lpV7TDKBpN8oWpZhh/I5BPbmj25sRaMxgtjVmvQkLtkkd1hQvwQ=="), + + Convert.FromBase64String("AvhtCoKer4MeuduDHrnbg5iWgJTT3AeaxvmCdbu80K/xHLqttNjyrICCAAHAAaBxIZlpWi4LXWSzPCK7S/GX6s9t6KeNAsi6lvgYOUBdHqB2fxcRz1ZUZJRDK2LNic0Y+VMgvUun8x7Mtl26+ZDa/Q=="), + Convert.FromBase64String("AvhuCoJosIMPzCWEA5OHAIOYloCU09wHmsb5gnW7vNCv8Ry6rbTY8qyAggABwAGgYjV4hqsKkR7BaVZogU6B+jawGGLWBJQ1QC6N4SdDXjWgIs6cwoVgB2KHvUl9j+SNs/3CnX1TgniZDC2V7RV+8TQ="), + Convert.FromBase64String("AviwCoIHa4MQyOCDFJiogwFJmpQLLGOcUzgT9KqdeDfK9iZT0Jf/hYC4RAlep7MAAAAAAAAAAAAAAADyiHN+ZkLhKwlCn6U+xz3GGKRBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAicBU8wICgOW3yGXXJhf7mD4FxUjphe2lbjbzM5JqpA3WHYTOOS6ugBZvxSSZqybLjxYlaaadsEJuILazCeBq9s4usyn9OieA="), + Convert.FromBase64String("AvhuCoIBd4MPQkCEA5OHAIOYloCU09wHmsb5gnW7vNCv8Ry6rbTY8qyAggABwAGgyjuKrQ9o5ovapvwvxlCH9k8Va1GLdvC0bEpvScReuQagHzi4NHJLijTbkHS1j+NnYSm0agzHUfkdAhTfoX4WRVM="), + Convert.FromBase64String("AviwCoIs+oMPQkCDGewEgwLoZ5Q6vcJLbAB8izcFqmy9wbjRw9mDxIC4RF+/uc8AAAAAAAAAAAAAAABvc8aSXTL/vv3hMqgxnN/9J+ZlYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABezXwICgxBQL+6Jj4J2qptDTXdneZoW5Hfp4FbGwPJCGENMPn0+gOS6AnoEkuTMYBMVIRt8gar5o8KarGKOg7KAwxVCdgHs="), + + Convert.FromBase64String("AvkEkQqCp6uDD0JAgxWmr4ME6eiUAAAAAHFyfeIuXp2Lrw7axvN9oDKAuQQkdl6CfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAQzcAm+Q8fsyb+94PF4BVOqBlGH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAaiqtLiDvYrW1bk4rXjQuU+5/oE8AABdxnBQAAAAAAAAAAAAAAAAAAAAA5PEAAAAAAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAjz+AAAAAAAAAAAAAAAAAAJaNwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqrJAAAAAAAAAAAAAAAAAA9CQAAAAAAAAAAAAAAAAAAVqKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5OmuXFMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHhmaLxu6nNAS02ld1x3T6/IFbZrNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqQWcuwAAAAAAAAAAAAAAALuao+JhJUpvPHUlUnbecZNGsN4QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX14QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAggAAAAAAAAA5zV6K4FJXzlHEc93RAAAAAAAAAAAAAAAAAABrkgAAAAAAAAAAAAAAAAAAAAEAAABnY+GyAAAAAAAAci5t9WolE1qJYHLf/5yRYX+r1N/ErOHV3Cvc6IKCZh10c9z352FZwB5k0ehrqyuqJFPuObxNT0pvBKUbbtzp5hwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQv9LTVieQeGEtBubGnvMZXPa6+WZVFfJQ6Okdb2yaltpsH+L5A1oVBbSnmezkGf5XV1Mbo9nfbiiFKhbIl6c/Q2uGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCAoJFo00Skrr7PAtOGO+RjeIKCuaI78pAzQafM+wolF9UZoFYVRWaPvWrl6UTVawENKxepe9TuANgQ4jR58UR3WO1J"), + Convert.FromBase64String("AvkEUQqCpzaDD0JAgxWmr4MFRXOUX/E31LD9zUncowx89X5XigJtJ4mAuQPkH62UjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAQzcBCPMO5e1UqVZfN6876FApA/UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAANFUdoKHDAUlmfw/BiddySZX3ERkAAAAAAAAAAAAAAAAAAAAAAAABk94gdw8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYrVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFnR4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWoogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD0JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIS2HSf2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGIAAAAAAAAA+4ZtqqeTUsxWigBdlgAAAGdj4bIAAAAAAAChYGw58OznDJZLi65tZrYvwpNX/yr/AKEJRABo8ud9WgrMQGnKAr9O+PDJOmSyL51ogRPq2+qSjYYPtYBFV2BTGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQ5T7hhmN1PvLUKL62VSaK5ZoFy+f9A0LtpQFnKy0sOhhIF4hKcyZ8V3EIAj6v/fCIj6Kq8VwCYwmFnFJSU/ahxsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwICgIYAj3Q48eLVrLz9U+pVs9yRY7BJER/gizxujbX/kEyWgVAaOvIWrZqhqRfVcuC5wRd5Jj5vRpgOCXuh0VvRGw5U="), + Convert.FromBase64String("AvhwCoMeODKDD0JAgxnsBIPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaDqtGJxD7OBzoyGBCAQvytIEnGi+EVwdzZlUCcSqpnb+qB5FtgUtJEcEr0Wcuc6jrNk0hi+BNvTG3mM+dMZGgZgxw=="), + Convert.FromBase64String("+MGDDCW8gwhaDoMDNl+U8a8mI5ZyvtcxGBxYqIKauQVQxU2AuFoDv7tk5xQrlZzLPI/B7XdpAEdCwZfiglECfgAAgItqAMlBhcMf+jcG0czp1SWgDxx9SikRdUwAAID/llVGLQOp3BGLIxSABY56OwUQQuyDZjeUAAAAi1B/BS43oOxOlAX65fFZCcbu7yp58kiq7zs48pqz5DHs5QiwffOXoHUYhNqxqMBKCpERvyWFJ+SeiPXyW6UCvYiBH5FyQH1t"), + Convert.FromBase64String("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"), + + Convert.FromBase64String("AvhwCoMWDG2DAYahgwwwZYPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaBL8+2GumLtef4TVqHIHmjpmYo8MN+3Q5FySA2aUOsJYaA7kfSVx3IyDc9uXLy2cDH1s8VLQv6xpQBZbJPo0xBwWQ=="), + Convert.FromBase64String("AvhuCoK+EoMBhqCEA5OHAIOYloCU09wHmsb5gnW7vNCv8Ry6rbTY8qyAggABwICgcExTmkmitkVJUwBsiYknDuhDzfM980g0sxiCplavFvegTlSr4zndPBPIaWl3HiKaEI8WAZpvGRqd+7ba4xSJUGc="), + Convert.FromBase64String("AvhxCoIBc4MBhqCDFtoEglIIlHp6NeFF16IQPEic4MwGjQaAMkAHhwqoe+5TgACAwAGgb1pkoH7WydD4A8MACWgay+0o5P4c5oMAV+as+GuS4o+gL3OhoFxrqNy2DNQdXrfqeZJdLv5Qh5+0RCrdYKtUFHU="), + Convert.FromBase64String("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"), + Convert.FromBase64String("AvhvCoMBhfWDAYaghAOThwCDmJaAlNPcB5rG+YJ1u7zQr/Ecuq202PKsgIIAAcABoGBTzkRrXFFmqBSzOH3e6gG4zDfgOOZ6OPBRU8WI+wpRoGk2bII2zBQJRgc/Cb8bunQ9X5Hd1v4Bza2V5kwd7wpO"), + + Convert.FromBase64String("AvhwCoMwUYCDAYaggwwwZIPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaCPDWWjXPjGxjetWwY4tvFsTEcEDSDV/WHi//Rh5PI7u6BPMVmJ7+dwgcXUWpCVkWPrc6DafFI/R/PrJ6eLy1iPZA=="), + Convert.FromBase64String("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") + }, + ParentBeaconBlockRoot = new("0x3c91f05470cdc6942d0b347b3258dfeb6f9cf68a24cf26cf0d72bd467003c437"), + ReceiptsRoot = new("0xbe404128db2f49d82825bccf1568f3cd876b023feb74ba637cb7a93cca3e0007"), + StateRoot = new("0xf1054086f7dec9f3badfc063d5a9932dbeac44ed1fe1e810718a754001503fae"), + Withdrawals = Array.Empty(), + LogsBloom = new(Convert.FromHexString("02402900000c040281010814014100004000010800001000300402004004032000090000282100000002c01140400480811900480001288208002a45002082c508120404420000082001000805c00200114c04030410081081086820102820094e0241000a2800000040080102104800000004000002085002c10014302a00601000000211800020000c001010014000024000200022800a044020004202100002000010400200000040600000000200080440042c04800104400200000100120408102200224448000118200800012020a0000140858004c611000c104028004070800800922004010000020203000004818000880288140000080110008020")), + PrevRandao = new("0xb4df95545f5218867dff8faf7a3c04238d746a474e2f043fd45b22b0123995d5") + }); + // OP-mainnet + yield return ("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", + new ExecutionPayloadV3() + { + BaseFeePerGas = 0x55502, + BlobGasUsed = 0, + BlockHash = new("0x4682e6ae5e83d3901ffb0094636f106386cee5fa7aa283292225bb0a9de4e83a"), + BlockNumber = 0x7b802d9, + ExcessBlobGas = 0, + ExecutionRequests = null, + ExtraData = Array.Empty(), + FeeRecipient = new("0x4200000000000000000000000000000000000011"), + GasLimit = 0x3938700, + GasUsed = 0xc5e787, + Timestamp = 0x6763df6b, + ParentHash = new("0xf1309f038d6481b76e50404d19c5adcdc293226548cb594a2e85e10b776714e9"), + Transactions = new byte[][] + { + Convert.FromBase64String("fvj4oL1rW324wN4m8eNy1xUciORi+xruPTtnk5B048UEJVdslN6t3q3erd6t3q3erd6t3q3erQABlEIAAAAAAAAAAAAAAAAAAAAAAAAVgICDD0JAgLikRApeIAAAFGsAD3nFAAAAAAAAAAEAAAAAZ2PfGwAAAAABRxRsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiww43EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkCvPkYqq5Czb2IR0tAVy4IBUgHxLU946PKqbYTUlCfxPuipAAAAAAAAAAAAAAAAaIckZmijuH9U3rO5S6R6b2PzKYU="), + Convert.FromBase64String("AviSCoMCr9mEDXPNHoQNc80egwSwb5RvH+WwSN4EF8ToOLH8QkWq8lTx3ICkskYMSAALBq153tZZ1FgAAAAAAAAAACd7Gitgk+mX4Y4Tp58AwICgzABFQH2OpZ9vFPMOKrrRfzGG8BaCWW2OQXH94vJhEYOgF8XLnSvvevnn0b4gg3BlxPXlldM+2U3Cj6r0EHgbsBs="), + Convert.FromBase64String("Avi0CoMga9qEBfXhAIULqkCXQIMCSfCUlLAIqgBXnBMHsO8sSZrZiozljliAuESpBZy7AAAAAAAAAAAAAAAAfWLJRD4FbFP2fsaPgupeukbu6ooAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfXhAMABoJrw4MJoUaWz8jkkcZLrBeQnI11G+ckvmuqPZ8K54iB8oEOnZIAVHgtN9pH5ivuM4fC8GK5Lf9KYLImQqRpQ8ESr"), + Convert.FromBase64String("AvkBMgqC4XiEAX14QIQBiCJEgwknwJSAK2W12QFmIeZgA67QsWYVCT8yi4C4xKAFl6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV+rblU6j7YAAAAAAAAAAAAAAAAAAAAAAAACfNs9HXb23wuMbEl22WXAAAAAAAAAAAAAAAAhwDa7DWvj/iMFr3wQYd0yz11mbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPJbvBimB7viGMh7of8OZz2bU91YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj4B7AgKAziQjqPHFC7J9lnGp2WeWBNy9NJWCQXTIDW0pQ4KSBpaAZYy4sd7nYcG6AFWekRWNu0C99BIb9rFNUarP0esRiEg=="), + Convert.FromBase64String("AvkBUAqCnnSDmJaAg59IqYMFe9mUNyGw4SJ2jO3fs97IEOZMNhF3+CaAuORHT9h0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJ+IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACiL0SPFSmTAAaAMQxWct66oIFFvTumRsRWuKN7XLzhQR3s/K0ygcfO6eKAptn9R5/V5bNRC+931lCv7tzDDZehXhaOZTtwpHIZuTA=="), + + Convert.FromBase64String("+KuDCMQ4gy3GwIMCGOOUQgAAAAAAAAAAAAAAAAAAAAAAAEKAuESpBZy7AAAAAAAAAAAAAAAALuz6UAwzwHWN0cDgm5SSlufjl0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD7dcy0LAicAADegAb0ltzDB4z9OhkAQmb3T3d1xzM9auhtNG2XePRiy6NigOQq+GExG/Egys+h/xj1L85aCxsuCeUgm9FkLjflVsW8="), + Convert.FromBase64String("+KuDCMQ5gy3GwIMBNDeUlLAIqgBXnBMHsO8sSZrZiozljliAuESpBZy7AAAAAAAAAAAAAAAADDM2ikzscOx2C8y2wXC9Xe2ZyQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE1FQDeg/v1VhEo1X5lq7RZs4N3nRwjBoigPGH6X4N4pWJ0vBVygIt81KE+sV+C/j6cMiTxEx4jStYl9n+H9pE2ky4dQnUM="), + Convert.FromBase64String("AvhwCoMPDP2DGXCYgyQWqIPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaBf0yttDLrInNR1t5DuenWeSiss9fhGIg98PulKHARY3KBqpfOK2PJGpIJmqqUOGEPR+uFGe511dHFNqSl5w6S5Jw=="), + Convert.FromBase64String("AvhtCoKetoMeumWDHrplg5iWgJTT3AeaxvmCdbu80K/xHLqttNjyrICCAAHAAaCnyo4TyRZ6H5a6Caz/3DiNnwXTGIKFyfIySwGnAee1i6ARSgQ/l3yFNACJeNrHGT5nbWxgv3jnfVGoNSbgjfsF3w=="), + Convert.FromBase64String("AvhuCoJot4MPzCWEA5OHAIOYloCU09wHmsb5gnW7vNCv8Ry6rbTY8qyAggABwAGg4rLDabPmqQvZ0Wfa9uHEWTbFY+Pmw6ZuCC6iJriXv8CgYcDVQhGIE+2lMU30p8kO3GWbHNx1fPZMv/3sz3DOv5w="), + + Convert.FromBase64String("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"), + Convert.FromBase64String("+QErgwEktIMUnQiDIuTwlHnjhYXct2RH/wcuvlPVZkwoL3INgLjEp+69sgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAOZ8zzmL1QWwOZszI6eqkKLhZLGTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOkllv3B7hADigZkGFXIwNlDKKQ61q8xmXxXAC5n7cigYmTlwvhQjV5zigTMc0As20qvsAG4aojUa5TdN6Ok54FLGc4f6hObDdGOo="), + Convert.FromBase64String("AvhxCoCDD0JAgxYbNYMBhqCUW9+FIW7B441kWMhwmSpp444D9++IP7uYB/c1IYCAwAGgW0FR3XjgLlQR/0Bphkq8z8wxgtFtJee43FSmDP24M0mgKKOoGbIngKRJvS3FNhff4GI3nq0BUQED40E0rZimoYo="), + Convert.FromBase64String("AvhuCoIBfoMPQkCEA5OHAIOYloCU09wHmsb5gnW7vNCv8Ry6rbTY8qyAggABwICgPu8KXHtO3azbKMd1vo4toH8ofOO4v50PL/Z5exZ3ncygWg8+w2tHmGy8Gyj8e87ZRGMVZ0H4zb3eUmaagKSUq+w="), + Convert.FromBase64String("AvixCoMEBRODD0JAg90QEoMBhqCUlLAIqgBXnBMHsO8sSZrZiozljliAuESpBZy7AAAAAAAAAAAAAAAACcn4BRwxdV9jgvwspASW/5qDcaIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkQhjlMABoCOg+caUBu2C8TNovzaweEzdx7hUS7augnFQCpE4EqNFoDW7SvMUVSvI/JnOQghjEIFZldooqXBCc9q4Najnyz7r"), + + Convert.FromBase64String("AvixCoMEBRSDD0JAg90QEoMBhqCUlLAIqgBXnBMHsO8sSZrZiozljliAuESpBZy7AAAAAAAAAAAAAAAAlfRX/++OJako0CjB1HxhKh1j7RcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHdH44MABoCwXvQXP5LGGISCVEHPGMP/0tNNAIALrOQEvc54H7gNboHdrCq/sjylKh55RuT1da0ynM21Uij+1/a2DJ8DZReUg"), + Convert.FromBase64String("AvkE2QqDAVr+gw9CQIMVp+qDBeOQlAAAAAD8BMkQoLX+ozsD4ER60LCqhwHtn7OMdv25BGSkTJznAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9/cbB4uRiaEZHXbHe9GXaANDv7YAAAAAAAAAAAAAAAAAAAAA/LCApNbDmpNU2p65vBBM1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY+G/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQy40Xckt/cLsx9ndk8QGkMAZMglstaOvcc6ytCDBsc2UVFlv72cmf8IlKX1hz7iW+QPKDk2ZpaI7twZCFW1+MocAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY+G/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIIX9/UrDKCBaxlW8kqKBvEskD7UXf+mfThFhjvLQ/EUNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPAAAAAAAAAAAAAAAAAAu95DdeZOjX9hHwFPt2ulA0FVZYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY+G/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEF/TrJWjRxb7mJl/GY1N8J/0eu1Al6g9Y1zN83ftU0FAX1gsINjplEW0SYVGZoQq6lh04VNHPh2iehQlxw63qStHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQVv9XwkTmtuFOJiEZvKpeVgf2ISmViWFPu+llfQOBbF9UC7GwknrDUanrjfA1DbRkZcdJQq9bNQqt/yfYDmnvLQbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCAoMKb0fWeC4TTP5nIiZkRF1l/yvZxBFXjS5z7UW/94aF0oHV/jc5YM31BPC+iVErlPWHH7gLhkj901mqq3OHc+5Om"), + Convert.FromBase64String("AvkDUgqDAVkFgw9CQIMVpx2DAsf+lAAAAAD8VpR8fnGD+MpLYjmMqt8LgLkC5KAF09IAAAAAAAAAAAAAAACKNnfbw6pZtVaL2sHjCTujqQHZSwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj4cIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg8wU4yGMS2YwlVPuPWybP5ae0G+wqH/H9he6HKH7oy3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK9TUAAAAAAAAAAAAAAABibC10OHUHbKJbVBSzu71fsv/w3wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj4pMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQV4sBjCwXaMhLcG/m4C2He/3hIYNnIwFYP3leuDEnkINb168DLGeK6ZXjw3J2Sp6TrdNq+vHhBAWc1tlfGcndPEcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABB7tyoZ97tuAXkpDjNC/yQ0JDgz/nZZa5EKTvNd96GSLAvJWWBTfdI3H+x3TCDlrLMzzRWc6dB7iR5jR+r54nDMhsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwICgXfxvlaTcry4mIJ5xaM5EIfCrgMkWMW6uE+Fb+ys7X3agVLPF8nE8MLT9TV+N1EB/GMh7Ak0anzAWf3n67QgMU6k="), + Convert.FromBase64String("AvkBUAqC0jmDD0JAgxnsRIMJJ8CUgCtltdkBZiHmYAOu0LFmFQk/MouAuOSVQ1rJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBSViug1FwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGbASDNd3COFBEwAAAAAAAAAAAAAAAIcA2uw1r4/4jBa98EGHdMs9dZm0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGFdAAAAAAAAAAAAAAAAHHVO1txQeHsmj/JzEi0dmEC0UpKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj4B7AAaD+BouowklB2HVS5MmJtk+r/9gd21rnH8MrNXJ1w+CeYKAc91ns6Z/OXTKcTCgCw42b5k1G2RNwxi28cBKN+nhL1Q=="), + Convert.FromBase64String("AvhwCoMeODmDD0JAgxnoUIPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaDFhCtP+fra+CZIaRNXno5VcLF4cNGJV9LOUahCr9KU6qATVziH1jyToWVE4s98W8QHAe0tbfiTNk/U2TwLvcNk3w=="), + + Convert.FromBase64String("AvkHcQqCBqSDFJb5gxSW+YMJXguU28bE5RB8xIeKolr+kizSFLtnvfqAuQcE5KmyDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGKZuvtSX3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgAAAAAAAAAAAAAAAAJw2YpO6fok84YTXV5QzDWdOTRfCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWEKgIiQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSRwtVCJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAAAAAAAAAAAAAAOrLgW32QCfzylNnNe+mg1zacNeFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxtZsy/uUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAA28bE5RB8xIeKolr+kizSFLtnvfoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj49QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2PfJAAAAAAAAAAAAAAAAAtO1L3N1/Oa0z3brcWmjnPR6qnZAAAAAAAAAAAAAAAAgPvsBollMlQFSv+Yh6QGj5LzX98AAAAAAAAAAAAAAACA++wGiWUyVAVK/5iHpAaPkvNf3wAAAAAAAAAAAAAAAJw2YpO6fok84YTXV5QzDWdOTRfCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAteYg9IAAAAAAAAAAAAAAAAAA7u7u7u7u7u7u7u7u7u7u7u7u7u4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALG1mzL+5QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyxjnFM4E/SqnXg3yvYmU9CX/4UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsimwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCBpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj3yQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQYqusHGozvfTdTOGeBKeVbO7lopwVwtFrIkPgck1wZPlZn7PXH7yg3M8MvMN55d/Fa7KUxaauH0hSGfsHvwM/WYbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGhhj2KrbGTFcKiNp9sul51QTwiXs7hn75WSY29JWkkaFRi1a7QTwOVE5MVXesd/6LGJUPC4LcWr0L+DUuQbYnLGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAgKDUXOESecpLxqVYsbvxKpP/MVu2dyMzDpskf8YPLYcTy6A9+suswst4MZFDZ06FXFWGvmOLwEZBuI/sawIbACykCA=="), + Convert.FromBase64String("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"), + Convert.FromBase64String("AvhwCoMWDHSDAYahgwwssYPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaBKYsAY08acCHWjELBB4Q1YnoqOGdsHTaJDDDZsWyHDv6ADBa7ZIpK9KoMH6ss6eCgLgKQktFK/JVuDFzQzj+of4A=="), + Convert.FromBase64String("AvkDFQolgwGGoIMW1WiDAb+1lAtO1L3N1/Oa0z3brcWmjnPR6qnZhrXmIPSAALkCpHaSuoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2Pj4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY98wAAAAAAAAAAAAAAAAC07Uvc3X85rTPdutxaaOc9HqqdkAAAAAAAAAAAAAAAA6Pma01BO4bKlFPoRgW4y862Yd3wAAAAAAAAAAAAAAADo+ZrTUE7hsqUU+hGBbjLzrZh3fAAAAAAAAAAAAAAAAnDZik7p+iTzhhNdXlDMNZ05NF8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC15iD0gAAAAAAAAAAAAAAAAADu7u7u7u7u7u7u7u7u7u7u7u7u7gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAscANBFbNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALLGOcUzgT9KqdeDfK9iZT0Jf/hQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyKbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEIGkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAgKAvPcWwWzSe/GyJDW+nBYhLZ02cRCHOH3lPuZk/prRovqAZeMig2gxAHpoD5y3KgQwbJRSt9FMqBW/XJ1GcwiXU0Q=="), + Convert.FromBase64String("AvhuCoK+GYMBhqCEA5OHAIOYloCU09wHmsb5gnW7vNCv8Ry6rbTY8qyAggABwAGgOnbIpFrU9ivskOnqHKRqx14d3Ql7iYU7W9NqY2bDCHygeVvlaZmAaHu8YiRn2P+cdq30iNiNZquFFAEMIgI6ll4="), + + Convert.FromBase64String("AvkDFQolgwGGoIMW2gSDAb+plAtO1L3N1/Oa0z3brcWmjnPR6qnZhrXmIPSAALkCpHaSuoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2Pj3QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY98tAAAAAAAAAAAAAAAAC07Uvc3X85rTPdutxaaOc9HqqdkAAAAAAAAAAAAAAAClXGl8NCDc/hyjzDzF8YJLE97uEAAAAAAAAAAAAAAAAKVcaXw0INz+HKPMPMXxgksT3u4QAAAAAAAAAAAAAAAAnDZik7p+iTzhhNdXlDMNZ05NF8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC15iD0gAAAAAAAAAAAAAAAAADu7u7u7u7u7u7u7u7u7u7u7u7u7gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAscKJ1i8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALLGOcUzgT9KqdeDfK9iZT0Jf/hQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyKbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEIGkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAaAwJUyiRPIG4es4hxoiRZNsTpC2p11bxO3D0DnAgyJ37qBt+zk6SvYJ878q+MT7YIeEIVCAGo+fZHtp5AUku8VC/A=="), + Convert.FromBase64String("AvhwCoMwUYeDAYaggwwssIPk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaBgDHLl2qhSeodPCp4j4UCIksKvRj9+Yzkzbpx+lRCpcqAIROUhJhBZYZr0PBO6ftRqJeZMYhLlgPFUGqh/nen6aw=="), + Convert.FromBase64String("AvhvCoMBhfyDAYaghAOThwCDmJaAlNPcB5rG+YJ1u7zQr/Ecuq202PKsgIIAAcABoOTxmbPBAFx+ekbXqY22KVYWpuT61VUZEUFQpZolxrDuoAnZRtd6l5reYIiSqwq1/ZWMsu9MrAbSg5dMPBpL5DCU"), + Convert.FromBase64String("AvkElwqCA5eDAYaggxbaBIMDkxiUEZXPZfg7Oldo88SW06Ba1kEsZLeGRDZMW7AAuQQkmqp4eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AAAAAAAAAAAAAAAAAAAAAAJcMLHhiZRZSSozyVpuwOf/joVycRyX466u3zxZ5ijWEiQRlw68DBnOktxzpr8qk5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABENkxbsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAzBEHJLZZabzefxCWCsCQwfAfhHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhNZXRhTWFzawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1aXBmczovL1FtYWF6bjE2OTM5Zkh0VnBXVHM1b3ZrNERLU3NSdWVNazd5d3h4M0hMa251bmcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAABrCBe/swv4xN34nPbk/S7FFxnoZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADOQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQYjRbJdZeq1Bpr6jkxgHJD5kQzYgf50Todb5lgofpvFSDiC4z8a30RN0KtBZzEszo+gWXa8jRfgHH7uGRIW3BD4cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMABoH5Br0lxhDsqJFMLn16UL5fIXCiW3Drx5ADp08U6EyaOoB8Hh+OLL9kts7Ei+RW0fic8jNdUr/IDm3IWxdE9iqUu"), + Convert.FromBase64String("AvhvCoMBo6SDAYafhAOThwCDmJaAlNPcB5rG+YJ1u7zQr/Ecuq202PKsgIIAAcABoGxM9g0uW+nuutMDimZShI1ibRbgrDSdY3k/LhuahbsLoEdEEz9WhOQg0VEv0Ba2oFMiHYWAhlROKiuEdJlSJ9pd"), + + Convert.FromBase64String("AvhwCoM1IxeDAYafgwwsr4Pk4cCUq/TarBiSVTDR5Pmf1TjVe4vxAXyAhCT4iGPAAaALs7rNaib36BudX2/W4zQyzJ8CWny8n7xi8hGafiokq6A+L1TYZDHuJ1N87121UaXmcgRuL8bI6afweH+qbBFJAw=="), + Convert.FromBase64String("AvhtCoMETzwFgwwwEYM0y+yUO3Sb5soz8n4oNxOO3mn4xsU/kgeAhP21oD7AgKD3scFSmumEN//g+zWAeHd7OdpcV7LEVGJB1a60QmqNxKByrZO493VevxxZhleny42G6t0etyGkenEzp3l/WZ+1Yg=="), + }, + ParentBeaconBlockRoot = new("0x5f064007409e7e2c51811e448c61f98cc85af44f77922f3e2717847482fa6b14"), + ReceiptsRoot = new("0x6da79badb38a47d4f94b3887e3c9ea03cac0c13a190c6ca4b0c7cc485532a6ce"), + StateRoot = new("0xadb8655e6510b2376c8631a0c6f460f8d4aa418a6502db0e09d3003622b3c80b"), + Withdrawals = Array.Empty(), + LogsBloom = new(Convert.FromHexString("5618309111040001808010800203440001800508420420040804011040c0110007291200200c068101000010810c3110215104404000261006288440403410c006002801041820aaa305140a0000000380808c000026003080400004800040403090800a222400009c114000030008299dc00402280c8a001981203a080c0888102014314810041058a00e004008004021c0d8210030020000020c0c1a8000308a80000020b0020000008442005002a0203001010140030840822300800001a68200128308008301282808264042408101880200a684070c2098022000226084011c980900244042283040828031112070008000508009c80602400000cf1890")), + PrevRandao = new("0xae6223389278dd4d32efdfff1141888a75202098042137afa5f7d294796ded20") + }); + // OP-sepolia + yield return ("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eV0C1C4IRAfZhkIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFnNwJhPWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABa3FO2IXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABdVrMV3IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCnQaRieAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/W2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1tgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/W2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/WyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1sgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/WuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/W4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1ugAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/W6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY+Y4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA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", + new ExecutionPayloadV3() + { + BaseFeePerGas = 0x108, + BlobGasUsed = 0, + BlockHash = new("0x7f007a35cd262d8d99a36f69d7bb6e8315682c2a810642bb93def01f64314be2"), + BlockNumber = 0x1468d1e, + ExcessBlobGas = 0, + ExecutionRequests = null, + ExtraData = Convert.FromHexString("00000000fa00000006"), + FeeRecipient = new("0x4200000000000000000000000000000000000011"), + GasLimit = 0x3938700, + GasUsed = 0x548e02, + Timestamp = 0x6763f5e8, + ParentHash = new("0x493b5117ac4457d004d9f9e0139c5f844c9894df333da27055e425944ea44ef5"), + Transactions = new byte[][] + { + Convert.FromBase64String("fvj4oF0kYcUcgt9O8FOt/4uOAUehrTbLN8bX0IZFQl89D/xwlN6t3q3erd6t3q3erd6t3q3erQABlEIAAAAAAAAAAAAAAAAAAAAAAAAVgICDD0JAgLikRApeIAAAHbAADScwAAAAAAAAAAIAAAAAZ2P1nAAAAAAAb40gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCzq4zgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATxhfVJGN8sbuHdGU7mM8oTuguoDD4M3EWioaqPwAg7rAAAAAAAAAAAAAAAAjyO7OPUxYA5dj92q7EHxP6tG6Yw="), + Convert.FromBase64String("AvkBXoOqN9yBqoUBKgXyAIUBKgXzCIMCH5iU8iF1DlKqCAg10pV/Lu0NXX3djDiIAWNFeF2KAAC45FZZHVlhcmJ0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4QVEm4GFtmKGG0LQaa+vKHPHshYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0JB3+8S3QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAMABoK8h/J8K2YG9YB+kX0+Jcd+qZ99bDf497E8Gkw6xllxHoDMDXjTBeVcJHkI2GFeRq4gCvBwSuIXJnHirsY/89A5p"), + Convert.FromBase64String("AvkBXYOqN9yCDqWEBfXhAIQF9eEAgwFcPJTyIXUOUqoICDXSlX8u7Q1dfd2MOIgBY0V4XYoAALjkVlkdWWFyYnQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlv7ZmpvjiPo7V5zshrXhkDq5hIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFi8xv9moEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAwAGg3jLNP0NvINuM0OFdoszCV3CVAM7xSacqT8Bh+bq1Baqgdh+RIWr9345C38P6R29zGhrt244m1WWyNmY8ivHqcIw="), + Convert.FromBase64String("+QNQgywWRIMPalqDGIRqlIxEDBXXZzxm5aboGZ/taec6X7mrgLkC5Buv3hkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnbs8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ27PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwzYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiFloAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAADMl9UANrAl9lCh8WwudywGe6vFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmVEhAFUb9ygKvyRpXhJLbus2PWpuoAlZj1oa3TFRdKFKRQa82peg1egAsQeEw/NvZvZLG/Gr6064m+KAMudP5hmHdqL5fegY/U="), + Convert.FromBase64String("+QNQgyxaF4MPalqDGD1hlIxEDBXXZzxm5aboGZ/taec6X7mrgLkC5Buv3hkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnbs8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ27PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADuaygAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8logAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKwHd+YmzUC67+P1b2AO8GSTO3+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmVuhAFUb9ygVL39xluN65xlSyBa+lpG19k0VIyXu/9VeaFMyJGdrZCgcN61uYmJwZThLm7cH8HiTnROLeY0OGcI/ako9jZT4W4="), + + Convert.FromBase64String("AvkBWYOqN9wCgw9CQIMPRFCDAVxzlPIhdQ5SqggINdKVfy7tDV193Yw4iAFjRXhdigAAuORWWR1ZYXJidAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJjVcfEI3LpAiX1IuNGiW9RBtczPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWK/p8gxY20AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAADAAaAkQTC5X2jZDEqbIJp/2GniTPJ5boyb493XPM2QtyeG66A4MaVdVwaoiq6uNZ4wjTvCdDtBRZISysj1Zne0yQbW6A=="), + Convert.FromBase64String("Aviwg6o33EWDAYaggwGKwILVvZS5RnskEX/XnVbzlq3DzNtpXZBa5IC4RAlep7MAAAAAAAAAAAAAAAAyZ+ctyHgKFRL6adp3Wexm8wNQ4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/7sOwAGgfv5W0wrWDY5yhV0BfQiVZBjyHUuNGGMLRmMKQLn8572gMWrsbb5QedSu4qB4tkhAEOl5yQp/wBrrtFKXcp+nBQA="), + Convert.FromBase64String("Avjxg6o33CaDAYaggwGKwIMClBKUMmfnLch4ChUS+mnad1nsZvMDUOOAuIRi5MVFAAAAAAAAAAAAAAAARkyOwQDy9C+05C4H4gPaIyT5/GcAAAAAAAAAAAAAAABRgvO5y1ING6Ql+bye7Dzo+WJeYwAAAAAAAAAAAAAAAKBkv7XH6BQmZH3CCg2FTaFThVncAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACo/ENMDMq3AAaCYmXnSzSGpswxuUHRoPLf9f2Ixr0G/E3uTcvwPSnrvzKBOrC9VVBX1yNFkBQKD7uJaPhaT5feQM/bO2QiNEs3W/w=="), + Convert.FromBase64String("AvjRg6o33A2DAYaggwGKwIMChJqUMmfnLch4ChUS+mnad1nsZvMDUOOAuGSDQPVJAAAAAAAAAAAAAAAAuUZ7JBF/151W85atw8zbaV2QWuQAAAAAAAAAAAAAAABDBpnFTlj+iqVezYICqddiOu4iPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMi2cwAGgDyskqgGuelCKv8AHeqN3EitY4gzHN/zjhCCKN3FJ7hWgWgxeVJlyJeKg/sD61gyW7KN7id5RZ4dsk9fY5C8nBok="), + Convert.FromBase64String("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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZzcCYT1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWtxTtiFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXVazFdyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQp0GkYngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABY0V4XYoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWNFeF2KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFjRXhdigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1tgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/W2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1tgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/W0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1sgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnY/WyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2P1rgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdj9bgAAAAAAAAAAAAA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") + }, + ParentBeaconBlockRoot = new("0x859272c18aad3de6dd556680419591b9d8acf242c16ac51fbcabefc16a17ba68"), + ReceiptsRoot = new("0xaa27e8eab6d7398581b73eaf6f29a79e08b3b6c75b7c90a3f195b6e8e5304c88"), + StateRoot = new("0x808e89b7a69cad0cf59f156af6e65ded0d6ca8571782f3d4b94da6b3564ed273"), + Withdrawals = Array.Empty(), + LogsBloom = new(Convert.FromHexString("54000001110180400008008614000042000408010000802440000400a0800260200022220400000000400028100008000020120400022000080004000aa4a00201060041200000800080a00a40004900008020040004a040240885a004000000090001010300008000000000000408020400002101010040000040100105000081aa10408204012400082085008000010442020001106910c0108008000800000228000000044040400043210000004080a108000420028410000040000000404000000208044842084005200020001001002002004148000200048d048960014210410808030120010200000001300050081000048000040020430800000000")), + PrevRandao = new("0xd0e7fd5c4bd98eabb96356f50d855d3c39377d256589cf276541b84a30e3a9ea") + }); + } +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/CLConfig.cs b/src/Nethermind/Nethermind.Optimism/CL/CLConfig.cs new file mode 100644 index 00000000000..0ccafb965b7 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/CLConfig.cs @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; + +namespace Nethermind.Optimism.CL; + +public class CLConfig : ICLConfig +{ + public bool Enabled { get; set; } = false; + public string P2PHost { get; set; } = "127.0.0.1"; + public int P2PPort { get; set; } = 3030; + public string? L1BeaconApiEndpoint { get; set; } + public string? L1EthApiEndpoint { get; set; } +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/ICLChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Optimism/CL/ICLChainSpecEngineParameters.cs new file mode 100644 index 00000000000..b96be6b126f --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/ICLChainSpecEngineParameters.cs @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Specs.ChainSpecStyle; + +namespace Nethermind.Optimism.CL; + +public class CLChainSpecEngineParameters : IChainSpecEngineParameters +{ + public Address? BatcherInboxAddress { get; set; } + public Address? BatcherAddress { get; set; } + public Address? SequencerP2PAddress { get; set; } + public string[]? Nodes { get; set; } + public string? EngineName => "OptimismCL"; + public string? SealEngineType => null; +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/ICLConfig.cs b/src/Nethermind/Nethermind.Optimism/CL/ICLConfig.cs new file mode 100644 index 00000000000..b1c67504bcc --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/ICLConfig.cs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Config; +using Nethermind.Core; + +namespace Nethermind.Optimism.CL; + +public interface ICLConfig : IConfig +{ + [ConfigItem(Description = "Use enshrined op cl.", DefaultValue = "false")] + bool Enabled { get; set; } + [ConfigItem(Description = "CL p2p communication host", DefaultValue = "127.0.0.1")] + public string P2PHost { get; set; } + [ConfigItem(Description = "CL p2p communication host", DefaultValue = "3030")] + public int P2PPort { get; set; } + [ConfigItem(Description = "URL to L1 beacon node", DefaultValue = "null")] + string? L1BeaconApiEndpoint { get; set; } + [ConfigItem(Description = "URL to L1 execution node.", DefaultValue = "null")] + string? L1EthApiEndpoint { get; set; } +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs b/src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs new file mode 100644 index 00000000000..11e12241d6f --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Threading; +using Nethermind.Core; +using Nethermind.Core.Specs; +using Nethermind.Crypto; +using Nethermind.Logging; +using Nethermind.Optimism.Rpc; +using Nethermind.Serialization.Json; + +namespace Nethermind.Optimism.CL; + +public class OptimismCL : IDisposable +{ + private readonly ILogger _logger; + private readonly OptimismCLP2P _p2p; + private readonly IOptimismEngineRpcModule _engineRpcModule; + private readonly CLChainSpecEngineParameters _chainSpecEngineParameters; + + public OptimismCL(ISpecProvider specProvider, CLChainSpecEngineParameters engineParameters, ICLConfig config, IJsonSerializer jsonSerializer, + IEthereumEcdsa ecdsa, ITimestamper timestamper, ILogManager logManager, IOptimismEngineRpcModule engineRpcModule) + { + ArgumentNullException.ThrowIfNull(engineParameters.SequencerP2PAddress); + ArgumentNullException.ThrowIfNull(engineParameters.Nodes); + + _engineRpcModule = engineRpcModule; + _logger = logManager.GetClassLogger(); + _chainSpecEngineParameters = engineParameters; + + _p2p = new OptimismCLP2P(specProvider.ChainId, engineParameters.Nodes, config, _chainSpecEngineParameters.SequencerP2PAddress, timestamper, logManager, engineRpcModule); + } + + public void Start() + { + _p2p.Start(); + } + + public void Dispose() + { + _p2p.Dispose(); + } +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/P2P/IP2PBlockValidator.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/IP2PBlockValidator.cs new file mode 100644 index 00000000000..86e5a42b4cb --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/P2P/IP2PBlockValidator.cs @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Merge.Plugin.Data; + +namespace Nethermind.Optimism.CL; + +// Validates p2p "blocks" messages +public interface IP2PBlockValidator +{ + ValidityStatus Validate(ExecutionPayloadV3 payload, P2PTopic topic); + ValidityStatus ValidateSignature(ReadOnlySpan payloadData, Span signature); + ValidityStatus IsBlockNumberPerHeightLimitReached(ExecutionPayloadV3 payload); +} + +public enum ValidityStatus +{ + Valid, + Reject +} + +public enum P2PTopic +{ + BlocksV1, + BlocksV2, + BlocksV3 +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/P2P/IPayloadDecoder.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/IPayloadDecoder.cs new file mode 100644 index 00000000000..b9095164e9c --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/P2P/IPayloadDecoder.cs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Merge.Plugin.Data; + +namespace Nethermind.Optimism.CL; + +public interface IPayloadDecoder +{ + ExecutionPayloadV3 DecodePayload(ReadOnlySpan data); + byte[] EncodePayload(ExecutionPayloadV3 payload); +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs new file mode 100644 index 00000000000..f47e190dad6 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs @@ -0,0 +1,268 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Libp2p.Core; +using Nethermind.Libp2p.Core.Discovery; +using Nethermind.Libp2p.Protocols.Pubsub; +using Nethermind.Libp2p.Stack; +using Nethermind.Libp2p.Protocols; +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Multiformats.Address; +using Nethermind.Core; +using Nethermind.Core.Collections; +using Nethermind.Libp2p.Protocols.Pubsub.Dto; +using Nethermind.Logging; +using ILogger = Nethermind.Logging.ILogger; +using Nethermind.Merge.Plugin.Data; +using Nethermind.Optimism.CL; +using Nethermind.Optimism.Rpc; +using Nethermind.Core.Crypto; +using Nethermind.JsonRpc; +using Snappier; + +namespace Nethermind.Optimism; + +public class OptimismCLP2P : IDisposable +{ + private readonly ServiceProvider _serviceProvider; + private PubsubRouter? _router; + private readonly CancellationTokenSource _cancellationTokenSource = new(); + private readonly ILogger _logger; + private readonly IOptimismEngineRpcModule _engineRpcModule; + private readonly IP2PBlockValidator _blockValidator; + private readonly Multiaddress[] _staticPeerList; + private readonly ICLConfig _config; + private ILocalPeer? _localPeer; + private readonly Task _mainLoopTask; + + private readonly string _blocksV2TopicId; + + private ITopic? _blocksV2Topic; + + private const int MaxGossipSize = 10485760; + + public OptimismCLP2P(ulong chainId, string[] staticPeerList, ICLConfig config, Address sequencerP2PAddress, ITimestamper timestamper, ILogManager logManager, IOptimismEngineRpcModule engineRpcModule) + { + _logger = logManager.GetClassLogger(); + _config = config; + _staticPeerList = staticPeerList.Select(addr => Multiaddress.Decode(addr)).ToArray(); + _engineRpcModule = engineRpcModule; + _blockValidator = new P2PBlockValidator(chainId, sequencerP2PAddress, timestamper, _logger); + + _blocksV2TopicId = $"/optimism/{chainId}/2/blocks"; + + _serviceProvider = new ServiceCollection() + .AddSingleton() + .AddLibp2p(builder => builder) + .AddSingleton(new IdentifyProtocolSettings + { + ProtocolVersion = "", + AgentVersion = "optimism" + }) + .AddSingleton(new Settings()) + .BuildServiceProvider(); + + _mainLoopTask = new(async () => + { + await MainLoop(); + }); + } + + private ulong _headPayloadNumber; + private readonly Channel _blocksP2PMessageChannel = Channel.CreateBounded(10); // for safety add capacity + + private async void OnMessage(byte[] msg) + { + try + { + if (TryValidateAndDecodePayload(msg, out var payload)) + { + if (_logger.IsTrace) _logger.Trace($"Received payload prom p2p: {payload}"); + await _blocksP2PMessageChannel.Writer.WriteAsync(payload, _cancellationTokenSource.Token); + } + } + catch (Exception e) + { + if (e is not OperationCanceledException && _logger.IsError) _logger.Error("Unhandled exception in Optimism CL P2P:", e); + } + } + + private async Task MainLoop() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + ExecutionPayloadV3 payload = + await _blocksP2PMessageChannel.Reader.ReadAsync(_cancellationTokenSource.Token); + + if (_headPayloadNumber >= (ulong)payload.BlockNumber) + { + // Old payload. skip + return; + } + + if (_blockValidator.IsBlockNumberPerHeightLimitReached(payload) is not ValidityStatus.Valid) + { + return; + } + + if (await SendNewPayloadToEL(payload) && await SendForkChoiceUpdatedToEL(payload.BlockHash)) + { + _headPayloadNumber = (ulong)payload.BlockNumber; + } + } + catch (Exception e) + { + if (_logger.IsError && e is not OperationCanceledException and not ChannelClosedException) + _logger.Error("Unhandled exception in Optimism CL P2P:", e); + } + } + } + + private bool TryValidateAndDecodePayload(byte[] msg, [MaybeNullWhen(false)] out ExecutionPayloadV3 payload) + { + int length = Snappy.GetUncompressedLength(msg); + if (length is < 65 or > MaxGossipSize) + { + payload = null; + return false; + } + + using ArrayPoolList decompressed = new(length, length); + Snappy.Decompress(msg, decompressed.AsSpan()); + + Span signature = decompressed.AsSpan()[..65]; + ReadOnlySpan payloadData = decompressed.AsSpan()[65..]; + + if (_blockValidator.ValidateSignature(payloadData, signature) != ValidityStatus.Valid) + { + payload = null; + return false; + } + + try + { + payload = PayloadDecoder.Instance.DecodePayload(payloadData); + } + catch (ArgumentException e) + { + if (_logger.IsTrace) _logger.Trace($"Unable to decode payload from p2p. {e.Message}"); + + payload = null; + return false; + } + + ValidityStatus validationResult = _blockValidator.Validate(payload, P2PTopic.BlocksV3); + + if (validationResult == ValidityStatus.Reject) + { + payload = null; + return false; + } + return true; + } + + private async Task SendNewPayloadToEL(ExecutionPayloadV3 executionPayload) + { + _cancellationTokenSource.Token.ThrowIfCancellationRequested(); + ResultWrapper npResult = await _engineRpcModule.engine_newPayloadV3(executionPayload, Array.Empty(), + executionPayload.ParentBeaconBlockRoot); + + _cancellationTokenSource.Token.ThrowIfCancellationRequested(); + + if (npResult.Result.ResultType == ResultType.Failure) + { + if (_logger.IsError) + { + _logger.Error($"NewPayload request error: {npResult.Result.Error}"); + } + return false; + } + + if (npResult.Data.Status == PayloadStatus.Invalid) + { + if (_logger.IsTrace) _logger.Trace($"Got invalid payload from p2p"); + return false; + } + + return true; + } + + private async Task SendForkChoiceUpdatedToEL(Hash256 headBlockHash) + { + _cancellationTokenSource.Token.ThrowIfCancellationRequested(); + ResultWrapper fcuResult = await _engineRpcModule.engine_forkchoiceUpdatedV3( + new ForkchoiceStateV1(headBlockHash, headBlockHash, headBlockHash), + null); + + _cancellationTokenSource.Token.ThrowIfCancellationRequested(); + + if (fcuResult.Result.ResultType == ResultType.Failure) + { + if (_logger.IsError) + { + _logger.Error($"ForkChoiceUpdated request error: {fcuResult.Result.Error}"); + } + return false; + } + + if (fcuResult.Data.PayloadStatus.Status == PayloadStatus.Invalid) + { + if (_logger.IsTrace) _logger.Trace($"Got invalid payload from p2p"); + return false; + } + + return true; + } + + public void Start() + { + if (_logger.IsInfo) _logger.Info("Starting Optimism CL P2P"); + + IPeerFactory peerFactory = _serviceProvider.GetService()!; + _localPeer = peerFactory.Create(new Identity(), $"/ip4/{_config.P2PHost}/tcp/{_config.P2PPort}"); + + _router = _serviceProvider.GetService()!; + + _blocksV2Topic = _router.GetTopic(_blocksV2TopicId); + _blocksV2Topic.OnMessage += OnMessage; + + _ = _router.RunAsync(_localPeer, new Settings + { + DefaultSignaturePolicy = Settings.SignaturePolicy.StrictNoSign, + GetMessageId = CalculateMessageId + }, token: _cancellationTokenSource.Token); + + PeerStore peerStore = _serviceProvider.GetService()!; + peerStore.Discover(_staticPeerList); + + _mainLoopTask.Start(); + + if (_logger.IsInfo) _logger.Info($"Started P2P: {_localPeer.Address}"); + } + + private MessageId CalculateMessageId(Message message) + { + var sha256 = IncrementalHash.CreateHash(HashAlgorithmName.SHA256); + sha256.AppendData(BitConverter.GetBytes((ulong)message.Topic.Length)); + sha256.AppendData(Encoding.ASCII.GetBytes(message.Topic)); + sha256.AppendData(message.Data.Span); + return new MessageId(sha256.GetHashAndReset()); + } + + public void Dispose() + { + _blocksV2Topic?.Unsubscribe(); + _cancellationTokenSource.Cancel(); + _blocksP2PMessageChannel.Writer.Complete(); + } +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/P2P/P2PBlockValidator.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/P2PBlockValidator.cs new file mode 100644 index 00000000000..574af324d4f --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/P2P/P2PBlockValidator.cs @@ -0,0 +1,164 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Crypto; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.Merge.Plugin.Data; +using NonBlocking; + +namespace Nethermind.Optimism.CL; + +public class P2PBlockValidator : IP2PBlockValidator +{ + private readonly ILogger _logger; + private readonly ITimestamper _timestamper; + private readonly Dictionary _numberOfBlocksSeen = new(); + private readonly Address _sequencerP2PAddress; + private readonly byte[] _chainId; + + + public P2PBlockValidator(UInt256 chainId, Address sequencerP2PAddress, ITimestamper timestamper, ILogger logger) + { + _logger = logger; + _timestamper = timestamper; + _sequencerP2PAddress = sequencerP2PAddress; + _chainId = chainId.ToBigEndian(); + } + + public ValidityStatus Validate(ExecutionPayloadV3 payload, P2PTopic topic) + { + if (!IsTopicValid(topic) || !IsTimestampValid(payload) || !IsBlockHashValid(payload) || + !IsBlobGasUsedValid(payload, topic) || !IsExcessBlobGasValid(payload, topic) || + !IsParentBeaconBlockRootValid(payload, topic)) + { + return ValidityStatus.Reject; + } + + return ValidityStatus.Valid; + } + + // This method is not thread safe + public ValidityStatus IsBlockNumberPerHeightLimitReached(ExecutionPayloadV3 payload) + { + // [REJECT] if more than 5 different blocks have been seen with the same block height + _numberOfBlocksSeen.TryGetValue(payload.BlockNumber, out var currentCount); + _numberOfBlocksSeen[payload.BlockNumber] = currentCount + 1; + return currentCount > 5 ? ValidityStatus.Reject : ValidityStatus.Valid; + } + + public ValidityStatus ValidateSignature(ReadOnlySpan payloadData, Span signature) + { + return IsSignatureValid(payloadData, signature) ? ValidityStatus.Valid : ValidityStatus.Reject; + } + + private bool IsTopicValid(P2PTopic topic) + { + // Reject everything except V3 for now + // We assume later that we receive only V3 messages + if (topic != P2PTopic.BlocksV3) + { + if (_logger.IsError) _logger.Error($"Invalid topic: {topic}"); + return false; + } + + return true; + } + + private bool IsTimestampValid(ExecutionPayloadV3 payload) + { + // [REJECT] if the payload.timestamp is older than 60 seconds in the past (graceful boundary for worst-case propagation and clock skew) + // [REJECT] if the payload.timestamp is more than 5 seconds into the future + ulong timestamp = _timestamper.UnixTime.Seconds; + if (payload.Timestamp < timestamp - 60 || timestamp + 5 < payload.Timestamp) + { + if (_logger.IsError) _logger.Error($"Invalid Timestamp: now {timestamp}, payload: {payload.Timestamp}"); + return false; + } + + return true; + } + + private bool IsBlockHashValid(ExecutionPayloadV3 payload) + { + // [REJECT] if the block_hash in the payload is not valid + payload.TryGetBlock(out Block? block); + if (block is null) + { + if (_logger.IsError) _logger.Error($"Error creating block"); + return false; + } + + Hash256 calculatedHash = block.Header.CalculateHash(); + if (payload.BlockHash != calculatedHash) + { + if (_logger.IsError) _logger.Error($"Invalid block hash: expected {payload.BlockHash}, got: {calculatedHash}"); + return false; + } + + return true; + } + + private bool IsBlobGasUsedValid(ExecutionPayloadV3 payload, P2PTopic topic) + { + // [REJECT] if the block is on a topic >= V3 and has a blob gas-used value that is not zero + if (payload.BlobGasUsed != 0) + { + if (_logger.IsError) _logger.Error($"Invalid BlobGasUsed: {payload.BlobGasUsed}"); + return false; + } + + return true; + } + + private bool IsExcessBlobGasValid(ExecutionPayloadV3 payload, P2PTopic topic) + { + // [REJECT] if the block is on a topic >= V3 and has an excess blob gas value that is not zero + if (payload.ExcessBlobGas != 0) + { + if (_logger.IsError) _logger.Error($"Invalid ExcessBlobGas {payload.ExcessBlobGas}"); + return false; + } + + return true; + } + + private bool IsParentBeaconBlockRootValid(ExecutionPayloadV3 payload, P2PTopic topic) + { + // [REJECT] if the block is on a topic >= V3 and the parent beacon block root is nil + if (payload.ParentBeaconBlockRoot is null) + { + if (_logger.IsError) _logger.Error($"Invalid BeaconBlockRoot"); + return false; + } + + return true; + } + + private bool IsSignatureValid(ReadOnlySpan payloadData, Span signature) + { + if (signature[64] > 3) return false; + // domain(all zeros) + chain id + payload hash + Span sequencerSignedData = stackalloc byte[32 + 32 + 32]; + + _chainId.CopyTo(sequencerSignedData.Slice(32, 32)); + KeccakHash.ComputeHashBytes(payloadData).CopyTo(sequencerSignedData.Slice(64, 32)); + byte[] signedHash = KeccakHash.ComputeHashBytes(sequencerSignedData); + + Span publicKey = stackalloc byte[65]; + bool success = SpanSecP256k1.RecoverKeyFromCompact( + publicKey, + signedHash, + signature.Slice(0, 64), + signature[64], + false); + + Address? address = success ? PublicKey.ComputeAddress(publicKey.Slice(1, 64)) : null; + + return address == _sequencerP2PAddress; + } +} diff --git a/src/Nethermind/Nethermind.Optimism/CL/P2P/PayloadDecoder.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/PayloadDecoder.cs new file mode 100644 index 00000000000..2ac55d2463b --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/CL/P2P/PayloadDecoder.cs @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Buffers.Binary; +using Nethermind.Core; +using Nethermind.Core.Extensions; +using Nethermind.Merge.Plugin.Data; + +namespace Nethermind.Optimism.CL; + +public class PayloadDecoder : IPayloadDecoder +{ + public static readonly PayloadDecoder Instance = new(); + + private const int PrefixDataSize = 560; + + private PayloadDecoder() + { + } + + public ExecutionPayloadV3 DecodePayload(ReadOnlySpan data) + { + ExecutionPayloadV3 payload = new(); + + if (PrefixDataSize >= data.Length) + { + throw new ArgumentException("Invalid payload data size"); + } + + ReadOnlySpan movingData = data; + payload.ParentBeaconBlockRoot = new(movingData.TakeAndMove(32)); + payload.ParentHash = new(movingData.TakeAndMove(32)); + payload.FeeRecipient = new(movingData.TakeAndMove(20)); + payload.StateRoot = new(movingData.TakeAndMove(32)); + payload.ReceiptsRoot = new(movingData.TakeAndMove(32)); + payload.LogsBloom = new(movingData.TakeAndMove(256)); + payload.PrevRandao = new(movingData.TakeAndMove(32)); + payload.BlockNumber = (long)BinaryPrimitives.ReadUInt64LittleEndian(movingData.TakeAndMove(8)); + payload.GasLimit = (long)BinaryPrimitives.ReadUInt64LittleEndian(movingData.TakeAndMove(8)); + payload.GasUsed = (long)BinaryPrimitives.ReadUInt64LittleEndian(movingData.TakeAndMove(8)); + payload.Timestamp = BinaryPrimitives.ReadUInt64LittleEndian(movingData.TakeAndMove(8)); + UInt32 extraDataOffset = 32 + BinaryPrimitives.ReadUInt32LittleEndian(movingData.TakeAndMove(4)); + payload.BaseFeePerGas = new(movingData.TakeAndMove(32)); + payload.BlockHash = new(movingData.TakeAndMove(32)); + UInt32 transactionsOffset = 32 + BinaryPrimitives.ReadUInt32LittleEndian(movingData.TakeAndMove(4)); + UInt32 withdrawalsOffset = 32 + BinaryPrimitives.ReadUInt32LittleEndian(movingData.TakeAndMove(4)); + payload.BlobGasUsed = BinaryPrimitives.ReadUInt64LittleEndian(movingData.TakeAndMove(8)); + payload.ExcessBlobGas = BinaryPrimitives.ReadUInt64LittleEndian(movingData.TakeAndMove(8)); + + if (withdrawalsOffset > data.Length || transactionsOffset >= withdrawalsOffset || extraDataOffset > transactionsOffset || withdrawalsOffset != data.Length) + { + throw new ArgumentException($"Invalid offsets. Data length: {data.Length}, extraData: {extraDataOffset}, transactions: {transactionsOffset}, withdrawals: {withdrawalsOffset}"); + } + + payload.ExtraData = data[(int)extraDataOffset..(int)transactionsOffset].ToArray(); + payload.Transactions = DecodeTransactions(data[(int)transactionsOffset..(int)withdrawalsOffset]); + payload.Withdrawals = []; + + return payload; + } + + byte[][] DecodeTransactions(ReadOnlySpan data) + { + if (4 > data.Length) throw new ArgumentException("Invalid transaction data"); + UInt32 firstTxOffset = BinaryPrimitives.ReadUInt32LittleEndian(data[..4]); + UInt32 txCount = firstTxOffset / 4; + byte[][] txs = new byte[txCount][]; + int previous = (int)firstTxOffset; + for (int i = 0; i < txCount; i++) + { + int next; + if (i + 1 < txCount) + { + if (i * 4 + 8 > data.Length) throw new ArgumentException("Invalid transaction data"); + next = (int)BinaryPrimitives.ReadUInt32LittleEndian(data[(i * 4 + 4)..(i * 4 + 8)]); + } + else + { + next = data.Length; + } + if (previous >= next || next > data.Length) throw new ArgumentException("Invalid transaction offset"); + txs[i] = data[previous..next].ToArray(); + previous = next; + } + + return txs; + } + + public byte[] EncodePayload(ExecutionPayloadV3 payload) => throw new NotImplementedException(); +} diff --git a/src/Nethermind/Nethermind.Optimism/Nethermind.Optimism.csproj b/src/Nethermind/Nethermind.Optimism/Nethermind.Optimism.csproj index 939e7284adb..261f414a45a 100644 --- a/src/Nethermind/Nethermind.Optimism/Nethermind.Optimism.csproj +++ b/src/Nethermind/Nethermind.Optimism/Nethermind.Optimism.csproj @@ -5,6 +5,12 @@ true + + + + + + @@ -13,6 +19,7 @@ + diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index 91956235e67..b0a87e678b6 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Autofac; using Nethermind.Api; @@ -27,6 +28,8 @@ using Nethermind.Facade.Eth.RpcTransaction; using Nethermind.Merge.Plugin.Synchronization; using Nethermind.HealthChecks; +using Nethermind.Init.Steps; +using Nethermind.Optimism.CL; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Serialization.Rlp; @@ -55,6 +58,8 @@ public class OptimismPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitial private IBeaconPivot? _beaconPivot; private BeaconSync? _beaconSync; + private OptimismCL? _cl; + public bool ShouldRunSteps(INethermindApi api) => api.ChainSpec.SealEngineType == SealEngineType; #region IConsensusPlugin @@ -279,6 +284,18 @@ public async Task InitRpcModules() _api.RpcModuleProvider.RegisterSingle(opEngine); + StepDependencyException.ThrowIfNull(_api.EthereumEcdsa); + + ICLConfig clConfig = _api.Config(); + if (clConfig.Enabled) + { + CLChainSpecEngineParameters chainSpecEngineParameters = _api.ChainSpec.EngineChainSpecParametersProvider + .GetChainSpecParameters(); + _cl = new OptimismCL(_api.SpecProvider, chainSpecEngineParameters, clConfig, _api.EthereumJsonSerializer, + _api.EthereumEcdsa, _api.Timestamper, _api!.LogManager, opEngine); + _cl.Start(); + } + if (_logger.IsInfo) _logger.Info("Optimism Engine Module has been enabled"); } From abd10ffdf2751b386bf99c718505fcab003a0ecc Mon Sep 17 00:00:00 2001 From: ak88 Date: Thu, 2 Jan 2025 16:38:11 +0100 Subject: [PATCH 064/113] New sys address for eip 2935 (#7982) --- src/Nethermind/Nethermind.Core/Eip2935Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Eip2935Constants.cs b/src/Nethermind/Nethermind.Core/Eip2935Constants.cs index 7758e288687..d894e6228d4 100644 --- a/src/Nethermind/Nethermind.Core/Eip2935Constants.cs +++ b/src/Nethermind/Nethermind.Core/Eip2935Constants.cs @@ -11,7 +11,7 @@ public static class Eip2935Constants /// /// The HISTORY_STORAGE_ADDRESS parameter. /// - public static readonly Address BlockHashHistoryAddress = new("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e"); + public static readonly Address BlockHashHistoryAddress = new("0x0f792be4b0c0cb4dae440ef133e90c0ecd48cccc"); /// /// The HISTORY_SERVE_WINDOW parameter. From 0d824976ac198fb05a9b41c6405c91d728240a2c Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Thu, 2 Jan 2025 17:22:19 +0000 Subject: [PATCH 065/113] Use system processor for SkipValidation txs (#7995) --- .../TransactionProcessing/TransactionProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 9638f58ff7f..103efd7e0cf 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -122,7 +122,7 @@ public TransactionResult Warmup(Transaction transaction, in BlockExecutionContex private TransactionResult ExecuteCore(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { - if (tx.IsSystem()) + if (tx.IsSystem() || opts == ExecutionOptions.SkipValidation) { _systemTransactionProcessor ??= new SystemTransactionProcessor(SpecProvider, WorldState, VirtualMachine, _codeInfoRepository, _logManager); return _systemTransactionProcessor.Execute(tx, blCtx.Header, tracer, opts); From 0cfedec0ca385be3074c534bc27de2b9ad2b7c78 Mon Sep 17 00:00:00 2001 From: ak88 Date: Thu, 2 Jan 2025 20:57:22 +0100 Subject: [PATCH 066/113] Updated addresses for devnet 5 (#7994) --- src/Nethermind/Nethermind.Core/Eip7002Constants.cs | 2 +- src/Nethermind/Nethermind.Core/Eip7251Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Core/Eip7002Constants.cs b/src/Nethermind/Nethermind.Core/Eip7002Constants.cs index fd826e87683..ea4bee6597a 100644 --- a/src/Nethermind/Nethermind.Core/Eip7002Constants.cs +++ b/src/Nethermind/Nethermind.Core/Eip7002Constants.cs @@ -5,5 +5,5 @@ namespace Nethermind.Core; public static class Eip7002Constants { - public static readonly Address WithdrawalRequestPredeployAddress = new("0x09Fc772D0857550724b07B850a4323f39112aAaA"); + public static readonly Address WithdrawalRequestPredeployAddress = new("0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA"); } diff --git a/src/Nethermind/Nethermind.Core/Eip7251Constants.cs b/src/Nethermind/Nethermind.Core/Eip7251Constants.cs index 7ae7e5eece1..01f0095c341 100644 --- a/src/Nethermind/Nethermind.Core/Eip7251Constants.cs +++ b/src/Nethermind/Nethermind.Core/Eip7251Constants.cs @@ -5,5 +5,5 @@ namespace Nethermind.Core; public static class Eip7251Constants { - public static readonly Address ConsolidationRequestPredeployAddress = new("0x01aBEa29659e5e97C95107F20bb753cD3e09bBBb"); + public static readonly Address ConsolidationRequestPredeployAddress = new("0x00431F263cE400f4455c2dCf564e53007Ca4bbBb"); } From 08b13892cc4dc435af708ee0cd19723e60fbccff Mon Sep 17 00:00:00 2001 From: ak88 Date: Thu, 2 Jan 2025 22:16:20 +0100 Subject: [PATCH 067/113] Dont charge double account access gas for ext op (#7993) --- src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs | 5 ----- .../TransactionProcessing/TransactionProcessor.cs | 1 - src/Nethermind/Nethermind.Evm/VirtualMachine.cs | 6 +++--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs index a6d60dda916..65cf30cee0e 100644 --- a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs +++ b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs @@ -154,11 +154,6 @@ public static Transaction Convert(PostStateJson postStateJson, TransactionJson t transactionJson.AuthorizationList .Select(i => { - if (i.ChainId > ulong.MaxValue) - { - i.ChainId = 0; - transaction.SenderAddress = Address.Zero; - } if (i.Nonce > ulong.MaxValue) { i.Nonce = 0; diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 103efd7e0cf..c09b858f389 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -41,7 +41,6 @@ public abstract class TransactionProcessorBase : ITransactionProcessor private readonly ICodeInfoRepository _codeInfoRepository; private SystemTransactionProcessor? _systemTransactionProcessor; private readonly ILogManager _logManager; - private readonly HashSet
_accessedAddresses = []; [Flags] protected enum ExecutionOptions diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index 56149f85a78..585aa1f05df 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -1268,7 +1268,7 @@ private CallResult ExecuteCode Date: Fri, 3 Jan 2025 13:37:29 +0000 Subject: [PATCH 068/113] Faster Keccak Xor (#7998) --- .../Nethermind.Core/Crypto/KeccakHash.cs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Crypto/KeccakHash.cs b/src/Nethermind/Nethermind.Core/Crypto/KeccakHash.cs index 3d7ca55b79d..29b4521d0a7 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/KeccakHash.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/KeccakHash.cs @@ -435,6 +435,8 @@ private static unsafe void XorVectors(Span state, ReadOnlySpan input state256 = Vector512.Xor(state256, input256); } + if (input.Length == vectorLength) return; + input = input[vectorLength..]; stateRef = ref Unsafe.Add(ref stateRef, vectorLength); } @@ -452,6 +454,8 @@ private static unsafe void XorVectors(Span state, ReadOnlySpan input state256 = Vector256.Xor(state256, input256); } + if (input.Length == vectorLength) return; + input = input[vectorLength..]; stateRef = ref Unsafe.Add(ref stateRef, vectorLength); } @@ -467,11 +471,32 @@ private static unsafe void XorVectors(Span state, ReadOnlySpan input state128 = Vector128.Xor(state128, input128); } + if (input.Length == vectorLength) return; + input = input[vectorLength..]; stateRef = ref Unsafe.Add(ref stateRef, vectorLength); } - // Handle remaining elements + // As 25 longs in state, 1 more to process after the vector sizes + if (input.Length >= sizeof(ulong)) + { + int ulongLength = input.Length - (int)((uint)input.Length % sizeof(ulong)); + ref byte inputRef = ref MemoryMarshal.GetReference(input); + for (int i = 0; i < ulongLength; i += sizeof(ulong)) + { + ref ulong state64 = ref Unsafe.As(ref Unsafe.Add(ref stateRef, i)); + ulong input64 = Unsafe.As(ref Unsafe.Add(ref inputRef, i)); + state64 ^= input64; + } + + // Should exit here for 25 longs + if (input.Length == ulongLength) return; + + input = input[ulongLength..]; + stateRef = ref Unsafe.Add(ref stateRef, ulongLength); + } + + // Handle remaining bytes for (int i = 0; i < input.Length; i++) { Unsafe.Add(ref stateRef, i) ^= input[i]; From a7fd114222d8ce8713631f82589c946f8490c221 Mon Sep 17 00:00:00 2001 From: Ruben Buniatyan Date: Fri, 3 Jan 2025 19:02:58 +0100 Subject: [PATCH 069/113] Revamp README and guidelines (#7996) --- CODE_OF_CONDUCT.md | 74 +++++++++++++------------------- CONTRIBUTING.md | 6 +-- README.md | 104 ++++++++++++++++++++++++++------------------- 3 files changed, 93 insertions(+), 91 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index dcdf79ff7d4..3123ba3d8c1 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,10 +1,6 @@ # Nethermind Code of Conduct -## Preamble - -The Nethermind Community was created to foster an open, innovative and inclusive community around open source development. -To clarify expected behaviour in our communities we have adopted the Contributor Covenant. This code of conduct -has been adopted by many other open source communities and we feel it expresses our values well. +The Nethermind Community was created to foster an open, innovative, and inclusive community around open-source development. To clarify expected behavior in our communities, we have adopted the Contributor Covenant. Many other open-source communities have adopted this code of conduct, and we feel it expresses our values well. ## Our Pledge @@ -12,8 +8,8 @@ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. @@ -28,18 +24,17 @@ community include: * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community -* Be friendly and patient +* Focusing on what is best not just for us as individuals, but for the overall + community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or - advances of any kind +* The use of sexualized language or imagery, and sexual attention or advances of + any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission +* Publishing others' private information, such as a physical or email address, + without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting @@ -59,25 +54,10 @@ decisions when appropriate. This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, +Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. -## Contributing - -Read carefully our Contributing Guidelines to know how to contribute properly in our -project. Members and maintainers must adhere to some rules regarding to pull requests -reviews and creation of issues and pull requests: - -* During code reviews do not comment on coding standards and styles -focus on algorithmical, -structural or naming issues-, help to solve problem. -* When creating an issue or a pull request, follow the templates provided by the repository and -fill in the indicated items correctly. If you do not want to use a template, open a blank issue/PR -and make sure that in its description is not missing any information requested by the templates. Help -the community to get to know your work better. - -make sure your description is not missing any information requested by the templates - ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be @@ -104,15 +84,15 @@ behavior was inappropriate. A public apology may be requested. ### 2. Warning -**Community Impact**: A violation through a single incident or series -of actions. +**Community Impact**: A violation through a single incident or series of +actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. +like social media. Violating these terms may lead to a temporary or permanent +ban. ### 3. Temporary Ban @@ -128,23 +108,27 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. -**Consequence**: A permanent ban from any sort of public interaction within -the community. +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27a6e7b0451..b9adeabc56d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,11 +8,11 @@ We expect project participants to adhere to our [code of conduct](./CODE_OF_COND ## Asking questions and providing feedback -Have a question? Instead of opening an issue, please ask on our [Discord channel](https://discord.gg/N6Fhbg9u). +Have a question? Instead of opening an issue, please ask on our [Discord channel](https://discord.gg/GXJFaYk). Our active community will be keen to assist you. Your well-worded questions will also serve as a resource to others searching for help. -Your comments and feedback are welcome, and the development team is almost always available on [Discord](https://discord.gg/76ggjqDz). +Your comments and feedback are welcome, and the development team is almost always available on [Discord](https://discord.gg/GXJFaYk). ## Reporting issues @@ -51,7 +51,7 @@ Branch names must follow the `kebab-case` or `snake_case` pattern and be all low - `feature/1234-issue-title` - `shanghai/feature/1234-issue-title` -- `fix/1234-bug-decription` +- `fix/1234-bug-description` - `shanghai/refactor/title` ### File headers diff --git a/README.md b/README.md index 517c22522e8..97e1d1fcebb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ [![Ask on Discourse](https://img.shields.io/discourse/posts?style=social&label=Community&logo=discourse&server=https%3A%2F%2Fcommunity.nethermind.io)](https://community.nethermind.io/c/nethermind-client) [![GitPOAPs](https://public-api.gitpoap.io/v1/repo/NethermindEth/nethermind/badge)](https://www.gitpoap.io/gh/NethermindEth/nethermind) -Nethermind is a high-performance, highly configurable Ethereum execution client built on .NET that runs on Linux, Windows, and macOS and supports Clique, Aura, and Ethash. With breakneck sync speeds and support for external plugins, it provides reliable access to rich on-chain data thanks to a high-performance JSON-RPC interface and node health monitoring with Grafana and Seq. +The Nethermind Ethereum execution client, built on .NET, delivers industry-leading performance in syncing and tip-of-chain processing. With its modular design and plugin system, it offers extensibility and features for new chains. As one of the most adopted execution clients on Ethereum, Nethermind plays a crucial role in enhancing the diversity and resilience of the Ethereum ecosystem. ## Documentation @@ -24,90 +24,108 @@ Nethermind documentation is available at [docs.nethermind.io](https://docs.nethe **Ethereum** · **Gnosis** · **Optimism** · **Base** · **Taiko** · **Linea** · **Energy Web** -## Download and run +## Installing -Release builds are available on the [Releases page](https://github.com/nethermindeth/nethermind/releases) and at [downloads.nethermind.io](https://downloads.nethermind.io). +The standalone release builds are available on [GitHub Releases](https://github.com/nethermindeth/nethermind/releases). -### On Linux +### Package managers -#### Install using PPA +- **Linux** -1. `sudo add-apt-repository ppa:nethermindeth/nethermind` \ - If command not found: `sudo apt-get install software-properties-common` -2. `sudo apt-get install nethermind` -3. `nethermind -c mainnet` + On Debian-based distros, Nethermind can be installed via Launchpad PPA: -### On Windows + ```bash + sudo add-apt-repository ppa:nethermindeth/nethermind + # If command not found, run + # sudo apt-get install software-properties-common -#### Prerequisites + sudo apt-get install nethermind + ``` -In some cases, [Visual C++ Redistributable](https://aka.ms/vcredist) may need an update: +- **Windows** -``` -winget install Microsoft.VCRedist.2015+.x64 -``` + On Windows, Nethermind can be installed via Windows Package Manager: -#### Install using Windows Package Manager + ```powershell + winget install nethermind + ``` -1. `winget install nethermind` -2. `nethermind -c mainnet` +- **macOS** -### On macOS + On macOS, Nethermind can be installed via Homebrew: -#### Install using Homebrew + ```bash + brew tap nethermindeth/nethermind + brew install nethermind + ``` -1. `brew tap nethermindeth/nethermind` -2. `brew install nethermind` -3. `nethermind -c mainnet` +Once installed, Nethermind can be launched as follows: -## Docker image +```bash +nethermind -c mainnet --data-dir path/to/data/dir +``` -The official Docker images of Nethermind are available on [Docker Hub](https://hub.docker.com/r/nethermind/nethermind). +For further instructions, see [Running a node](https://docs.nethermind.io/get-started/running-node). -### Get the digest of the Docker image +### Docker containers -In case of any Docker image need to be updated in the repository, you can update the digest of these images as follows: +The official Docker images of Nethermind are available on [Docker Hub](https://hub.docker.com/r/nethermind/nethermind) and tagged as follows: -```sh -docker inspect --format='{{index .RepoDigests 0}}' -``` +- `latest`: the latest version of Nethermind (the default tag) +- `latest-chiseled`: a rootless and chiseled image of the latest version of Nethermind +- `x.x.x`: a specific version of Nethermind +- `x.x.x-chiseled`: a rootless and chiseled image of the specific version of Nethermind -The output should show the image digest, and then you can copy that to the `FROM` tag in the Dockerfile. +For more info, see [Installing Nethermind](https://docs.nethermind.io/get-started/installing-nethermind). ## Building from source -### Prerequisites +### Docker image + +This is the easiest and fastest way to build Nethermind if you don't want to clone the Nethermind repo, deal with .NET SDK installation, and other configurations. Running the following simple command builds the Docker image, which is ready to run right after: -Install [.NET SDK](https://dotnet.microsoft.com/en-us/download). +```bash +docker build https://github.com/nethermindeth/nethermind.git -t nethermind +``` -### Clone the repository +For more info, see [Bulding Docker image](https://docs.nethermind.io/developers/building-from-source#bulding-docker-image). -```sh +### Standalone binaries + +**Prerequisites** + +Install the [.NET SDK](https://aka.ms/dotnet/download). + +**Clone the repository** + +```bash git clone --recursive https://github.com/nethermindeth/nethermind.git ``` -### Build and run +**Build and run** -```sh +```bash cd nethermind/src/Nethermind/Nethermind.Runner dotnet run -c release -- -c mainnet ``` -### Test +**Test** -```sh +```bash cd nethermind/src/Nethermind -# Run Nethermind tests: +# Run Nethermind tests dotnet test Nethermind.sln -c release -# Run Ethereum Foundation tests: +# Run Ethereum Foundation tests dotnet test EthereumTests.sln -c release ``` +For more info, see [Building standalone binaries](https://docs.nethermind.io/developers/building-from-source#building-standalone-binaries). + ## Contributing -BEFORE you start work on a feature or fix, please read and follow our [contribution guide](https://github.com/nethermindeth/nethermind/blob/master/CONTRIBUTING.md) to help avoid any wasted or duplicate effort. +BEFORE you start work on a feature or fix, please read and follow our [contributing guidelines](./CONTRIBUTING.md) to help avoid any wasted or duplicate effort. ## Security @@ -115,4 +133,4 @@ If you believe you have found a security vulnerability in our code, please repor ## License -Nethermind is an open-source software licensed under the [LGPL-3.0](https://github.com/nethermindeth/nethermind/blob/master/LICENSE-LGPL). +Nethermind is an open-source software licensed under the [LGPL-3.0](./LICENSE-LGPL). From f6277ba80afd125dccd61661254a94cb9f1af0a2 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel <31224949+emlautarom1@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:53:34 -0300 Subject: [PATCH 070/113] Add Holocene timestamps for OP and Base (mainnet) (#8002) --- src/Nethermind/Chains/base-mainnet.json | 2 ++ src/Nethermind/Chains/op-mainnet.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Nethermind/Chains/base-mainnet.json b/src/Nethermind/Chains/base-mainnet.json index 642f5ae56c0..eb4c84a03b7 100644 --- a/src/Nethermind/Chains/base-mainnet.json +++ b/src/Nethermind/Chains/base-mainnet.json @@ -10,6 +10,7 @@ "ecotoneTimestamp": "0x65f23e01", "fjordTimestamp": "0x668eb001", "graniteTimestamp": "0x66e1be81", + "holoceneTimestamp": "0x67800ea1", "l1FeeRecipient": "0x420000000000000000000000000000000000001A", "l1BlockAddress": "0x4200000000000000000000000000000000000015", "canyonBaseFeeChangeDenominator": "250", @@ -71,6 +72,7 @@ "rip7212TransitionTimestamp": "0x668eb001", "opGraniteTransitionTimestamp": "0x66e1be81", + "opHoloceneTransitionTimestamp": "0x67800ea1", "terminalTotalDifficulty": "0" }, diff --git a/src/Nethermind/Chains/op-mainnet.json b/src/Nethermind/Chains/op-mainnet.json index 92b65c15058..ac66f64183d 100644 --- a/src/Nethermind/Chains/op-mainnet.json +++ b/src/Nethermind/Chains/op-mainnet.json @@ -10,6 +10,7 @@ "ecotoneTimestamp": "0x65f23e01", "fjordTimestamp": "0x668eb001", "graniteTimestamp": "0x66e1be81", + "holoceneTimestamp": "0x67800ea1", "l1FeeRecipient": "0x420000000000000000000000000000000000001A", "l1BlockAddress": "0x4200000000000000000000000000000000000015", "canyonBaseFeeChangeDenominator": "250", @@ -76,6 +77,7 @@ "rip7212TransitionTimestamp": "0x668eb001", "opGraniteTransitionTimestamp": "0x66e1be81", + "opHoloceneTransitionTimestamp": "0x67800ea1", "terminalTotalDifficulty": "210470125" }, From 43ab75d1ca7ef0179d5046a79da1f6ac2b2ad0dd Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sat, 4 Jan 2025 00:06:47 +0000 Subject: [PATCH 071/113] Recovering trie node message should be less severe (#8004) --- .../Nethermind.Synchronization/Trie/TrieNodeRecovery.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization/Trie/TrieNodeRecovery.cs b/src/Nethermind/Nethermind.Synchronization/Trie/TrieNodeRecovery.cs index 4536b5f08bb..3f29eb4c90c 100644 --- a/src/Nethermind/Nethermind.Synchronization/Trie/TrieNodeRecovery.cs +++ b/src/Nethermind/Nethermind.Synchronization/Trie/TrieNodeRecovery.cs @@ -104,11 +104,16 @@ private ArrayPoolList AllocatePeers() => } catch (OperationCanceledException) { - if (_logger.IsTrace) _logger.Trace($"Cancelled recovering RLP from peer {peer}"); + if (_logger.IsTrace) _logger.Trace($"Cancelled recovering RLP {rlpHash} from peer {peer}"); + } + catch (TimeoutException) + { + if (_logger.IsTrace) _logger.Trace($"Timeout recovering RLP {rlpHash} from peer {peer}"); } catch (Exception e) { - if (_logger.IsError) _logger.Error($"Could not recover from {peer}", e); + if (_logger.IsWarn) _logger.Warn($"Could not recover RLP {rlpHash} from {peer}"); + if (_logger.IsDebug) _logger.Error($"DEBUG/ERROR Could not recover RLP {rlpHash} from {peer}", e); } return (recovery, null); From 95ec36973620cd3b967e19a6c782defbb9a85693 Mon Sep 17 00:00:00 2001 From: Tanishq Jasoria Date: Sat, 4 Jan 2025 18:25:20 +0530 Subject: [PATCH 072/113] v2 Implement EIP-7623: Increase calldata cost (#7859) Co-authored-by: Lukasz Rozmej Co-authored-by: ak88 --- .../Validators/TxValidator.cs | 7 +- .../Nethermind.Core/Specs/IReleaseSpec.cs | 5 ++ .../Specs/ReleaseSpecDecorator.cs | 1 + .../Nethermind.Evm.Test/Eip2028Tests.cs | 20 +++-- .../Nethermind.Evm.Test/Eip7623Tests.cs | 34 ++++++++ .../EvmPooledMemoryTests.cs | 4 +- .../GasPriceExtractorTests.cs | 11 ++- .../IntrinsicGasCalculatorTests.cs | 78 ++++++++++++------- .../TestAllTracerWithOutput.cs | 11 +-- .../Tracing/BlockReceiptsTracerTests.cs | 1 + .../Tracing/ParityLikeTxTracerTests.cs | 1 + .../TransactionProcessorTests.cs | 21 +++-- src/Nethermind/Nethermind.Evm/GasCostOf.cs | 4 + .../Nethermind.Evm/IntrinsicGasCalculator.cs | 61 +++++++++++---- .../Nethermind.Evm/Tracing/AccessTxTracer.cs | 22 ++---- .../Tracing/AlwaysCancelTxTracer.cs | 5 +- .../Tracing/BlockReceiptsTracer.cs | 11 +-- .../Tracing/CallOutputTracer.cs | 12 ++- .../Tracing/CancellationTxTracer.cs | 5 +- .../Tracing/CompositeTxTracer.cs | 5 +- .../Tracing/Debugger/DebugTracer.cs | 5 +- .../Tracing/EstimateGasTracer.cs | 9 ++- .../Nethermind.Evm/Tracing/GasEstimator.cs | 12 +-- .../JavaScript/GethLikeJavaScriptTxTracer.cs | 9 ++- .../Custom/Native/Call/NativeCallTracer.cs | 9 ++- .../Native/Prestate/NativePrestateTracer.cs | 5 +- .../GethStyle/GethLikeTxMemoryTracer.cs | 5 +- .../Tracing/GethStyle/GethLikeTxTracer.cs | 5 +- .../Nethermind.Evm/Tracing/ITxTracer.cs | 5 +- .../Nethermind.Evm/Tracing/NullTxTracer.cs | 5 +- .../Tracing/ParityStyle/ParityLikeTxTracer.cs | 5 +- .../Tracing/Proofs/ProofTxTracer.cs | 20 ++--- .../Nethermind.Evm/Tracing/TxTracer.cs | 5 +- .../TransactionProcessing/GasConsumed.cs | 10 +++ .../SystemTransactionProcessor.cs | 2 +- .../TransactionProcessor.cs | 44 ++++++----- .../Nethermind.Facade/BlockchainBridge.cs | 1 + .../Nethermind.Facade/CallOutput.cs | 1 + .../Simulate/SimulateTxMutatorTracer.cs | 11 ++- .../Eth/EthRpcModule.TransactionExecutor.cs | 16 +++- .../OptimismTransactionProcessor.cs | 9 ++- .../OverridableReleaseSpec.cs | 1 + .../ChainSpecStyle/ChainParameters.cs | 1 + .../ChainSpecBasedSpecProvider.cs | 1 + .../ChainSpecStyle/ChainSpecLoader.cs | 1 + .../Json/ChainSpecParamsJson.cs | 1 + .../Nethermind.Specs/Forks/18_Prague.cs | 1 + .../Nethermind.Specs/ReleaseSpec.cs | 1 + .../TaikoTransactionProcessor.cs | 10 +-- .../Nethermind.Test.Runner/StateTestRunner.cs | 2 +- .../StateTestTxTracer.cs | 5 +- 51 files changed, 345 insertions(+), 191 deletions(-) create mode 100644 src/Nethermind/Nethermind.Evm.Test/Eip7623Tests.cs create mode 100644 src/Nethermind/Nethermind.Evm/TransactionProcessing/GasConsumed.cs diff --git a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs index b5db9fd9eef..0c52d02f53f 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs @@ -110,11 +110,14 @@ public sealed class IntrinsicGasTxValidator : ITxValidator public static readonly IntrinsicGasTxValidator Instance = new(); private IntrinsicGasTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + { // This is unnecessarily calculated twice - at validation and execution times. - transaction.GasLimit < IntrinsicGasCalculator.Calculate(transaction, releaseSpec) + IntrinsicGas intrinsicGas = IntrinsicGasCalculator.Calculate(transaction, releaseSpec); + return transaction.GasLimit < intrinsicGas.MinimalGas ? TxErrorMessages.IntrinsicGasTooLow : ValidationResult.Success; + } } public sealed class ReleaseSpecTxValidator(Func validate) : ITxValidator diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs index 0241fa1912a..96e0a1ce4d6 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs @@ -332,6 +332,11 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec /// Taiko Ontake bool IsOntakeEnabled { get; } + /// + /// Increase call data cost + /// + bool IsEip7623Enabled { get; } + /// /// Should transactions be validated against chainId. /// diff --git a/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs b/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs index 5688b8bdbf3..ceb35477ec5 100644 --- a/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs +++ b/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs @@ -83,6 +83,7 @@ public class ReleaseSpecDecorator(IReleaseSpec spec) : IReleaseSpec public virtual bool IsOpGraniteEnabled => spec.IsOpGraniteEnabled; public virtual bool IsOpHoloceneEnabled => spec.IsOpHoloceneEnabled; public virtual bool IsOntakeEnabled => spec.IsOntakeEnabled; + public virtual bool IsEip7623Enabled => spec.IsEip7623Enabled; public virtual ulong WithdrawalTimestamp => spec.WithdrawalTimestamp; public virtual ulong Eip4844TransitionTimestamp => spec.Eip4844TransitionTimestamp; public virtual bool IsEip158IgnoredAccount(Address address) => spec.IsEip158IgnoredAccount(address); diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs index 2d4daf0c885..e0286a9a48d 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs @@ -23,16 +23,18 @@ private class AfterIstanbul : Eip2028Tests public void non_zero_transaction_data_cost_should_be_16() { Transaction transaction = new Transaction { Data = new byte[] { 1 }, To = Address.Zero }; - long cost = IntrinsicGasCalculator.Calculate(transaction, Spec); - cost.Should().Be(GasCostOf.Transaction + GasCostOf.TxDataNonZeroEip2028); + IntrinsicGas cost = IntrinsicGasCalculator.Calculate(transaction, Spec); + cost.Should().Be(new IntrinsicGas(Standard: GasCostOf.Transaction + GasCostOf.TxDataNonZeroEip2028, + FloorGas: 0)); } [Test] public void zero_transaction_data_cost_should_be_4() { Transaction transaction = new Transaction { Data = new byte[] { 0 }, To = Address.Zero }; - long cost = IntrinsicGasCalculator.Calculate(transaction, Spec); - cost.Should().Be(GasCostOf.Transaction + GasCostOf.TxDataZero); + IntrinsicGas cost = IntrinsicGasCalculator.Calculate(transaction, Spec); + cost.Should().Be(new IntrinsicGas(Standard: GasCostOf.Transaction + GasCostOf.TxDataZero, + FloorGas: 0)); } } @@ -45,16 +47,18 @@ private class BeforeIstanbul : Eip2028Tests public void non_zero_transaction_data_cost_should_be_68() { Transaction transaction = new Transaction { Data = new byte[] { 1 }, To = Address.Zero }; - long cost = IntrinsicGasCalculator.Calculate(transaction, Spec); - cost.Should().Be(GasCostOf.Transaction + GasCostOf.TxDataNonZero); + IntrinsicGas cost = IntrinsicGasCalculator.Calculate(transaction, Spec); + cost.Should().Be(new IntrinsicGas(Standard: GasCostOf.Transaction + GasCostOf.TxDataNonZero, + FloorGas: 0)); } [Test] public void zero_transaction_data_cost_should_be_4() { Transaction transaction = new Transaction { Data = new byte[] { 0 }, To = Address.Zero }; - long cost = IntrinsicGasCalculator.Calculate(transaction, Spec); - cost.Should().Be(GasCostOf.Transaction + GasCostOf.TxDataZero); + IntrinsicGas cost = IntrinsicGasCalculator.Calculate(transaction, Spec); + cost.Should().Be(new IntrinsicGas(Standard: GasCostOf.Transaction + GasCostOf.TxDataZero, + FloorGas: 0)); } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip7623Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip7623Tests.cs new file mode 100644 index 00000000000..b67e8283c53 --- /dev/null +++ b/src/Nethermind/Nethermind.Evm.Test/Eip7623Tests.cs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using FluentAssertions; +using Nethermind.Core; +using Nethermind.Specs; +using NUnit.Framework; + +namespace Nethermind.Evm.Test; + +[TestFixture] +public class Eip7623Tests : VirtualMachineTestsBase +{ + protected override long BlockNumber => MainnetSpecProvider.ParisBlockNumber; + protected override ulong Timestamp => MainnetSpecProvider.PragueBlockTimestamp; + + [Test] + public void non_zero_data_transaction_floor_cost_should_be_40() + { + var transaction = new Transaction { Data = new byte[] { 1 }, To = Address.Zero }; + IntrinsicGas cost = IntrinsicGasCalculator.Calculate(transaction, Spec); + cost.Should().Be(new IntrinsicGas(Standard: GasCostOf.Transaction + GasCostOf.TxDataNonZeroEip2028, + FloorGas: GasCostOf.Transaction + GasCostOf.TotalCostFloorPerTokenEip7623 * 4)); + } + + [Test] + public void zero_data_transaction_floor_cost_should_be_10() + { + var transaction = new Transaction { Data = new byte[] { 0 }, To = Address.Zero }; + IntrinsicGas cost = IntrinsicGasCalculator.Calculate(transaction, Spec); + cost.Should().Be(new IntrinsicGas(Standard: GasCostOf.Transaction + GasCostOf.TxDataZero, + FloorGas: GasCostOf.Transaction + GasCostOf.TotalCostFloorPerTokenEip7623)); + } +} diff --git a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs index 9259b78e7eb..314100692a9 100644 --- a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs @@ -234,11 +234,11 @@ public class MyTracer : ITxTracer, IDisposable public string lastmemline; - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256 stateRoot = null) + public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { } - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256 stateRoot = null) + public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { } diff --git a/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs b/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs index 874b16e4908..5be2cbaa009 100644 --- a/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Linq; using FluentAssertions; using Nethermind.Core; @@ -32,8 +33,9 @@ public void Intrinsic_gas_cost_assumption_is_correct() Rlp rlp = BuildHeader(); Transaction tx = Build.A.Transaction.WithData(rlp.Bytes).TestObject; - long gasCost = IntrinsicGasCalculator.Calculate(tx, Spec); - gasCost.Should().BeLessThan(21000 + 9600); + IntrinsicGas gasCost = IntrinsicGasCalculator.Calculate(tx, Spec); + gasCost.FloorGas.Should().Be(0); + gasCost.Standard.Should().BeLessThan(21000 + 9600); } [Test] @@ -42,8 +44,9 @@ public void Keccak_gas_cost_assumption_is_correct() Rlp rlp = BuildHeader(); Transaction tx = Build.A.Transaction.WithData(rlp.Bytes).TestObject; - long gasCost = IntrinsicGasCalculator.Calculate(tx, Spec); - gasCost.Should().BeLessThan(21000 + 9600); + var gasCost = IntrinsicGasCalculator.Calculate(tx, Spec); + gasCost.FloorGas.Should().Be(0); + gasCost.Standard.Should().BeLessThan(21000 + 9600); byte[] bytecode = Prepare.EvmCode diff --git a/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs b/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs index 6d98c21351a..cac1206d630 100644 --- a/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Collections.Generic; using System.IO; using FluentAssertions; @@ -16,6 +17,15 @@ namespace Nethermind.Evm.Test { + + [Flags] + public enum GasOptions + { + None = 0, + AfterRepricing = 1, + FloorCostEnabled = 2, + } + [TestFixture] public class IntrinsicGasCalculatorTests { @@ -33,18 +43,19 @@ public class IntrinsicGasCalculatorTests yield return (new List { Address.Zero, (UInt256)1, Address.Zero, (UInt256)1 }, 8600); } - public static IEnumerable<(byte[] Data, int OldCost, int NewCost)> DataTestCaseSource() + public static IEnumerable<(byte[] Data, int OldCost, int NewCost, int FloorCost)> DataTestCaseSource() { - yield return (new byte[] { 0 }, 4, 4); - yield return (new byte[] { 1 }, 68, 16); - yield return (new byte[] { 0, 0, 1 }, 76, 24); - yield return (new byte[] { 1, 1, 0 }, 140, 36); - yield return (new byte[] { 0, 0, 1, 1 }, 144, 40); + yield return ([0], 4, 4, 21010); + yield return ([1], 68, 16, 21040); + yield return ([0, 0, 1], 76, 24, 21060); + yield return ([1, 1, 0], 140, 36, 21090); + yield return ([0, 0, 1, 1], 144, 40, 21100); } [TestCaseSource(nameof(TestCaseSource))] public void Intrinsic_cost_is_calculated_properly((Transaction Tx, long Cost, string Description) testCase) { - IntrinsicGasCalculator.Calculate(testCase.Tx, Berlin.Instance).Should().Be(testCase.Cost); + IntrinsicGas gas = IntrinsicGasCalculator.Calculate(testCase.Tx, Berlin.Instance); + gas.Should().Be(new IntrinsicGas(Standard: testCase.Cost, FloorGas: 0)); } [TestCaseSource(nameof(AccessTestCaseSource))] @@ -74,7 +85,8 @@ void Test(IReleaseSpec spec, bool supportsAccessLists) } else { - IntrinsicGasCalculator.Calculate(tx, spec).Should().Be(21000 + testCase.Cost, spec.Name); + IntrinsicGas gas = IntrinsicGasCalculator.Calculate(tx, spec); + gas.Should().Be(new IntrinsicGas(Standard: 21000 + testCase.Cost, FloorGas: 0), spec.Name); } } @@ -91,31 +103,45 @@ void Test(IReleaseSpec spec, bool supportsAccessLists) } [TestCaseSource(nameof(DataTestCaseSource))] - public void Intrinsic_cost_of_data_is_calculated_properly((byte[] Data, int OldCost, int NewCost) testCase) + public void Intrinsic_cost_of_data_is_calculated_properly((byte[] Data, int OldCost, int NewCost, int FloorCost) testCase) { Transaction tx = Build.A.Transaction.SignedAndResolved().WithData(testCase.Data).TestObject; - void Test(IReleaseSpec spec, bool isAfterRepricing) + + void Test(IReleaseSpec spec, GasOptions options) { - IntrinsicGasCalculator.Calculate(tx, spec).Should() + IntrinsicGas gas = IntrinsicGasCalculator.Calculate(tx, spec); + + bool isAfterRepricing = options.HasFlag(GasOptions.AfterRepricing); + bool floorCostEnabled = options.HasFlag(GasOptions.FloorCostEnabled); + + gas.Standard.Should() .Be(21000 + (isAfterRepricing ? testCase.NewCost : testCase.OldCost), spec.Name, testCase.Data.ToHexString()); + gas.FloorGas.Should().Be(floorCostEnabled ? testCase.FloorCost : 0); + + gas.Should().Be(new IntrinsicGas( + Standard: 21000 + (isAfterRepricing ? testCase.NewCost : testCase.OldCost), + FloorGas: floorCostEnabled ? testCase.FloorCost : 0), + spec.Name, testCase.Data.ToHexString()); } - Test(Homestead.Instance, false); - Test(Frontier.Instance, false); - Test(SpuriousDragon.Instance, false); - Test(TangerineWhistle.Instance, false); - Test(Byzantium.Instance, false); - Test(Constantinople.Instance, false); - Test(ConstantinopleFix.Instance, false); - Test(Istanbul.Instance, true); - Test(MuirGlacier.Instance, true); - Test(Berlin.Instance, true); - Test(GrayGlacier.Instance, true); - Test(Shanghai.Instance, true); - Test(Cancun.Instance, true); + Test(Homestead.Instance, GasOptions.None); + Test(Frontier.Instance, GasOptions.None); + Test(SpuriousDragon.Instance, GasOptions.None); + Test(TangerineWhistle.Instance, GasOptions.None); + Test(Byzantium.Instance, GasOptions.None); + Test(Constantinople.Instance, GasOptions.None); + Test(ConstantinopleFix.Instance, GasOptions.None); + Test(Istanbul.Instance, GasOptions.AfterRepricing); + Test(MuirGlacier.Instance, GasOptions.AfterRepricing); + Test(Berlin.Instance, GasOptions.AfterRepricing); + Test(GrayGlacier.Instance, GasOptions.AfterRepricing); + Test(Shanghai.Instance, GasOptions.AfterRepricing); + Test(Cancun.Instance, GasOptions.AfterRepricing); + Test(Prague.Instance, GasOptions.AfterRepricing | GasOptions.FloorCostEnabled); } + public static IEnumerable<(AuthorizationTuple[] contractCode, long expectedCost)> AuthorizationListTestCaseSource() { yield return ( @@ -179,8 +205,8 @@ public void Calculate_TxHasAuthorizationList_ReturnsExpectedCostOfTx((Authorizat .WithAuthorizationCode(testCase.AuthorizationList) .TestObject; - IntrinsicGasCalculator.Calculate(tx, Prague.Instance) - .Should().Be(GasCostOf.Transaction + (testCase.ExpectedCost)); + IntrinsicGas gas = IntrinsicGasCalculator.Calculate(tx, Prague.Instance); + gas.Standard.Should().Be(GasCostOf.Transaction + (testCase.ExpectedCost)); } [Test] diff --git a/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs b/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs index ba19921a4bc..bc5b05cc781 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs @@ -5,6 +5,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Evm.Tracing; +using Nethermind.Evm.TransactionProcessing; namespace Nethermind.Evm.Test { @@ -39,18 +40,18 @@ public TestAllTracerWithOutput() public long Refund { get; private set; } - public List ReportedActionErrors { get; set; } = new List(); + public List ReportedActionErrors { get; set; } = new(); - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { - GasSpent = gasSpent; + GasSpent = gasSpent.SpentGas; ReturnValue = output; StatusCode = Evm.StatusCode.Success; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[]? output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { - GasSpent = gasSpent; + GasSpent = gasSpent.SpentGas; Error = error; ReturnValue = output ?? []; StatusCode = Evm.StatusCode.Failure; diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs index c6d96d3a8ec..ce9bcbffb25 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs @@ -5,6 +5,7 @@ using Nethermind.Core; using Nethermind.Core.Test.Builders; using Nethermind.Evm.Tracing; +using Nethermind.Evm.TransactionProcessing; using NSubstitute; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs index c45d3dd622f..554a7021286 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs @@ -11,6 +11,7 @@ using Nethermind.Int256; using Nethermind.Evm.Precompiles; using Nethermind.Evm.Tracing.ParityStyle; +using Nethermind.Evm.TransactionProcessing; using Nethermind.State; using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs index 31ffec46b8e..7aa81eace5a 100644 --- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs @@ -391,7 +391,7 @@ public void Can_estimate_with_refund() Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA, _isEip155Enabled).WithCode(initByteCode).WithGasLimit(gasLimit).TestObject; Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; - long intrinsic = IntrinsicGasCalculator.Calculate(tx, MuirGlacier.Instance); + IntrinsicGas intrinsicGas = IntrinsicGasCalculator.Calculate(tx, MuirGlacier.Instance); GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); @@ -404,7 +404,7 @@ public void Can_estimate_with_refund() GasEstimator estimator = new(_transactionProcessor, _stateProvider, _specProvider, blocksConfig); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; - actualIntrinsic.Should().Be(intrinsic); + actualIntrinsic.Should().Be(intrinsicGas.Standard); IReleaseSpec releaseSpec = Berlin.Instance; tracer.CalculateAdditionalGasRequired(tx, releaseSpec).Should().Be(RefundOf.SSetReversedEip2200 + GasCostOf.CallStipend - GasCostOf.SStoreNetMeteredEip2200 + 1); tracer.GasSpent.Should().Be(54764L); @@ -432,8 +432,7 @@ public void Can_estimate_with_destroy_refund_and_below_intrinsic_pre_berlin() Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; IReleaseSpec releaseSpec = MuirGlacier.Instance; - long intrinsic = IntrinsicGasCalculator.Calculate(tx, releaseSpec); - + IntrinsicGas intrinsicGas = IntrinsicGasCalculator.Calculate(tx, releaseSpec); _transactionProcessor.Execute(initTx, block.Header, NullTxTracer.Instance); EstimateGasTracer tracer = new(); @@ -446,7 +445,7 @@ public void Can_estimate_with_destroy_refund_and_below_intrinsic_pre_berlin() GasEstimator estimator = new(_transactionProcessor, _stateProvider, _specProvider, blocksConfig); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; - actualIntrinsic.Should().Be(intrinsic); + actualIntrinsic.Should().Be(intrinsicGas.Standard); tracer.CalculateAdditionalGasRequired(tx, releaseSpec).Should().Be(24080); tracer.GasSpent.Should().Be(35228L); long estimate = estimator.Estimate(tx, block.Header, tracer, 0); @@ -498,7 +497,7 @@ public void Can_estimate_with_stipend() Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; IReleaseSpec releaseSpec = MuirGlacier.Instance; - long intrinsic = IntrinsicGasCalculator.Calculate(tx, releaseSpec); + IntrinsicGas intrinsicGas = IntrinsicGasCalculator.Calculate(tx, releaseSpec); GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); @@ -511,7 +510,7 @@ public void Can_estimate_with_stipend() GasEstimator estimator = new(_transactionProcessor, _stateProvider, _specProvider, blocksConfig); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; - actualIntrinsic.Should().Be(intrinsic); + actualIntrinsic.Should().Be(intrinsicGas.Standard); tracer.CalculateAdditionalGasRequired(tx, releaseSpec).Should().Be(2300); tracer.GasSpent.Should().Be(85669L); long estimate = estimator.Estimate(tx, block.Header, tracer, 0); @@ -540,7 +539,7 @@ public void Can_estimate_with_stipend_and_refund() Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; IReleaseSpec releaseSpec = MuirGlacier.Instance; - long intrinsic = IntrinsicGasCalculator.Calculate(tx, releaseSpec); + IntrinsicGas intrinsicGas = IntrinsicGasCalculator.Calculate(tx, releaseSpec); GethLikeTxMemoryTracer gethTracer = new(GethTraceOptions.Default); _transactionProcessor.CallAndRestore(tx, block.Header, gethTracer); @@ -553,7 +552,7 @@ public void Can_estimate_with_stipend_and_refund() GasEstimator estimator = new(_transactionProcessor, _stateProvider, _specProvider, blocksConfig); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; - actualIntrinsic.Should().Be(intrinsic); + actualIntrinsic.Should().Be(intrinsicGas.Standard); tracer.CalculateAdditionalGasRequired(tx, releaseSpec).Should().Be(RefundOf.SSetReversedEip2200 + GasCostOf.CallStipend); tracer.GasSpent.Should().Be(87429L); long estimate = estimator.Estimate(tx, block.Header, tracer, 0); @@ -580,7 +579,7 @@ public void Can_estimate_with_single_call() Block block = Build.A.Block.WithNumber(MainnetSpecProvider.MuirGlacierBlockNumber).WithTransactions(tx).WithGasLimit(2 * gasLimit).TestObject; IReleaseSpec releaseSpec = Berlin.Instance; - long intrinsic = IntrinsicGasCalculator.Calculate(tx, releaseSpec); + IntrinsicGas intrinsicGas = IntrinsicGasCalculator.Calculate(tx, releaseSpec); _transactionProcessor.Execute(initTx, block.Header, NullTxTracer.Instance); @@ -591,7 +590,7 @@ public void Can_estimate_with_single_call() GasEstimator estimator = new(_transactionProcessor, _stateProvider, _specProvider, blocksConfig); long actualIntrinsic = tx.GasLimit - tracer.IntrinsicGasAt; - actualIntrinsic.Should().Be(intrinsic); + actualIntrinsic.Should().Be(intrinsicGas.Standard); tracer.CalculateAdditionalGasRequired(tx, releaseSpec).Should().Be(1); tracer.GasSpent.Should().Be(54224L); long estimate = estimator.Estimate(tx, block.Header, tracer, 0); diff --git a/src/Nethermind/Nethermind.Evm/GasCostOf.cs b/src/Nethermind/Nethermind.Evm/GasCostOf.cs index 07ca52e64b0..e5cb9617ba5 100644 --- a/src/Nethermind/Nethermind.Evm/GasCostOf.cs +++ b/src/Nethermind/Nethermind.Evm/GasCostOf.cs @@ -63,5 +63,9 @@ public static class GasCostOf public const long TLoad = WarmStateRead; // eip-1153 public const long TStore = WarmStateRead; // eip-1153 public const long PerAuthBaseCost = 12500; // eip-7702 + public const long TotalCostFloorPerTokenEip7623 = 10; // eip-7632 + + public const long TxDataNonZeroMultiplier = TxDataNonZero / TxDataZero; + public const long TxDataNonZeroMultiplierEip2028 = TxDataNonZeroEip2028 / TxDataZero; } } diff --git a/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs b/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs index a8e5dc5c86f..01d5ebf6ab9 100644 --- a/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs +++ b/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs @@ -7,41 +7,48 @@ using System.IO; using Nethermind.Core; using Nethermind.Core.Eip2930; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Int256; -using Nethermind.Core.Extensions; namespace Nethermind.Evm; + +public readonly record struct IntrinsicGas(long Standard, long FloorGas) +{ + public long MinimalGas { get; } = Math.Max(Standard, FloorGas); + public static explicit operator long(IntrinsicGas gas) => gas.MinimalGas; +} + public static class IntrinsicGasCalculator { - public static long Calculate(Transaction transaction, IReleaseSpec releaseSpec) => - GasCostOf.Transaction - + DataCost(transaction, releaseSpec) - + CreateCost(transaction, releaseSpec) - + AccessListCost(transaction, releaseSpec) - + AuthorizationListCost(transaction, releaseSpec); + public static IntrinsicGas Calculate(Transaction transaction, IReleaseSpec releaseSpec) + { + var intrinsicGas = GasCostOf.Transaction + + DataCost(transaction, releaseSpec) + + CreateCost(transaction, releaseSpec) + + AccessListCost(transaction, releaseSpec) + + AuthorizationListCost(transaction, releaseSpec); + var floorGas = CalculateFloorCost(transaction, releaseSpec); + return new IntrinsicGas(intrinsicGas, floorGas); + } private static long CreateCost(Transaction transaction, IReleaseSpec releaseSpec) => transaction.IsContractCreation && releaseSpec.IsEip2Enabled ? GasCostOf.TxCreate : 0; private static long DataCost(Transaction transaction, IReleaseSpec releaseSpec) { - long txDataNonZeroGasCost = releaseSpec.IsEip2028Enabled ? GasCostOf.TxDataNonZeroEip2028 : GasCostOf.TxDataNonZero; - Span data = transaction.Data.GetValueOrDefault().Span; - - int totalZeros = data.CountZeros(); - long baseDataCost = transaction.IsContractCreation && releaseSpec.IsEip3860Enabled - ? EvmPooledMemory.Div32Ceiling((UInt256)data.Length) * GasCostOf.InitCodeWord + ? EvmPooledMemory.Div32Ceiling((UInt256)transaction.Data.GetValueOrDefault().Length) * + GasCostOf.InitCodeWord : 0; - return baseDataCost + - totalZeros * GasCostOf.TxDataZero + - (data.Length - totalZeros) * txDataNonZeroGasCost; + long tokensInCallData = CalculateTokensInCallData(transaction, releaseSpec); + + return baseDataCost + tokensInCallData * GasCostOf.TxDataZero; } - private static long AccessListCost(Transaction transaction, IReleaseSpec releaseSpec) + public static long AccessListCost(Transaction transaction, IReleaseSpec releaseSpec) { AccessList? accessList = transaction.AccessList; if (accessList is not null) @@ -88,4 +95,24 @@ static void ThrowInvalidDataException(IReleaseSpec releaseSpec) throw new InvalidDataException($"Transaction with an authorization list received within the context of {releaseSpec.Name}. Eip-7702 is not enabled."); } } + + private static long CalculateTokensInCallData(Transaction transaction, IReleaseSpec releaseSpec) + { + long txDataNonZeroMultiplier = releaseSpec.IsEip2028Enabled + ? GasCostOf.TxDataNonZeroMultiplierEip2028 + : GasCostOf.TxDataNonZeroMultiplier; + Span data = transaction.Data.GetValueOrDefault().Span; + + int totalZeros = data.CountZeros(); + + return totalZeros + (data.Length - totalZeros) * txDataNonZeroMultiplier; + } + + private static long CalculateFloorCost(Transaction transaction, IReleaseSpec releaseSpec) + { + if (!releaseSpec.IsEip7623Enabled) return 0; + long tokensInCallData = CalculateTokensInCallData(transaction, releaseSpec); + + return GasCostOf.Transaction + tokensInCallData * GasCostOf.TotalCostFloorPerTokenEip7623; + } } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs index da352b46a33..563a3eca47b 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs @@ -5,30 +5,24 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Eip2930; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing { - public class AccessTxTracer : TxTracer + public class AccessTxTracer(params Address[] addressesToOptimize) : TxTracer { - private readonly Address[] _addressesToOptimize; - public override bool IsTracingReceipt => true; public override bool IsTracingAccess => true; - public AccessTxTracer(params Address[] addressesToOptimize) - { - _addressesToOptimize = addressesToOptimize; - } - - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { - GasSpent += gasSpent; + GasSpent += gasSpent.SpentGas; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { - GasSpent += gasSpent; + GasSpent += gasSpent.SpentGas; } public override void ReportAccess(IReadOnlySet
accessedAddresses, IReadOnlySet accessedStorageCells) @@ -49,9 +43,9 @@ public override void ReportAccess(IReadOnlySet
accessedAddresses, IRead set.Add(storageCell.Index); } - for (int i = 0; i < _addressesToOptimize.Length; i++) + for (int i = 0; i < addressesToOptimize.Length; i++) { - Address address = _addressesToOptimize[i]; + Address address = addressesToOptimize[i]; if (dictionary.TryGetValue(address, out ISet set) && set.Count == 0) { dictionary.Remove(address); diff --git a/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs index bc9d29caef5..c11d9fc01aa 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs @@ -6,6 +6,7 @@ using System.Threading; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing; @@ -43,9 +44,9 @@ public static AlwaysCancelTxTracer Instance public bool IsTracingFees => true; public bool IsTracingLogs => true; - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) => throw new OperationCanceledException(ErrorMessage); + public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) => throw new OperationCanceledException(ErrorMessage); - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) => throw new OperationCanceledException(ErrorMessage); + public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) => throw new OperationCanceledException(ErrorMessage); public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env) => throw new OperationCanceledException(ErrorMessage); diff --git a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs index 62ea3998e16..50e2e94de88 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs @@ -6,6 +6,7 @@ using System.Linq; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing; @@ -30,9 +31,9 @@ public class BlockReceiptsTracer : IBlockTracer, ITxTracer, IJournal, ITxTr public bool IsTracingFees => _currentTxTracer.IsTracingFees; public bool IsTracingLogs => _currentTxTracer.IsTracingLogs; - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { - _txReceipts.Add(BuildReceipt(recipient, gasSpent, StatusCode.Success, logs, stateRoot)); + _txReceipts.Add(BuildReceipt(recipient, gasSpent.SpentGas, StatusCode.Success, logs, stateRoot)); // hacky way to support nested receipt tracers if (_otherTracer is ITxTracer otherTxTracer) @@ -43,13 +44,13 @@ public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEn if (_currentTxTracer.IsTracingReceipt) { // TODO: is no stateRoot a bug? - _currentTxTracer.MarkAsSuccess(recipient, gasSpent, output, logs, null); + _currentTxTracer.MarkAsSuccess(recipient, gasSpent, output, logs); } } - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { - _txReceipts.Add(BuildFailedReceipt(recipient, gasSpent, error, stateRoot)); + _txReceipts.Add(BuildFailedReceipt(recipient, gasSpent.SpentGas, error, stateRoot)); // hacky way to support nested receipt tracers if (_otherTracer is ITxTracer otherTxTracer) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs index 404b6bb66c4..d443e1abb77 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs @@ -3,6 +3,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; namespace Nethermind.Evm.Tracing { @@ -12,21 +13,24 @@ public class CallOutputTracer : TxTracer public byte[]? ReturnValue { get; set; } public long GasSpent { get; set; } + public long OperationGas { get; set; } public string? Error { get; set; } public byte StatusCode { get; set; } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { - GasSpent = gasSpent; + GasSpent = gasSpent.SpentGas; + OperationGas = gasSpent.OperationGas; ReturnValue = output; StatusCode = Evm.StatusCode.Success; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { - GasSpent = gasSpent; + GasSpent = gasSpent.SpentGas; + OperationGas = gasSpent.OperationGas; Error = error; ReturnValue = output; StatusCode = Evm.StatusCode.Failure; diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs index 45a5f903a37..958d1ed496f 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs @@ -6,6 +6,7 @@ using System.Threading; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing; @@ -171,7 +172,7 @@ public void ReportStorageRead(in StorageCell storageCell) } } - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { token.ThrowIfCancellationRequested(); if (innerTracer.IsTracingReceipt) @@ -180,7 +181,7 @@ public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEn } } - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { token.ThrowIfCancellationRequested(); if (innerTracer.IsTracingReceipt) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs index 85e30708cf4..70b95154b9d 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing; @@ -126,7 +127,7 @@ public void ReportStorageRead(in StorageCell storageCell) } } - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { for (int index = 0; index < _txTracers.Count; index++) { @@ -138,7 +139,7 @@ public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEn } } - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { for (int index = 0; index < _txTracers.Count; index++) { diff --git a/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs index e37a5ce52b5..332cf15c240 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/Debugger/DebugTracer.cs @@ -7,6 +7,7 @@ using System.Threading; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing.Debugger; @@ -187,10 +188,10 @@ public void CheckBreakPoint() } } - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) => InnerTracer.MarkAsSuccess(recipient, gasSpent, output, logs, stateRoot); - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string error, Hash256? stateRoot = null) => InnerTracer.MarkAsFailed(recipient, gasSpent, output, error, stateRoot); public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs index 4e21841e5b9..447394dd716 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs @@ -6,6 +6,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing @@ -35,16 +36,16 @@ public EstimateGasTracer() public byte StatusCode { get; set; } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { - GasSpent = gasSpent; + GasSpent = gasSpent.SpentGas; ReturnValue = output; StatusCode = Evm.StatusCode.Success; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[]? output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { - GasSpent = gasSpent; + GasSpent = gasSpent.SpentGas; Error = error; ReturnValue = output ?? []; StatusCode = Evm.StatusCode.Failure; diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs b/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs index a673ef8b657..4bed1b2c603 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs @@ -50,13 +50,13 @@ public GasEstimator(ITransactionProcessor transactionProcessor, IReadOnlyStatePr return gasTracer.CalculateAdditionalGasRequired(tx, releaseSpec); } - long intrinsicGas = IntrinsicGasCalculator.Calculate(tx, releaseSpec); + var lowerBound = IntrinsicGasCalculator.Calculate(tx, releaseSpec).MinimalGas; // Setting boundaries for binary search - determine lowest and highest gas can be used during the estimation: - long leftBound = (gasTracer.GasSpent != 0 && gasTracer.GasSpent >= intrinsicGas) + long leftBound = (gasTracer.GasSpent != 0 && gasTracer.GasSpent >= lowerBound) ? gasTracer.GasSpent - 1 - : intrinsicGas - 1; - long rightBound = (tx.GasLimit != 0 && tx.GasLimit >= intrinsicGas) + : lowerBound - 1; + long rightBound = (tx.GasLimit != 0 && tx.GasLimit >= lowerBound) ? tx.GasLimit : header.GasLimit; @@ -132,11 +132,11 @@ public OutOfGasTracer() public override bool IsTracingActions => true; public bool OutOfGas { get; private set; } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs index dde143ac7e3..208a54882ee 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/JavaScript/GethLikeJavaScriptTxTracer.cs @@ -8,6 +8,7 @@ using Nethermind.Core; using Nethermind.Int256; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; namespace Nethermind.Evm.Tracing.GethStyle.Custom.JavaScript; @@ -169,18 +170,18 @@ private void InvokeExit(long gas, ReadOnlyMemory output, string? error = n _depth--; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[]? output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { base.MarkAsFailed(recipient, gasSpent, output, error, stateRoot); - _ctx.gasUsed = gasSpent; + _ctx.gasUsed = gasSpent.SpentGas; _ctx.Output = output; _ctx.error = error; } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { base.MarkAsSuccess(recipient, gasSpent, output, logs, stateRoot); - _ctx.gasUsed = gasSpent; + _ctx.gasUsed = gasSpent.SpentGas; _ctx.Output = output; } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Call/NativeCallTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Call/NativeCallTracer.cs index 032f37be17a..e968124aca5 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Call/NativeCallTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Call/NativeCallTracer.cs @@ -8,6 +8,7 @@ using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; using Nethermind.Serialization.Json; @@ -160,19 +161,19 @@ public override void ReportSelfDestruct(Address address, UInt256 balance, Addres } } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { base.MarkAsSuccess(recipient, gasSpent, output, logs, stateRoot); NativeCallTracerCallFrame firstCallFrame = _callStack[0]; - firstCallFrame.GasUsed = gasSpent; + firstCallFrame.GasUsed = gasSpent.SpentGas; firstCallFrame.Output = new ArrayPoolList(output.Length, output); } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[]? output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { base.MarkAsFailed(recipient, gasSpent, output, error, stateRoot); NativeCallTracerCallFrame firstCallFrame = _callStack[0]; - firstCallFrame.GasUsed = gasSpent; + firstCallFrame.GasUsed = gasSpent.SpentGas; if (output is not null) firstCallFrame.Output = new ArrayPoolList(output.Length, output); diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Prestate/NativePrestateTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Prestate/NativePrestateTracer.cs index f880d2bccc8..c0b3915d230 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Prestate/NativePrestateTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/Custom/Native/Prestate/NativePrestateTracer.cs @@ -7,6 +7,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; using Nethermind.Serialization.Json; using Nethermind.State; @@ -73,14 +74,14 @@ public override GethLikeTxTrace BuildResult() return result; } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { base.MarkAsSuccess(recipient, gasSpent, output, logs, stateRoot); if (_diffMode) ProcessDiffState(); } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[]? output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { base.MarkAsFailed(recipient, gasSpent, output, error, stateRoot); if (_diffMode) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxMemoryTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxMemoryTracer.cs index c6b64574ecc..7b1bf902e3f 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxMemoryTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxMemoryTracer.cs @@ -6,6 +6,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing.GethStyle; @@ -14,11 +15,11 @@ public class GethLikeTxMemoryTracer : GethLikeTxTracer { public GethLikeTxMemoryTracer(GethTraceOptions options) : base(options) => IsTracingMemory = IsTracingFullMemory; - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { base.MarkAsSuccess(recipient, gasSpent, output, logs, stateRoot); - Trace.Gas = gasSpent; + Trace.Gas = gasSpent.SpentGas; } public override void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs index e9cface33be..6ab13cdf9a1 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs @@ -4,6 +4,7 @@ using System; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; namespace Nethermind.Evm.Tracing.GethStyle; @@ -29,12 +30,12 @@ protected GethLikeTxTracer(GethTraceOptions options) public sealed override bool IsTracingStack { get; protected set; } protected bool IsTracingFullMemory { get; } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { Trace.ReturnValue = output; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[]? output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { Trace.Failed = true; Trace.ReturnValue = output ?? []; diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs index 876844c3673..8e038a6691b 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; using Nethermind.State.Tracing; @@ -158,7 +159,7 @@ public interface ITxTracer : IWorldStateTracer, IDisposable /// Logs for transaction /// State root after transaction, depends on EIP-658 /// Depends on - void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null); + void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null); /// /// Transaction failed @@ -169,7 +170,7 @@ public interface ITxTracer : IWorldStateTracer, IDisposable /// Error that failed the transaction /// State root after transaction, depends on EIP-658 /// Depends on - void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string? error, Hash256? stateRoot = null); + void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null); /// /// diff --git a/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs index 06d2ed89517..b8d3f6613a9 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing; @@ -22,9 +23,9 @@ private NullTxTracer() { } [StackTraceHidden] private static void ThrowInvalidOperationException() => throw new InvalidOperationException(ErrorMessage); - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) => ThrowInvalidOperationException(); - public override void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) => ThrowInvalidOperationException(); public override void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env) => ThrowInvalidOperationException(); diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs index 9418785abd3..bb68ecc2dbd 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs @@ -8,6 +8,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing.ParityStyle @@ -187,7 +188,7 @@ private void PopAction() _currentAction = _actionStack.Count == 0 ? null : _actionStack.Peek(); } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { if (_currentAction is not null) { @@ -202,7 +203,7 @@ public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] outp _trace.Action!.Result!.Output = output; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { if (_currentAction is not null) { diff --git a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs index 3fcc82c3bdf..a83c902ced9 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs @@ -5,19 +5,13 @@ using System.Collections.Generic; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing.Proofs { - public class ProofTxTracer : TxTracer + public class ProofTxTracer(bool treatSystemAccountDifferently) : TxTracer { - private readonly bool _treatSystemAccountDifferently; - - public ProofTxTracer(bool treatSystemAccountDifferently) - { - _treatSystemAccountDifferently = treatSystemAccountDifferently; - } - public HashSet
Accounts { get; } = new(); public HashSet Storages { get; } = new(); @@ -38,7 +32,7 @@ public override void ReportBlockHash(Hash256 blockHash) public override void ReportBalanceChange(Address address, UInt256? before, UInt256? after) { - if (_treatSystemAccountDifferently && Address.SystemUser == address && before is null && after?.IsZero != false) + if (treatSystemAccountDifferently && Address.SystemUser == address && before is null && after?.IsZero != false) { return; } @@ -48,7 +42,7 @@ public override void ReportBalanceChange(Address address, UInt256? before, UInt2 public override void ReportCodeChange(Address address, byte[]? before, byte[]? after) { - if (_treatSystemAccountDifferently && Address.SystemUser == address && before is null && after == Array.Empty()) + if (treatSystemAccountDifferently && Address.SystemUser == address && before is null && after == Array.Empty()) { return; } @@ -58,7 +52,7 @@ public override void ReportCodeChange(Address address, byte[]? before, byte[]? a public override void ReportNonceChange(Address address, UInt256? before, UInt256? after) { - if (_treatSystemAccountDifferently && Address.SystemUser == address && before is null && after?.IsZero != false) + if (treatSystemAccountDifferently && Address.SystemUser == address && before is null && after?.IsZero != false) { return; } @@ -85,12 +79,12 @@ public override void ReportAccountRead(Address address) Accounts.Add(address); } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { Output = output; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { Output = output; } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs index dee699912cc..8676caed544 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/TxTracer.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Int256; namespace Nethermind.Evm.Tracing; @@ -50,8 +51,8 @@ public virtual void ReportAccountRead(Address address) { } public virtual void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value) { } public virtual void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[] after) { } public virtual void ReportStorageRead(in StorageCell storageCell) { } - public virtual void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { } - public virtual void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256? stateRoot = null) { } + public virtual void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { } + public virtual void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { } public virtual void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env) { } public virtual void ReportOperationError(EvmExceptionType error) { } public virtual void ReportOperationRemainingGas(long gas) { } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/GasConsumed.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/GasConsumed.cs new file mode 100644 index 00000000000..0de17e147eb --- /dev/null +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/GasConsumed.cs @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Evm.TransactionProcessing; + +public readonly record struct GasConsumed(long SpentGas, long OperationGas) +{ + public static implicit operator long(GasConsumed gas) => gas.SpentGas; + public static implicit operator GasConsumed(long spentGas) => new(spentGas, spentGas); +} diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs index dfcc817703e..6e3190a9e9f 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/SystemTransactionProcessor.cs @@ -46,7 +46,7 @@ protected override TransactionResult Execute(Transaction tx, in BlockExecutionCo protected override IReleaseSpec GetSpec(Transaction tx, BlockHeader header) => new SystemTransactionReleaseSpec(base.GetSpec(tx, header), _isAura, header.IsGenesis); - protected override TransactionResult ValidateGas(Transaction tx, BlockHeader header, long intrinsicGas, bool validate) => TransactionResult.Ok; + protected override TransactionResult ValidateGas(Transaction tx, BlockHeader header, long minGasRequired, bool validate) => TransactionResult.Ok; protected override TransactionResult IncrementNonce(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts) => TransactionResult.Ok; diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index c09b858f389..98ba3f4fe83 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -143,7 +143,8 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon bool commit = opts.HasFlag(ExecutionOptions.Commit) || (!opts.HasFlag(ExecutionOptions.SkipValidation) && !spec.IsEip658Enabled); TransactionResult result; - if (!(result = ValidateStatic(tx, header, spec, opts, out long intrinsicGas))) return result; + IntrinsicGas intrinsicGas = IntrinsicGasCalculator.Calculate(tx, spec); + if (!(result = ValidateStatic(tx, header, spec, opts, in intrinsicGas))) return result; UInt256 effectiveGasPrice = tx.CalculateEffectiveGasPrice(spec.IsEip1559Enabled, header.BaseFeePerGas); @@ -164,9 +165,9 @@ protected virtual TransactionResult Execute(Transaction tx, in BlockExecutionCon ExecutionEnvironment env = BuildExecutionEnvironment(tx, in blCtx, spec, effectiveGasPrice, _codeInfoRepository, accessTracker); - long gasAvailable = tx.GasLimit - intrinsicGas; - ExecuteEvmCall(tx, header, spec, tracer, opts, delegationRefunds, accessTracker, gasAvailable, env, out TransactionSubstate? substate, out long spentGas, out byte statusCode); - PayFees(tx, header, spec, tracer, substate, spentGas, premiumPerGas, blobBaseFee, statusCode); + long gasAvailable = tx.GasLimit - intrinsicGas.Standard; + ExecuteEvmCall(tx, header, spec, tracer, opts, delegationRefunds, intrinsicGas.FloorGas, accessTracker, gasAvailable, env, out TransactionSubstate? substate, out GasConsumed spentGas, out byte statusCode); + PayFees(tx, header, spec, tracer, substate, spentGas.SpentGas, premiumPerGas, blobBaseFee, statusCode); // Finalize if (restore) @@ -338,15 +339,15 @@ private static void UpdateMetrics(ExecutionOptions opts, UInt256 effectiveGasPri /// The release spec with which the transaction will be executed /// Options (Flags) to use for execution /// Calculated intrinsic gas + /// /// protected virtual TransactionResult ValidateStatic( Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, - out long intrinsicGas) + in IntrinsicGas intrinsicGas) { - intrinsicGas = IntrinsicGasCalculator.Calculate(tx, spec); bool validate = !opts.HasFlag(ExecutionOptions.SkipValidation); @@ -373,15 +374,15 @@ protected virtual TransactionResult ValidateStatic( return TransactionResult.TransactionSizeOverMaxInitCodeSize; } - return ValidateGas(tx, header, intrinsicGas, validate); + return ValidateGas(tx, header, intrinsicGas.MinimalGas, validate); } - protected virtual TransactionResult ValidateGas(Transaction tx, BlockHeader header, long intrinsicGas, bool validate) + protected virtual TransactionResult ValidateGas(Transaction tx, BlockHeader header, long minGasRequired, bool validate) { - if (tx.GasLimit < intrinsicGas) + if (tx.GasLimit < minGasRequired) { - TraceLogInvalidTx(tx, $"GAS_LIMIT_BELOW_INTRINSIC_GAS {tx.GasLimit} < {intrinsicGas}"); - return TransactionResult.GasLimitBelowIntrinsicGas; + TraceLogInvalidTx(tx, $"GAS_LIMIT_BELOW_INTRINSIC_GAS {tx.GasLimit} < {minGasRequired}"); + return "gas limit below intrinsic gas"; } if (validate && tx.GasLimit > header.GasLimit - header.GasUsed) @@ -589,17 +590,18 @@ protected virtual void ExecuteEvmCall( ITxTracer tracer, ExecutionOptions opts, int delegationRefunds, + long floorGas, in StackAccessTracker accessedItems, in long gasAvailable, in ExecutionEnvironment env, out TransactionSubstate? substate, - out long spentGas, + out GasConsumed gasConsumed, out byte statusCode) { _ = ShouldValidate(opts); substate = null; - spentGas = tx.GasLimit; + gasConsumed = tx.GasLimit; statusCode = StatusCode.Failure; long unspentGas = gasAvailable; @@ -685,7 +687,8 @@ protected virtual void ExecuteEvmCall( statusCode = StatusCode.Success; } - spentGas = Refund(tx, header, spec, opts, substate, unspentGas, env.TxExecutionContext.GasPrice, delegationRefunds); + gasConsumed = Refund(tx, header, spec, opts, substate, unspentGas, + env.TxExecutionContext.GasPrice, delegationRefunds, floorGas); goto Complete; } catch (Exception ex) when (ex is EvmException or OverflowException) // TODO: OverflowException? still needed? hope not @@ -698,7 +701,7 @@ protected virtual void ExecuteEvmCall( Complete: if (!opts.HasFlag(ExecutionOptions.SkipValidation)) - header.GasUsed += spentGas; + header.GasUsed += gasConsumed.SpentGas; } protected virtual void PayValue(Transaction tx, IReleaseSpec spec, ExecutionOptions opts) @@ -748,15 +751,18 @@ protected void TraceLogInvalidTx(Transaction transaction, string reason) if (Logger.IsTrace) Logger.Trace($"Invalid tx {transaction.Hash} ({reason})"); } - protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, - in TransactionSubstate substate, in long unspentGas, in UInt256 gasPrice, int codeInsertRefunds) + protected virtual GasConsumed Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, + in TransactionSubstate substate, in long unspentGas, in UInt256 gasPrice, int codeInsertRefunds, long floorGas) { long spentGas = tx.GasLimit; + long operationGas = tx.GasLimit; var codeInsertRefund = (GasCostOf.NewAccount - GasCostOf.PerAuthBaseCost) * codeInsertRefunds; if (!substate.IsError) { spentGas -= unspentGas; + operationGas -= unspentGas; + spentGas = Math.Max(spentGas, floorGas); long totalToRefund = codeInsertRefund; if (!substate.ShouldRevert) @@ -769,6 +775,7 @@ protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec s if (!opts.HasFlag(ExecutionOptions.SkipValidation)) WorldState.AddToBalance(tx.SenderAddress!, (ulong)(unspentGas + actualRefund) * gasPrice, spec); spentGas -= actualRefund; + operationGas -= actualRefund; } else if (codeInsertRefund > 0) { @@ -780,9 +787,10 @@ protected virtual long Refund(Transaction tx, BlockHeader header, IReleaseSpec s if (!opts.HasFlag(ExecutionOptions.SkipValidation)) WorldState.AddToBalance(tx.SenderAddress!, (ulong)refund * gasPrice, spec); spentGas -= refund; + operationGas -= refund; } - return spentGas; + return new GasConsumed(spentGas, operationGas); } [DoesNotReturn] diff --git a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs index 42e3c884e2f..3d7800d6fe9 100644 --- a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs +++ b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs @@ -225,6 +225,7 @@ public CallOutput CreateAccessList(BlockHeader header, Transaction tx, Cancellat { Error = tryCallResult.Success ? callOutputTracer.Error : tryCallResult.Error, GasSpent = accessTxTracer.GasSpent, + OperationGas = callOutputTracer.OperationGas, OutputData = callOutputTracer.ReturnValue, InputError = !tryCallResult.Success, AccessList = accessTxTracer.AccessList diff --git a/src/Nethermind/Nethermind.Facade/CallOutput.cs b/src/Nethermind/Nethermind.Facade/CallOutput.cs index 0343d3aca3e..550d90dd279 100644 --- a/src/Nethermind/Nethermind.Facade/CallOutput.cs +++ b/src/Nethermind/Nethermind.Facade/CallOutput.cs @@ -12,6 +12,7 @@ public class CallOutput public byte[] OutputData { get; set; } = []; public long GasSpent { get; set; } + public long OperationGas { get; set; } public bool InputError { get; set; } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs index 0f49c9494c1..a30f942cdce 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs @@ -9,6 +9,7 @@ using Nethermind.Core.Crypto; using Nethermind.Evm; using Nethermind.Evm.Tracing; +using Nethermind.Evm.TransactionProcessing; using Nethermind.Facade.Proxy.Models.Simulate; using Nethermind.Int256; using Log = Nethermind.Facade.Proxy.Models.Simulate.Log; @@ -55,12 +56,11 @@ public override void ReportAction(long gas, UInt256 value, Address from, Address } } - public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, - Hash256? stateRoot = null) + public override void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null) { TraceResult = new SimulateCallResult { - GasUsed = (ulong)gasSpent, + GasUsed = (ulong)gasSpent.SpentGas, ReturnData = output, Status = StatusCode.Success, Logs = logs.Select((entry, i) => new Log @@ -77,12 +77,11 @@ public override void MarkAsSuccess(Address recipient, long gasSpent, byte[] outp }; } - public override void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, - Hash256? stateRoot = null) + public override void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null) { TraceResult = new SimulateCallResult { - GasUsed = (ulong)gasSpent, + GasUsed = (ulong)gasSpent.SpentGas, Error = new Error { Message = error diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.TransactionExecutor.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.TransactionExecutor.cs index 5f573a07c3f..9222731565f 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.TransactionExecutor.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.TransactionExecutor.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using Nethermind.Blockchain.Find; using Nethermind.Core; @@ -114,12 +115,21 @@ private class CreateAccessListTxExecutor(IBlockchainBridge blockchainBridge, IBl private static UInt256 GetResultGas(Transaction transaction, CallOutput result) { long gas = result.GasSpent; + long operationGas = result.OperationGas; if (result.AccessList is not null) { - // if we generated access list, we need to fix actual gas cost, as all storage was considered warm - gas -= IntrinsicGasCalculator.Calculate(transaction, Berlin.Instance); + var oldIntrinsicCost = IntrinsicGasCalculator.AccessListCost(transaction, Berlin.Instance); transaction.AccessList = result.AccessList; - gas += IntrinsicGasCalculator.Calculate(transaction, Berlin.Instance); + var newIntrinsicCost = IntrinsicGasCalculator.AccessListCost(transaction, Berlin.Instance); + long updatedAccessListCost = newIntrinsicCost - oldIntrinsicCost; + if (gas > operationGas) + { + if (gas - operationGas < updatedAccessListCost) gas = operationGas + updatedAccessListCost; + } + else + { + gas += updatedAccessListCost; + } } return (UInt256)gas; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs index b13b19502cc..af6a12e9134 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs @@ -151,8 +151,8 @@ protected override void PayFees(Transaction tx, BlockHeader header, IReleaseSpec } } - protected override long Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, - in TransactionSubstate substate, in long unspentGas, in UInt256 gasPrice, int refunds) + protected override GasConsumed Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, + in TransactionSubstate substate, in long unspentGas, in UInt256 gasPrice, int codeInsertRefunds, long floorGas) { // if deposit: skip refunds, skip tipping coinbase // Regolith changes this behaviour to report the actual gasUsed instead of always reporting all gas used. @@ -160,9 +160,10 @@ protected override long Refund(Transaction tx, BlockHeader header, IReleaseSpec { // Record deposits as using all their gas // System Transactions are special & are not recorded as using any gas (anywhere) - return tx.IsOPSystemTransaction ? 0 : tx.GasLimit; + var gas = tx.IsOPSystemTransaction ? 0 : tx.GasLimit; + return gas; } - return base.Refund(tx, header, spec, opts, substate, unspentGas, gasPrice, refunds); + return base.Refund(tx, header, spec, opts, substate, unspentGas, gasPrice, codeInsertRefunds, floorGas); } } diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs index 1187f58d568..4085e4e06a3 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs @@ -122,6 +122,7 @@ public bool IsOntakeEnabled get => _isOntakeEnabled ?? _spec.IsOntakeEnabled; set => _isOntakeEnabled = value; } + public bool IsEip7623Enabled => _spec.IsEip7623Enabled; public bool IsEip3607Enabled { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs index 72badcbc77a..ba6959f71cd 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs @@ -131,6 +131,7 @@ public class ChainParameters public ulong? Eip7702TransitionTimestamp { get; set; } public ulong? OpGraniteTransitionTimestamp { get; set; } public ulong? OpHoloceneTransitionTimestamp { get; set; } + public ulong? Eip7623TransitionTimestamp { get; set; } #region EIP-4844 parameters /// diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index ca46a2ce93f..00cce5ab6fd 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -233,6 +233,7 @@ private ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseStartBloc releaseSpec.IsEip7251Enabled = (chainSpec.Parameters.Eip7251TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.Eip7251ContractAddress = chainSpec.Parameters.Eip7251ContractAddress; + releaseSpec.IsEip7623Enabled = (chainSpec.Parameters.Eip7623TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsOntakeEnabled = (chainSpec.Parameters.OntakeTransition ?? long.MaxValue) <= releaseStartBlock; diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index dc7b75faa8b..07b25396a8d 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -160,6 +160,7 @@ bool GetForInnerPathExistence(KeyValuePair o) => Eip6110TransitionTimestamp = chainSpecJson.Params.Eip6110TransitionTimestamp, DepositContractAddress = chainSpecJson.Params.DepositContractAddress ?? Eip6110Constants.MainnetDepositContractAddress, Eip7002TransitionTimestamp = chainSpecJson.Params.Eip7002TransitionTimestamp, + Eip7623TransitionTimestamp = chainSpecJson.Params.Eip7623TransitionTimestamp, Eip7002ContractAddress = chainSpecJson.Params.Eip7002ContractAddress ?? Eip7002Constants.WithdrawalRequestPredeployAddress, Eip7251TransitionTimestamp = chainSpecJson.Params.Eip7251TransitionTimestamp, Eip7251ContractAddress = chainSpecJson.Params.Eip7251ContractAddress ?? Eip7251Constants.ConsolidationRequestPredeployAddress, diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs index ff9e33274c6..1c65c71e133 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs @@ -154,6 +154,7 @@ internal class ChainSpecParamsJson public ulong? Eip6110TransitionTimestamp { get; set; } public Address DepositContractAddress { get; set; } public ulong? Eip7002TransitionTimestamp { get; set; } + public ulong? Eip7623TransitionTimestamp { get; set; } public Address Eip7002ContractAddress { get; set; } public ulong? Eip7251TransitionTimestamp { get; set; } public Address Eip7251ContractAddress { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs index 46550401b5f..ab2937f6eb5 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs @@ -20,6 +20,7 @@ protected Prague() IsEip6110Enabled = true; IsEip7002Enabled = true; IsEip7251Enabled = true; + IsEip7623Enabled = true; Eip2935ContractAddress = Eip2935Constants.BlockHashHistoryAddress; } diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index f01c3fa9f91..f5727f711d0 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -85,6 +85,7 @@ public bool IsEip1559Enabled public bool IsRip7212Enabled { get; set; } public bool IsOpGraniteEnabled { get; set; } public bool IsOpHoloceneEnabled { get; set; } + public bool IsEip7623Enabled { get; set; } public bool IsEip5656Enabled { get; set; } public bool IsEip6780Enabled { get; set; } public bool IsEip4788Enabled { get; set; } diff --git a/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs b/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs index 4bd8f8965b2..0f7891a68fd 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoTransactionProcessor.cs @@ -22,16 +22,16 @@ public class TaikoTransactionProcessor( ) : TransactionProcessorBase(specProvider, worldState, virtualMachine, codeInfoRepository, logManager) { protected override TransactionResult ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, - out long intrinsicGas) - => base.ValidateStatic(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, out intrinsicGas); + in IntrinsicGas intrinsicGas) + => base.ValidateStatic(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, in intrinsicGas); protected override TransactionResult BuyGas(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, in UInt256 effectiveGasPrice, out UInt256 premiumPerGas, out UInt256 senderReservedGasPayment, out UInt256 blobBaseFee) => base.BuyGas(tx, header, spec, tracer, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, in effectiveGasPrice, out premiumPerGas, out senderReservedGasPayment, out blobBaseFee); - protected override long Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, - in TransactionSubstate substate, in long unspentGas, in UInt256 gasPrice, int codeInsertRefunds) - => base.Refund(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, substate, unspentGas, gasPrice, codeInsertRefunds); + protected override GasConsumed Refund(Transaction tx, BlockHeader header, IReleaseSpec spec, ExecutionOptions opts, + in TransactionSubstate substate, in long unspentGas, in UInt256 gasPrice, int codeInsertRefunds, long floorGas) + => base.Refund(tx, header, spec, tx.IsAnchorTx ? opts | ExecutionOptions.SkipValidationAndCommit : opts, substate, unspentGas, gasPrice, codeInsertRefunds, floorGas); protected override void PayFees(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, in TransactionSubstate substate, in long spentGas, in UInt256 premiumPerGas, in UInt256 blobBaseFee, in byte statusCode) { diff --git a/src/Nethermind/Nethermind.Test.Runner/StateTestRunner.cs b/src/Nethermind/Nethermind.Test.Runner/StateTestRunner.cs index b44812e2d8e..6519c6a1f9a 100644 --- a/src/Nethermind/Nethermind.Test.Runner/StateTestRunner.cs +++ b/src/Nethermind/Nethermind.Test.Runner/StateTestRunner.cs @@ -91,7 +91,7 @@ public IEnumerable RunTests() var txTrace = txTracer.BuildResult(); txTrace.Result.Time = result.TimeInMs; txTrace.State.StateRoot = result.StateRoot; - txTrace.Result.GasUsed -= IntrinsicGasCalculator.Calculate(test.Transaction, test.Fork); + txTrace.Result.GasUsed -= IntrinsicGasCalculator.Calculate(test.Transaction, test.Fork).Standard; WriteErr(txTrace); } diff --git a/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs b/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs index 2d00f475f49..d19098ec3ef 100644 --- a/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs +++ b/src/Nethermind/Nethermind.Test.Runner/StateTestTxTracer.cs @@ -9,6 +9,7 @@ using Nethermind.Int256; using Nethermind.Evm; using Nethermind.Evm.Tracing; +using Nethermind.Evm.TransactionProcessing; namespace Nethermind.Test.Runner; @@ -36,13 +37,13 @@ public class StateTestTxTracer : ITxTracer, IDisposable public bool IsTracing => IsTracingReceipt || IsTracingActions || IsTracingOpLevelStorage || IsTracingMemory || IsTracingInstructions || IsTracingRefunds || IsTracingCode || IsTracingStack || IsTracingBlockHash || IsTracingAccess || IsTracingFees || IsTracingLogs; - public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256 stateRoot = null) + public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256 stateRoot = null) { _trace.Result.Output = output; _trace.Result.GasUsed = gasSpent; } - public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Hash256 stateRoot = null) + public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string error, Hash256 stateRoot = null) { _trace.Result.Error = _traceEntry?.Error ?? error; _trace.Result.Output = output ?? Bytes.Empty; From e50539b72258eab090c8ecf9cd1ec87c6181113f Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 5 Jan 2025 12:17:08 +0000 Subject: [PATCH 073/113] Back Bloom with inline array rather than byte[] (#8009) --- .../Nethermind.Core.Test/BloomTests.cs | 2 +- src/Nethermind/Nethermind.Core/Bloom.cs | 31 +++++++++++-------- .../Extensions/SpanExtensions.cs | 4 +++ .../Nethermind.Db/Blooms/BloomStorage.cs | 2 +- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Nethermind/Nethermind.Core.Test/BloomTests.cs b/src/Nethermind/Nethermind.Core.Test/BloomTests.cs index ec802f49e4a..fdf90eff785 100644 --- a/src/Nethermind/Nethermind.Core.Test/BloomTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/BloomTests.cs @@ -18,7 +18,7 @@ public void Test() { Bloom bloom = new(); bloom.Set(Keccak.OfAnEmptyString.Bytes); - byte[] bytes = bloom.Bytes; + ReadOnlySpan bytes = bloom.Bytes; Bloom bloom2 = new(bytes); Assert.That(bloom2.ToString(), Is.EqualTo(bloom.ToString())); } diff --git a/src/Nethermind/Nethermind.Core/Bloom.cs b/src/Nethermind/Nethermind.Core/Bloom.cs index 50673c9ee30..2eb42c42113 100644 --- a/src/Nethermind/Nethermind.Core/Bloom.cs +++ b/src/Nethermind/Nethermind.Core/Bloom.cs @@ -2,8 +2,9 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text.Json.Serialization; - using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Serialization.Json; @@ -17,10 +18,9 @@ public class Bloom : IEquatable public const int BitLength = 2048; public const int ByteLength = BitLength / 8; - public Bloom() - { - Bytes = new byte[ByteLength]; - } + private BloomData _bloomData; + + public Bloom() { } public Bloom(Bloom?[] blooms) : this() { @@ -34,8 +34,6 @@ public Bloom(Bloom?[] blooms) : this() public Bloom(LogEntry[]? logEntries, Bloom? blockBloom = null) { - Bytes = new byte[ByteLength]; - if (logEntries is null) return; Add(logEntries, blockBloom); @@ -43,15 +41,15 @@ public Bloom(LogEntry[]? logEntries, Bloom? blockBloom = null) public Bloom(byte[] bytes) { - Bytes = bytes; + bytes.CopyTo(Bytes); } public Bloom(ReadOnlySpan bytes) { - Bytes = bytes.ToArray(); + bytes.CopyTo(Bytes); } - public byte[] Bytes { get; } + public Span Bytes => _bloomData.AsSpan(); public void Set(ReadOnlySpan sequence) { @@ -119,7 +117,7 @@ public override bool Equals(object? obj) return Equals((Bloom)obj); } - public override int GetHashCode() => new ReadOnlySpan(Bytes).FastHash(); + public override int GetHashCode() => Bytes.FastHash(); public void Add(LogEntry[] logEntries, Bloom? blockBloom = null) { @@ -144,7 +142,7 @@ public void Accumulate(Bloom? bloom) return; } - Bytes.AsSpan().Or(bloom.Bytes); + Bytes.Or(bloom.Bytes); } public bool Matches(LogEntry logEntry) @@ -223,9 +221,16 @@ public BloomExtract(int index1, int index2, int index3) public Bloom Clone() { Bloom clone = new(); - Bytes.CopyTo(clone.Bytes, 0); + Bytes.CopyTo(clone.Bytes); return clone; } + + [InlineArray(ByteLength)] + public struct BloomData + { + private byte _element0; + public Span AsSpan() => MemoryMarshal.CreateSpan(ref _element0, ByteLength); + } } public ref struct BloomStructRef diff --git a/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs index a7fcbdd71a3..f053b5ce226 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/SpanExtensions.cs @@ -173,6 +173,10 @@ public static ArrayPoolList ToPooledList(this in ReadOnlySpan span) return newList; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int FastHash(this Span input) + => FastHash((ReadOnlySpan)input); + [SkipLocalsInit] public static int FastHash(this ReadOnlySpan input) { diff --git a/src/Nethermind/Nethermind.Db/Blooms/BloomStorage.cs b/src/Nethermind/Nethermind.Db/Blooms/BloomStorage.cs index 9570e4e41f5..b94e2bd4d64 100644 --- a/src/Nethermind/Nethermind.Db/Blooms/BloomStorage.cs +++ b/src/Nethermind/Nethermind.Db/Blooms/BloomStorage.cs @@ -283,7 +283,7 @@ public void Store(long blockNumber, Bloom bloom) } } - private static uint CountBits(Bloom bloom) => bloom.Bytes.AsSpan().CountBits(); + private static uint CountBits(Bloom bloom) => bloom.Bytes.CountBits(); public long GetBucket(long blockNumber) => blockNumber / LevelElementSize; From 9a07a4a08b5fdf05400aa12b2e004906ae3d8369 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Mon, 6 Jan 2025 08:56:37 +0000 Subject: [PATCH 074/113] Back signature by Vector512 rather than byte[] (#8008) --- .../Ethereum.Basic.Test/TransactionTests.cs | 8 ++-- .../Consensus/ClefSignerTests.cs | 2 +- .../Consensus/NullSignerTests.cs | 2 +- .../Consensus/SignerTests.cs | 2 +- .../CliqueSealer.cs | 4 +- .../Crypto/SignatureTests.cs | 2 +- .../Nethermind.Core/Crypto/Signature.cs | 40 ++++++++++++------- .../Nethermind.Core/Extensions/Bytes.cs | 8 ++++ src/Nethermind/Nethermind.Core/Transaction.cs | 2 +- .../RpcTransaction/AuthorizationListForRpc.cs | 4 +- .../RpcTransaction/LegacyTransactionForRpc.cs | 16 ++++++-- .../Modules/Eth/EthRpcSimulateTestsBase.cs | 2 +- .../Modules/Eth/EthRpcModule.cs | 8 ++-- .../Modules/Eth/IEthRpcModule.cs | 3 +- .../Modules/Parity/ParityTransaction.cs | 7 ++-- .../Modules/Personal/IPersonalRpcModule.cs | 3 +- .../Modules/Personal/PersonalRpcModule.cs | 5 +-- .../Serializers/DiscoveryMsgSerializerBase.cs | 4 +- .../Eip7702/AuthorizationTupleDecoder.cs | 8 ++-- 19 files changed, 81 insertions(+), 49 deletions(-) diff --git a/src/Nethermind/Ethereum.Basic.Test/TransactionTests.cs b/src/Nethermind/Ethereum.Basic.Test/TransactionTests.cs index 4d1b4cfea7d..bef75e44fe9 100644 --- a/src/Nethermind/Ethereum.Basic.Test/TransactionTests.cs +++ b/src/Nethermind/Ethereum.Basic.Test/TransactionTests.cs @@ -50,9 +50,9 @@ public void Test(TransactionTest test) Transaction decodedSigned = Rlp.Decode(test.Signed); ethereumEcdsa.Sign(test.PrivateKey, decodedUnsigned, false); - Assert.That(decodedUnsigned.Signature.R, Is.EqualTo(decodedSigned.Signature.R), "R"); - BigInteger expectedS = decodedSigned.Signature.S.ToUnsignedBigInteger(); - BigInteger actualS = decodedUnsigned.Signature.S.ToUnsignedBigInteger(); + Assert.That(decodedUnsigned.Signature.R.Span.SequenceEqual(decodedSigned.Signature.R.Span), "R"); + BigInteger expectedS = decodedSigned.Signature.S.Span.ToUnsignedBigInteger(); + BigInteger actualS = decodedUnsigned.Signature.S.Span.ToUnsignedBigInteger(); BigInteger otherS = EthereumEcdsa.LowSTransform - actualS; // test does not use normalized signature @@ -62,7 +62,7 @@ public void Test(TransactionTest test) } ulong vToCompare = decodedUnsigned.Signature.V; - if (otherS == decodedSigned.Signature.S.ToUnsignedBigInteger()) + if (otherS == decodedSigned.Signature.S.Span.ToUnsignedBigInteger()) { vToCompare = vToCompare == 27ul ? 28ul : 27ul; } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/ClefSignerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/ClefSignerTests.cs index fec0f25713b..f0729770df6 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/ClefSignerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/ClefSignerTests.cs @@ -29,7 +29,7 @@ public async Task Sign_SigningHash_RequestHasCorrectParameters() var result = sut.Sign(Keccak.Zero); - Assert.That(new Signature(returnValue).Bytes, Is.EqualTo(result.Bytes)); + Assert.That(new Signature(returnValue).Bytes.SequenceEqual(result.Bytes)); } [Test] diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs index cfac44513dd..628ff7f9c60 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/NullSignerTests.cs @@ -27,7 +27,7 @@ public async Task Test_signing() { NullSigner signer = NullSigner.Instance; await signer.Sign((Transaction)null!); - signer.Sign((Hash256)null!).Bytes.Should().HaveCount(64); + signer.Sign((Hash256)null!).Bytes.Length.Should().Be(64); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs index 23957d53a0c..edd88c1a722 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Consensus/SignerTests.cs @@ -64,7 +64,7 @@ public async Task Test_signing() { Signer signer = new(1, TestItem.PrivateKeyA, LimboLogs.Instance); await signer.Sign(Build.A.Transaction.TestObject); - signer.Sign(Keccak.Zero).Bytes.Should().HaveCount(64); + signer.Sign(Keccak.Zero).Bytes.Length.Should().Be(64); } } } diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs index c445b5e591f..48e1d01c63f 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealer.cs @@ -77,8 +77,8 @@ public CliqueSealer(ISigner signer, ICliqueConfig config, ISnapshotManager snaps } // Copy signature bytes (R and S) - byte[] signatureBytes = signature.Bytes; - Array.Copy(signatureBytes, 0, header.ExtraData, header.ExtraData.Length - Clique.ExtraSealLength, signatureBytes.Length); + ReadOnlySpan signatureBytes = signature.Bytes; + signatureBytes.CopyTo(header.ExtraData.AsSpan(header.ExtraData.Length - Clique.ExtraSealLength)); // Copy signature's recovery id (V) byte recoveryId = signature.RecoveryId; header.ExtraData[^1] = recoveryId; diff --git a/src/Nethermind/Nethermind.Core.Test/Crypto/SignatureTests.cs b/src/Nethermind/Nethermind.Core.Test/Crypto/SignatureTests.cs index b521707ded0..d810fd16248 100644 --- a/src/Nethermind/Nethermind.Core.Test/Crypto/SignatureTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Crypto/SignatureTests.cs @@ -41,7 +41,7 @@ public void can_recover_from_message() var signatureObject = new Signature(signatureSlice, recoveryId); var keccak = Keccak.Compute(Bytes.Concat(messageType, data)); Span publicKey = stackalloc byte[65]; - bool result = SpanSecP256k1.RecoverKeyFromCompact(publicKey, keccak.Bytes, signatureObject.Bytes, signatureObject.RecoveryId, false); + bool result = SpanSecP256k1.RecoverKeyFromCompact(publicKey, keccak.Bytes, signatureObject.Bytes.ToArray(), signatureObject.RecoveryId, false); result.Should().BeTrue(); } } diff --git a/src/Nethermind/Nethermind.Core/Crypto/Signature.cs b/src/Nethermind/Nethermind.Core/Crypto/Signature.cs index 7f64c7b56a7..36823e91268 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Signature.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Signature.cs @@ -2,22 +2,25 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Buffers; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using Nethermind.Core.Attributes; using Nethermind.Core.Extensions; using Nethermind.Int256; namespace Nethermind.Core.Crypto { - public class Signature : IEquatable + public class Signature : MemoryManager, IEquatable { public const int VOffset = 27; + private Vector512 _signature; public Signature(ReadOnlySpan bytes, int recoveryId) { ArgumentOutOfRangeException.ThrowIfNotEqual(bytes.Length, 64); - bytes.CopyTo(Bytes.AsSpan()); + bytes.CopyTo(Bytes); V = (ulong)recoveryId + VOffset; } @@ -25,7 +28,7 @@ public Signature(ReadOnlySpan bytes) { ArgumentOutOfRangeException.ThrowIfNotEqual(bytes.Length, 65); - bytes[..64].CopyTo(Bytes.AsSpan()); + bytes[..64].CopyTo(Bytes); V = bytes[64]; } @@ -33,8 +36,9 @@ public Signature(ReadOnlySpan r, ReadOnlySpan s, ulong v) { ArgumentOutOfRangeException.ThrowIfLessThan(v, (ulong)VOffset); - r.CopyTo(Bytes.AsSpan(32 - r.Length, r.Length)); - s.CopyTo(Bytes.AsSpan(64 - s.Length, s.Length)); + Span span = Bytes; + r.CopyTo(span.Slice(32 - r.Length, r.Length)); + s.CopyTo(span.Slice(64 - s.Length, s.Length)); V = v; } @@ -42,8 +46,9 @@ public Signature(in UInt256 r, in UInt256 s, ulong v) { ArgumentOutOfRangeException.ThrowIfLessThan(v, (ulong)VOffset); - r.ToBigEndian(Bytes.AsSpan(0, 32)); - s.ToBigEndian(Bytes.AsSpan(32, 32)); + Span span = Bytes; + r.ToBigEndian(span.Slice(0, 32)); + s.ToBigEndian(span.Slice(32, 32)); V = v; } @@ -52,18 +57,19 @@ public Signature(string hexString) : this(Core.Extensions.Bytes.FromHexString(hexString)) { } + public Span Bytes => MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref _signature, 1)); + public override Memory Memory => CreateMemory(64); - public byte[] Bytes { get; } = new byte[64]; public ulong V { get; set; } public ulong? ChainId => V < 35 ? null : (ulong?)(V + (V % 2) - 36) / 2; public byte RecoveryId => V <= VOffset + 1 ? (byte)(V - VOffset) : (byte)(1 - V % 2); - public byte[] R => Bytes.Slice(0, 32); - public Span RAsSpan => Bytes.AsSpan(0, 32); - public byte[] S => Bytes.Slice(32, 32); - public Span SAsSpan => Bytes.AsSpan(32, 32); + public Memory R => Memory.Slice(0, 32); + public ReadOnlySpan RAsSpan => Bytes.Slice(0, 32); + public Memory S => Memory.Slice(32, 32); + public ReadOnlySpan SAsSpan => Bytes.Slice(32, 32); [Todo("Change signature to store 65 bytes and just slice it for normal Bytes.")] public byte[] BytesWithRecovery @@ -71,7 +77,7 @@ public byte[] BytesWithRecovery get { var result = new byte[65]; - Array.Copy(Bytes, result, 64); + Bytes.CopyTo(result); result[64] = RecoveryId; return result; } @@ -87,7 +93,7 @@ public bool Equals(Signature? other) { if (other is null) return false; if (ReferenceEquals(this, other)) return true; - return Core.Extensions.Bytes.AreEqual(Bytes, other.Bytes) && V == other.V; + return _signature == other._signature && V == other.V; } public override bool Equals(object? obj) @@ -102,5 +108,11 @@ public override int GetHashCode() { return MemoryMarshal.Read(Bytes); } + + public void Dispose() { } + protected override void Dispose(bool disposing) { } + public override Span GetSpan() => Bytes; + public override MemoryHandle Pin(int elementIndex = 0) => default; + public override void Unpin() { } } } diff --git a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs index 39d8429cec8..8a1705705cb 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs @@ -346,6 +346,14 @@ public static byte[] Concat(byte[] bytes, byte suffix) return result; } + public static byte[] Concat(ReadOnlySpan bytes, byte suffix) + { + byte[] result = new byte[bytes.Length + 1]; + result[^1] = suffix; + bytes.CopyTo(result); + return result; + } + public static byte[] Reverse(byte[] bytes) { byte[] result = new byte[bytes.Length]; diff --git a/src/Nethermind/Nethermind.Core/Transaction.cs b/src/Nethermind/Nethermind.Core/Transaction.cs index 8018975a0ce..8d7b10d2e76 100644 --- a/src/Nethermind/Nethermind.Core/Transaction.cs +++ b/src/Nethermind/Nethermind.Core/Transaction.cs @@ -231,7 +231,7 @@ public string ToString(string indent) builder.AppendLine($"{indent}Nonce: {Nonce}"); builder.AppendLine($"{indent}Value: {Value}"); builder.AppendLine($"{indent}Data: {(Data.AsArray() ?? []).ToHexString()}"); - builder.AppendLine($"{indent}Signature: {(Signature?.Bytes ?? []).ToHexString()}"); + builder.AppendLine($"{indent}Signature: {Signature?.Bytes.ToHexString()}"); builder.AppendLine($"{indent}V: {Signature?.V}"); builder.AppendLine($"{indent}ChainId: {Signature?.ChainId}"); builder.AppendLine($"{indent}Timestamp: {Timestamp}"); diff --git a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs index ec6f7407eef..38bc0484741 100644 --- a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs +++ b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs @@ -56,8 +56,8 @@ authorizationList is null tuple.Nonce, tuple.CodeAddress, tuple.AuthoritySignature.RecoveryId, - new UInt256(tuple.AuthoritySignature.S), - new UInt256(tuple.AuthoritySignature.R)))); + new UInt256(tuple.AuthoritySignature.S.Span), + new UInt256(tuple.AuthoritySignature.R.Span)))); public AuthorizationTuple[] ToAuthorizationList() => _tuples .Select(static tuple => new AuthorizationTuple( diff --git a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs index 3b77fc2dc88..d3940047940 100644 --- a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs +++ b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/LegacyTransactionForRpc.cs @@ -73,9 +73,19 @@ public LegacyTransactionForRpc(Transaction transaction, int? txIndex = null, Has GasPrice = transaction.GasPrice; ChainId = transaction.ChainId; - R = new UInt256(transaction.Signature?.R ?? [], true); - S = new UInt256(transaction.Signature?.S ?? [], true); - V = transaction.Signature?.V ?? 0; + Signature? signature = transaction.Signature; + if (signature is null) + { + R = UInt256.Zero; + S = UInt256.Zero; + V = 0; + } + else + { + R = new UInt256(signature.R.Span, true); + S = new UInt256(signature.S.Span, true); + V = signature.V; + } } public override Transaction ToTransaction() diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcSimulateTestsBase.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcSimulateTestsBase.cs index 50a822efecf..643bb241982 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcSimulateTestsBase.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/EthRpcSimulateTestsBase.cs @@ -127,7 +127,7 @@ protected static byte[] GenerateTransactionDataForEcRecover(Hash256 keccak, Sign { AbiDefinition call = new AbiDefinitionParser().Parse(GetEcRecoverContractJsonAbi(name)); AbiEncodingInfo functionInfo = call.GetFunction(name).GetCallInfo(); - return AbiEncoder.Instance.Encode(functionInfo.EncodingStyle, functionInfo.Signature, keccak, signature.V, signature.R, signature.S); + return AbiEncoder.Instance.Encode(functionInfo.EncodingStyle, functionInfo.Signature, keccak, signature.V, signature.R.ToArray(), signature.S.ToArray()); } private static Address? ParseEcRecoverAddress(byte[] data, string name = "recover") diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index f64a3a7cad0..3af1a71c3da 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -264,7 +264,7 @@ public ResultWrapper eth_getCode(Address address, BlockParameter? blockP : []); } - public ResultWrapper eth_sign(Address addressData, byte[] message) + public ResultWrapper> eth_sign(Address addressData, byte[] message) { Signature sig; try @@ -277,15 +277,15 @@ public ResultWrapper eth_sign(Address addressData, byte[] message) } catch (SecurityException e) { - return ResultWrapper.Fail(e.Message, ErrorCodes.AccountLocked); + return ResultWrapper>.Fail(e.Message, ErrorCodes.AccountLocked); } catch (Exception) { - return ResultWrapper.Fail($"Unable to sign as {addressData}"); + return ResultWrapper>.Fail($"Unable to sign as {addressData}"); } if (_logger.IsTrace) _logger.Trace($"eth_sign request {addressData}, {message}, result: {sig}"); - return ResultWrapper.Success(sig.Bytes); + return ResultWrapper>.Success(sig.Memory); } public virtual Task> eth_sendTransaction(TransactionForRpc rpcTx) diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs index 4e7f22a9665..70f98a767c3 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/IEthRpcModule.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Collections.Generic; using System.Threading.Tasks; using Nethermind.Blockchain.Find; @@ -132,7 +133,7 @@ public interface IEthRpcModule : IRpcModule ResultWrapper eth_getCode(Address address, BlockParameter? blockParameter = null); [JsonRpcMethod(IsImplemented = false, Description = "Signs a transaction", IsSharable = true)] - ResultWrapper eth_sign(Address addressData, byte[] message); + ResultWrapper> eth_sign(Address addressData, byte[] message); [JsonRpcMethod(IsImplemented = true, Description = "Send a transaction to the tx pool and broadcasting", diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Parity/ParityTransaction.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Parity/ParityTransaction.cs index e1217254547..5aeb8b1d20a 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Parity/ParityTransaction.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Parity/ParityTransaction.cs @@ -1,12 +1,13 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Text.Json.Serialization; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Int256; using Nethermind.Evm; -using System.Text.Json.Serialization; namespace Nethermind.JsonRpc.Modules.Parity { @@ -34,8 +35,8 @@ public class ParityTransaction public ulong? ChainId { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.Never)] public object Condition { get; set; } - public byte[] R { get; set; } - public byte[] S { get; set; } + public Memory R { get; set; } + public Memory S { get; set; } public UInt256 V { get; set; } public UInt256 StandardV { get; set; } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/IPersonalRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/IPersonalRpcModule.cs index 81805f149bd..8b280b7a07e 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/IPersonalRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/IPersonalRpcModule.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Facade.Eth.RpcTransaction; @@ -36,6 +37,6 @@ public interface IPersonalRpcModule : IRpcModule [JsonRpcMethod(Description = "The sign method calculates an Ethereum specific signature with: sign(keccack256(\"\x19Ethereum Signed Message:\n\" + len(message) + message))).", IsImplemented = false, ExampleResponse = "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b")] - ResultWrapper personal_sign([JsonRpcParameter(ExampleValue = "[\"0xdeadbeaf\", \"0x9b2055d370f73ec7d8a03e965129118dc8f5bf83\"]")] byte[] message, Address address, string passphrase = null); + ResultWrapper> personal_sign([JsonRpcParameter(ExampleValue = "[\"0xdeadbeaf\", \"0x9b2055d370f73ec7d8a03e965129118dc8f5bf83\"]")] byte[] message, Address address, string passphrase = null); } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/PersonalRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/PersonalRpcModule.cs index db941f73ed6..0967e9bd03f 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/PersonalRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Personal/PersonalRpcModule.cs @@ -15,7 +15,6 @@ namespace Nethermind.JsonRpc.Modules.Personal { public class PersonalRpcModule : IPersonalRpcModule { - private readonly Encoding _messageEncoding = Encoding.UTF8; private readonly IEcdsa _ecdsa; private readonly IWallet _wallet; private readonly IKeyStore _keyStore; @@ -84,7 +83,7 @@ private static byte[] ToEthSignedMessage(byte[] message) } [RequiresSecurityReview("Consider removing any operations that allow to provide passphrase in JSON RPC")] - public ResultWrapper personal_sign(byte[] message, Address address, string passphrase = null) + public ResultWrapper> personal_sign(byte[] message, Address address, string passphrase = null) { if (!_wallet.IsUnlocked(address)) { @@ -96,7 +95,7 @@ public ResultWrapper personal_sign(byte[] message, Address address, stri } message = ToEthSignedMessage(message); - return ResultWrapper.Success(_wallet.Sign(Keccak.Compute(message), address).Bytes); + return ResultWrapper>.Success(_wallet.Sign(Keccak.Compute(message), address).Memory); } } } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs index ff17a82c6f9..03b443249b7 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs @@ -48,7 +48,7 @@ protected void Serialize(byte type, Span data, IByteBuffer byteBuffer) Signature signature = _ecdsa.Sign(_privateKey, toSign); byteBuffer.SetWriterIndex(startWriteIndex + 32); - byteBuffer.WriteBytes(signature.Bytes, 0, 64); + byteBuffer.WriteBytes(signature.Bytes); byteBuffer.WriteByte(signature.RecoveryId); byteBuffer.SetReaderIndex(startReadIndex + 32); @@ -76,7 +76,7 @@ protected void AddSignatureAndMdc(IByteBuffer byteBuffer, int dataLength) Signature signature = _ecdsa.Sign(_privateKey, toSign); byteBuffer.SetWriterIndex(startWriteIndex + 32); - byteBuffer.WriteBytes(signature.Bytes, 0, 64); + byteBuffer.WriteBytes(signature.Bytes); byteBuffer.WriteByte(signature.RecoveryId); byteBuffer.SetWriterIndex(startWriteIndex + length); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs index 192f4a64e49..aabe1727043 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs @@ -78,8 +78,8 @@ public void Encode(RlpStream stream, AuthorizationTuple item, RlpBehaviors rlpBe stream.Encode(item.CodeAddress); stream.Encode(item.Nonce); stream.Encode(item.AuthoritySignature.V - Signature.VOffset); - stream.Encode(new UInt256(item.AuthoritySignature.R, true)); - stream.Encode(new UInt256(item.AuthoritySignature.S, true)); + stream.Encode(new UInt256(item.AuthoritySignature.R.Span, true)); + stream.Encode(new UInt256(item.AuthoritySignature.S.Span, true)); } public NettyRlpStream EncodeWithoutSignature(UInt256 chainId, Address codeAddress, ulong nonce) @@ -106,8 +106,8 @@ public void EncodeWithoutSignature(RlpStream stream, UInt256 chainId, Address co private static int GetContentLength(AuthorizationTuple tuple) => GetContentLengthWithoutSig(tuple.ChainId, tuple.CodeAddress, tuple.Nonce) + Rlp.LengthOf(tuple.AuthoritySignature.V - Signature.VOffset) - + Rlp.LengthOf(new UInt256(tuple.AuthoritySignature.R.AsSpan(), true)) - + Rlp.LengthOf(new UInt256(tuple.AuthoritySignature.S.AsSpan(), true)); + + Rlp.LengthOf(new UInt256(tuple.AuthoritySignature.R.Span, true)) + + Rlp.LengthOf(new UInt256(tuple.AuthoritySignature.S.Span, true)); private static int GetContentLengthWithoutSig(UInt256 chainId, Address codeAddress, ulong nonce) => Rlp.LengthOf(chainId) From 396cbf137b06abbbc69320a04ec280f4e3b6ef7e Mon Sep 17 00:00:00 2001 From: "core-repository-dispatch-app[bot]" <173070810+core-repository-dispatch-app[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 10:00:13 +0100 Subject: [PATCH 075/113] Auto-update fast sync settings (#8006) Co-authored-by: rubo --- .../Nethermind.Runner/configs/base-mainnet.json | 6 +++--- .../Nethermind.Runner/configs/base-sepolia.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/chiado.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/energyweb.json | 8 ++++---- src/Nethermind/Nethermind.Runner/configs/exosama.json | 8 ++++---- src/Nethermind/Nethermind.Runner/configs/gnosis.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json | 8 ++++---- src/Nethermind/Nethermind.Runner/configs/joc-testnet.json | 8 ++++---- .../Nethermind.Runner/configs/linea-mainnet.json | 8 ++++---- .../Nethermind.Runner/configs/linea-sepolia.json | 8 ++++---- src/Nethermind/Nethermind.Runner/configs/mainnet.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/op-mainnet.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/op-sepolia.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/sepolia.json | 6 +++--- src/Nethermind/Nethermind.Runner/configs/volta.json | 8 ++++---- 15 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json index 692be680acc..7374adbce2e 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.json @@ -14,8 +14,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 24310000, - "PivotHash": "0x417f11e9ecf84f33722b817548441a596006fe41923ef283eaf142c0b09057df", + "PivotNumber": 24610000, + "PivotHash": "0xaac317116b7b61da5d18fce044ba9f26c6e851d59b567ea599ce27a37bcd4d07", "PivotTotalDifficulty": "0" }, "Discovery": { @@ -39,4 +39,4 @@ "Optimism": { "SequencerUrl": "https://mainnet-sequencer.base.org" } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json index 0034b4b6715..b7c75e2715b 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.json @@ -14,8 +14,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 19820000, - "PivotHash": "0x1866ba44cc6f250f1127c401ab3f91e02bc5310d8717f49f2b5c304c5d364ea6", + "PivotNumber": 20120000, + "PivotHash": "0x2a4af7399b5df6bf9939b2570f27b9558ca7a2b9732082ab0dce729189cba806", "PivotTotalDifficulty": "0" }, "Discovery": { @@ -39,4 +39,4 @@ "Optimism": { "SequencerUrl": "https://sepolia-sequencer.base.org" } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.json b/src/Nethermind/Nethermind.Runner/configs/chiado.json index 0fc475a3b89..6b5048fddfd 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.json +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.json @@ -17,8 +17,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 13540000, - "PivotHash": "0x9caa530d8ecba3d2ae14ede428b6814ee98861d272db473f5a0ffeb7bb57ccf0", + "PivotNumber": 13650000, + "PivotHash": "0xd648941eec27fd01e12926ceb9886b696fca2a147be2157f56740e772993443f", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", "FastSyncCatchUpHeightDelta": 10000000000, "UseGethLimitsInFastBlocks": false @@ -57,4 +57,4 @@ 16 ] } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb.json b/src/Nethermind/Nethermind.Runner/configs/energyweb.json index 0db75c48f17..4660a38876c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.json +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.json @@ -12,9 +12,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 33500000, - "PivotHash": "0x9889c00d49a47aa28aecee906bf6ff1009ae4aad28987a1fc7765e00f7257095", - "PivotTotalDifficulty": "11399459291851438526023049348964235083395554979", + "PivotNumber": 33610000, + "PivotHash": "0x0c1edd7be6bc0c572dcbbea921463f99ffc0ef6ef85c9d46c7591b3a60910e74", + "PivotTotalDifficulty": "11436890352212741757004020555781729586655483070", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, @@ -33,4 +33,4 @@ "Merge": { "Enabled": false } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama.json b/src/Nethermind/Nethermind.Runner/configs/exosama.json index 4b1028670e2..b41460967c3 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.json +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.json @@ -12,9 +12,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 13800000, - "PivotHash": "0x09481e05ba5ea79fbf3d0ad65f85746e510d9a58e5cc3c4ec8bf4dbcf21cc751", - "PivotTotalDifficulty": "4695896663508950795794569582558401317732053281", + "PivotNumber": 13920000, + "PivotHash": "0x6e7b680f8c614eb52b2672b6e12912e6accc0152faaa8fbcc15424be411d124d", + "PivotTotalDifficulty": "4736730547539463411410174535450213503106533280", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, @@ -33,4 +33,4 @@ "Merge": { "Enabled": false } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.json b/src/Nethermind/Nethermind.Runner/configs/gnosis.json index ea7742c1a59..35f77e1b0c0 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.json +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.json @@ -14,8 +14,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 37750000, - "PivotHash": "0x7ed0ac3f5d0032c4c794c363f5073aba604416fae8b117e472f5fe824c8600a6", + "PivotNumber": 37870000, + "PivotHash": "0xa5952faa70fb98ea5b5e01218280613629db71c14d3b8cddbd0ae65f27e7d12f", "PivotTotalDifficulty": "8626000110427538733349499292577475819600160930", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 @@ -50,4 +50,4 @@ 16 ] } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json index 29eec0cff2d..955e5dbceab 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.json @@ -12,9 +12,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 15160000, - "PivotHash": "0x76f2b33e4a63cac3fe1f230c42f578a3728d55b743b257f97edcbe725601b915", - "PivotTotalDifficulty": "29376308" + "PivotNumber": 15280000, + "PivotHash": "0xf220f87a9110c8b36643e73c9b3a108ffc7024f91f2e230d26f2077b0490803e", + "PivotTotalDifficulty": "29546556" }, "Metrics": { "NodeName": "JOC-Mainnet" @@ -29,4 +29,4 @@ "Merge": { "Enabled": false } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json index f15fc3d7b21..7f1138861b5 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.json @@ -12,9 +12,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 8760000, - "PivotHash": "0x7e7b570759ae5dbe167ef5afdf34d38a4f5113d5cf66192f43e59a0aa4109c07", - "PivotTotalDifficulty": "15552727" + "PivotNumber": 8880000, + "PivotHash": "0x3b533c1becbee50930f5fa593e38452a55613bff77cd2b600f16b7c6553516b2", + "PivotTotalDifficulty": "15724091" }, "Metrics": { "NodeName": "JOC-Testnet" @@ -29,4 +29,4 @@ "Merge": { "Enabled": false } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json index 6117826b3a4..7a4d5d64c93 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet.json @@ -17,13 +17,13 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 13890000, - "PivotHash": "0xd8769b604da37c0873f54c3ff2b1cb34a158c5ec61c8183a3fe9d7cbc71f2176", - "PivotTotalDifficulty": "27780001", + "PivotNumber": 14170000, + "PivotHash": "0xf3185a0fa4ac82b7f61f02d791b9afffb1fd846de5e0a1a6046b585a2dd23f72", + "PivotTotalDifficulty": "28340001", "HeaderStateDistance": 6 }, "JsonRpc": { "Enabled": true, "Port": 8545 } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json index 22e1a456c94..9fdae84699a 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia.json @@ -17,13 +17,13 @@ }, "Sync": { "SnapSync": true, - "PivotNumber": 7540000, - "PivotHash": "0x0a13ca1767c2f037f5fe806f43c63934b7d1af6c75736916074d52c5a09d1305", - "PivotTotalDifficulty": "15080001", + "PivotNumber": 7830000, + "PivotHash": "0x946fe6bc077d6ac99b497087c20652275bf381d50b7a642dd71c413354a75881", + "PivotTotalDifficulty": "15660001", "HeaderStateDistance": 6 }, "JsonRpc": { "Enabled": true, "Port": 8545 } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.json b/src/Nethermind/Nethermind.Runner/configs/mainnet.json index 9c809222ae3..d0dd5adb2d0 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.json @@ -10,8 +10,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 21503000, - "PivotHash": "0xa90c674e7137bfb87cce458b18b5391ff615944060128ef9c9d5b7b1f4d09cb1", + "PivotNumber": 21553000, + "PivotHash": "0x8925e2f94a0aa8e2a88dcbbb791aa8879018376b44af8a7d144766640271c590", "PivotTotalDifficulty": "58750003716598352816469", "FastSyncCatchUpHeightDelta": "10000000000" }, @@ -36,4 +36,4 @@ "Merge": { "Enabled": true } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json index bd98ba39bd7..2a23fce70ea 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.json @@ -17,8 +17,8 @@ "AncientBodiesBarrier": 105235063, "AncientReceiptsBarrier": 105235063, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 129900000, - "PivotHash": "0x6ed7a63e1752a64fa777d1f07974b50bd43270c9d9333c88535cea0cf7e7cbbb", + "PivotNumber": 130210000, + "PivotHash": "0x6e2afe91c0edf2ec45d222badc329ea9e5203455d06a8b83a0887dc67fccbbce", "PivotTotalDifficulty": "0" }, "Discovery": { @@ -42,4 +42,4 @@ "Optimism": { "SequencerUrl": "https://mainnet-sequencer.optimism.io" } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json index c99d06eaea9..46fe1ee7404 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.json @@ -14,8 +14,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 21800000, - "PivotHash": "0x2785448281eaa9cd8b1f828ec54cc090df5bb6075110df31217a9d6651a9f4e0", + "PivotNumber": 22100000, + "PivotHash": "0xb63135d4f2fc43d05f889136b10f506a3fbcd300c97551c9f47fa3cffc14881b", "PivotTotalDifficulty": "0" }, "Discovery": { @@ -39,4 +39,4 @@ "Optimism": { "SequencerUrl": "https://sepolia-sequencer.optimism.io" } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.json b/src/Nethermind/Nethermind.Runner/configs/sepolia.json index c98f63a3863..d69dfb11d81 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.json +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.json @@ -18,8 +18,8 @@ "FastSync": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 7374000, - "PivotHash": "0x089a3035ba78279275bbd907a09d6c401f1ff305d8cd1dacba207f3127940e47", + "PivotNumber": 7421000, + "PivotHash": "0x4727d5229de8745b1d941f9ac9397f7db36e04bda3ae395729553df4a2a86c25", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": 10000000000 }, @@ -38,4 +38,4 @@ "Merge": { "Enabled": true } -} +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.json b/src/Nethermind/Nethermind.Runner/configs/volta.json index 1d02eb071f8..41afe7ec51c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.json +++ b/src/Nethermind/Nethermind.Runner/configs/volta.json @@ -16,9 +16,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 30460000, - "PivotHash": "0x03df63df628a75b21087556f0178a84ee610a2007ce700e8bd2e923bb6c1b3b9", - "PivotTotalDifficulty": "10365000896411785597094390542371659720572358821", + "PivotNumber": 30550000, + "PivotHash": "0x492805d60d627cbc278b6f8375de1ff226b60096d85940e8566412efc6853f7c", + "PivotTotalDifficulty": "10395626309434670058806094257040518859603187282", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, @@ -37,4 +37,4 @@ "Merge": { "Enabled": false } -} +} \ No newline at end of file From b0d9bb17231d116c2e51a666e0e5d8bd0f1ad132 Mon Sep 17 00:00:00 2001 From: Ahmad Bitar <33181301+smartprogrammer93@users.noreply.github.com> Date: Mon, 6 Jan 2025 14:40:20 +0300 Subject: [PATCH 076/113] Fix ChargeAccountAccessGas logic (#7997) --- src/Nethermind/Nethermind.Evm/VirtualMachine.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index 585aa1f05df..a4c00b27cf6 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -500,10 +500,9 @@ private bool ChargeAccountAccessGas(ref long gasAvailable, EvmState vmState, Add } bool notOutOfGas = ChargeAccountGas(ref gasAvailable, vmState, address, spec); return notOutOfGas - && chargeForDelegation - && vmState.Env.TxExecutionContext.CodeInfoRepository.TryGetDelegation(_state, address, out Address delegated) - ? ChargeAccountGas(ref gasAvailable, vmState, delegated, spec) - : notOutOfGas; + && (!chargeForDelegation + || !vmState.Env.TxExecutionContext.CodeInfoRepository.TryGetDelegation(_state, address, out Address delegated) + || ChargeAccountGas(ref gasAvailable, vmState, delegated, spec)); bool ChargeAccountGas(ref long gasAvailable, EvmState vmState, Address address, IReleaseSpec spec) { @@ -2075,7 +2074,7 @@ private void InstructionExtCodeSize(Address address, ref E UInt256 result = (UInt256)accountCode.Span.Length; if (delegation is not null) { - //If the account has been delegated only the first two bytes of the delegation header counts as size + //If the account has been delegated only the first two bytes of the delegation header counts as size result = (UInt256)Eip7702Constants.FirstTwoBytesOfHeader.Length; } stack.PushUInt256(in result); From 2d768751b8e6d2bf6fa91ad76c4d27681c52a8bd Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 6 Jan 2025 12:40:04 +0000 Subject: [PATCH 077/113] Bls precompiles: update gas costs (#7890) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marek Moraczyński --- .../Ethereum.Blockchain.Test/Eip2537Tests.cs | 33 ++- .../Ethereum.Blockchain.Test/MetaTests.cs | 1 + .../Precompiles/Bls/Discount.cs | 275 +++++++++--------- .../Precompiles/Bls/G1AddPrecompile.cs | 2 +- .../Precompiles/Bls/G1MSMPrecompile.cs | 2 +- .../Precompiles/Bls/G2AddPrecompile.cs | 2 +- .../Precompiles/Bls/G2MSMPrecompile.cs | 2 +- .../Precompiles/Bls/G2MulPrecompile.cs | 2 +- .../Precompiles/Bls/MapFp2ToG2Precompile.cs | 2 +- .../Precompiles/Bls/PairingCheckPrecompile.cs | 4 +- 10 files changed, 161 insertions(+), 164 deletions(-) diff --git a/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs b/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs index ec0b408d0db..78f020c88b3 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/Eip2537Tests.cs @@ -7,20 +7,21 @@ namespace Ethereum.Blockchain.Test { - [TestFixture] - [Parallelizable(ParallelScope.All)] - public class Eip2537Tests : GeneralStateTestBase - { - [TestCaseSource(nameof(LoadTests))] - public void Test(GeneralStateTest test) - { - Assert.That(RunTest(test).Pass, Is.True); - } - - public static IEnumerable LoadTests() - { - var loader = new TestsSourceLoader(new LoadGeneralStateTestsStrategy(), "../EIPTests/StateTests/stEIP2537"); - return (IEnumerable)loader.LoadTests(); - } - } + // Tests need to be updated + // [TestFixture] + // [Parallelizable(ParallelScope.All)] + // public class Eip2537Tests : GeneralStateTestBase + // { + // [TestCaseSource(nameof(LoadTests))] + // public void Test(GeneralStateTest test) + // { + // Assert.That(RunTest(test).Pass, Is.True); + // } + // + // public static IEnumerable LoadTests() + // { + // var loader = new TestsSourceLoader(new LoadGeneralStateTestsStrategy(), "../EIPTests/StateTests/stEIP2537"); + // return (IEnumerable)loader.LoadTests(); + // } + // } } diff --git a/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs b/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs index 6797ee8c60d..fcdc07e0d10 100644 --- a/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs +++ b/src/Nethermind/Ethereum.Blockchain.Test/MetaTests.cs @@ -22,6 +22,7 @@ public class MetaTests "ref", "TestFiles", "Blockhash", + "stEIP2537", // ToDo Remove this after updating tests "Data" }; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/Discount.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/Discount.cs index a84d69d1d06..3b05ee5ecb1 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/Discount.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/Discount.cs @@ -1,8 +1,6 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System.Collections.Generic; - namespace Nethermind.Evm.Precompiles.Bls { /// @@ -10,146 +8,143 @@ namespace Nethermind.Evm.Precompiles.Bls /// internal static class Discount { - public static int For(int k) - { - return k switch - { - 0 => 0, - var x when x >= 128 => 174, - _ => _discountTable[k] - }; - } + public static int ForG1(int k) => k >= 128 ? _maxDiscountG1 : _discountTable[k].g1; + public static int ForG2(int k) => k >= 128 ? _maxDiscountG2 : _discountTable[k].g2; + + private const int _maxDiscountG1 = 519; + private const int _maxDiscountG2 = 524; - private static readonly Dictionary _discountTable = new() + private static readonly (int g1, int g2)[] _discountTable = { - { 1, 1200 }, - { 2, 888 }, - { 3, 764 }, - { 4, 641 }, - { 5, 594 }, - { 6, 547 }, - { 7, 500 }, - { 8, 453 }, - { 9, 438 }, - { 10, 423 }, - { 11, 408 }, - { 12, 394 }, - { 13, 379 }, - { 14, 364 }, - { 15, 349 }, - { 16, 334 }, - { 17, 330 }, - { 18, 326 }, - { 19, 322 }, - { 20, 318 }, - { 21, 314 }, - { 22, 310 }, - { 23, 306 }, - { 24, 302 }, - { 25, 298 }, - { 26, 294 }, - { 27, 289 }, - { 28, 285 }, - { 29, 281 }, - { 30, 277 }, - { 31, 273 }, - { 32, 269 }, - { 33, 268 }, - { 34, 266 }, - { 35, 265 }, - { 36, 263 }, - { 37, 262 }, - { 38, 260 }, - { 39, 259 }, - { 40, 257 }, - { 41, 256 }, - { 42, 254 }, - { 43, 253 }, - { 44, 251 }, - { 45, 250 }, - { 46, 248 }, - { 47, 247 }, - { 48, 245 }, - { 49, 244 }, - { 50, 242 }, - { 51, 241 }, - { 52, 239 }, - { 53, 238 }, - { 54, 236 }, - { 55, 235 }, - { 56, 233 }, - { 57, 232 }, - { 58, 231 }, - { 59, 229 }, - { 60, 228 }, - { 61, 226 }, - { 62, 225 }, - { 63, 223 }, - { 64, 222 }, - { 65, 221 }, - { 66, 220 }, - { 67, 219 }, - { 68, 219 }, - { 69, 218 }, - { 70, 217 }, - { 71, 216 }, - { 72, 216 }, - { 73, 215 }, - { 74, 214 }, - { 75, 213 }, - { 76, 213 }, - { 77, 212 }, - { 78, 211 }, - { 79, 211 }, - { 80, 210 }, - { 81, 209 }, - { 82, 208 }, - { 83, 208 }, - { 84, 207 }, - { 85, 206 }, - { 86, 205 }, - { 87, 205 }, - { 88, 204 }, - { 89, 203 }, - { 90, 202 }, - { 91, 202 }, - { 92, 201 }, - { 93, 200 }, - { 94, 199 }, - { 95, 199 }, - { 96, 198 }, - { 97, 197 }, - { 98, 196 }, - { 99, 196 }, - { 100, 195 }, - { 101, 194 }, - { 102, 193 }, - { 103, 193 }, - { 104, 192 }, - { 105, 191 }, - { 106, 191 }, - { 107, 190 }, - { 108, 189 }, - { 109, 188 }, - { 110, 188 }, - { 111, 187 }, - { 112, 186 }, - { 113, 185 }, - { 114, 185 }, - { 115, 184 }, - { 116, 183 }, - { 117, 182 }, - { 118, 182 }, - { 119, 181 }, - { 120, 180 }, - { 121, 179 }, - { 122, 179 }, - { 123, 178 }, - { 124, 177 }, - { 125, 176 }, - { 126, 176 }, - { 127, 175 }, - { 128, 174 } + (0, 0), // 0 + (1000, 1000), // 1 + (949, 1000), // 2 + (848, 923), // 3 + (797, 884), // 4 + (764, 855), // 5 + (750, 832), // 6 + (738, 812), // 7 + (728, 796), // 8 + (719, 782), // 9 + (712, 770), // 10 + (705, 759), // 11 + (698, 749), // 12 + (692, 740), // 13 + (687, 732), // 14 + (682, 724), // 15 + (677, 717), // 16 + (673, 711), // 17 + (669, 704), // 18 + (665, 699), // 19 + (661, 693), // 20 + (658, 688), // 21 + (654, 683), // 22 + (651, 679), // 23 + (648, 674), // 24 + (645, 670), // 25 + (642, 666), // 26 + (640, 663), // 27 + (637, 659), // 28 + (635, 655), // 29 + (632, 652), // 30 + (630, 649), // 31 + (627, 646), // 32 + (625, 643), // 33 + (623, 640), // 34 + (621, 637), // 35 + (619, 634), // 36 + (617, 632), // 37 + (615, 629), // 38 + (613, 627), // 39 + (611, 624), // 40 + (609, 622), // 41 + (608, 620), // 42 + (606, 618), // 43 + (604, 615), // 44 + (603, 613), // 45 + (601, 611), // 46 + (599, 609), // 47 + (598, 607), // 48 + (596, 606), // 49 + (595, 604), // 50 + (593, 602), // 51 + (592, 600), // 52 + (591, 598), // 53 + (589, 597), // 54 + (588, 595), // 55 + (586, 593), // 56 + (585, 592), // 57 + (584, 590), // 58 + (582, 589), // 59 + (581, 587), // 60 + (580, 586), // 61 + (579, 584), // 62 + (577, 583), // 63 + (576, 582), // 64 + (575, 580), // 65 + (574, 579), // 66 + (573, 578), // 67 + (572, 576), // 68 + (570, 575), // 69 + (569, 574), // 70 + (568, 573), // 71 + (567, 571), // 72 + (566, 570), // 73 + (565, 569), // 74 + (564, 568), // 75 + (563, 567), // 76 + (562, 566), // 77 + (561, 565), // 78 + (560, 563), // 79 + (559, 562), // 80 + (558, 561), // 81 + (557, 560), // 82 + (556, 559), // 83 + (555, 558), // 84 + (554, 557), // 85 + (553, 556), // 86 + (552, 555), // 87 + (551, 554), // 88 + (550, 553), // 89 + (549, 552), // 90 + (548, 552), // 91 + (547, 551), // 92 + (547, 550), // 93 + (546, 549), // 94 + (545, 548), // 95 + (544, 547), // 96 + (543, 546), // 97 + (542, 545), // 98 + (541, 545), // 99 + (540, 544), // 100 + (540, 543), // 101 + (539, 542), // 102 + (538, 541), // 103 + (537, 541), // 104 + (536, 540), // 105 + (536, 539), // 106 + (535, 538), // 107 + (534, 537), // 108 + (533, 537), // 109 + (532, 536), // 110 + (532, 535), // 111 + (531, 535), // 112 + (530, 534), // 113 + (529, 533), // 114 + (528, 532), // 115 + (528, 532), // 116 + (527, 531), // 117 + (526, 530), // 118 + (525, 530), // 119 + (525, 529), // 120 + (524, 528), // 121 + (523, 528), // 122 + (522, 527), // 123 + (522, 526), // 124 + (521, 526), // 125 + (520, 525), // 126 + (520, 524), // 127 + (519, 524) // 128 }; } } diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs index 53df7f426df..aa8c155a747 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1AddPrecompile.cs @@ -23,7 +23,7 @@ private G1AddPrecompile() public static Address Address { get; } = Address.FromNumber(0x0b); - public long BaseGasCost(IReleaseSpec releaseSpec) => 500L; + public long BaseGasCost(IReleaseSpec releaseSpec) => 375L; public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs index 3627c6bfae7..4c6a12618c0 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs @@ -30,7 +30,7 @@ private G1MSMPrecompile() public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) { int k = inputData.Length / ItemSize; - return 12000L * k * Discount.For(k) / 1000; + return 12000L * k * Discount.ForG1(k) / 1000; } public const int ItemSize = 160; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs index 710954f3a3b..4cafcb61634 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs @@ -23,7 +23,7 @@ private G2AddPrecompile() public static Address Address { get; } = Address.FromNumber(0x0e); - public long BaseGasCost(IReleaseSpec releaseSpec) => 800L; + public long BaseGasCost(IReleaseSpec releaseSpec) => 600L; public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs index ca261920ed7..c8ea845b994 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs @@ -30,7 +30,7 @@ private G2MSMPrecompile() public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) { int k = inputData.Length / ItemSize; - return 45000L * k * Discount.For(k) / 1000; + return 22500L * k * Discount.ForG2(k) / 1000; } public const int ItemSize = 288; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs index fbe99e32867..bf849287a5d 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs @@ -23,7 +23,7 @@ private G2MulPrecompile() public static Address Address { get; } = Address.FromNumber(0x0f); - public long BaseGasCost(IReleaseSpec releaseSpec) => 45000L; + public long BaseGasCost(IReleaseSpec releaseSpec) => 22500L; public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs index 5190c58be57..04827c9e46d 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs @@ -23,7 +23,7 @@ private MapFp2ToG2Precompile() public static Address Address { get; } = Address.FromNumber(0x13); - public long BaseGasCost(IReleaseSpec releaseSpec) => 75000; + public long BaseGasCost(IReleaseSpec releaseSpec) => 23800L; public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs index 75cd9167364..e398ba1c781 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs @@ -25,9 +25,9 @@ private PairingCheckPrecompile() { } public static Address Address { get; } = Address.FromNumber(0x11); - public long BaseGasCost(IReleaseSpec releaseSpec) => 65000L; + public long BaseGasCost(IReleaseSpec releaseSpec) => 37700L; - public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 43000L * (inputData.Length / PairSize); + public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 32600L * (inputData.Length / PairSize); [SkipLocalsInit] public (ReadOnlyMemory, bool) Run(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) From 910e471a35840ba51c46a2ef82b079a5e1de6a86 Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 6 Jan 2025 12:52:15 +0000 Subject: [PATCH 078/113] Bls precompiles: remove MUL (#7932) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marek Moraczyński --- .../BlsMulG1PrecompileTests.cs | 2 +- .../BlsMulG2PrecompileTests.cs | 2 +- .../Nethermind.Evm/CodeInfoRepository.cs | 2 - .../Precompiles/Bls/G1MSMPrecompile.cs | 2 +- .../Precompiles/Bls/G1MulPrecompile.cs | 59 ------------------ .../Precompiles/Bls/G2AddPrecompile.cs | 2 +- .../Precompiles/Bls/G2MSMPrecompile.cs | 2 +- .../Precompiles/Bls/G2MulPrecompile.cs | 61 ------------------- .../Precompiles/Bls/MapFp2ToG2Precompile.cs | 2 +- .../Precompiles/Bls/MapFpToG1Precompile.cs | 2 +- .../Precompiles/Bls/PairingCheckPrecompile.cs | 2 +- .../BlsG1MulBenchmark.cs | 2 +- .../BlsG2MulBenchmark.cs | 2 +- 13 files changed, 10 insertions(+), 132 deletions(-) delete mode 100644 src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs diff --git a/src/Nethermind/Nethermind.Evm.Test/BlsMulG1PrecompileTests.cs b/src/Nethermind/Nethermind.Evm.Test/BlsMulG1PrecompileTests.cs index 26efd4d3724..c1089b16060 100644 --- a/src/Nethermind/Nethermind.Evm.Test/BlsMulG1PrecompileTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/BlsMulG1PrecompileTests.cs @@ -17,7 +17,7 @@ public class BlsG1MulPrecompileTests [Test] public void Test() { - IPrecompile precompile = G1MulPrecompile.Instance; + IPrecompile precompile = G1MSMPrecompile.Instance; foreach ((byte[] input, ReadOnlyMemory expectedResult) in Inputs) { diff --git a/src/Nethermind/Nethermind.Evm.Test/BlsMulG2PrecompileTests.cs b/src/Nethermind/Nethermind.Evm.Test/BlsMulG2PrecompileTests.cs index 625dd89e7df..3ab9a85a5d8 100644 --- a/src/Nethermind/Nethermind.Evm.Test/BlsMulG2PrecompileTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/BlsMulG2PrecompileTests.cs @@ -19,7 +19,7 @@ public void Test() { foreach ((byte[] input, ReadOnlyMemory expectedResult) in Inputs) { - IPrecompile precompile = G2MulPrecompile.Instance; + IPrecompile precompile = G2MSMPrecompile.Instance; (ReadOnlyMemory output, bool success) = precompile.Run(input, MuirGlacier.Instance); output.ToArray().Should().BeEquivalentTo(expectedResult.ToArray()); success.Should().BeTrue(); diff --git a/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs b/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs index 6103e2df810..499758f8c38 100644 --- a/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs +++ b/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs @@ -42,10 +42,8 @@ private static FrozenDictionary InitializePrecompiledCon [Blake2FPrecompile.Address] = new(Blake2FPrecompile.Instance), [G1AddPrecompile.Address] = new(G1AddPrecompile.Instance), - [G1MulPrecompile.Address] = new(G1MulPrecompile.Instance), [G1MSMPrecompile.Address] = new(G1MSMPrecompile.Instance), [G2AddPrecompile.Address] = new(G2AddPrecompile.Instance), - [G2MulPrecompile.Address] = new(G2MulPrecompile.Instance), [G2MSMPrecompile.Address] = new(G2MSMPrecompile.Instance), [PairingCheckPrecompile.Address] = new(PairingCheckPrecompile.Instance), [MapFpToG1Precompile.Address] = new(MapFpToG1Precompile.Instance), diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs index 4c6a12618c0..70f5c2d0d5c 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MSMPrecompile.cs @@ -23,7 +23,7 @@ private G1MSMPrecompile() { } - public static Address Address { get; } = Address.FromNumber(0x0d); + public static Address Address { get; } = Address.FromNumber(0x0c); public long BaseGasCost(IReleaseSpec releaseSpec) => 0L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs deleted file mode 100644 index 18eb5889913..00000000000 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G1MulPrecompile.cs +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using System.Runtime.CompilerServices; -using Nethermind.Core; -using Nethermind.Core.Specs; -using G1 = Nethermind.Crypto.Bls.P1; - -namespace Nethermind.Evm.Precompiles.Bls; - -/// -/// https://eips.ethereum.org/EIPS/eip-2537 -/// -public class G1MulPrecompile : IPrecompile -{ - public static readonly G1MulPrecompile Instance = new(); - - private G1MulPrecompile() - { - } - - public static Address Address { get; } = Address.FromNumber(0x0c); - - public long BaseGasCost(IReleaseSpec releaseSpec) => 12000L; - - public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; - - [SkipLocalsInit] - public (ReadOnlyMemory, bool) Run(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) - { - Metrics.BlsG1MulPrecompile++; - - const int expectedInputLength = BlsConst.LenG1 + BlsConst.LenFr; - if (inputData.Length != expectedInputLength) - { - return IPrecompile.Failure; - } - - G1 x = new(stackalloc long[G1.Sz]); - if (!x.TryDecodeRaw(inputData[..BlsConst.LenG1].Span) || !(BlsConst.DisableSubgroupChecks || x.InGroup())) - { - return IPrecompile.Failure; - } - - bool scalarIsInfinity = !inputData.Span[BlsConst.LenG1..].ContainsAnyExcept((byte)0); - if (scalarIsInfinity || x.IsInf()) - { - return (BlsConst.G1Inf, true); - } - - Span scalar = stackalloc byte[32]; - inputData.Span[BlsConst.LenG1..].CopyTo(scalar); - scalar.Reverse(); - - G1 res = x.Mult(scalar); - return (res.EncodeRaw(), true); - } -} diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs index 4cafcb61634..8d387733516 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2AddPrecompile.cs @@ -21,7 +21,7 @@ private G2AddPrecompile() { } - public static Address Address { get; } = Address.FromNumber(0x0e); + public static Address Address { get; } = Address.FromNumber(0x0d); public long BaseGasCost(IReleaseSpec releaseSpec) => 600L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs index c8ea845b994..2208dbb6d7a 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MSMPrecompile.cs @@ -23,7 +23,7 @@ private G2MSMPrecompile() { } - public static Address Address { get; } = Address.FromNumber(0x10); + public static Address Address { get; } = Address.FromNumber(0xe); public long BaseGasCost(IReleaseSpec releaseSpec) => 0L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs index bf849287a5d..e69de29bb2d 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/G2MulPrecompile.cs @@ -1,61 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using System.Runtime.CompilerServices; -using Nethermind.Core; -using Nethermind.Core.Specs; - -using G2 = Nethermind.Crypto.Bls.P2; - -namespace Nethermind.Evm.Precompiles.Bls; - -/// -/// https://eips.ethereum.org/EIPS/eip-2537 -/// -public class G2MulPrecompile : IPrecompile -{ - public static readonly G2MulPrecompile Instance = new(); - - private G2MulPrecompile() - { - } - - public static Address Address { get; } = Address.FromNumber(0x0f); - - public long BaseGasCost(IReleaseSpec releaseSpec) => 22500L; - - public long DataGasCost(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; - - [SkipLocalsInit] - public (ReadOnlyMemory, bool) Run(ReadOnlyMemory inputData, IReleaseSpec releaseSpec) - { - Metrics.BlsG2MulPrecompile++; - - const int expectedInputLength = BlsConst.LenG2 + BlsConst.LenFr; - - if (inputData.Length != expectedInputLength) - { - return IPrecompile.Failure; - } - - G2 x = new(stackalloc long[G2.Sz]); - if (!x.TryDecodeRaw(inputData[..BlsConst.LenG2].Span) || !(BlsConst.DisableSubgroupChecks || x.InGroup())) - { - return IPrecompile.Failure; - } - - bool scalarIsInfinity = !inputData[BlsConst.LenG2..].Span.ContainsAnyExcept((byte)0); - if (scalarIsInfinity || x.IsInf()) - { - return (BlsConst.G2Inf, true); - } - - Span scalar = stackalloc byte[32]; - inputData.Span[BlsConst.LenG2..].CopyTo(scalar); - scalar.Reverse(); - - G2 res = x.Mult(scalar); - return (res.EncodeRaw(), true); - } -} diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs index 04827c9e46d..0256db63c6f 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFp2ToG2Precompile.cs @@ -21,7 +21,7 @@ private MapFp2ToG2Precompile() { } - public static Address Address { get; } = Address.FromNumber(0x13); + public static Address Address { get; } = Address.FromNumber(0x11); public long BaseGasCost(IReleaseSpec releaseSpec) => 23800L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFpToG1Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFpToG1Precompile.cs index eb1032ea1f5..f0bbd633509 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFpToG1Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/MapFpToG1Precompile.cs @@ -20,7 +20,7 @@ private MapFpToG1Precompile() { } - public static Address Address { get; } = Address.FromNumber(0x12); + public static Address Address { get; } = Address.FromNumber(0x10); public long BaseGasCost(IReleaseSpec releaseSpec) => 5500L; diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs index e398ba1c781..4b2572e248c 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Bls/PairingCheckPrecompile.cs @@ -23,7 +23,7 @@ public class PairingCheckPrecompile : IPrecompile private PairingCheckPrecompile() { } - public static Address Address { get; } = Address.FromNumber(0x11); + public static Address Address { get; } = Address.FromNumber(0xf); public long BaseGasCost(IReleaseSpec releaseSpec) => 37700L; diff --git a/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG1MulBenchmark.cs b/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG1MulBenchmark.cs index 7d1adc95338..b32430d5b9d 100644 --- a/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG1MulBenchmark.cs +++ b/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG1MulBenchmark.cs @@ -11,7 +11,7 @@ public class BlsG1MulBenchmark : PrecompileBenchmarkBase { protected override IEnumerable Precompiles => new[] { - G1MulPrecompile.Instance + G1MSMPrecompile.Instance }; protected override string InputsDirectory => "blsg1mul"; diff --git a/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG2MulBenchmark.cs b/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG2MulBenchmark.cs index 6df853a9778..6eb529ed24f 100644 --- a/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG2MulBenchmark.cs +++ b/src/Nethermind/Nethermind.Precompiles.Benchmark/BlsG2MulBenchmark.cs @@ -11,7 +11,7 @@ public class BlsG2MulBenchmark : PrecompileBenchmarkBase { protected override IEnumerable Precompiles => new[] { - G2MulPrecompile.Instance + G2MSMPrecompile.Instance }; protected override string InputsDirectory => "blsg2mul"; From 76eb8c0c518c5d1226bd748ac52ad6741321f4d1 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Mon, 6 Jan 2025 13:15:48 +0000 Subject: [PATCH 079/113] Move prewarming as early as possible (#8001) --- .../Processing/BlockProcessor.cs | 70 +++++++++++++------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs index 03e7021b280..c6ba69e0ec8 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs @@ -18,6 +18,7 @@ using Nethermind.Consensus.Withdrawals; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Threading; using Nethermind.Crypto; @@ -85,28 +86,38 @@ public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, { if (suggestedBlocks.Count == 0) return []; - TxHashCalculator.CalculateInBackground(suggestedBlocks); - BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks)); - /* We need to save the snapshot state root before reorganization in case the new branch has invalid blocks. In case of invalid blocks on the new branch we will discard the entire branch and come back to the previous head state.*/ Hash256 previousBranchStateRoot = CreateCheckpoint(); InitBranch(newBranchStateRoot); + + Block suggestedBlock = suggestedBlocks[0]; + // Start prewarming as early as possible + WaitForCacheClear(); + (CancellationTokenSource? prewarmCancellation, Task? preWarmTask) + = PreWarmTransactions(suggestedBlock, newBranchStateRoot); + + BlocksProcessing?.Invoke(this, new BlocksProcessingEventArgs(suggestedBlocks)); + Hash256 preBlockStateRoot = newBranchStateRoot; bool notReadOnly = !options.ContainsFlag(ProcessingOptions.ReadOnlyChain); int blocksCount = suggestedBlocks.Count; Block[] processedBlocks = new Block[blocksCount]; - - Task? preWarmTask = null; try { for (int i = 0; i < blocksCount; i++) { - preWarmTask = null; WaitForCacheClear(); - Block suggestedBlock = suggestedBlocks[i]; + suggestedBlock = suggestedBlocks[i]; + // If prewarmCancellation is not null it means we are in first iteration of loop + // and started prewarming at method entry, so don't start it again + if (prewarmCancellation is null) + { + (prewarmCancellation, preWarmTask) = PreWarmTransactions(suggestedBlock, preBlockStateRoot); + } + if (blocksCount > 64 && i % 8 == 0) { if (_logger.IsInfo) _logger.Info($"Processing part of a long blocks branch {i}/{blocksCount}. Block: {suggestedBlock}"); @@ -120,23 +131,20 @@ the previous head state.*/ Block processedBlock; TxReceipt[] receipts; - bool skipPrewarming = preWarmer is null || suggestedBlock.Transactions.Length < 3; - if (!skipPrewarming) + if (prewarmCancellation is not null) { - using CancellationTokenSource cancellationTokenSource = new(); - preWarmTask = preWarmer.PreWarmCaches(suggestedBlock, preBlockStateRoot, _specProvider.GetSpec(suggestedBlock.Header), cancellationTokenSource.Token, _beaconBlockRootHandler); (processedBlock, receipts) = ProcessOne(suggestedBlock, options, blockTracer); // Block is processed, we can cancel the prewarm task - cancellationTokenSource.Cancel(); + CancellationTokenExtensions.CancelDisposeAndClear(ref prewarmCancellation); } else { + // Even though we skip prewarming we still need to ensure the caches are cleared CacheType result = preWarmer?.ClearCaches() ?? default; if (result != default) { if (_logger.IsWarn) _logger.Warn($"Low txs, caches {result} are not empty. Clearing them."); } - // Even though we skip prewarming we still need to ensure the caches are cleared (processedBlock, receipts) = ProcessOne(suggestedBlock, options, blockTracer); } @@ -168,7 +176,13 @@ the previous head state.*/ preBlockStateRoot = processedBlock.StateRoot; // Make sure the prewarm task is finished before we reset the state preWarmTask?.GetAwaiter().GetResult(); + preWarmTask = null; _stateProvider.Reset(resizeCollections: true); + + // Calculate the transaction hashes in the background and release tx sequence memory + // Hashes will be required for PersistentReceiptStorage in ForkchoiceUpdatedHandler + // Though we still want to release the memory even if syncing rather than processing live + TxHashCalculator.CalculateInBackground(suggestedBlock); } if (options.ContainsFlag(ProcessingOptions.DoNotUpdateHead)) @@ -181,6 +195,7 @@ the previous head state.*/ catch (Exception ex) // try to restore at all cost { if (_logger.IsWarn) _logger.Warn($"Encountered exception {ex} while processing blocks."); + CancellationTokenExtensions.CancelDisposeAndClear(ref prewarmCancellation); QueueClearCaches(preWarmTask); preWarmTask?.GetAwaiter().GetResult(); RestoreBranch(previousBranchStateRoot); @@ -188,6 +203,20 @@ the previous head state.*/ } } + private (CancellationTokenSource prewarmCancellation, Task preWarmTask) PreWarmTransactions(Block suggestedBlock, Hash256 preBlockStateRoot) + { + if (preWarmer is null || suggestedBlock.Transactions.Length < 3) return (null, null); + + CancellationTokenSource prewarmCancellation = new(); + Task preWarmTask = preWarmer.PreWarmCaches(suggestedBlock, + preBlockStateRoot, + _specProvider.GetSpec(suggestedBlock.Header), + prewarmCancellation.Token, + _beaconBlockRootHandler); + + return (prewarmCancellation, preWarmTask); + } + private void WaitForCacheClear() => _clearTask.GetAwaiter().GetResult(); private void QueueClearCaches(Task? preWarmTask) @@ -472,13 +501,13 @@ void ApplyTransition() } } - private class TxHashCalculator(List suggestedBlocks) : IThreadPoolWorkItem + private class TxHashCalculator(Block suggestedBlock) : IThreadPoolWorkItem { - public static void CalculateInBackground(List suggestedBlocks) + public static void CalculateInBackground(Block suggestedBlock) { // Memory has been reserved on the transactions to delay calculate the hashes // We calculate the hashes in the background to release that memory - ThreadPool.UnsafeQueueUserWorkItem(new TxHashCalculator(suggestedBlocks), preferLocal: false); + ThreadPool.UnsafeQueueUserWorkItem(new TxHashCalculator(suggestedBlock), preferLocal: false); } void IThreadPoolWorkItem.Execute() @@ -486,13 +515,10 @@ void IThreadPoolWorkItem.Execute() // Hashes will be required for PersistentReceiptStorage in UpdateMainChain ForkchoiceUpdatedHandler // Which occurs after the block has been processed; however the block is stored in cache and picked up // from there so we can calculate the hashes now for that later use. - foreach (Block block in CollectionsMarshal.AsSpan(suggestedBlocks)) + foreach (Transaction tx in suggestedBlock.Transactions) { - foreach (Transaction tx in block.Transactions) - { - // Calculate the hashes to release the memory from the transactionSequence - tx.CalculateHashInternal(); - } + // Calculate the hashes to release the memory from the transactionSequence + tx.CalculateHashInternal(); } } } From 8df3c947de39d148f980b219adb5a3296db7974c Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 7 Jan 2025 15:22:06 +0800 Subject: [PATCH 080/113] Feature/verifytrie admin rpc (#7962) --- .../Nethermind.Api/IApiWithBlockchain.cs | 2 + .../Nethermind.Api/NethermindApi.cs | 2 + .../Nethermind.Init/InitializeStateDb.cs | 14 ++-- .../Steps/RegisterRpcModules.cs | 3 + .../Modules/AdminModuleTests.cs | 25 +++++++ .../Modules/Admin/AdminRpcModule.cs | 41 +++++++++++ .../Modules/Admin/IAdminRpcModule.cs | 12 +++- .../Ethereum/ContextWithMocks.cs | 2 + .../SynchronizerModuleTests.cs | 54 +++------------ .../FastSync/BlockingVerifyTrie.cs | 69 +++++++++++++++++++ .../FastSync/IBlockingVerifyTrie.cs | 11 +++ .../FastSync/ITreeSync.cs | 5 +- .../FastSync/TreeSync.cs | 5 +- .../VerifyStateOnStateSyncFinished.cs | 52 +------------- .../Nethermind.Trie/Pruning/TrieStore.cs | 7 +- 15 files changed, 197 insertions(+), 107 deletions(-) create mode 100644 src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs create mode 100644 src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs index da24eaa918b..ffd5934f56d 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs @@ -23,6 +23,7 @@ using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules.Eth.GasPrice; using Nethermind.State; +using Nethermind.Synchronization.FastSync; using Nethermind.Trie; using Nethermind.Trie.Pruning; using Nethermind.TxPool; @@ -63,6 +64,7 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory /// DO NOT USE OUTSIDE OF PROCESSING BLOCK CONTEXT! /// IWorldState? WorldState { get; set; } + IBlockingVerifyTrie? BlockingVerifyTrie { get; set; } IReadOnlyStateProvider? ChainHeadStateProvider { get; set; } IStateReader? StateReader { get; set; } IWorldStateManager? WorldStateManager { get; set; } diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 1e7ad8cfdd4..3abc9a2dc5b 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -58,6 +58,7 @@ using Nethermind.Trie; using Nethermind.Consensus.Processing.CensorshipDetector; using Nethermind.Facade.Find; +using Nethermind.Synchronization.FastSync; namespace Nethermind.Api { @@ -196,6 +197,7 @@ public ISealEngine SealEngine public IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool => ApiWithNetworkServiceContainer?.Resolve(); public ISynchronizer? Synchronizer => ApiWithNetworkServiceContainer?.Resolve(); public ISyncServer? SyncServer => ApiWithNetworkServiceContainer?.Resolve(); + public IBlockingVerifyTrie? BlockingVerifyTrie { get; set; } public IWorldState? WorldState { get; set; } public IReadOnlyStateProvider? ChainHeadStateProvider { get; set; } public IWorldStateManager? WorldStateManager { get; set; } diff --git a/src/Nethermind/Nethermind.Init/InitializeStateDb.cs b/src/Nethermind/Nethermind.Init/InitializeStateDb.cs index 4fd09fe8e97..261bc3ecdaa 100644 --- a/src/Nethermind/Nethermind.Init/InitializeStateDb.cs +++ b/src/Nethermind/Nethermind.Init/InitializeStateDb.cs @@ -22,6 +22,7 @@ using Nethermind.Logging; using Nethermind.Serialization.Json; using Nethermind.State; +using Nethermind.Synchronization.FastSync; using Nethermind.Synchronization.Trie; using Nethermind.Trie; using Nethermind.Trie.Pruning; @@ -87,7 +88,7 @@ public Task Execute(CancellationToken cancellationToken) syncConfig.DownloadBodiesInFastSync = true; } - IKeyValueStore codeDb = getApi.DbProvider.CodeDb; + IDb codeDb = getApi.DbProvider.CodeDb; IKeyValueStoreWithBatching stateDb = getApi.DbProvider.StateDb; IPersistenceStrategy persistenceStrategy; IPruningStrategy pruningStrategy; @@ -185,6 +186,8 @@ public Task Execute(CancellationToken cancellationToken) getApi.DbProvider, getApi.LogManager); + setApi.BlockingVerifyTrie = new BlockingVerifyTrie(mainWorldTrieStore, stateManager.GlobalStateReader, codeDb!, getApi.ProcessExit!, getApi.LogManager); + // TODO: Don't forget this TrieStoreBoundaryWatcher trieStoreBoundaryWatcher = new(stateManager, _api.BlockTree!, _api.LogManager); getApi.DisposeStack.Push(trieStoreBoundaryWatcher); @@ -199,9 +202,12 @@ public Task Execute(CancellationToken cancellationToken) if (_api.Config().DiagnosticMode == DiagnosticMode.VerifyTrie) { _logger!.Info("Collecting trie stats and verifying that no nodes are missing..."); - Hash256 stateRoot = getApi.BlockTree!.Head?.StateRoot ?? Keccak.EmptyTreeHash; - TrieStats stats = stateManager.GlobalStateReader.CollectStats(stateRoot, getApi.DbProvider.CodeDb, _api.LogManager, _api.ProcessExit!.Token); - _logger.Info($"Starting from {getApi.BlockTree.Head?.Number} {getApi.BlockTree.Head?.StateRoot}{Environment.NewLine}" + stats); + BlockHeader? head = getApi.BlockTree!.Head?.Header; + if (head is not null) + { + setApi.BlockingVerifyTrie.TryStartVerifyTrie(head); + _logger.Info($"Starting from {head.Number} {head.StateRoot}{Environment.NewLine}"); + } } // Init state if we need system calls before actual processing starts diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index daa7ce6fc7d..8f15d15d8e2 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -127,11 +127,14 @@ public virtual async Task Execute(CancellationToken cancellationToken) ManualPruningTrigger pruningTrigger = new(); _api.PruningTrigger.Add(pruningTrigger); (IApiWithStores getFromApi, IApiWithBlockchain setInApi) = _api.ForInit; + AdminRpcModule adminRpcModule = new( _api.BlockTree, networkConfig, _api.PeerPool, _api.StaticNodesManager, + _api.BlockingVerifyTrie!, + _api.WorldStateManager.GlobalStateReader, _api.Enode, initConfig.BaseDbPath, pruningTrigger, diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs index c3d123f4a53..fdada32f4d1 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs @@ -18,7 +18,9 @@ using Nethermind.Network.Config; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.State; using Nethermind.Stats.Model; +using Nethermind.Synchronization.FastSync; using NSubstitute; using NUnit.Framework; @@ -32,6 +34,8 @@ public class AdminModuleTests private EthereumJsonSerializer _serializer = null!; private NetworkConfig _networkConfig = null!; private IBlockTree _blockTree = null!; + private IBlockingVerifyTrie _blockingVerifyTrie = null!; + private IStateReader _stateReader = null!; private const string _enodeString = "enode://e1b7e0dc09aae610c9dec8a0bee62bab9946cc27ebdd2f9e3571ed6d444628f99e91e43f4a14d42d498217608bb3e1d1bc8ec2aa27d7f7e423413b851bae02bc@127.0.0.1:30303"; private const string _exampleDataDir = "/example/dbdir"; @@ -39,6 +43,8 @@ public class AdminModuleTests public void Setup() { _blockTree = Build.A.BlockTree().OfChainLength(5).TestObject; + _blockingVerifyTrie = Substitute.For(); + _stateReader = Substitute.For(); _networkConfig = new NetworkConfig(); IPeerPool peerPool = Substitute.For(); ConcurrentDictionary dict = new(); @@ -57,6 +63,8 @@ public void Setup() _networkConfig, peerPool, staticNodesManager, + _blockingVerifyTrie, + _stateReader, enode, _exampleDataDir, new ManualPruningTrigger(), @@ -110,6 +118,23 @@ public async Task Test_admin_dataDir() response.Result!.ToString().Should().Be(_exampleDataDir); } + [Test] + public async Task Test_admin_verifyTrie() + { + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie", "latest")).Should().Contain("Unable to start verify trie"); + _stateReader.HasStateForRoot(Arg.Any()).Returns(true); + _blockingVerifyTrie.TryStartVerifyTrie(Arg.Any()).Returns(true); + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie", "latest")).Should().Contain("Starting"); + } + + [Test] + public async Task Test_hasStateForBlock() + { + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_isStateRootAvailable", "latest")).Should().Contain("false"); + _stateReader.HasStateForRoot(Arg.Any()).Returns(true); + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_isStateRootAvailable", "latest")).Should().Contain("true"); + } + [Test] public async Task Smoke_solc() { diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs index a6c501da755..6ccd648c721 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Find; using Nethermind.Blockchain.FullPruning; using Nethermind.Config; using Nethermind.Core; @@ -12,7 +13,9 @@ using Nethermind.Network; using Nethermind.Network.Config; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.State; using Nethermind.Stats.Model; +using Nethermind.Synchronization.FastSync; namespace Nethermind.JsonRpc.Modules.Admin; @@ -26,6 +29,8 @@ public class AdminRpcModule : IAdminRpcModule private readonly IEnode _enode; private readonly string _dataDir; private readonly ManualPruningTrigger _pruningTrigger; + private readonly IBlockingVerifyTrie _blockingVerifyTrie; + private readonly IStateReader _stateReader; private NodeInfo _nodeInfo = null!; public AdminRpcModule( @@ -33,6 +38,8 @@ public AdminRpcModule( INetworkConfig networkConfig, IPeerPool peerPool, IStaticNodesManager staticNodesManager, + IBlockingVerifyTrie blockingVerifyTrie, + IStateReader stateReader, IEnode enode, string dataDir, ManualPruningTrigger pruningTrigger, @@ -44,6 +51,8 @@ public AdminRpcModule( _peerPool = peerPool ?? throw new ArgumentNullException(nameof(peerPool)); _networkConfig = networkConfig ?? throw new ArgumentNullException(nameof(networkConfig)); _staticNodesManager = staticNodesManager ?? throw new ArgumentNullException(nameof(staticNodesManager)); + _blockingVerifyTrie = blockingVerifyTrie ?? throw new ArgumentNullException(nameof(blockingVerifyTrie)); + _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); _pruningTrigger = pruningTrigger; _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); @@ -135,8 +144,40 @@ public ResultWrapper admin_setSolc() return ResultWrapper.Success(true); } + public ResultWrapper admin_isStateRootAvailable(BlockParameter block) + { + BlockHeader? header = _blockTree.FindHeader(block); + if (header is null) + { + return ResultWrapper.Fail("Unable to find block. Unable to know state root to verify."); + } + + return ResultWrapper.Success(_stateReader.HasStateForBlock(header)); + } + public ResultWrapper admin_prune() { return ResultWrapper.Success(_pruningTrigger.Trigger()); } + + public ResultWrapper admin_verifyTrie(BlockParameter block) + { + BlockHeader? header = _blockTree.FindHeader(block); + if (header is null) + { + return ResultWrapper.Fail("Unable to find block. Unable to know state root to verify."); + } + + if (!_stateReader.HasStateForBlock(header)) + { + return ResultWrapper.Fail("Unable to start verify trie. State for block missing."); + } + + if (!_blockingVerifyTrie.TryStartVerifyTrie(header)) + { + return ResultWrapper.Fail("Unable to start verify trie. Verify trie already running."); + } + + return ResultWrapper.Success("Starting."); + } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs index ecfa719bf8b..f9a338e95db 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; +using Nethermind.Blockchain.Find; using Nethermind.Blockchain.FullPruning; namespace Nethermind.JsonRpc.Modules.Admin; @@ -57,14 +58,19 @@ ResultWrapper admin_peers( IsImplemented = true)] ResultWrapper admin_dataDir(); - [JsonRpcMethod(Description = "[DEPRECATED]", IsImplemented = false)] ResultWrapper admin_setSolc(); - [JsonRpcMethod(Description = "Runs full pruning if enabled.", + [JsonRpcMethod(Description = "True if state root for the block is available", + EdgeCaseHint = "", + ExampleResponse = "\"Starting\"", + IsImplemented = true)] + ResultWrapper admin_isStateRootAvailable(BlockParameter block); + + [JsonRpcMethod(Description = "Runs VerifyTrie.", EdgeCaseHint = "", ExampleResponse = "\"Starting\"", IsImplemented = true)] - ResultWrapper admin_prune(); + ResultWrapper admin_verifyTrie(BlockParameter block); } diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index bc7560cb850..00fcaf0ff35 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs @@ -47,6 +47,7 @@ using Nethermind.Blockchain.Blocks; using Nethermind.Core; using Nethermind.Facade.Find; +using Nethermind.Synchronization.FastSync; namespace Nethermind.Runner.Test.Ethereum { @@ -94,6 +95,7 @@ public static NethermindApi ContextWithMocks() SealValidator = Substitute.For(), SessionMonitor = Substitute.For(), WorldState = Substitute.For(), + BlockingVerifyTrie = Substitute.For(), StateReader = Substitute.For(), TransactionProcessor = Substitute.For(), TxSender = Substitute.For(), diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs index 10e0481d5fe..a444fbef96e 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs @@ -38,63 +38,27 @@ public IContainer CreateTestContainer() .AddSingleton(stateReader) .AddSingleton(treeSync) .AddSingleton(blockQueue) + .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .AddSingleton(LimboLogs.Instance) .Build(); } [Test] - public void TestOnTreeSyncFinish_CallVisit() + public async Task TestOnTreeSyncFinish_CallVisit() { IContainer ctx = CreateTestContainer(); ITreeSync treeSync = ctx.Resolve(); - IStateReader stateReader = ctx.Resolve(); + IBlockingVerifyTrie verifyTrie = ctx.Resolve(); - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); - - stateReader - .Received(1) - .RunTreeVisitor(Arg.Any(), Arg.Is(TestItem.KeccakA), Arg.Any()); - } - - [Test] - public async Task TestOnTreeSyncFinish_BlockProcessingQueue_UntilFinished() - { - IContainer ctx = CreateTestContainer(); - ITreeSync treeSync = ctx.Resolve(); - IStateReader stateReader = ctx.Resolve(); - IBlockProcessingQueue blockQueue = ctx.Resolve(); - - ManualResetEvent treeVisitorBlocker = new ManualResetEvent(false); - - stateReader - .When(sr => sr.RunTreeVisitor(Arg.Any(), Arg.Is(TestItem.KeccakA), Arg.Any())) - .Do((ci) => - { - treeVisitorBlocker.WaitOne(); - }); - - Task triggerTask = Task.Run(() => - { - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); - }); - - await Task.Delay(100); - - Task blockQueueTask = Task.Run(() => - { - blockQueue.BlockRemoved += - Raise.EventWith(null, new BlockRemovedEventArgs(null!, ProcessingResult.Success)); - }); + BlockHeader header = Build.A.BlockHeader.WithStateRoot(TestItem.KeccakA).TestObject; + treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(header)); + treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(header)); await Task.Delay(100); - blockQueueTask.IsCompleted.Should().BeFalse(); - treeVisitorBlocker.Set(); - - await triggerTask; - await blockQueueTask; - blockQueue.BlockRemoved += Raise.EventWith(null, new BlockRemovedEventArgs(null!, ProcessingResult.Success)); + verifyTrie + .Received(1) + .TryStartVerifyTrie(Arg.Any()); } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs new file mode 100644 index 00000000000..eb14dca75dd --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Threading; +using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; +using Nethermind.Config; +using Nethermind.Consensus.Processing; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Db; +using Nethermind.Logging; +using Nethermind.State; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; + +namespace Nethermind.Synchronization.FastSync; + +public class BlockingVerifyTrie( + ITrieStore trieStore, + IStateReader stateReader, + [KeyFilter(DbNames.Code)] IDb codeDb, + IProcessExitSource exitSource, + ILogManager logManager) : IBlockingVerifyTrie +{ + private readonly ILogger _logger = logManager.GetClassLogger(); + + private bool _alreadyRunning = false; + + public bool TryStartVerifyTrie(BlockHeader stateAtBlock) + { + if (Interlocked.CompareExchange(ref _alreadyRunning, true, false)) + { + return false; + } + + Task.Factory.StartNew(() => + { + try + { + _logger!.Info("Collecting trie stats and verifying that no nodes are missing..."); + + Hash256 rootNode = stateAtBlock.StateRoot; + + // This is to block processing as with halfpath old nodes will be removed + using IBlockCommitter? _ = trieStore.BeginBlockCommit(stateAtBlock.Number + 1); + + TrieStats stats = stateReader.CollectStats(rootNode, codeDb, logManager, exitSource.Token); + if (stats.MissingNodes > 0) + { + _logger.Error($"Missing node found!"); + } + + _logger.Info($"Stats after finishing state \n" + stats); + } + catch (OperationCanceledException) + { + } + catch (Exception e) + { + _logger.Error($"Error in verify trie", e); + } + + }, TaskCreationOptions.LongRunning); + + return true; + } +} diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs new file mode 100644 index 00000000000..a47d33dd466 --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; + +namespace Nethermind.Synchronization.FastSync; + +public interface IBlockingVerifyTrie +{ + bool TryStartVerifyTrie(BlockHeader stateAtBlock); +} diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs index 3dc7ca4450e..20995559577 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core; using Nethermind.Core.Crypto; namespace Nethermind.Synchronization.FastSync; @@ -10,8 +11,8 @@ public interface ITreeSync { public event EventHandler SyncCompleted; - public class SyncCompletedEventArgs(Hash256 root) : EventArgs + public class SyncCompletedEventArgs(BlockHeader header) : EventArgs { - public Hash256 Root => root; + public BlockHeader Pivot => header; } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs index 4266b6e6aa5..8e8e520944b 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs @@ -765,7 +765,10 @@ private void VerifyPostSyncCleanUp() CleanupMemory(); - SyncCompleted?.Invoke(this, new ITreeSync.SyncCompletedEventArgs(_rootNode)); + if (_stateSyncPivot.GetPivotHeader() is { } pivotHeader) + { + SyncCompleted?.Invoke(this, new ITreeSync.SyncCompletedEventArgs(pivotHeader)); + } } private void CleanupMemory() diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs index 1331350810f..67ccc96a969 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs @@ -1,30 +1,12 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; -using System.Threading; using Autofac; -using Autofac.Features.AttributeFilters; -using Nethermind.Config; -using Nethermind.Consensus.Processing; -using Nethermind.Core.Crypto; -using Nethermind.Db; -using Nethermind.Logging; -using Nethermind.State; -using Nethermind.Trie; namespace Nethermind.Synchronization.FastSync; -public class VerifyStateOnStateSyncFinished( - IBlockProcessingQueue processingQueue, - ITreeSync treeSync, - IStateReader stateReader, - [KeyFilter(DbNames.Code)] IDb codeDb, - IProcessExitSource exitSource, - ILogManager logManager) : IStartable +public class VerifyStateOnStateSyncFinished(IBlockingVerifyTrie blockingVerifyTrie, ITreeSync treeSync) : IStartable { - private readonly ILogger _logger = logManager.GetClassLogger(); - public void Start() { treeSync.SyncCompleted += TreeSyncOnOnVerifyPostSyncCleanup; @@ -34,36 +16,6 @@ private void TreeSyncOnOnVerifyPostSyncCleanup(object? sender, ITreeSync.SyncCom { treeSync.SyncCompleted -= TreeSyncOnOnVerifyPostSyncCleanup; - ManualResetEvent processingBlocker = new ManualResetEvent(false); - - processingQueue.BlockRemoved += ProcessingQueueOnBlockRemoved; - - try - { - Hash256 rootNode = evt.Root; - _logger!.Info("Collecting trie stats and verifying that no nodes are missing..."); - TrieStats stats = stateReader.CollectStats(rootNode, codeDb, logManager, exitSource.Token); - if (stats.MissingNodes > 0) - { - _logger.Error($"Missing node found!"); - } - _logger.Info($"Stats after finishing state \n" + stats); - } - catch (Exception e) - { - _logger.Error($"Error in verify trie", e); - } - finally - { - processingBlocker.Set(); - processingQueue.BlockRemoved -= ProcessingQueueOnBlockRemoved; - } - - return; - - void ProcessingQueueOnBlockRemoved(object? o, BlockRemovedEventArgs blockRemovedEventArgs) - { - processingBlocker.WaitOne(); - } + blockingVerifyTrie.TryStartVerifyTrie(evt.Pivot); } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs index 629ff50b54d..af3eb1ff028 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs @@ -323,12 +323,15 @@ public IBlockCommitter BeginBlockCommit(long blockNumber) { if (_pruningStrategy.PruningEnabled) { + while (!Monitor.TryEnter(_dirtyNodesLock, TimeSpan.FromSeconds(10))) + { + if (_logger.IsInfo) _logger.Info("Waiting for state to be unlocked."); + } + if (_currentBlockCommitter is not null) { throw new InvalidOperationException("Cannot start a new block commit when an existing one is still not closed"); } - - Monitor.Enter(_dirtyNodesLock); } _currentBlockCommitter = new BlockCommitter(this, CreateCommitSet(blockNumber)); From 73aff9b8707812b16c57e829711852ea618c9557 Mon Sep 17 00:00:00 2001 From: Ahmad Bitar <33181301+smartprogrammer93@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:14:07 +0300 Subject: [PATCH 081/113] fix s and r values in AuthorizationListForRpc (#8013) --- .../Eth/RpcTransaction/AuthorizationListForRpc.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs index 38bc0484741..682e1ffe747 100644 --- a/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs +++ b/src/Nethermind/Nethermind.Facade/Eth/RpcTransaction/AuthorizationListForRpc.cs @@ -56,8 +56,8 @@ authorizationList is null tuple.Nonce, tuple.CodeAddress, tuple.AuthoritySignature.RecoveryId, - new UInt256(tuple.AuthoritySignature.S.Span), - new UInt256(tuple.AuthoritySignature.R.Span)))); + new UInt256(tuple.AuthoritySignature.S.Span, true), + new UInt256(tuple.AuthoritySignature.R.Span, true)))); public AuthorizationTuple[] ToAuthorizationList() => _tuples .Select(static tuple => new AuthorizationTuple( From 34da23ed21ac2aac0b16f0bbcd24d7b2a1f48d8b Mon Sep 17 00:00:00 2001 From: Marcin Sobczak <77129288+marcindsobczak@users.noreply.github.com> Date: Tue, 7 Jan 2025 12:44:47 +0100 Subject: [PATCH 082/113] Add filter for max transaction size (#7925) Co-authored-by: Ruben Buniatyan Co-authored-by: lukasz.rozmej --- src/Nethermind/Nethermind.Core/Transaction.cs | 14 ++++----- .../Nethermind.Core/TxTypeExtensions.cs | 16 ++++++++-- .../Eth/V68/Eth68ProtocolHandlerTests.cs | 2 +- .../Subprotocols/Eth/PooledTxsRequestor.cs | 23 ++++++++------- .../TxBroadcasterTests.cs | 2 +- .../TxPoolTests.Blobs.cs | 18 ++++++++++++ .../Nethermind.TxPool.Test/TxPoolTests.cs | 14 +++++++++ .../Nethermind.TxPool/AcceptTxResult.cs | 5 ++++ .../Nethermind.TxPool/Filters/SizeTxFilter.cs | 29 +++++++++++++++++++ .../Nethermind.TxPool/ITxPoolConfig.cs | 8 +++++ .../NetworkTransactionSizeCalculator.cs | 6 ++-- .../TransactionExtensions.cs | 4 +-- src/Nethermind/Nethermind.TxPool/TxPool.cs | 1 + .../Nethermind.TxPool/TxPoolConfig.cs | 4 +++ 14 files changed, 119 insertions(+), 27 deletions(-) create mode 100644 src/Nethermind/Nethermind.TxPool/Filters/SizeTxFilter.cs diff --git a/src/Nethermind/Nethermind.Core/Transaction.cs b/src/Nethermind/Nethermind.Core/Transaction.cs index 8d7b10d2e76..e47e4301200 100644 --- a/src/Nethermind/Nethermind.Core/Transaction.cs +++ b/src/Nethermind/Nethermind.Core/Transaction.cs @@ -47,10 +47,10 @@ public class Transaction public UInt256 MaxPriorityFeePerGas => GasPrice; public UInt256 DecodedMaxFeePerGas { get; set; } public UInt256 MaxFeePerGas => Supports1559 ? DecodedMaxFeePerGas : GasPrice; - public bool SupportsAccessList => Type >= TxType.AccessList && Type != TxType.DepositTx; - public bool Supports1559 => Type >= TxType.EIP1559 && Type != TxType.DepositTx; - public bool SupportsBlobs => Type == TxType.Blob && Type != TxType.DepositTx; - public bool SupportsAuthorizationList => Type == TxType.SetCode && Type != TxType.DepositTx; + public bool SupportsAccessList => Type.SupportsAccessList(); + public bool Supports1559 => Type.Supports1559(); + public bool SupportsBlobs => Type.SupportsBlobs(); + public bool SupportsAuthorizationList => Type.SupportsAuthorizationList(); public long GasLimit { get; set; } public Address? To { get; set; } public UInt256 Value { get; set; } @@ -195,9 +195,9 @@ private void ClearPreHashInternal() /// /// Encoded transaction length /// - public int GetLength(ITransactionSizeCalculator sizeCalculator) + public int GetLength(ITransactionSizeCalculator sizeCalculator, bool shouldCountBlobs) { - return _size ??= sizeCalculator.GetLength(this); + return _size ??= sizeCalculator.GetLength(this, shouldCountBlobs); } public string ToShortString() @@ -334,7 +334,7 @@ public class SystemTransaction : Transaction /// Created because of cyclic dependencies between Core and Rlp modules public interface ITransactionSizeCalculator { - int GetLength(Transaction tx); + int GetLength(Transaction tx, bool shouldCountBlobs = true); } /// diff --git a/src/Nethermind/Nethermind.Core/TxTypeExtensions.cs b/src/Nethermind/Nethermind.Core/TxTypeExtensions.cs index 8450ffa2650..0a9632b51de 100644 --- a/src/Nethermind/Nethermind.Core/TxTypeExtensions.cs +++ b/src/Nethermind/Nethermind.Core/TxTypeExtensions.cs @@ -6,7 +6,17 @@ namespace Nethermind.Core; public static class TxTypeExtensions { public static bool IsTxTypeWithAccessList(this TxType txType) - { - return txType != TxType.Legacy; - } + => txType != TxType.Legacy; + + public static bool SupportsAccessList(this TxType txType) + => txType >= TxType.AccessList && txType != TxType.DepositTx; + + public static bool Supports1559(this TxType txType) + => txType >= TxType.EIP1559 && txType != TxType.DepositTx; + + public static bool SupportsBlobs(this TxType txType) + => txType == TxType.Blob && txType != TxType.DepositTx; + + public static bool SupportsAuthorizationList(this TxType txType) + => txType == TxType.SetCode && txType != TxType.DepositTx; } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs index 1e6ff9b22b9..99a5d7b3d12 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V68/Eth68ProtocolHandlerTests.cs @@ -231,7 +231,7 @@ public void should_divide_GetPooledTransactionsMessage_if_max_message_size_is_ex _syncManager, RunImmediatelyScheduler.Instance, _transactionPool, - new PooledTxsRequestor(_transactionPool, new TxPoolConfig()), + new PooledTxsRequestor(_transactionPool, new TxPoolConfig() { MaxTxSize = sizeOfOneTx }), _gossipPolicy, new ForkInfo(_specProvider, _genesisBlock.Header.Hash!), LimboLogs.Instance, diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs index f0d77bf2694..50da6984e7c 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/PooledTxsRequestor.cs @@ -13,19 +13,16 @@ namespace Nethermind.Network.P2P.Subprotocols.Eth { - public class PooledTxsRequestor : IPooledTxsRequestor + public class PooledTxsRequestor(ITxPool txPool, ITxPoolConfig txPoolConfig) : IPooledTxsRequestor { private const int MaxNumberOfTxsInOneMsg = 256; - private readonly ITxPool _txPool; - private readonly bool _blobSupportEnabled; + private readonly bool _blobSupportEnabled = txPoolConfig.BlobsSupport.IsEnabled(); + private readonly long _configuredMaxTxSize = txPoolConfig.MaxTxSize ?? long.MaxValue; - private readonly ClockKeyCache _pendingHashes = new(MemoryAllowance.TxHashCacheSize); + private readonly long _configuredMaxBlobTxSize = txPoolConfig.MaxBlobTxSize is not null + ? txPoolConfig.MaxBlobTxSize.Value + (long)Eip4844Constants.MaxBlobGasPerBlock : long.MaxValue; - public PooledTxsRequestor(ITxPool txPool, ITxPoolConfig txPoolConfig) - { - _txPool = txPool; - _blobSupportEnabled = txPoolConfig.BlobsSupport.IsEnabled(); - } + private readonly ClockKeyCache _pendingHashes = new(MemoryAllowance.TxHashCacheSize); public void RequestTransactions(Action send, IOwnedReadOnlyList hashes) { @@ -71,6 +68,10 @@ public void RequestTransactionsEth68(Action maxSize) + continue; + if (txSize > packetSizeLeft && toRequestCount > 0) { RequestPooledTransactionsEth66(send, hashesToRequest); @@ -96,7 +97,7 @@ private ArrayPoolList AddMarkUnknownHashes(ReadOnlySpan hashes for (int i = 0; i < hashes.Length; i++) { Hash256 hash = hashes[i]; - if (!_txPool.IsKnown(hash) && _pendingHashes.Set(hash)) + if (!txPool.IsKnown(hash) && _pendingHashes.Set(hash)) { discoveredTxHashes.Add(hash); } @@ -111,7 +112,7 @@ private ArrayPoolList AddMarkUnknownHashes(ReadOnlySpan hashes for (int i = 0; i < hashes.Length; i++) { Hash256 hash = hashes[i]; - if (!_txPool.IsKnown(hash) && !_txPool.ContainsTx(hash, (TxType)types[i]) && _pendingHashes.Set(hash)) + if (!txPool.IsKnown(hash) && !txPool.ContainsTx(hash, (TxType)types[i]) && _pendingHashes.Set(hash)) { discoveredTxHashesAndSizes.Add((hash, types[i], sizes[i])); } diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs index bfb6e47ea4d..e82bfd381e1 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxBroadcasterTests.cs @@ -196,7 +196,7 @@ public void should_announce_details_of_full_blob_tx() _broadcaster.AddPeer(peer); _broadcaster.BroadcastPersistentTxs(); - peer.Received(1).SendNewTransactions(Arg.Is>(t => t.FirstOrDefault().GetLength() == size), false); + peer.Received(1).SendNewTransactions(Arg.Is>(t => t.FirstOrDefault().GetLength(true) == size), false); } [Test] diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.Blobs.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.Blobs.cs index 6e2d074f0d2..823c29abc7b 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.Blobs.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.Blobs.cs @@ -42,6 +42,24 @@ public void should_reject_blob_tx_if_blobs_not_supported([Values(true, false)] b : AcceptTxResult.NotSupportedTxType); } + [Test] + public void should_reject_blob_tx_if_max_size_is_exceeded([Values(true, false)] bool sizeExceeded, [Values(1, 2, 3, 4, 5, 6)] int numberOfBlobs) + { + Transaction tx = Build.A.Transaction + .WithShardBlobTxTypeAndFields(numberOfBlobs) + .WithMaxPriorityFeePerGas(1.GWei()) + .WithMaxFeePerGas(1.GWei()) + .SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).TestObject; + EnsureSenderBalance(TestItem.AddressA, UInt256.MaxValue); + + var txPoolConfig = new TxPoolConfig() { MaxBlobTxSize = tx.GetLength(shouldCountBlobs: false) - (sizeExceeded ? 1 : 0) }; + _txPool = CreatePool(txPoolConfig, GetCancunSpecProvider()); + + AcceptTxResult result = _txPool.SubmitTx(tx, TxHandlingOptions.PersistentBroadcast); + result.Should().Be(sizeExceeded ? AcceptTxResult.MaxTxSizeExceeded : AcceptTxResult.Accepted); + _txPool.GetPendingBlobTransactionsCount().Should().Be(sizeExceeded ? 0 : 1); + } + [Test] public void blob_pool_size_should_be_correct([Values(true, false)] bool persistentStorageEnabled) { diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 15080e212a2..995725f12e2 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -361,6 +361,20 @@ public void should_ignore_block_gas_limit_exceeded() result.Should().Be(AcceptTxResult.GasLimitExceeded); } + [Test] + public void should_reject_tx_if_max_size_is_exceeded([Values(true, false)] bool sizeExceeded) + { + Transaction tx = Build.A.Transaction.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).TestObject; + EnsureSenderBalance(tx); + + var txPoolConfig = new TxPoolConfig() { MaxTxSize = tx.GetLength() - (sizeExceeded ? 1 : 0) }; + _txPool = CreatePool(txPoolConfig); + + AcceptTxResult result = _txPool.SubmitTx(tx, TxHandlingOptions.PersistentBroadcast); + result.Should().Be(sizeExceeded ? AcceptTxResult.MaxTxSizeExceeded : AcceptTxResult.Accepted); + _txPool.GetPendingTransactionsCount().Should().Be(sizeExceeded ? 0 : 1); + } + [Test] public void should_accept_tx_when_base_fee_is_high() { diff --git a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs index fc2cc0c1a1c..6ea1126b15e 100644 --- a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs +++ b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs @@ -90,6 +90,11 @@ namespace Nethermind.TxPool /// public static readonly AcceptTxResult NotSupportedTxType = new(15, nameof(NotSupportedTxType)); + /// + /// Transaction size exceeds configured max size. + /// + public static readonly AcceptTxResult MaxTxSizeExceeded = new(16, nameof(MaxTxSizeExceeded)); + /// /// The node is syncing and cannot accept transactions at this time. /// diff --git a/src/Nethermind/Nethermind.TxPool/Filters/SizeTxFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/SizeTxFilter.cs new file mode 100644 index 00000000000..9060df8518e --- /dev/null +++ b/src/Nethermind/Nethermind.TxPool/Filters/SizeTxFilter.cs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Logging; + +namespace Nethermind.TxPool.Filters; + +/// +/// Ignores transactions that exceed configured max transaction size limit. +/// +internal sealed class SizeTxFilter(ITxPoolConfig txPoolConfig, ILogger logger) : IIncomingTxFilter +{ + private readonly long _configuredMaxTxSize = txPoolConfig.MaxTxSize ?? long.MaxValue; + private readonly long _configuredMaxBlobTxSize = txPoolConfig.MaxBlobTxSize ?? long.MaxValue; + + public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandlingOptions txHandlingOptions) + { + long maxSize = tx.SupportsBlobs ? _configuredMaxBlobTxSize : _configuredMaxTxSize; + + if (tx.GetLength(shouldCountBlobs: false) > maxSize) + { + if (logger.IsTrace) logger.Trace($"Skipped adding transaction {tx.ToString(" ")}, max tx size exceeded."); + return AcceptTxResult.MaxTxSizeExceeded; + } + + return AcceptTxResult.Accepted; + } +} diff --git a/src/Nethermind/Nethermind.TxPool/ITxPoolConfig.cs b/src/Nethermind/Nethermind.TxPool/ITxPoolConfig.cs index 1f064c616c3..49a7adbdb6a 100644 --- a/src/Nethermind/Nethermind.TxPool/ITxPoolConfig.cs +++ b/src/Nethermind/Nethermind.TxPool/ITxPoolConfig.cs @@ -43,6 +43,14 @@ public interface ITxPoolConfig : IConfig long? GasLimit { get; set; } + [ConfigItem(DefaultValue = "131072", + Description = "The max transaction size allowed, in bytes.")] + long? MaxTxSize { get; set; } + + [ConfigItem(DefaultValue = "1048576", + Description = "The max blob transaction size allowed, excluding blobs, in bytes.")] + long? MaxBlobTxSize { get; set; } + [ConfigItem(DefaultValue = "null", Description = "The current transaction pool state reporting interval, in minutes.")] int? ReportMinutes { get; set; } diff --git a/src/Nethermind/Nethermind.TxPool/NetworkTransactionSizeCalculator.cs b/src/Nethermind/Nethermind.TxPool/NetworkTransactionSizeCalculator.cs index 42a8cf0e3b9..122ce4d0792 100644 --- a/src/Nethermind/Nethermind.TxPool/NetworkTransactionSizeCalculator.cs +++ b/src/Nethermind/Nethermind.TxPool/NetworkTransactionSizeCalculator.cs @@ -15,8 +15,10 @@ public NetworkTransactionSizeCalculator(TxDecoder txDecoder) _txDecoder = txDecoder; } - public int GetLength(Transaction tx) + public int GetLength(Transaction tx, bool shouldCountBlobs) { - return _txDecoder.GetLength(tx, RlpBehaviors.InMempoolForm | RlpBehaviors.SkipTypedWrapping); + return shouldCountBlobs + ? _txDecoder.GetLength(tx, RlpBehaviors.InMempoolForm | RlpBehaviors.SkipTypedWrapping) + : _txDecoder.GetLength(tx, RlpBehaviors.SkipTypedWrapping); } } diff --git a/src/Nethermind/Nethermind.TxPool/TransactionExtensions.cs b/src/Nethermind/Nethermind.TxPool/TransactionExtensions.cs index 44598b63e01..45fefb2495e 100644 --- a/src/Nethermind/Nethermind.TxPool/TransactionExtensions.cs +++ b/src/Nethermind/Nethermind.TxPool/TransactionExtensions.cs @@ -16,9 +16,9 @@ public static class TransactionExtensions private static readonly long MaxSizeOfTxForBroadcast = 4.KiB(); //4KB, as in Geth https://github.com/ethereum/go-ethereum/pull/27618 private static readonly ITransactionSizeCalculator _transactionSizeCalculator = new NetworkTransactionSizeCalculator(TxDecoder.Instance); - public static int GetLength(this Transaction tx) + public static int GetLength(this Transaction tx, bool shouldCountBlobs = true) { - return tx.GetLength(_transactionSizeCalculator); + return tx.GetLength(_transactionSizeCalculator, shouldCountBlobs); } public static bool CanPayBaseFee(this Transaction tx, UInt256 currentBaseFee) => tx.MaxFeePerGas >= currentBaseFee; diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index f1f56aa01fc..056990d9caa 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -127,6 +127,7 @@ public TxPool(IEthereumEcdsa ecdsa, _preHashFilters = [ new NotSupportedTxFilter(txPoolConfig, _logger), + new SizeTxFilter(txPoolConfig, _logger), new GasLimitTxFilter(_headInfo, txPoolConfig, _logger), new PriorityFeeTooLowFilter(_logger), new FeeTooLowFilter(_headInfo, _transactions, _blobTransactions, thereIsPriorityContract, _logger), diff --git a/src/Nethermind/Nethermind.TxPool/TxPoolConfig.cs b/src/Nethermind/Nethermind.TxPool/TxPoolConfig.cs index 16d7b5fc6cb..48e4de8fc1f 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPoolConfig.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPoolConfig.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Extensions; + namespace Nethermind.TxPool { public class TxPoolConfig : ITxPoolConfig @@ -18,6 +20,8 @@ public class TxPoolConfig : ITxPoolConfig public int MaxPendingBlobTxsPerSender { get; set; } = 16; public int HashCacheSize { get; set; } = 512 * 1024; public long? GasLimit { get; set; } = null; + public long? MaxTxSize { get; set; } = 128.KiB(); + public long? MaxBlobTxSize { get; set; } = 1.MiB(); public int? ReportMinutes { get; set; } = null; } } From 1320ca368e3de16b2dad7d6855f19c5d654050bb Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 7 Jan 2025 12:12:54 +0000 Subject: [PATCH 083/113] Fix/unspent gas 7623 master (#8017) Co-authored-by: Tanishq Jasoria --- .../TransactionProcessorEip7623Tests.cs | 99 +++++++++++++++++++ .../TransactionProcessor.cs | 7 +- 2 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip7623Tests.cs diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip7623Tests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip7623Tests.cs new file mode 100644 index 00000000000..d0f029608bd --- /dev/null +++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorEip7623Tests.cs @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Grpc.Core; +using Nethermind.Core; +using Nethermind.Core.Extensions; +using Nethermind.Core.Specs; +using Nethermind.Core.Test.Builders; +using Nethermind.Crypto; +using Nethermind.Db; +using Nethermind.Evm.Tracing; +using Nethermind.Evm.TransactionProcessing; +using Nethermind.Facade; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.Specs; +using Nethermind.Specs.Forks; +using Nethermind.State; +using Nethermind.Trie.Pruning; +using NUnit.Framework; + +namespace Nethermind.Evm.Test; + +public class TransactionProcessorEip7623Tests +{ + private ISpecProvider _specProvider; + private IEthereumEcdsa _ethereumEcdsa; + private TransactionProcessor _transactionProcessor; + private IWorldState _stateProvider; + + [SetUp] + public void Setup() + { + MemDb stateDb = new(); + _specProvider = new TestSpecProvider(Prague.Instance); + TrieStore trieStore = new(stateDb, LimboLogs.Instance); + _stateProvider = new WorldState(trieStore, new MemDb(), LimboLogs.Instance); + CodeInfoRepository codeInfoRepository = new(); + VirtualMachine virtualMachine = new(new TestBlockhashProvider(_specProvider), _specProvider, codeInfoRepository, LimboLogs.Instance); + _transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, virtualMachine, codeInfoRepository, LimboLogs.Instance); + _ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId); + } + + [TestCase(21006, true, TestName = "GasLimit=IntrinsicGas")] + [TestCase(21010, false, TestName = "GasLimit=FloorGas")] + + public void transaction_validation_intrinsic_below_floor(long gasLimit, bool isFail) + { + _stateProvider.CreateAccount(TestItem.AddressA, 1.Ether()); + _stateProvider.Commit(_specProvider.GenesisSpec); + _stateProvider.CommitTree(0); + + Transaction tx = Build.A.Transaction + .WithData([0]) + .WithGasPrice(1) + .WithMaxFeePerGas(1) + .WithTo(TestItem.AddressB) + .WithValue(100.GWei()) + .WithGasLimit(gasLimit) + .SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA) + .TestObject; + + Block block = Build.A.Block.WithNumber(long.MaxValue) + .WithTimestamp(MainnetSpecProvider.PragueBlockTimestamp) + .WithTransactions(tx) + .WithGasLimit(10000000).TestObject; + + TransactionResult result = _transactionProcessor.Execute(tx, block.Header, NullTxTracer.Instance); + Assert.That(result.Fail, Is.EqualTo(isFail)); + } + + [Test] + public void balance_validation_intrinsic_below_floor() + { + _stateProvider.CreateAccount(TestItem.AddressA, 1.Ether()); + _stateProvider.Commit(_specProvider.GenesisSpec); + _stateProvider.CommitTree(0); + + Transaction tx = Build.A.Transaction + .WithData([0]) + .WithGasPrice(1) + .WithMaxFeePerGas(1) + .WithTo(TestItem.AddressB) + .WithValue(100.GWei()) + .WithGasLimit(21010) + .SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA) + .TestObject; + + Block block = Build.A.Block.WithNumber(long.MaxValue) + .WithTimestamp(MainnetSpecProvider.PragueBlockTimestamp) + .WithTransactions(tx) + .WithGasLimit(10000000).TestObject; + + _transactionProcessor.Execute(tx, block.Header, NullTxTracer.Instance); + + UInt256 balance = _stateProvider.GetBalance(TestItem.AddressA); + Assert.That(balance, Is.EqualTo(1.Ether() - 100.GWei() - 21010)); + } +} diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 98ba3f4fe83..e98e35048b6 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -763,6 +763,9 @@ protected virtual GasConsumed Refund(Transaction tx, BlockHeader header, IReleas spentGas -= unspentGas; operationGas -= unspentGas; spentGas = Math.Max(spentGas, floorGas); + // As per eip-7623, the spent gas is updated to the maximum of the actual gas used or the floor gas, + // now we need to recalculate the unspent gas that should be refunded. + var unspentGasRefund = tx.GasLimit - spentGas; long totalToRefund = codeInsertRefund; if (!substate.ShouldRevert) @@ -770,10 +773,10 @@ protected virtual GasConsumed Refund(Transaction tx, BlockHeader header, IReleas long actualRefund = RefundHelper.CalculateClaimableRefund(spentGas, totalToRefund, spec); if (Logger.IsTrace) - Logger.Trace("Refunding unused gas of " + unspentGas + " and refund of " + actualRefund); + Logger.Trace("Refunding unused gas of " + unspentGasRefund + " and refund of " + actualRefund); // If noValidation we didn't charge for gas, so do not refund if (!opts.HasFlag(ExecutionOptions.SkipValidation)) - WorldState.AddToBalance(tx.SenderAddress!, (ulong)(unspentGas + actualRefund) * gasPrice, spec); + WorldState.AddToBalance(tx.SenderAddress!, (ulong)(unspentGasRefund + actualRefund) * gasPrice, spec); spentGas -= actualRefund; operationGas -= actualRefund; } From 6e5bef300564160e81dca2719f06be407f033c67 Mon Sep 17 00:00:00 2001 From: Tanishq Jasoria Date: Tue, 7 Jan 2025 17:47:36 +0530 Subject: [PATCH 084/113] update ring buffer size for eip-2935 (#8018) --- src/Nethermind/Nethermind.Core/Eip2935Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Core/Eip2935Constants.cs b/src/Nethermind/Nethermind.Core/Eip2935Constants.cs index d894e6228d4..c03e7e792a4 100644 --- a/src/Nethermind/Nethermind.Core/Eip2935Constants.cs +++ b/src/Nethermind/Nethermind.Core/Eip2935Constants.cs @@ -16,5 +16,5 @@ public static class Eip2935Constants /// /// The HISTORY_SERVE_WINDOW parameter. /// - public static readonly long RingBufferSize = 8192; + public static readonly long RingBufferSize = 8191; } From 54eb0a5fbf02b4597145e95276c1bb847951d9a3 Mon Sep 17 00:00:00 2001 From: Ruben Buniatyan Date: Tue, 7 Jan 2025 14:00:45 +0100 Subject: [PATCH 085/113] Update Nethermind.Numerics.Int256 (#8012) --- src/Nethermind/Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props index 8a9ba749697..3f6601b4df5 100644 --- a/src/Nethermind/Directory.Packages.props +++ b/src/Nethermind/Directory.Packages.props @@ -54,7 +54,7 @@ - + From 0574723c7e2a9679559030fcd253bab81c837149 Mon Sep 17 00:00:00 2001 From: Ruben Buniatyan Date: Tue, 7 Jan 2025 14:01:55 +0100 Subject: [PATCH 086/113] Fix empty value handling of configuration options (#8010) --- ...figProvider_FindIncorrectSettings_Tests.cs | 131 ++++++++++++++---- .../Nethermind.Config/ConfigSourceHelper.cs | 6 +- .../Nethermind.Config/EnvConfigSource.cs | 7 +- 3 files changed, 114 insertions(+), 30 deletions(-) diff --git a/src/Nethermind/Nethermind.Config.Test/ConfigProvider_FindIncorrectSettings_Tests.cs b/src/Nethermind/Nethermind.Config.Test/ConfigProvider_FindIncorrectSettings_Tests.cs index 5f6fb10b984..e06da50a042 100644 --- a/src/Nethermind/Nethermind.Config.Test/ConfigProvider_FindIncorrectSettings_Tests.cs +++ b/src/Nethermind/Nethermind.Config.Test/ConfigProvider_FindIncorrectSettings_Tests.cs @@ -2,24 +2,42 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections; using System.Collections.Generic; using NSubstitute; using NUnit.Framework; namespace Nethermind.Config.Test; -[TestFixture] +[FixtureLifeCycle(LifeCycle.InstancePerTestCase)] [Parallelizable(ParallelScope.All)] public class ConfigProvider_FindIncorrectSettings_Tests { + private IEnvironment _env; + + [SetUp] + public void Initialize() + { + _env = Substitute.For(); + _env.GetEnvironmentVariable(Arg.Any()) + .Returns(call => + { + IDictionary vars = _env.GetEnvironmentVariables(); + var key = call.Arg(); + + return vars.Contains(key) ? vars[key] : null; + }); + } + [Test] public void CorrectSettingNames_CaseInsensitive() { JsonConfigSource? jsonSource = new("SampleJson/CorrectSettingNames.json"); - IEnvironment? env = Substitute.For(); - env.GetEnvironmentVariables().Returns(new Dictionary() { { "NETHERMIND_NETWORKCONFIG_MAXCANDIDATEPEERCOUNT", "500" } }); - EnvConfigSource? envSource = new(env); + Dictionary envVars = new() { { "NETHERMIND_NETWORKCONFIG_MAXCANDIDATEPEERCOUNT", "500" } }; + + _env.GetEnvironmentVariables().Returns(envVars); + EnvConfigSource? envSource = new(_env); ArgsConfigSource? argsSource = new(new Dictionary() { { "DiscoveryConfig.BucketSize", "10" }, @@ -33,20 +51,19 @@ public void CorrectSettingNames_CaseInsensitive() configProvider.Initialize(); (_, IList<(IConfigSource Source, string Category, string Name)> Errors) = configProvider.FindIncorrectSettings(); - Assert.That(Errors.Count, Is.EqualTo(0)); + Assert.That(Errors, Is.Empty); } [Test] public void NoCategorySettings() { - IEnvironment? env = Substitute.For(); - env.GetEnvironmentVariables().Returns(new Dictionary() { + _env.GetEnvironmentVariables().Returns(new Dictionary() { { "NETHERMIND_CLI_SWITCH_LOCAL", "http://localhost:80" }, { "NETHERMIND_CONFIG", "test2.json" }, { "NETHERMIND_XYZ", "xyz" }, // not existing, should get error { "QWER", "qwerty" } // not Nethermind setting, no error }); - EnvConfigSource? envSource = new(env); + EnvConfigSource? envSource = new(_env); ConfigProvider? configProvider = new(); configProvider.AddSource(envSource); @@ -55,10 +72,12 @@ public void NoCategorySettings() (string ErrorMsg, IList<(IConfigSource Source, string Category, string Name)> Errors) = configProvider.FindIncorrectSettings(); - Assert.That(Errors.Count, Is.EqualTo(1)); - Assert.That(Errors[0].Name, Is.EqualTo("XYZ")); - Assert.That(ErrorMsg, Is.EqualTo($"ConfigType:EnvironmentVariable(NETHERMIND_*)|Category:|Name:XYZ")); - + Assert.That(Errors, Has.Count.EqualTo(1)); + Assert.Multiple(() => + { + Assert.That(Errors[0].Name, Is.EqualTo("XYZ")); + Assert.That(ErrorMsg, Is.EqualTo($"ConfigType:EnvironmentVariable(NETHERMIND_*)|Category:|Name:XYZ")); + }); } [Test] @@ -66,11 +85,10 @@ public void SettingWithTypos() { JsonConfigSource? jsonSource = new("SampleJson/ConfigWithTypos.json"); - IEnvironment? env = Substitute.For(); - env.GetEnvironmentVariables().Returns(new Dictionary() { + _env.GetEnvironmentVariables().Returns(new Dictionary() { { "NETHERMIND_NETWORKCONFIG_MAXCANDIDATEPERCOUNT", "500" } // incorrect, should be NETHERMIND_NETWORKCONFIG_MAXCANDIDATEPEERCOUNT }); - EnvConfigSource? envSource = new(env); + EnvConfigSource? envSource = new(_env); ConfigProvider? configProvider = new(); configProvider.AddSource(jsonSource); @@ -80,21 +98,23 @@ public void SettingWithTypos() (string ErrorMsg, IList<(IConfigSource Source, string Category, string Name)> Errors) = configProvider.FindIncorrectSettings(); - Assert.That(Errors.Count, Is.EqualTo(3)); - Assert.That(Errors[0].Name, Is.EqualTo("Concurrenc")); - Assert.That(Errors[1].Category, Is.EqualTo("BlomConfig")); - Assert.That(Errors[2].Name, Is.EqualTo("MAXCANDIDATEPERCOUNT")); - Assert.That(ErrorMsg, Is.EqualTo($"ConfigType:JsonConfigFile|Category:DiscoveRyConfig|Name:Concurrenc{Environment.NewLine}ConfigType:JsonConfigFile|Category:BlomConfig|Name:IndexLevelBucketSizes{Environment.NewLine}ConfigType:EnvironmentVariable(NETHERMIND_*)|Category:NETWORKCONFIG|Name:MAXCANDIDATEPERCOUNT")); + Assert.That(Errors, Has.Count.EqualTo(3)); + Assert.Multiple(() => + { + Assert.That(Errors[0].Name, Is.EqualTo("Concurrenc")); + Assert.That(Errors[1].Category, Is.EqualTo("BlomConfig")); + Assert.That(Errors[2].Name, Is.EqualTo("MAXCANDIDATEPERCOUNT")); + Assert.That(ErrorMsg, Is.EqualTo($"ConfigType:JsonConfigFile|Category:DiscoveRyConfig|Name:Concurrenc{Environment.NewLine}ConfigType:JsonConfigFile|Category:BlomConfig|Name:IndexLevelBucketSizes{Environment.NewLine}ConfigType:EnvironmentVariable(NETHERMIND_*)|Category:NETWORKCONFIG|Name:MAXCANDIDATEPERCOUNT")); + }); } [Test] public void IncorrectFormat() { - IEnvironment? env = Substitute.For(); - env.GetEnvironmentVariables().Returns(new Dictionary() { + _env.GetEnvironmentVariables().Returns(new Dictionary() { { "NETHERMIND_NETWORKCONFIGMAXCANDIDATEPEERCOUNT", "500" } // incorrect, should be NETHERMIND_NETWORKCONFIG_MAXCANDIDATEPEERCOUNT }); - EnvConfigSource? envSource = new(env); + EnvConfigSource? envSource = new(_env); ConfigProvider? configProvider = new(); configProvider.AddSource(envSource); @@ -103,9 +123,68 @@ public void IncorrectFormat() (string ErrorMsg, IList<(IConfigSource Source, string Category, string Name)> Errors) = configProvider.FindIncorrectSettings(); - Assert.That(Errors.Count, Is.EqualTo(1)); - Assert.That(Errors[0].Name, Is.EqualTo("NETWORKCONFIGMAXCANDIDATEPEERCOUNT")); - Assert.That(ErrorMsg, Is.EqualTo($"ConfigType:EnvironmentVariable(NETHERMIND_*)|Category:|Name:NETWORKCONFIGMAXCANDIDATEPEERCOUNT")); + Assert.That(Errors, Has.Count.EqualTo(1)); + Assert.Multiple(() => + { + Assert.That(Errors[0].Name, Is.EqualTo("NETWORKCONFIGMAXCANDIDATEPEERCOUNT")); + Assert.That(ErrorMsg, Is.EqualTo($"ConfigType:EnvironmentVariable(NETHERMIND_*)|Category:|Name:NETWORKCONFIGMAXCANDIDATEPEERCOUNT")); + }); + } + + [Test] + public void Should_keep_blank_string_values() + { + Dictionary envVars = new() + { + { "NETHERMIND_BLOCKSCONFIG_EXTRADATA", "" } + }; + + _env.GetEnvironmentVariables().Returns(envVars); + EnvConfigSource? envSource = new(_env); + + ConfigProvider? configProvider = new(); + configProvider.AddSource(envSource); + + (bool isSet, object value) = envSource.GetValue(typeof(string), "BlocksConfig", "ExtraData"); + + Assert.Multiple(() => + { + Assert.That(isSet, Is.True); + Assert.That(value, Is.Empty); + }); } + [Test] + public void Should_ignore_blank_nonstring_values() + { + Dictionary envVars = new() + { + { "NETHERMIND_BLOOMCONFIG_INDEX", " " }, + { "NETHERMIND_BLOOMCONFIG_MIGRATION", "" } + }; + + _env.GetEnvironmentVariables().Returns(envVars); + EnvConfigSource? envSource = new(_env); + + ConfigProvider? configProvider = new(); + configProvider.AddSource(envSource); + + Assert.DoesNotThrow(configProvider.Initialize); + + (bool isSet, object value) = envSource.GetValue(typeof(bool), "BloomConfig", "Index"); + + Assert.Multiple(() => + { + Assert.That(isSet, Is.False); + Assert.That(((ValueTuple)value).Item2, Is.False); + }); + + (isSet, value) = envSource.GetValue(typeof(bool), "BloomConfig", "Migration"); + + Assert.Multiple(() => + { + Assert.That(isSet, Is.False); + Assert.That(((ValueTuple)value).Item2, Is.False); + }); + } } diff --git a/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs b/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs index 35983aec109..8b305d4fb1f 100644 --- a/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs +++ b/src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs @@ -35,7 +35,7 @@ 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("[")) + if (itemType == typeof(byte) && !valueString.AsSpan().TrimStart().StartsWith('[')) { // hex encoded byte array value = Bytes.FromHexString(valueString.Trim()); @@ -99,13 +99,13 @@ public static object ParseValue(Type valueType, string valueString, string categ } private static bool IsNullString(string valueString) => - string.IsNullOrEmpty(valueString) || valueString.Equals("null", StringComparison.OrdinalIgnoreCase); + valueString?.Equals("null", StringComparison.OrdinalIgnoreCase) ?? true; 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) { - if (!itemValue.StartsWith("0x")) + if (!itemValue.StartsWith("0x", StringComparison.Ordinal)) { value = null; return false; diff --git a/src/Nethermind/Nethermind.Config/EnvConfigSource.cs b/src/Nethermind/Nethermind.Config/EnvConfigSource.cs index 49772650b76..0234482e570 100644 --- a/src/Nethermind/Nethermind.Config/EnvConfigSource.cs +++ b/src/Nethermind/Nethermind.Config/EnvConfigSource.cs @@ -23,6 +23,11 @@ public EnvConfigSource(IEnvironment environmentWrapper) public (bool IsSet, object Value) GetValue(Type type, string category, string name) { (bool isSet, string value) = GetRawValue(category, name); + + // Unset blank values for non-string types + if (type != typeof(string) && string.IsNullOrWhiteSpace(value)) + isSet = false; + return (isSet, isSet ? ConfigSourceHelper.ParseValue(type, value, category, name) : ConfigSourceHelper.GetDefault(type)); } @@ -30,7 +35,7 @@ public EnvConfigSource(IEnvironment environmentWrapper) { var variableName = string.IsNullOrEmpty(category) ? $"NETHERMIND_{name.ToUpperInvariant()}" : $"NETHERMIND_{category.ToUpperInvariant()}_{name.ToUpperInvariant()}"; var variableValueString = _environmentWrapper.GetEnvironmentVariable(variableName); - return string.IsNullOrWhiteSpace(variableValueString) ? (false, null) : (true, variableValueString); + return (variableValueString is not null, variableValueString); } public IEnumerable<(string Category, string Name)> GetConfigKeys() From 95b7d2324ceaf22af91191b992e86e34829828df Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 7 Jan 2025 18:32:27 +0300 Subject: [PATCH 087/113] Ssz encoding generator (#7299) Co-authored-by: Marc Harvey-Hill Co-authored-by: LLHOYH Co-authored-by: ak88 Co-authored-by: Lukasz Rozmej --- src/Nethermind/Directory.Packages.props | 4 +- .../Collections/ArrayPoolSpan.cs | 38 + .../Merkle.BitArray.cs | 8 +- .../Merkle.Containers.cs | 427 ----------- .../Nethermind.Merkleization/Merkle.cs | 118 ++- .../Nethermind.Merkleization/Merkleizer.cs | 620 ++++++---------- .../BitArrayTests.cs | 4 +- .../HashTreeRootTests.cs | 585 --------------- .../MerkleTests.cs | 38 +- .../SszContainersTests.cs | 628 ---------------- .../Crypto/Ssz.Root.cs | 2 + .../MiscDependencies/Ssz.Bytes32.cs | 2 +- .../Ssz.BasicTypes.cs | 36 +- .../Ssz.Configuration.cs | 64 -- .../Ssz.Containers.cs | 1 + .../Ssz.Decode.cs | 203 ++++++ .../Ssz.Encode.cs | 35 + .../SszSerializableAttribute.cs | 21 + .../EncodingTest.cs | 41 ++ ...ind.Serialization.SszGenerator.Test.csproj | 32 + .../SszTypes.cs | 157 ++++ .../AnalyzerReleases.Shipped.md | 3 + .../AnalyzerReleases.Unshipped.md | 9 + .../Analyzers/CollectionTypeAnalyzer.cs | 78 ++ .../PropertyRequiredInSszTypeAnalyzer.cs | 49 ++ .../Analyzers/SszDiagnosticAnalyzer.cs | 29 + .../Attributes.cs | 22 + .../IsExternalInit.cs | 12 + .../Kind.cs | 16 + ...thermind.Serialization.SszGenerator.csproj | 19 + .../Properties/launchSettings.json | 12 + .../README.md | 75 ++ .../SszGenerator.cs | 673 ++++++++++++++++++ .../SszProperty.cs | 99 +++ .../SszType.cs | 178 +++++ .../ShutterApiSimulator.cs | 5 - .../Nethermind.Shutter.csproj | 2 +- .../SlotDecryptionIdentites.cs | 26 + src/Nethermind/Nethermind.sln | 13 + src/bench_precompiles | 2 +- 40 files changed, 2138 insertions(+), 2248 deletions(-) create mode 100644 src/Nethermind/Nethermind.Core/Collections/ArrayPoolSpan.cs delete mode 100644 src/Nethermind/Nethermind.Merkleization/Merkle.Containers.cs delete mode 100644 src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs delete mode 100644 src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs delete mode 100644 src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Configuration.cs create mode 100644 src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Decode.cs create mode 100644 src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Encode.cs create mode 100644 src/Nethermind/Nethermind.Serialization.Ssz/SszSerializableAttribute.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator.Test/EncodingTest.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator.Test/Nethermind.Serialization.SszGenerator.Test.csproj create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator.Test/SszTypes.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Shipped.md create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Unshipped.md create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/CollectionTypeAnalyzer.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/PropertyRequiredInSszTypeAnalyzer.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/SszDiagnosticAnalyzer.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/Attributes.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/IsExternalInit.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/Kind.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/Nethermind.Serialization.SszGenerator.csproj create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/Properties/launchSettings.json create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/README.md create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/SszGenerator.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/SszProperty.cs create mode 100644 src/Nethermind/Nethermind.Serialization.SszGenerator/SszType.cs create mode 100644 src/Nethermind/Nethermind.Shutter/SlotDecryptionIdentites.cs diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props index 3f6601b4df5..49b57be6042 100644 --- a/src/Nethermind/Directory.Packages.props +++ b/src/Nethermind/Directory.Packages.props @@ -36,6 +36,8 @@ + + @@ -83,4 +85,4 @@ - \ No newline at end of file + diff --git a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolSpan.cs b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolSpan.cs new file mode 100644 index 00000000000..79c836a61ee --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolSpan.cs @@ -0,0 +1,38 @@ + +using System.Buffers; +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Nethermind.Core.Collections; + +public readonly struct ArrayPoolSpan(ArrayPool arrayPool, int length) : IDisposable +{ + private readonly T[] _array = arrayPool.Rent(length); + private readonly int _length = length; + public ArrayPoolSpan(int length) : this(ArrayPool.Shared, length) { } + + public readonly int Length => _length; + public readonly ref T this[int index] + { + get + { + if (index > _length) + { + ThrowArgumentOutOfRangeException(); + } + + return ref _array[index]; + + [DoesNotReturn] + static void ThrowArgumentOutOfRangeException() + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + } + + public static implicit operator Span(ArrayPoolSpan arrayPoolSpan) => arrayPoolSpan._array.AsSpan(0, arrayPoolSpan._length); + public static implicit operator ReadOnlySpan(ArrayPoolSpan arrayPoolSpan) => arrayPoolSpan._array.AsSpan(0, arrayPoolSpan._length); + + public readonly void Dispose() => arrayPool.Return(_array); +} diff --git a/src/Nethermind/Nethermind.Merkleization/Merkle.BitArray.cs b/src/Nethermind/Nethermind.Merkleization/Merkle.BitArray.cs index 1c7257852ca..0dd25596531 100644 --- a/src/Nethermind/Nethermind.Merkleization/Merkle.BitArray.cs +++ b/src/Nethermind/Nethermind.Merkleization/Merkle.BitArray.cs @@ -8,17 +8,17 @@ namespace Nethermind.Merkleization; public static partial class Merkle { - public static void IzeBitvector(out UInt256 root, BitArray value) + public static void Ize(out UInt256 root, BitArray value) { Merkleizer merkleizer = new Merkleizer(0); - merkleizer.FeedBitvector(value); + merkleizer.Feed(value); merkleizer.CalculateRoot(out root); } - public static void IzeBitlist(out UInt256 root, BitArray value, ulong maximumBitlistLength) + public static void Ize(out UInt256 root, BitArray value, ulong limit) { Merkleizer merkleizer = new Merkleizer(0); - merkleizer.FeedBitlist(value, maximumBitlistLength); + merkleizer.Feed(value, limit); merkleizer.CalculateRoot(out root); } diff --git a/src/Nethermind/Nethermind.Merkleization/Merkle.Containers.cs b/src/Nethermind/Nethermind.Merkleization/Merkle.Containers.cs deleted file mode 100644 index a16b088d6e7..00000000000 --- a/src/Nethermind/Nethermind.Merkleization/Merkle.Containers.cs +++ /dev/null @@ -1,427 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using Nethermind.Int256; - -namespace Nethermind.Merkleization -{ - // public partial class Merkle - // { - // public static int DepositContractTreeDepth { get; private set; } - // private static int JustificationBitsLength; - // internal static ulong MaximumDepositContracts { get; private set; } - // - // internal static uint MaxValidatorsPerCommittee { get; private set; } - // - // internal static uint SlotsPerEpoch { get; private set; } - // internal static int SlotsPerEth1VotingPeriod { get; private set; } - // public static int SlotsPerHistoricalRoot { get; private set; } - // - // public static int EpochsPerHistoricalVector { get; private set; } - // public static int EpochsPerSlashingsVector { get; private set; } - // internal static ulong HistoricalRootsLimit { get; private set; } - // internal static ulong ValidatorRegistryLimit { get; private set; } - // - // internal static uint MaxProposerSlashings { get; private set; } - // internal static uint MaxAttesterSlashings { get; private set; } - // internal static uint MaxAttestations { get; private set; } - // internal static uint MaxDeposits { get; private set; } - // internal static uint MaxVoluntaryExits { get; private set; } - // - // public static void Init(int depositContractTreeDepth, - // int justificationBitsLength, - // ulong maximumValidatorsPerCommittee, - // ulong slotsPerEpoch, - // ulong slotsPerEth1VotingPeriod, - // ulong slotsPerHistoricalRoot, - // ulong epochsPerHistoricalVector, - // ulong epochsPerSlashingsVector, - // ulong historicalRootsLimit, - // ulong validatorRegistryLimit, - // ulong maximumProposerSlashings, - // ulong maximumAttesterSlashings, - // ulong maximumAttestations, - // ulong maximumDeposits, - // ulong maximumVoluntaryExits - // ) - // { - // DepositContractTreeDepth = depositContractTreeDepth; - // JustificationBitsLength = justificationBitsLength; - // MaxValidatorsPerCommittee = (uint)maximumValidatorsPerCommittee; - // SlotsPerEpoch = (uint)slotsPerEpoch; - // SlotsPerEth1VotingPeriod = (int)slotsPerEth1VotingPeriod; - // SlotsPerHistoricalRoot = (int)slotsPerHistoricalRoot; - // EpochsPerHistoricalVector = (int)epochsPerHistoricalVector; - // EpochsPerSlashingsVector = (int)epochsPerSlashingsVector; - // HistoricalRootsLimit = historicalRootsLimit; - // ValidatorRegistryLimit = validatorRegistryLimit; - // MaxProposerSlashings = (uint)maximumProposerSlashings; - // MaxAttesterSlashings = (uint)maximumAttesterSlashings; - // MaxAttestations = (uint)maximumAttestations; - // MaxDeposits = (uint)maximumDeposits; - // MaxVoluntaryExits = (uint)maximumVoluntaryExits; - // - // MaximumDepositContracts = (ulong) 1 << depositContractTreeDepth; - // } - // } - - public static partial class Merkle - { - - - //public static void Ize(out UInt256 root, BlsPublicKey container) - //{ - // Ize(out root, container.Bytes); - //} - - //public static void Ize(out UInt256 root, BlsSignature container) - //{ - // Ize(out root, container.Bytes); - //} - - //public static void Ize(out UInt256 root, Gwei container) - //{ - // Ize(out root, container.Amount); - //} - - //public static void Ize(out UInt256 root, Slot container) - //{ - // Ize(out root, container.Number); - //} - - //public static void Ize(out UInt256 root, Epoch container) - //{ - // Ize(out root, container.Number); - //} - - //public static void Ize(out UInt256 root, ValidatorIndex container) - //{ - // Ize(out root, container.Number); - //} - - //public static void Ize(out UInt256 root, CommitteeIndex container) - //{ - // Ize(out root, container.Number); - //} - - //public static void Ize(out UInt256 root, Eth1Data? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.DepositRoot); - // merkleizer.Feed(container.DepositCount); - // merkleizer.Feed(container.BlockHash); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, DepositMessage container) - //{ - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.PublicKey); - // merkleizer.Feed(container.WithdrawalCredentials); - // merkleizer.Feed(container.Amount); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, DepositData container) - //{ - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.PublicKey); - // merkleizer.Feed(container.WithdrawalCredentials); - // merkleizer.Feed(container.Amount); - // merkleizer.Feed(container.Signature); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, Ref container) - //{ - // if (container.Root is null) - // { - // Ize(out root, container.Item); - // container.Root = new Root(root); - // } - // else - // { - // container.Root.AsInt(out root); - // } - //} - - //public static void Ize(out UInt256 root, List> value) - //{ - // Merkleizer merkleizer = new Merkleizer(0); - // merkleizer.Feed(value, Ssz.Ssz.MaximumDepositContracts); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, List value) - //{ - // Merkleizer merkleizer = new Merkleizer(0); - // merkleizer.Feed(value, Ssz.Ssz.MaximumDepositContracts); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, AttestationData? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(3); - // merkleizer.Feed(container.Slot); - // merkleizer.Feed(container.Index); - // merkleizer.Feed(container.BeaconBlockRoot); - // merkleizer.Feed(container.Source); - // merkleizer.Feed(container.Target); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, BeaconBlockBody? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(3); - // merkleizer.Feed(container.RandaoReveal); - // merkleizer.Feed(container.Eth1Data); - // merkleizer.Feed(container.Graffiti); - // merkleizer.Feed(container.ProposerSlashings, Ssz.Ssz.MaxProposerSlashings); - // merkleizer.Feed(container.AttesterSlashings, Ssz.Ssz.MaxAttesterSlashings); - // merkleizer.Feed(container.Attestations, Ssz.Ssz.MaxAttestations); - // merkleizer.Feed(container.Deposits, Ssz.Ssz.MaxDeposits); - // merkleizer.Feed(container.VoluntaryExits, Ssz.Ssz.MaxVoluntaryExits); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, BeaconState? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(5); - // merkleizer.Feed(container.GenesisTime); - // merkleizer.Feed(container.Slot); - // merkleizer.Feed(container.Fork); - // merkleizer.Feed(container.LatestBlockHeader); - // merkleizer.Feed(container.BlockRoots); - // merkleizer.Feed(container.StateRoots); - // merkleizer.Feed(container.HistoricalRoots.ToArray(), Ssz.Ssz.HistoricalRootsLimit); - // merkleizer.Feed(container.Eth1Data); - // merkleizer.Feed(container.Eth1DataVotes.ToArray(), (uint)Ssz.Ssz.SlotsPerEth1VotingPeriod); - // merkleizer.Feed(container.Eth1DepositIndex); - // merkleizer.Feed(container.Validators, Ssz.Ssz.ValidatorRegistryLimit); - // merkleizer.Feed(container.Balances.ToArray().ToArray()); - // merkleizer.Feed(container.PreviousEpochAttestations, Ssz.Ssz.MaxAttestations * Ssz.Ssz.SlotsPerEpoch); - // merkleizer.Feed(container.CurrentEpochAttestations, Ssz.Ssz.MaxAttestations * Ssz.Ssz.SlotsPerEpoch); - // merkleizer.FeedBitvector(container.JustificationBits); - // merkleizer.Feed(container.PreviousJustifiedCheckpoint); - // merkleizer.Feed(container.CurrentJustifiedCheckpoint); - // merkleizer.Feed(container.FinalizedCheckpoint); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, BeaconBlock container) - //{ - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.Slot); - // merkleizer.Feed(container.ParentRoot); - // merkleizer.Feed(container.StateRoot); - // merkleizer.Feed(container.Body); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, Attestation? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.FeedBitlist(container.AggregationBits, Ssz.Ssz.MaxValidatorsPerCommittee); - // merkleizer.Feed(container.Data); - // merkleizer.Feed(container.Signature); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, IndexedAttestation? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.AttestingIndices.ToArray(), Ssz.Ssz.MaxValidatorsPerCommittee); - // merkleizer.Feed(container.Data); - // merkleizer.Feed(container.Signature); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, PendingAttestation? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.FeedBitlist(container.AggregationBits, Ssz.Ssz.MaxValidatorsPerCommittee); - // merkleizer.Feed(container.Data); - // merkleizer.Feed(container.InclusionDelay); - // merkleizer.Feed(container.ProposerIndex); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, AttesterSlashing? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(1); - // merkleizer.Feed(container.Attestation1); - // merkleizer.Feed(container.Attestation2); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, Deposit? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(1); - // merkleizer.Feed(container.Proof); - // merkleizer.Feed(container.Data); - // merkleizer.CalculateRoot(out root); - //} - - private static readonly UInt256 RootOfNull; - - //public static void Ize(out UInt256 root, ProposerSlashing container) - //{ - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.ProposerIndex); - // merkleizer.Feed(container.SignedHeader1); - // merkleizer.Feed(container.SignedHeader2); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, Fork? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.Value.PreviousVersion); - // merkleizer.Feed(container.Value.CurrentVersion); - // merkleizer.Feed(container.Value.Epoch); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, Checkpoint? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(1); - // merkleizer.Feed(container.Value.Epoch); - // merkleizer.Feed(container.Value.Root); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, HistoricalBatch? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(1); - // merkleizer.Feed(container.BlockRoots); - // merkleizer.Feed(container.StateRoots); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, SignedVoluntaryExit container) - //{ - // Merkleizer merkleizer = new Merkleizer(1); - // merkleizer.Feed(container.Message); - // merkleizer.Feed(container.Signature); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, VoluntaryExit container) - //{ - // Merkleizer merkleizer = new Merkleizer(1); - // merkleizer.Feed(container.Epoch); - // merkleizer.Feed(container.ValidatorIndex); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, Validator? container) - //{ - // if (container is null) - // { - // root = RootOfNull; - // return; - // } - - // Merkleizer merkleizer = new Merkleizer(3); - // merkleizer.Feed(container.PublicKey); - // merkleizer.Feed(container.WithdrawalCredentials); - // merkleizer.Feed(container.EffectiveBalance); - // merkleizer.Feed(container.IsSlashed); - // merkleizer.Feed(container.ActivationEligibilityEpoch); - // merkleizer.Feed(container.ActivationEpoch); - // merkleizer.Feed(container.ExitEpoch); - // merkleizer.Feed(container.WithdrawableEpoch); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, BeaconBlockHeader container) - //{ - // Merkleizer merkleizer = new Merkleizer(2); - // merkleizer.Feed(container.Slot); - // merkleizer.Feed(container.ParentRoot); - // merkleizer.Feed(container.StateRoot); - // merkleizer.Feed(container.BodyRoot); - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, SignedBeaconBlockHeader container) - //{ - // Merkleizer merkleizer = new Merkleizer(1); - // merkleizer.Feed(container.Message); - // merkleizer.Feed(container.Signature); - // merkleizer.CalculateRoot(out root); - //} - } -} diff --git a/src/Nethermind/Nethermind.Merkleization/Merkle.cs b/src/Nethermind/Nethermind.Merkleization/Merkle.cs index 23e161686fc..b35d618f986 100644 --- a/src/Nethermind/Nethermind.Merkleization/Merkle.cs +++ b/src/Nethermind/Nethermind.Merkleization/Merkle.cs @@ -28,6 +28,8 @@ private static void BuildZeroHashes() } } + private static readonly UInt256 RootOfNull; + static Merkle() { BuildZeroHashes(); @@ -88,48 +90,54 @@ public static void MixIn(ref UInt256 root, int value) root = HashConcatenation(root, lengthPart, 0); } - public static void Ize(out UInt256 root, bool value) + public static void Merkleize(out UInt256 root, bool value) { root = value ? UInt256.One : UInt256.Zero; } - public static void Ize(out UInt256 root, byte value) + public static void Merkleize(out UInt256 root, byte value) { root = new UInt256(value); } - public static void Ize(out UInt256 root, ushort value) + public static void Merkleize(out UInt256 root, ushort value) { root = new UInt256(value); } - public static void Ize(out UInt256 root, int value) + public static void Merkleize(out UInt256 root, int value) { var v = value < 0 ? ulong.MaxValue : 0L; root = new UInt256((ulong)value, v, v, v); } - public static void Ize(out UInt256 root, uint value) + public static void Merkleize(out UInt256 root, uint value) { root = new UInt256(value); } - public static void Ize(out UInt256 root, ulong value) + public static void Merkleize(out UInt256 root, long value) + { + var v = value < 0 ? ulong.MaxValue : 0L; + root = new UInt256((ulong)value, v, v, v); + } + + public static void Merkleize(out UInt256 root, ulong value) { root = new UInt256(value); } - public static void Ize(out UInt256 root, UInt128 value) + public static void Merkleize(out UInt256 root, UInt128 value) { root = new UInt256((ulong)(value & ulong.MaxValue), (ulong)(value >> 64)); } - public static void Ize(out UInt256 root, UInt256 value) + public static void Merkleize(out UInt256 root, UInt256 value) { root = value; } - public static void Ize(out UInt256 root, Bytes32 value) + public static void Merkleize(out UInt256 root, Bytes32 value) { ReadOnlySpan readOnlyBytes = value.AsSpan(); unsafe @@ -143,7 +151,7 @@ public static void Ize(out UInt256 root, Bytes32 value) } } - public static void Ize(out UInt256 root, Root value) + public static void Merkleize(out UInt256 root, Root value) { ReadOnlySpan readOnlyBytes = value.AsSpan(); unsafe @@ -157,7 +165,7 @@ public static void Ize(out UInt256 root, Root value) } } - public static void Ize(out UInt256 root, ReadOnlySpan value) + public static void Merkleize(out UInt256 root, ReadOnlySpan value) { const int typeSize = 1; int partialChunkLength = value.Length % (32 / typeSize); @@ -166,15 +174,15 @@ public static void Ize(out UInt256 root, ReadOnlySpan value) ReadOnlySpan fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc bool[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); } else { - Ize(out root, MemoryMarshal.Cast(value)); + Merkleize(out root, MemoryMarshal.Cast(value)); } } - public static void Ize(out UInt256 root, ReadOnlySpan value) + public static void Merkleize(out UInt256 root, ReadOnlySpan value) { const int typeSize = 1; int partialChunkLength = value.Length % (32 / typeSize); @@ -183,15 +191,15 @@ public static void Ize(out UInt256 root, ReadOnlySpan value) ReadOnlySpan fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc byte[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); } else { - Ize(out root, MemoryMarshal.Cast(value)); + Merkleize(out root, MemoryMarshal.Cast(value)); } } - public static void Ize(out UInt256 root, ReadOnlySpan value, ulong chunkCount) + public static void Merkleize(out UInt256 root, ReadOnlySpan value, ulong chunkCount) { const int typeSize = 1; int partialChunkLength = value.Length % (32 / typeSize); @@ -200,15 +208,15 @@ public static void Ize(out UInt256 root, ReadOnlySpan value, ulong chunkCo ReadOnlySpan fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc byte[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk), chunkCount); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk), chunkCount); } else { - Ize(out root, MemoryMarshal.Cast(value), chunkCount); + Merkleize(out root, MemoryMarshal.Cast(value), chunkCount); } } - public static void IzeBits(out UInt256 root, Span value, uint limit) + public static void MerkleizeBits(out UInt256 root, Span value, uint limit) { // reset lowest bit perf int lastBitPosition = ResetLastBit(ref value[^1]); @@ -225,11 +233,11 @@ public static void IzeBits(out UInt256 root, Span value, uint limit) Span fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc byte[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk), limit); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk), limit); } else { - Ize(out root, MemoryMarshal.Cast(value), default, limit); + Merkleize(out root, MemoryMarshal.Cast(value), default, limit); } MixIn(ref root, length); @@ -288,7 +296,7 @@ private static int ResetLastBit(ref byte lastByte) return 8; } - public static void Ize(out UInt256 root, ReadOnlySpan value) + public static void Merkleize(out UInt256 root, ReadOnlySpan value) { const int typeSize = 2; int partialChunkLength = value.Length % (32 / typeSize); @@ -297,15 +305,15 @@ public static void Ize(out UInt256 root, ReadOnlySpan value) ReadOnlySpan fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc ushort[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); } else { - Ize(out root, MemoryMarshal.Cast(value)); + Merkleize(out root, MemoryMarshal.Cast(value)); } } - public static void Ize(out UInt256 root, ReadOnlySpan value) + public static void Merkleize(out UInt256 root, ReadOnlySpan value) { const int typeSize = 4; int partialChunkLength = value.Length % (32 / typeSize); @@ -314,15 +322,15 @@ public static void Ize(out UInt256 root, ReadOnlySpan value) ReadOnlySpan fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc uint[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); } else { - Ize(out root, MemoryMarshal.Cast(value)); + Merkleize(out root, MemoryMarshal.Cast(value)); } } - public static void Ize(out UInt256 root, ReadOnlySpan value, ulong maxLength = 0U) + public static void Merkleize(out UInt256 root, ReadOnlySpan value, ulong maxLength = 0U) { const int typeSize = sizeof(ulong); ulong limit = (maxLength * typeSize + 31) / 32; @@ -332,11 +340,11 @@ public static void Ize(out UInt256 root, ReadOnlySpan value, ulong maxLen ReadOnlySpan fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc ulong[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk), limit); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk), limit); } else { - Ize(out root, MemoryMarshal.Cast(value), limit); + Merkleize(out root, MemoryMarshal.Cast(value), limit); } } @@ -349,15 +357,15 @@ public static void Ize(out UInt256 root, ReadOnlySpan value) ReadOnlySpan fullChunks = value[..^partialChunkLength]; Span lastChunk = stackalloc UInt128[32 / typeSize]; value[^partialChunkLength..].CopyTo(lastChunk); - Ize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); + Merkleize(out root, MemoryMarshal.Cast(fullChunks), MemoryMarshal.Cast(lastChunk)); } else { - Ize(out root, MemoryMarshal.Cast(value)); + Merkleize(out root, MemoryMarshal.Cast(value)); } } - public static void Ize(out UInt256 root, ReadOnlySpan value, ReadOnlySpan lastChunk, ulong limit = 0) + public static void Merkleize(out UInt256 root, ReadOnlySpan value, ReadOnlySpan lastChunk, ulong limit = 0) { if (limit == 0 && (value.Length + lastChunk.Length == 1)) { @@ -381,47 +389,7 @@ public static void Ize(out UInt256 root, ReadOnlySpan value, ReadOnlySp merkleizer.CalculateRoot(out root); } - //public static void Ize(out UInt256 root, List> value, ulong limit) - //{ - // int length = value.Count; - // if (limit == 0 && length == 1) - // { - // Merkle.Ize(out root, value[0]); - // return; - // } - - // int depth = NextPowerOfTwoExponent(limit == 0UL ? (ulong)length : limit); - // Merkleizer merkleizer = new Merkleizer(depth); - // for (int i = 0; i < length; i++) - // { - // Merkle.Ize(out UInt256 subroot, value[i]); - // merkleizer.Feed(subroot); - // } - - // merkleizer.CalculateRoot(out root); - //} - - //public static void Ize(out UInt256 root, List value, ulong limit) - //{ - // int length = value.Count; - // if (limit == 0 && length == 1) - // { - // Merkle.Ize(out root, value[0]); - // return; - // } - - // int depth = NextPowerOfTwoExponent(limit == 0UL ? (ulong)length : limit); - // Merkleizer merkleizer = new Merkleizer(depth); - // for (int i = 0; i < length; i++) - // { - // Merkle.Ize(out UInt256 subroot, value[i]); - // merkleizer.Feed(subroot); - // } - - // merkleizer.CalculateRoot(out root); - //} - - public static void Ize(out UInt256 root, ReadOnlySpan value, ulong limit = 0UL) + public static void Merkleize(out UInt256 root, ReadOnlySpan value, ulong limit = 0UL) { if (limit == 0 && value.Length == 1) { diff --git a/src/Nethermind/Nethermind.Merkleization/Merkleizer.cs b/src/Nethermind/Nethermind.Merkleization/Merkleizer.cs index edf48702878..2b102b25d00 100644 --- a/src/Nethermind/Nethermind.Merkleization/Merkleizer.cs +++ b/src/Nethermind/Nethermind.Merkleization/Merkleizer.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Runtime.InteropServices; using Nethermind.Core; using Nethermind.Core.Collections; @@ -58,26 +59,153 @@ public void Feed(UInt256 chunk) FeedAtLevel(chunk, 0); } - public void Feed(Span bytes) + public void Feed(long value) { - FeedAtLevel(MemoryMarshal.Cast(bytes)[0], 0); + Merkle.Merkleize(out _chunks[^1], value); + Feed(_chunks[^1]); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], data); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], MemoryMarshal.Cast(data)); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], MemoryMarshal.Cast(data)); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], MemoryMarshal.Cast(data)); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], MemoryMarshal.Cast(data)); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], MemoryMarshal.Cast(data)); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], MemoryMarshal.Cast(data)); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); + } + + public void Feed(Span data, int? limit = null) + { + if (data.Length is 0) + { + Merkle.Merkleize(out _chunks[^1], UInt256.Zero); + } + else + { + Merkle.Merkleize(out _chunks[^1], MemoryMarshal.Cast(data)); + } + + if (limit is not null) Merkle.MixIn(ref _chunks[^1], limit.Value); } public void Feed(bool value) { - Merkle.Ize(out _chunks[^1], value); + Merkle.Merkleize(out _chunks[^1], value); Feed(_chunks[^1]); } public void Feed(uint value) { - Merkle.Ize(out _chunks[^1], value); + Merkle.Merkleize(out _chunks[^1], value); + Feed(_chunks[^1]); + } + public void Feed(int value) + { + Merkle.Merkleize(out _chunks[^1], value); + Feed(_chunks[^1]); + } + public void Feed(int? value) + { + if (value is null) + { + return; + } + Merkle.Merkleize(out _chunks[^1], value.Value); Feed(_chunks[^1]); } public void Feed(ulong value) { - Merkle.Ize(out _chunks[^1], value); + Merkle.Merkleize(out _chunks[^1], value); Feed(_chunks[^1]); } @@ -88,7 +216,7 @@ public void Feed(byte[]? value) return; } - Merkle.Ize(out _chunks[^1], value); + Merkle.Merkleize(out _chunks[^1], value); Feed(_chunks[^1]); } @@ -99,31 +227,53 @@ public void FeedBits(byte[]? value, uint limit) return; } - Merkle.IzeBits(out _chunks[^1], value, limit); + Merkle.MerkleizeBits(out _chunks[^1], value, limit); Feed(_chunks[^1]); } - public void FeedBitvector(BitArray bitArray) + public void Feed(BitArray? vector) { + if (vector is null) return; // bitfield_bytes - byte[] bytes = new byte[(bitArray.Length + 7) / 8]; - bitArray.CopyTo(bytes, 0); + byte[] bytes = new byte[(vector.Length + 7) / 8]; + vector.CopyTo(bytes, 0); - Merkle.Ize(out _chunks[^1], bytes); + Merkle.Merkleize(out _chunks[^1], bytes); Feed(_chunks[^1]); } - public void FeedBitlist(BitArray bitArray, ulong maximumBitlistLength) + public void Feed(BitArray? list, ulong maximumBitlistLength) { + if (list is null) return; + // chunk count ulong chunkCount = (maximumBitlistLength + 255) / 256; // bitfield_bytes - byte[] bytes = new byte[(bitArray.Length + 7) / 8]; - bitArray.CopyTo(bytes, 0); + byte[] bytes = new byte[(list.Length + 7) / 8]; + list.CopyTo(bytes, 0); + + Merkle.Merkleize(out _chunks[^1], bytes, chunkCount); + Merkle.MixIn(ref _chunks[^1], list.Length); + Feed(_chunks[^1]); + } + + public void Feed(IReadOnlyList value, ulong maxLength) + { + if (value is null) + { + return; + } - Merkle.Ize(out _chunks[^1], bytes, chunkCount); - Merkle.MixIn(ref _chunks[^1], bitArray.Length); + using ArrayPoolSpan subRoots = new(value.Count); + + for (int i = 0; i < value.Count; i++) + { + Merkle.Merkleize(out subRoots[i], value[i]); + } + + Merkle.Merkleize(out _chunks[^1], subRoots, maxLength); + Merkle.MixIn(ref _chunks[^1], value.Count); Feed(_chunks[^1]); } @@ -134,405 +284,20 @@ public void Feed(IEnumerable>? value, ulong maxLength) return; } - using ArrayPoolList subRoots = new ArrayPoolList((int)maxLength); + using ArrayPoolSpan subRoots = new(value.Count()); + int i = 0; + foreach (ReadOnlyMemory memory in value) { - Merkle.Ize(out UInt256 root, memory.Span); - subRoots.Add(root); + Merkle.Merkleize(out UInt256 root, memory.Span); + subRoots[i++] = root; } - Merkle.Ize(out _chunks[^1], subRoots.AsSpan(), maxLength); - Merkle.MixIn(ref _chunks[^1], subRoots.Count); + Merkle.Merkleize(out _chunks[^1], subRoots, maxLength); + Merkle.MixIn(ref _chunks[^1], subRoots.Length); Feed(_chunks[^1]); } - //public void Feed(BlsPublicKey? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value.Bytes); - // Feed(_chunks[^1]); - //} - - //public void Feed(BlsSignature? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value.Bytes); - // Feed(_chunks[^1]); - //} - - //public void Feed(ValidatorIndex value) - //{ - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(IReadOnlyList value, ulong maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(IReadOnlyList value, ulong maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(IReadOnlyList value, ulong maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(IReadOnlyList value, ulong maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(IReadOnlyList value, ulong maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(IReadOnlyList value, ulong maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(Eth1Data[]? value, uint maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Length]; - // for (int i = 0; i < value.Length; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Length); - // Feed(_chunks[^1]); - //} - - //public void Feed(IReadOnlyList value, uint maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(ValidatorIndex[]? value, uint maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], MemoryMarshal.Cast(value.AsSpan()), maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Length); - // Feed(_chunks[^1]); - //} - - //public void Feed(Gwei[]? value, ulong maxLength) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], MemoryMarshal.Cast(value.AsSpan()), maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Length); - // Feed(_chunks[^1]); - //} - - //public void Feed(Gwei[]? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], MemoryMarshal.Cast(value.AsSpan())); - // Feed(_chunks[^1]); - //} - - //public void Feed(CommitteeIndex value) - //{ - // Merkle.Ize(out _chunks[^1], value.Number); - // Feed(_chunks[^1]); - //} - - //public void Feed(Epoch value) - //{ - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(Fork? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(Eth1Data? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(Checkpoint? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(BeaconBlockHeader value) - //{ - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(SignedBeaconBlockHeader value) - //{ - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(BeaconBlockBody? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(VoluntaryExit value) - //{ - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(AttestationData? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(IndexedAttestation? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(DepositData? value) - //{ - // if (value is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // Feed(_chunks[^1]); - //} - - //public void Feed(Ref value) - //{ - // if (value.Root is null) - // { - // if (value.Item is null) - // { - // return; - // } - - // Merkle.Ize(out _chunks[^1], value); - // value.Root = new Root(_chunks[^1]); - // Feed(_chunks[^1]); - // } - // else - // { - // Feed(value.Root); - // } - //} - - //public static UInt256 GetSubroot(DepositData depositData) - //{ - // Merkle.Ize(out UInt256 subRoot, depositData); - // return subRoot; - //} - - // public void Feed(List value, ulong maxLength) - // { - // Merkle.Ize(out _chunks[^1], value, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - // } - - //public void Feed(List> value, ulong maxLength) - //{ - // Merkle.Ize(out _chunks[^1], value, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - //public void Feed(List value, ulong maxLength) - //{ - // UInt256[] subRoots = new UInt256[value.Count]; - // for (int i = 0; i < value.Count; i++) - // { - // Merkle.Ize(out subRoots[i], value[i]); - // } - - // Merkle.Ize(out _chunks[^1], subRoots, maxLength); - // Merkle.MixIn(ref _chunks[^1], value.Count); - // Feed(_chunks[^1]); - //} - - - //public void Feed(ForkVersion value) - //{ - // Span padded = stackalloc byte[32]; - // value.AsSpan().CopyTo(padded); - // Merkle.Ize(out _chunks[^1], padded); - // Feed(_chunks[^1]); - //} - - //public void Feed(Gwei value) - //{ - // Merkle.Ize(out _chunks[^1], value.Amount); - // Feed(_chunks[^1]); - //} - - //public void Feed(Slot value) - //{ - // Merkle.Ize(out _chunks[^1], value.Number); - // Feed(_chunks[^1]); - //} - public void Feed(Bytes32 value) { // TODO: Is this going to have correct endianness? (the ulongs inside UInt256 are the correct order, @@ -550,51 +315,66 @@ public void Feed(IReadOnlyList value) // TODO: If the above MemoryMarshal.Cast of a single Bytes32, we could use that here // (rather than the CreateFromLittleEndian() that wants an (unnecessarily) writeable Span.) // Better yet, just MemoryMarshal.Cast the entire span and pass directly to Merkle.Ize ? - UInt256[] input = new UInt256[value.Count]; + using ArrayPoolSpan input = new(value.Count); for (int i = 0; i < value.Count; i++) { - Merkle.Ize(out input[i], value[i]); + Merkle.Merkleize(out input[i], value[i]); } - Merkle.Ize(out _chunks[^1], input); + Merkle.Merkleize(out _chunks[^1], input); Feed(_chunks[^1]); } public void Feed(IReadOnlyList value, ulong maxLength) + { + using ArrayPoolSpan subRoots = new(value.Count); + + for (int i = 0; i < value.Count; i++) + { + Merkle.Merkleize(out subRoots[i], value[i]); + } + + Merkle.Merkleize(out _chunks[^1], subRoots, maxLength); + Merkle.MixIn(ref _chunks[^1], value.Count); + Feed(_chunks[^1]); + } + + public void Feed(IReadOnlyList value, ulong maxLength) { // TODO: If UInt256 is the correct memory layout - UInt256[] subRoots = new UInt256[value.Count]; + using ArrayPoolSpan subRoots = new(value.Count); + for (int i = 0; i < value.Count; i++) { - Merkle.Ize(out subRoots[i], value[i]); + Merkle.Merkleize(out subRoots[i], value[i]); } - Merkle.Ize(out _chunks[^1], subRoots, maxLength); + Merkle.Merkleize(out _chunks[^1], subRoots, maxLength); Merkle.MixIn(ref _chunks[^1], value.Count); Feed(_chunks[^1]); } public void Feed(IReadOnlyList value) { - UInt256[] input = new UInt256[value.Count]; + using ArrayPoolSpan input = new(value.Count); for (int i = 0; i < value.Count; i++) { - Merkle.Ize(out input[i], value[i]); + Merkle.Merkleize(out input[i], value[i]); } - Merkle.Ize(out _chunks[^1], input); + Merkle.Merkleize(out _chunks[^1], input); Feed(_chunks[^1]); } public void Feed(IReadOnlyList value, ulong maxLength) { - UInt256[] subRoots = new UInt256[value.Count]; + using ArrayPoolSpan subRoots = new(value.Count); for (int i = 0; i < value.Count; i++) { - Merkle.Ize(out subRoots[i], value[i]); + Merkle.Merkleize(out subRoots[i], value[i]); } - Merkle.Ize(out _chunks[^1], subRoots, maxLength); + Merkle.Merkleize(out _chunks[^1], subRoots, maxLength); Merkle.MixIn(ref _chunks[^1], value.Count); Feed(_chunks[^1]); } diff --git a/src/Nethermind/Nethermind.Serialization.Ssz.Test/BitArrayTests.cs b/src/Nethermind/Nethermind.Serialization.Ssz.Test/BitArrayTests.cs index 3e850d02bff..21a8e9ab70e 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz.Test/BitArrayTests.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz.Test/BitArrayTests.cs @@ -53,7 +53,7 @@ public void Can_merkleize_bitarray_bitvector(bool[] value, string expectedByteSt // Act var hashTreeRoot = new byte[32]; - Merkle.IzeBitvector(out UInt256 root, input); + Merkle.Ize(out UInt256 root, input); root.ToLittleEndian(hashTreeRoot); // Assert @@ -97,7 +97,7 @@ public void Can_merkleize_bitarray_bitlist(bool[] value, ulong maximumBitlistLen // Act var hashTreeRoot = new byte[32]; - Merkle.IzeBitlist(out UInt256 root, input, maximumBitlistLength); + Merkle.Ize(out UInt256 root, input, maximumBitlistLength); root.ToLittleEndian(hashTreeRoot); // Assert diff --git a/src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs b/src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs deleted file mode 100644 index dfa6ff5867b..00000000000 --- a/src/Nethermind/Nethermind.Serialization.Ssz.Test/HashTreeRootTests.cs +++ /dev/null @@ -1,585 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using System.Linq; -using System.Runtime.InteropServices; -using Nethermind.Core; -//using Nethermind.Core2.Containers; -//using Nethermind.Core2.Crypto; -//using Nethermind.Core2.Types; -using Nethermind.Int256; -using Nethermind.Merkleization; -using NUnit.Framework; -using Shouldly; - -namespace Nethermind.Serialization.Ssz.Test -{ - [TestFixture] - public class HashTreeRootTests - { - [SetUp] - public void Setup() - { - Ssz.Init( - 32, - 4, - 2048, - 32, - 1024, - 8192, - 65536, - 8192, - 16_777_216, - 1_099_511_627_776, - 16, - 1, - 128, - 16, - 16 - ); - } - - //[Test] - //public void Can_merkleize_epoch_0() - //{ - // // arrange - // Epoch epoch = Epoch.Zero; - - // // act - // Merkleizer merklezier = new Merkleizer(0); - // merklezier.Feed(epoch); - // UInt256 root = merklezier.CalculateRoot(); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // // assert - // byte[] expected = HashUtility.Chunk(new byte[] { 0x0 }).ToArray(); - // bytes.ToArray().ShouldBe(expected); - //} - - //[Test] - //public void Can_merkleize_epoch_1() - //{ - // // arrange - // Epoch epoch = Epoch.One; - - // // act - // Merkleizer merklezier = new Merkleizer(0); - // merklezier.Feed(epoch); - // UInt256 root = merklezier.CalculateRoot(); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // // assert - // byte[] expected = HashUtility.Chunk(new byte[] { 0x1 }).ToArray(); - // bytes.ToArray().ShouldBe(expected); - //} - - [Test] - public void Can_merkleize_bytes32() - { - // arrange - Bytes32 bytes32 = new Bytes32(Enumerable.Repeat((byte)0x34, 32).ToArray()); - - // act - Merkle.Ize(out UInt256 root, bytes32); - Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // assert - byte[] expected = Enumerable.Repeat((byte)0x34, 32).ToArray(); - bytes.ToArray().ShouldBe(expected); - } - - //[Test] - //public void Can_merkleize_checkpoint() - //{ - // // arrange - // Checkpoint checkpoint = new Checkpoint( - // new Epoch(3), - // new Root(Enumerable.Repeat((byte)0x34, 32).ToArray()) - // ); - - // // act - // Merkle.Ize(out UInt256 root, checkpoint); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // // assert - // byte[] expected = HashUtility.Hash( - // HashUtility.Chunk(new byte[] { 0x03 }), - // Enumerable.Repeat((byte)0x34, 32).ToArray() - // ).ToArray(); - // bytes.ToArray().ShouldBe(expected); - //} - - //[Test] - //public void Can_merkleize_attestion_data() - //{ - // // arrange - // AttestationData attestationData = new AttestationData( - // Slot.One, - // new CommitteeIndex(2), - // new Root(Enumerable.Repeat((byte)0x12, 32).ToArray()), - // new Checkpoint( - // new Epoch(3), - // new Root(Enumerable.Repeat((byte)0x34, 32).ToArray()) - // ), - // new Checkpoint( - // new Epoch(4), - // new Root(Enumerable.Repeat((byte)0x56, 32).ToArray()) - // ) - // ); - - // // act - // Merkleizer merklezier = new Merkleizer(0); - // merklezier.Feed(attestationData); - // UInt256 root = merklezier.CalculateRoot(); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // // assert - // byte[] expected = HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Chunk(new byte[] { 0x01 }), // slot - // HashUtility.Chunk(new byte[] { 0x02 }) // committee - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x12, 32).ToArray(), // beacon block root - // HashUtility.Hash( // source - // HashUtility.Chunk(new byte[] { 0x03 }), - // Enumerable.Repeat((byte)0x34, 32).ToArray() - // ) - // ) - // ), - // HashUtility.Merge( - // HashUtility.Hash( // target - // HashUtility.Chunk(new byte[] { 0x04 }), - // Enumerable.Repeat((byte)0x56, 32).ToArray() - // ), - // HashUtility.ZeroHashes(0, 2) - // ) - // ).ToArray(); - // bytes.ToArray().ShouldBe(expected); - //} - - //[Test] - //public void Can_merkleize_deposit_data() - //{ - // // arrange - // DepositData depositData = new DepositData( - // new BlsPublicKey(Enumerable.Repeat((byte)0x12, BlsPublicKey.Length).ToArray()), - // new Bytes32(Enumerable.Repeat((byte)0x34, Bytes32.Length).ToArray()), - // new Gwei(5), - // new BlsSignature(Enumerable.Repeat((byte)0x67, BlsSignature.Length).ToArray()) - // ); - - // // act - // Merkle.Ize(out UInt256 root, depositData); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // // assert - // byte[] expected = HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( // public key - // Enumerable.Repeat((byte)0x12, 32).ToArray(), - // HashUtility.Chunk(Enumerable.Repeat((byte)0x12, 16).ToArray()) - // ), - // Enumerable.Repeat((byte)0x34, Bytes32.Length).ToArray() // withdrawal credentials - // ), - // HashUtility.Hash( - // HashUtility.Chunk(new byte[] { 0x05 }), // amount - // HashUtility.Hash( // signature - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x67, 32).ToArray(), - // Enumerable.Repeat((byte)0x67, 32).ToArray() - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x67, 32).ToArray(), - // Enumerable.Repeat((byte)0x00, 32).ToArray() - // ) - // ) - // ) - // ); - - // TestContext.Out.WriteLine("root: {0:x}", root); - // TestContext.Out.WriteLine("bytes: {0}", bytes.ToHexString(true)); - // TestContext.Out.WriteLine("expected: {0}", expected.ToHexString(true)); - - // bytes.ToArray().ShouldBe(expected); - //} - - //[Test] - //public void Can_merkleize_deposit_data_list() - //{ - // // arrange - // DepositData depositData1 = new DepositData( - // new BlsPublicKey(Enumerable.Repeat((byte)0x12, BlsPublicKey.Length).ToArray()), - // new Bytes32(Enumerable.Repeat((byte)0x34, Bytes32.Length).ToArray()), - // new Gwei(5), - // new BlsSignature(Enumerable.Repeat((byte)0x67, BlsSignature.Length).ToArray()) - // ); - // DepositData depositData2 = new DepositData( - // new BlsPublicKey(Enumerable.Repeat((byte)0x9a, BlsPublicKey.Length).ToArray()), - // new Bytes32(Enumerable.Repeat((byte)0xbc, Bytes32.Length).ToArray()), - // new Gwei(0xd), - // new BlsSignature(Enumerable.Repeat((byte)0xef, BlsSignature.Length).ToArray()) - // ); - // List depositDataList = new List { depositData1, depositData2 }; - - // // act - // Merkle.Ize(out UInt256 root, depositDataList); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // Merkle.Ize(out UInt256 root0, depositDataList[0]); - // TestContext.Out.WriteLine("root0: {0:x}", root0); - // Merkle.Ize(out UInt256 root1, depositDataList[1]); - // TestContext.Out.WriteLine("root1: {0:x}", root1); - - // // assert - // byte[] hash1 = HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( // public key - // Enumerable.Repeat((byte)0x12, 32).ToArray(), - // HashUtility.Chunk(Enumerable.Repeat((byte)0x12, 16).ToArray()) - // ), - // Enumerable.Repeat((byte)0x34, Bytes32.Length).ToArray() // withdrawal credentials - // ), - // HashUtility.Hash( - // HashUtility.Chunk(new byte[] { 0x05 }), // amount - // HashUtility.Hash( // signature - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x67, 32).ToArray(), - // Enumerable.Repeat((byte)0x67, 32).ToArray() - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x67, 32).ToArray(), - // Enumerable.Repeat((byte)0x00, 32).ToArray() - // ) - // ) - // ) - // ); - // byte[] hash2 = HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( // public key - // Enumerable.Repeat((byte)0x9a, 32).ToArray(), - // HashUtility.Chunk(Enumerable.Repeat((byte)0x9a, 16).ToArray()) - // ), - // Enumerable.Repeat((byte)0xbc, Bytes32.Length).ToArray() // withdrawal credentials - // ), - // HashUtility.Hash( - // HashUtility.Chunk(new byte[] { 0x0d }), // amount - // HashUtility.Hash( // signature - // HashUtility.Hash( - // Enumerable.Repeat((byte)0xef, 32).ToArray(), - // Enumerable.Repeat((byte)0xef, 32).ToArray() - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0xef, 32).ToArray(), - // Enumerable.Repeat((byte)0x00, 32).ToArray() - // ) - // ) - // ) - // ); - - // TestContext.Out.WriteLine("Hash1: {0}", Bytes.ToHexString(hash1, true)); - // TestContext.Out.WriteLine("Hash2: {0}", Bytes.ToHexString(hash2, true)); - - // byte[] hashList = HashUtility.Merge( // list, depth 32 - // HashUtility.Hash( - // hash1, - // hash2 - // ), - // HashUtility.ZeroHashes(1, 32) - // ).ToArray(); - // TestContext.Out.WriteLine("Hash list: {0}", Bytes.ToHexString(hashList, true)); - - // byte[] expected = HashUtility.Hash( - // hashList, - // HashUtility.Chunk(new byte[] { 0x02 }) // mix in length - // ); - // TestContext.Out.WriteLine("Hash expected: {0}", Bytes.ToHexString(expected, true)); - - // bytes.ToArray().ShouldBe(expected); - //} - - // TODO: Add tests for deposit, and deposit list (for beacon block body) - - // [Test] - // public void Can_merkleize_deposit() - // { - // // arrange - // Deposit deposit = new Deposit( - // Enumerable.Repeat(new Hash32(), 33), - // new DepositData( - // new BlsPublicKey(Enumerable.Repeat((byte) 0x12, BlsPublicKey.Length).ToArray()), - // new Hash32(Enumerable.Repeat((byte) 0x34, Hash32.Length).ToArray()), - // new Gwei(5), - // new BlsSignature(Enumerable.Repeat((byte) 0x67, BlsSignature.Length).ToArray()) - // ) - // ); - // - // // act - // Merkle.Ize(out UInt256 root, deposit); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - // - // // assert - // byte[] expected = HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( // public key - // Enumerable.Repeat((byte) 0x12, 32).ToArray(), - // HashUtility.Chunk(Enumerable.Repeat((byte) 0x12, 16).ToArray()) - // ), - // Enumerable.Repeat((byte) 0x34, Hash32.Length).ToArray() // withdrawal credentials - // ), - // HashUtility.Hash( - // HashUtility.Chunk(new byte[] {0x05}), // amount - // HashUtility.Hash( // signature - // HashUtility.Hash( - // Enumerable.Repeat((byte) 0x67, 32).ToArray(), - // Enumerable.Repeat((byte) 0x67, 32).ToArray() - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte) 0x67, 32).ToArray(), - // Enumerable.Repeat((byte) 0x00, 32).ToArray() - // ) - // ) - // ) - // ); - // - // TestContext.Out.WriteLine("root: {0:x}", root); - // TestContext.Out.WriteLine("bytes: {0}", bytes.ToHexString(true)); - // TestContext.Out.WriteLine("expected: {0}", expected.ToHexString(true)); - // - // bytes.ToArray().ShouldBe(expected); - // } - - //[Test] - //public void Can_merkleize_eth1data() - //{ - // // arrange - // Eth1Data eth1Data = new Eth1Data( - // new Root(Enumerable.Repeat((byte)0x34, Root.Length).ToArray()), - // 5, - // new Bytes32(Enumerable.Repeat((byte)0x67, Bytes32.Length).ToArray()) - // ); - - // // act - // Merkle.Ize(out UInt256 root, eth1Data); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // // assert - // byte[] expected = HashUtility.Hash( - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x34, 32).ToArray(), - // HashUtility.Chunk(new byte[] { 0x05 }) - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x67, 32).ToArray(), - // Enumerable.Repeat((byte)0x00, 32).ToArray() - // ) - // ).ToArray(); - // bytes.ToArray().ShouldBe(expected); - //} - - //[Test] - //public void Can_merkleize_empty_beacon_block_body() - //{ - // // arrange - // List proposerSlashings = new List(); - // List attesterSlashings = new List(); - // List attestations = new List(); - // List deposits = new List(); - // List voluntaryExits = new List(); - - // BeaconBlockBody beaconBlockBody = new BeaconBlockBody( - // new BlsSignature(Enumerable.Repeat((byte)0x12, BlsSignature.Length).ToArray()), - // new Eth1Data( - // new Root(Enumerable.Repeat((byte)0x34, Root.Length).ToArray()), - // 5, - // new Bytes32(Enumerable.Repeat((byte)0x67, Bytes32.Length).ToArray()) - // ), - // new Bytes32(Enumerable.Repeat((byte)0x89, Bytes32.Length).ToArray()), - // proposerSlashings, - // attesterSlashings, - // attestations, - // deposits, - // voluntaryExits - // ); - - // // act - // Merkle.Ize(out UInt256 root, beaconBlockBody); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - - // // assert - // byte[] proposerSlashingsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(4, 5)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] attesterSlashingsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(0, 1)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] attestationsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(7, 8)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] depositsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(4, 5)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] voluntaryExitsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(4, 5)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - - // byte[] expected = HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( // randao - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x12, 32).ToArray(), - // Enumerable.Repeat((byte)0x12, 32).ToArray() - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x12, 32).ToArray(), - // Enumerable.Repeat((byte)0x00, 32).ToArray() - // ) - // ), - // HashUtility.Hash( // eth1data - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x34, 32).ToArray(), - // HashUtility.Chunk(new byte[] { 0x05 }) - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x67, 32).ToArray(), - // Enumerable.Repeat((byte)0x00, 32).ToArray() - // ) - // ) - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte)0x89, Bytes32.Length).ToArray(), // graffiti - // proposerSlashingsHash // proposer slashings - // ) - // ), - // HashUtility.Hash( - // HashUtility.Hash( - // attesterSlashingsHash, // attester slashings - // attestationsHash // attestations - // ), - // HashUtility.Hash( - // depositsHash, // deposits - // voluntaryExitsHash // voluntary exits - // ) - // ) - // ); - - // bytes.ToArray().ShouldBe(expected); - //} - - // TODO: Finish test for beacon block body with data, e.g. deposit, to get it working - - // [Test] - // public void Can_merkleize_beacon_block_body_with_deposit() - // { - // // arrange - // List proposerSlashings = new List(); - // List attesterSlashings = new List(); - // List attestations = new List(); - // List deposits = new List() - // { - // new Deposit( - // Enumerable.Repeat(new Hash32(), 33), - // new DepositData( - // new BlsPublicKey(Enumerable.Repeat((byte) 0x12, BlsPublicKey.Length).ToArray()), - // new Hash32(Enumerable.Repeat((byte) 0x34, Hash32.Length).ToArray()), - // new Gwei(5), - // new BlsSignature(Enumerable.Repeat((byte) 0x67, BlsSignature.Length).ToArray()) - // ) - // ) - // }; - // List voluntaryExits = new List(); - // - // BeaconBlockBody beaconBlockBody = new BeaconBlockBody( - // new BlsSignature(Enumerable.Repeat((byte) 0x12, BlsSignature.Length).ToArray()), - // new Eth1Data( - // new Hash32(Enumerable.Repeat((byte) 0x34, Hash32.Length).ToArray()), - // 5, - // new Hash32(Enumerable.Repeat((byte) 0x67, Hash32.Length).ToArray()) - // ), - // new Bytes32(Enumerable.Repeat((byte) 0x89, Bytes32.Length).ToArray()), - // proposerSlashings, - // attesterSlashings, - // attestations, - // deposits, - // voluntaryExits - // ); - // - // // act - // Merkle.Ize(out UInt256 root, beaconBlockBody); - // Span bytes = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref root, 1)); - // - // // assert - // byte[] proposerSlashingsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(4, 5)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] attesterSlashingsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(0, 1)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] attestationsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(7, 8)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] depositsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(4, 5)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // byte[] voluntaryExitsHash = HashUtility.Hash( - // HashUtility.ZeroHashes(4, 5)[0], - // HashUtility.Chunk(new byte[] { 0x00 }) - // ); - // - // byte[] expected = HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( - // HashUtility.Hash( // randao - // HashUtility.Hash( - // Enumerable.Repeat((byte) 0x12, 32).ToArray(), - // Enumerable.Repeat((byte) 0x12, 32).ToArray() - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte) 0x12, 32).ToArray(), - // Enumerable.Repeat((byte) 0x00, 32).ToArray() - // ) - // ), - // HashUtility.Hash( // eth1data - // HashUtility.Hash( - // Enumerable.Repeat((byte) 0x34, 32).ToArray(), - // HashUtility.Chunk(new byte[] {0x05}) - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte) 0x67, 32).ToArray(), - // Enumerable.Repeat((byte) 0x00, 32).ToArray() - // ) - // ) - // ), - // HashUtility.Hash( - // Enumerable.Repeat((byte) 0x89, Bytes32.Length).ToArray(), // graffiti - // proposerSlashingsHash // proposer slashings - // ) - // ), - // HashUtility.Hash( - // HashUtility.Hash( - // attesterSlashingsHash, // attester slashings - // attestationsHash // attestations - // ), - // HashUtility.Hash( - // depositsHash, // deposits - // voluntaryExitsHash // voluntary exits - // ) - // ) - // ); - // - // bytes.ToArray().ShouldBe(expected); - // } - } -} diff --git a/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs b/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs index b54165083e5..f63bb3f0fe1 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz.Test/MerkleTests.cs @@ -67,42 +67,42 @@ public void Zero_hashes_0_is_correct() [Test] public void Can_merkleize_bool() { - Merkle.Ize(out UInt256 root, true); + Merkle.Merkleize(out UInt256 root, true); Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_byte() { - Merkle.Ize(out UInt256 root, (byte)34); + Merkle.Merkleize(out UInt256 root, (byte)34); Assert.That(root.ToHexString(true), Is.EqualTo("0x2200000000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_ushort() { - Merkle.Ize(out UInt256 root, (ushort)(34 + byte.MaxValue)); + Merkle.Merkleize(out UInt256 root, (ushort)(34 + byte.MaxValue)); Assert.That(root.ToHexString(true), Is.EqualTo("0x2101000000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_uint() { - Merkle.Ize(out UInt256 root, (uint)34 + byte.MaxValue + ushort.MaxValue); + Merkle.Merkleize(out UInt256 root, (uint)34 + byte.MaxValue + ushort.MaxValue); Assert.That(root.ToHexString(true), Is.EqualTo("0x2001010000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_int() { - Merkle.Ize(out UInt256 root, 34 + byte.MaxValue + ushort.MaxValue); + Merkle.Merkleize(out UInt256 root, 34 + byte.MaxValue + ushort.MaxValue); Assert.That(root.ToHexString(true), Is.EqualTo("0x2001010000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_ulong() { - Merkle.Ize(out UInt256 root, (ulong)34 + byte.MaxValue + ushort.MaxValue + uint.MaxValue); + Merkle.Merkleize(out UInt256 root, (ulong)34 + byte.MaxValue + ushort.MaxValue + uint.MaxValue); Assert.That(root.ToHexString(true), Is.EqualTo("0x1f01010001000000000000000000000000000000000000000000000000000000")); } @@ -116,7 +116,7 @@ public void Can_merkleize_uint128() input += uint.MaxValue; input += ulong.MaxValue; - Merkle.Ize(out UInt256 root, input); + Merkle.Merkleize(out UInt256 root, input); Assert.That(root.ToHexString(true), Is.EqualTo("0x1e01010001000000010000000000000000000000000000000000000000000000")); } @@ -130,35 +130,35 @@ public void Can_merkleize_uint256() input += uint.MaxValue; input += ulong.MaxValue; - Merkle.Ize(out UInt256 root, input); + Merkle.Merkleize(out UInt256 root, input); Assert.That(root.ToHexString(true), Is.EqualTo("0x1e01010001000000010000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_bool_vector() { - Merkle.Ize(out UInt256 root, new[] { true, false }); + Merkle.Merkleize(out UInt256 root, new[] { true, false }); Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_ushort_vector() { - Merkle.Ize(out UInt256 root, new[] { (ushort)1, (ushort)3 }); + Merkle.Merkleize(out UInt256 root, new[] { (ushort)1, (ushort)3 }); Assert.That(root.ToHexString(true), Is.EqualTo("0x0100030000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_uint_vector() { - Merkle.Ize(out UInt256 root, new[] { 1U, 3U }); + Merkle.Merkleize(out UInt256 root, new[] { 1U, 3U }); Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000003000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_ulong_vector() { - Merkle.Ize(out UInt256 root, new[] { 1UL, 3UL }); + Merkle.Merkleize(out UInt256 root, new[] { 1UL, 3UL }); Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000030000000000000000000000000000000000000000000000")); } @@ -172,14 +172,14 @@ public void Can_merkleize_uint128_vector() [Test] public void Can_merkleize_uint256_vector() { - Merkle.Ize(out UInt256 root, new UInt256[] { 1 }); + Merkle.Merkleize(out UInt256 root, new UInt256[] { 1 }); Assert.That(root.ToHexString(true), Is.EqualTo("0x0100000000000000000000000000000000000000000000000000000000000000")); } [Test] public void Can_merkleize_uint256_vector_longer() { - Merkle.Ize(out UInt256 root, new UInt256[] { 1, 2, 3, 4 }); + Merkle.Merkleize(out UInt256 root, new UInt256[] { 1, 2, 3, 4 }); Assert.That(root.ToHexString(true), Is.EqualTo("0xbfe3c665d2e561f13b30606c580cb703b2041287e212ade110f0bfd8563e21bb")); } @@ -193,35 +193,35 @@ public void Can_merkleize_uint128_vector_full() [Test] public void Can_merkleize_bitlist() { - Merkle.IzeBits(out UInt256 root, new byte[] { 123 }, 0); + Merkle.MerkleizeBits(out UInt256 root, new byte[] { 123 }, 0); Assert.That(root.ToHexString(true), Is.EqualTo("0xe5e12694be373406e317c583b5fd9e7a642913dc20a5c4947edb202dafbbc0ee")); } [Test] public void Can_merkleize_bitlist_with_limit() { - Merkle.IzeBits(out UInt256 root, new byte[] { 17 }, 2); + Merkle.MerkleizeBits(out UInt256 root, new byte[] { 17 }, 2); Assert.That(root.ToHexString(true), Is.EqualTo("0x60d461bd1cec1a858ba48a27799c9686c15ad1625743bafa70674afc530f981a")); } [Test] public void Can_merkleize_bitlist_high_limit_and_null() { - Merkle.IzeBits(out UInt256 root, new byte[] { 0 }, 8); + Merkle.MerkleizeBits(out UInt256 root, new byte[] { 0 }, 8); Assert.That(root.ToHexString(true), Is.EqualTo("0x881690bb860e3a4f7681f51f1eccc59dac2718eeb0c0585cd698ad0650938b33")); } [Test] public void Can_merkleize_bitlist_high_limit_and_small() { - Merkle.IzeBits(out UInt256 root, new byte[] { 3 }, 8); + Merkle.MerkleizeBits(out UInt256 root, new byte[] { 3 }, 8); Assert.That(root.ToHexString(true), Is.EqualTo("0x9e1ff035a32c3d3085074e676356984c077f70bed47814956a9ef8852dcb8161")); } [Test] public void Can_merkleize_bitvector() { - Merkle.Ize(out UInt256 root, new byte[] { 123 }); + Merkle.Merkleize(out UInt256 root, new byte[] { 123 }); Assert.That(root.ToHexString(true), Is.EqualTo("0x7b00000000000000000000000000000000000000000000000000000000000000")); } diff --git a/src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs b/src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs deleted file mode 100644 index 8e7821c667f..00000000000 --- a/src/Nethermind/Nethermind.Serialization.Ssz.Test/SszContainersTests.cs +++ /dev/null @@ -1,628 +0,0 @@ -//// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -//// SPDX-License-Identifier: LGPL-3.0-only - -//using System; -//using System.Collections; -//using System.Linq; -//using System.Text.Json; -//using Nethermind.Core.Crypto; -//using Nethermind.Core.Extensions; -//using Nethermind.Core2; -//using Nethermind.Core2.Containers; -//using Nethermind.Core2.Crypto; -//using Nethermind.Core2.Json; -//using Nethermind.Core2.Types; -//using Nethermind.Dirichlet.Numerics; -//using Nethermind.Merkleization; -//using NUnit.Framework; -//using Bytes = Nethermind.Core.Extensions.Bytes; -//using Shouldly; - -//namespace Nethermind.Serialization.Ssz.Test -//{ -// [TestFixture] -// public class SszContainersTests -// { -// public static BlsPublicKey TestKey1 = new BlsPublicKey( -// "0x000102030405060708090a0b0c0d0e0f" + -// "101112131415161718191a1b1c1d1e1f" + -// "202122232425262728292a2b2c2d2e2f"); - -// public static BlsSignature TestSig1 = new BlsSignature(new byte[BlsSignature.Length]); - -// [SetUp] -// public void Setup() -// { -// Ssz.Init( -// 32, -// 4, -// 2048, -// 32, -// 1024, -// 8192, -// 65536, -// 8192, -// 16_777_216, -// 1_099_511_627_776, -// 16, -// 1, -// 128, -// 16, -// 16 -// ); -// } - -// //[Test] -// public void Fork_there_and_back() -// { -// Fork container = new Fork(new ForkVersion(new byte[] { 0x01, 0x00, 0x00, 0x00 }), new ForkVersion(new byte[] { 0x02, 0x00, 0x00, 0x00 }), new Epoch(3)); -// Span encoded = new byte[Ssz.ForkLength]; -// Ssz.Encode(encoded, container); -// Fork decoded = Ssz.DecodeFork(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Checkpoint_there_and_back() -// { -// Checkpoint container = new Checkpoint(new Epoch(1), Sha256.RootOfAnEmptyString); -// Span encoded = new byte[Ssz.CheckpointLength]; -// Ssz.Encode(encoded, container); -// Checkpoint decoded = Ssz.DecodeCheckpoint(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Validator_there_and_back() -// { -// Validator container = new Validator( -// TestKey1, -// Sha256.Bytes32OfAnEmptyString, -// Gwei.One, -// true, -// new Epoch(4), -// new Epoch(5), -// new Epoch(6), -// new Epoch(7) -// ); - -// Span encoded = new byte[Ssz.ValidatorLength]; -// Ssz.Encode(encoded, container); -// Validator decoded = Ssz.DecodeValidator(encoded); -// decoded.ShouldBe(container); -// //Assert.AreEqual(container, decoded); -// Assert.AreEqual(7, decoded.WithdrawableEpoch.Number); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Attestation_data_there_and_back() -// { -// AttestationData container = new AttestationData( -// new Slot(1), -// new CommitteeIndex(2), -// Sha256.RootOfAnEmptyString, -// new Checkpoint(new Epoch(1), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(2), Sha256.RootOfAnEmptyString)); - -// Span encoded = new byte[Ssz.AttestationDataLength]; -// Ssz.Encode(encoded, container); -// AttestationData decoded = Ssz.DecodeAttestationData(encoded); -// Assert.AreEqual(container, decoded); - -// Span encodedAgain = new byte[Ssz.AttestationDataLength]; -// Ssz.Encode(encodedAgain, decoded); -// Assert.True(Bytes.AreEqual(encodedAgain, encoded)); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Indexed_attestation_there_and_back() -// { -// AttestationData data = new AttestationData( -// new Slot(1), -// new CommitteeIndex(2), -// Sha256.RootOfAnEmptyString, -// new Checkpoint(new Epoch(1), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(2), Sha256.RootOfAnEmptyString)); - -// IndexedAttestation container = new IndexedAttestation( -// new ValidatorIndex[3], -// data, -// TestSig1); - -// Span encoded = new byte[Ssz.IndexedAttestationLength(container)]; -// Ssz.Encode(encoded, container); -// IndexedAttestation decoded = Ssz.DecodeIndexedAttestation(encoded); - -// decoded.ShouldBe(container); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Pending_attestation_there_and_back() -// { -// AttestationData data = new AttestationData( -// new Slot(1), -// new CommitteeIndex(2), -// Sha256.RootOfAnEmptyString, -// new Checkpoint(new Epoch(1), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(2), Sha256.RootOfAnEmptyString)); - -// PendingAttestation container = new PendingAttestation( -// new BitArray(new byte[3]), -// data, -// new Slot(7), -// new ValidatorIndex(13)); - -// Span encoded = new byte[Ssz.PendingAttestationLength(container)]; -// Ssz.Encode(encoded, container); -// PendingAttestation? decoded = Ssz.DecodePendingAttestation(encoded); - -// decoded.ShouldBe(container); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Eth1_data_there_and_back() -// { -// Eth1Data container = new Eth1Data( -// Sha256.RootOfAnEmptyString, -// 1, -// Sha256.Bytes32OfAnEmptyString); -// Span encoded = new byte[Ssz.Eth1DataLength]; -// Ssz.Encode(encoded, container); -// Eth1Data decoded = Ssz.DecodeEth1Data(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Historical_batch_there_and_back() -// { -// Root[] blockRoots = Enumerable.Repeat(Root.Zero, Ssz.SlotsPerHistoricalRoot).ToArray(); -// Root[] stateRoots = Enumerable.Repeat(Root.Zero, Ssz.SlotsPerHistoricalRoot).ToArray(); -// blockRoots[3] = Sha256.RootOfAnEmptyString; -// stateRoots[7] = Sha256.RootOfAnEmptyString; -// HistoricalBatch container = new HistoricalBatch(blockRoots, stateRoots); -// Span encoded = new byte[Ssz.HistoricalBatchLength()]; -// Ssz.Encode(encoded, container); -// HistoricalBatch? decoded = Ssz.DecodeHistoricalBatch(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Deposit_data_there_and_back() -// { -// DepositData container = new DepositData( -// TestKey1, -// Sha256.Bytes32OfAnEmptyString, -// Gwei.One, -// TestSig1); -// Span encoded = new byte[Ssz.DepositDataLength]; -// Ssz.Encode(encoded, container); -// DepositData decoded = Ssz.DecodeDepositData(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Beacon_block_header_there_and_back() -// { -// BeaconBlockHeader container = new BeaconBlockHeader( -// new Slot(1), -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString); -// Span encoded = new byte[Ssz.BeaconBlockHeaderLength]; -// Ssz.Encode(encoded, container); -// BeaconBlockHeader decoded = Ssz.DecodeBeaconBlockHeader(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Proposer_slashing_there_and_back() -// { -// BeaconBlockHeader header1 = new BeaconBlockHeader( -// new Slot(1), -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString); - -// BeaconBlockHeader header2 = new BeaconBlockHeader( -// new Slot(2), -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString); - -// ProposerSlashing container = new ProposerSlashing( -// new ValidatorIndex(1), -// new SignedBeaconBlockHeader(header1, TestSig1), -// new SignedBeaconBlockHeader(header2, TestSig1)); - -// Span encoded = new byte[Ssz.ProposerSlashingLength]; -// Ssz.Encode(encoded, container); -// ProposerSlashing? decoded = Ssz.DecodeProposerSlashing(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Attester_slashing_there_and_back() -// { -// AttestationData data = new AttestationData( -// new Slot(1), -// new CommitteeIndex(2), -// Sha256.RootOfAnEmptyString, -// new Checkpoint(new Epoch(1), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(2), Sha256.RootOfAnEmptyString)); - -// IndexedAttestation indexedAttestation1 = new IndexedAttestation( -// new ValidatorIndex[3], -// data, -// TestSig1); - -// IndexedAttestation indexedAttestation2 = new IndexedAttestation( -// new ValidatorIndex[5], -// data, -// TestSig1); - -// AttesterSlashing container = new AttesterSlashing(indexedAttestation1, indexedAttestation2); - -// Span encoded = new byte[Ssz.AttesterSlashingLength(container)]; -// Ssz.Encode(encoded, container); -// AttesterSlashing? decoded = Ssz.DecodeAttesterSlashing(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Attestation_there_and_back() -// { -// AttestationData data = new AttestationData( -// new Slot(1), -// new CommitteeIndex(2), -// Sha256.RootOfAnEmptyString, -// new Checkpoint(new Epoch(1), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(2), Sha256.RootOfAnEmptyString)); - -// Attestation container = new Attestation( -// new BitArray(new byte[] { 1, 2, 3 }), -// data, -// TestSig1); - -// Span encoded = new byte[Ssz.AttestationLength(container)]; -// Ssz.Encode(encoded, container); -// Attestation decoded = Ssz.DecodeAttestation(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Deposit_there_and_back() -// { -// DepositData data = new DepositData( -// TestKey1, -// Sha256.Bytes32OfAnEmptyString, -// Gwei.One, -// TestSig1); - -// Bytes32[] proof = Enumerable.Repeat(Bytes32.Zero, Ssz.DepositContractTreeDepth + 1).ToArray(); -// proof[7] = Sha256.Bytes32OfAnEmptyString; -// Deposit container = new Deposit(proof, new Ref(data)); - -// Span encoded = new byte[Ssz.DepositLength()]; -// Ssz.Encode(encoded, container); -// Deposit? decoded = Ssz.DecodeDeposit(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Voluntary_exit_there_and_back() -// { -// VoluntaryExit container = new VoluntaryExit( -// new Epoch(1), -// new ValidatorIndex(2)); - -// Span encoded = new byte[Ssz.VoluntaryExitLength]; -// Ssz.Encode(encoded, container); -// VoluntaryExit? decoded = Ssz.DecodeVoluntaryExit(encoded); -// Assert.AreEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Beacon_block_body_there_and_back() -// { -// Eth1Data eth1Data = new Eth1Data( -// Sha256.RootOfAnEmptyString, -// 1, -// Sha256.Bytes32OfAnEmptyString); - -// Deposit zeroDeposit = new Deposit(Enumerable.Repeat(Bytes32.Zero, Ssz.DepositContractTreeDepth + 1), new Ref(DepositData.Zero)); -// BeaconBlockBody container = new BeaconBlockBody( -// TestSig1, -// eth1Data, -// new Bytes32(new byte[32]), -// Enumerable.Repeat(ProposerSlashing.Zero, 2).ToArray(), -// Enumerable.Repeat(AttesterSlashing.Zero, 3).ToArray(), -// Enumerable.Repeat(Attestation.Zero, 4).ToArray(), -// Enumerable.Repeat(zeroDeposit, 5).ToArray(), -// Enumerable.Repeat(SignedVoluntaryExit.Zero, 6).ToArray() -// ); - -// Span encoded = new byte[Ssz.BeaconBlockBodyLength(container)]; -// Ssz.Encode(encoded, container); -// BeaconBlockBody decoded = Ssz.DecodeBeaconBlockBody(encoded); - -// AssertBeaconBlockBodyEqual(container, decoded); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Beacon_block_body_more_detailed() -// { -// AttestationData data = new AttestationData( -// new Slot(1), -// new CommitteeIndex(4), -// Sha256.RootOfAnEmptyString, -// new Checkpoint(new Epoch(2), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(3), Sha256.RootOfAnEmptyString)); - -// Attestation attestation = new Attestation( -// new BitArray(new byte[5]), -// data, -// TestSig1); - -// Ref depositData = new Ref(new DepositData( -// TestKey1, -// Sha256.Bytes32OfAnEmptyString, -// new Gwei(7), -// TestSig1)); - -// Deposit deposit = new Deposit(Enumerable.Repeat(Bytes32.Zero, Ssz.DepositContractTreeDepth + 1), depositData); - -// IndexedAttestation indexedAttestation1 = new IndexedAttestation( -// new ValidatorIndex[8], -// data, -// TestSig1); - -// IndexedAttestation indexedAttestation2 = new IndexedAttestation( -// new ValidatorIndex[8], -// data, -// TestSig1); - -// AttesterSlashing slashing = new AttesterSlashing(indexedAttestation1, indexedAttestation2); - -// Eth1Data eth1Data = new Eth1Data( -// Sha256.RootOfAnEmptyString, -// 9, -// Sha256.Bytes32OfAnEmptyString); - -// Attestation[] attestations = Enumerable.Repeat(Attestation.Zero, 3).ToArray(); -// attestations[1] = attestation; - -// Deposit zeroDeposit = new Deposit(Enumerable.Repeat(Bytes32.Zero, Ssz.DepositContractTreeDepth + 1), new Ref(DepositData.Zero)); -// Deposit[] deposits = Enumerable.Repeat(zeroDeposit, 3).ToArray(); -// deposits[2] = deposit; - -// Bytes32 graffiti = new Bytes32(new byte[32]); - -// AttesterSlashing[] attesterSlashings = Enumerable.Repeat(AttesterSlashing.Zero, 3).ToArray(); -// attesterSlashings[0] = slashing; - -// ProposerSlashing[] proposerSlashings = Enumerable.Repeat(ProposerSlashing.Zero, 10).ToArray(); - -// SignedVoluntaryExit[] signedVoluntaryExits = Enumerable.Repeat(SignedVoluntaryExit.Zero, 11).ToArray(); - -// BeaconBlockBody body = new BeaconBlockBody( -// TestSig1, -// eth1Data, -// graffiti, -// proposerSlashings, -// attesterSlashings, -// attestations, -// deposits, -// signedVoluntaryExits -// ); - -// byte[] encoded = new byte[Ssz.BeaconBlockBodyLength(body)]; -// Ssz.Encode(encoded, body); -// } - -// [Test] -// public void Beacon_block_there_and_back() -// { -// Eth1Data eth1Data = new Eth1Data( -// Sha256.RootOfAnEmptyString, -// 1, -// Sha256.Bytes32OfAnEmptyString); - -// Deposit zeroDeposit = new Deposit(Enumerable.Repeat(Bytes32.Zero, Ssz.DepositContractTreeDepth + 1), new Ref(DepositData.Zero)); -// BeaconBlockBody beaconBlockBody = new BeaconBlockBody( -// TestSig1, -// eth1Data, -// new Bytes32(new byte[32]), -// Enumerable.Repeat(ProposerSlashing.Zero, 2).ToArray(), -// Enumerable.Repeat(AttesterSlashing.Zero, 3).ToArray(), -// Enumerable.Repeat(Attestation.Zero, 4).ToArray(), -// Enumerable.Repeat(zeroDeposit, 5).ToArray(), -// Enumerable.Repeat(SignedVoluntaryExit.Zero, 6).ToArray() -// ); - -// BeaconBlock container = new BeaconBlock( -// new Slot(1), -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString, -// beaconBlockBody); - -// Span encoded = new byte[Ssz.BeaconBlockLength(container)]; -// Ssz.Encode(encoded, container); -// BeaconBlock decoded = Ssz.DecodeBeaconBlock(encoded); - -// AssertBeaconBlockEqual(container, decoded); - -// Span encodedAgain = new byte[Ssz.BeaconBlockLength(container)]; -// Ssz.Encode(encodedAgain, decoded); - -// Assert.True(Bytes.AreEqual(encodedAgain, encoded)); - -// Merkle.Ize(out UInt256 root, container); -// } - -// [Test] -// public void Beacon_state_there_and_back() -// { -// Eth1Data eth1Data = new Eth1Data( -// Sha256.RootOfAnEmptyString, -// 1, -// Sha256.Bytes32OfAnEmptyString); - -// BeaconBlockHeader beaconBlockHeader = new BeaconBlockHeader( -// new Slot(14), -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString); - -// Deposit zeroDeposit = new Deposit(Enumerable.Repeat(Bytes32.Zero, Ssz.DepositContractTreeDepth + 1), new Ref(DepositData.Zero)); -// BeaconBlockBody beaconBlockBody = new BeaconBlockBody( -// TestSig1, -// eth1Data, -// new Bytes32(new byte[32]), -// Enumerable.Repeat(ProposerSlashing.Zero, 2).ToArray(), -// Enumerable.Repeat(AttesterSlashing.Zero, 3).ToArray(), -// Enumerable.Repeat(Attestation.Zero, 4).ToArray(), -// Enumerable.Repeat(zeroDeposit, 5).ToArray(), -// Enumerable.Repeat(SignedVoluntaryExit.Zero, 6).ToArray() -// ); - -// BeaconBlock beaconBlock = new BeaconBlock( -// new Slot(1), -// Sha256.RootOfAnEmptyString, -// Sha256.RootOfAnEmptyString, -// beaconBlockBody); - -// BeaconState container = new BeaconState( -// 123, -// new Slot(1), -// new Fork(new ForkVersion(new byte[] { 0x05, 0x00, 0x00, 0x00 }), -// new ForkVersion(new byte[] { 0x07, 0x00, 0x00, 0x00 }), new Epoch(3)), -// beaconBlockHeader, -// Enumerable.Repeat(Root.Zero, Ssz.SlotsPerHistoricalRoot).ToArray(), -// Enumerable.Repeat(Root.Zero, Ssz.SlotsPerHistoricalRoot).ToArray(), -// Enumerable.Repeat(Root.Zero, 13).ToArray(), -// eth1Data, -// Enumerable.Repeat(Eth1Data.Zero, 2).ToArray(), -// 1234, -// Enumerable.Repeat(Validator.Zero, 7).ToArray(), -// new Gwei[3], -// Enumerable.Repeat(Bytes32.Zero, Ssz.EpochsPerHistoricalVector).ToArray(), -// new Gwei[Ssz.EpochsPerSlashingsVector], -// Enumerable.Repeat(PendingAttestation.Zero, 1).ToArray(), -// Enumerable.Repeat(PendingAttestation.Zero, 11).ToArray(), -// new BitArray(new byte[] { 0x09 }), -// new Checkpoint(new Epoch(3), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(5), Sha256.RootOfAnEmptyString), -// new Checkpoint(new Epoch(7), Sha256.RootOfAnEmptyString) -// ); - -// JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; -// options.ConfigureNethermindCore2(); -// TestContext.Out.WriteLine("Original state: {0}", JsonSerializer.Serialize(container, options)); - -// int encodedLength = Ssz.BeaconStateLength(container); -// TestContext.Out.WriteLine("Encoded length: {0}", encodedLength); -// Span encoded = new byte[encodedLength]; -// Ssz.Encode(encoded, container); -// BeaconState decoded = Ssz.DecodeBeaconState(encoded); - -// TestContext.Out.WriteLine("Decoded state: {0}", JsonSerializer.Serialize(decoded, options)); - -// AssertBeaconStateEqual(container, decoded); - -// Span encodedAgain = new byte[Ssz.BeaconStateLength(decoded)]; -// Ssz.Encode(encodedAgain, decoded); - -// byte[] encodedArray = encoded.ToArray(); -// byte[] encodedAgainArray = encodedAgain.ToArray(); - -// encodedAgainArray.Length.ShouldBe(encodedArray.Length); -// //encodedAgainArray.ShouldBe(encodedArray); -// //Assert.True(Bytes.AreEqual(encodedAgain, encoded)); - -// Merkle.Ize(out UInt256 root, container); -// } - -// private void AssertBeaconBlockBodyEqual(BeaconBlockBody expected, BeaconBlockBody actual) -// { -// actual.RandaoReveal.ShouldBe(expected.RandaoReveal); -// actual.Eth1Data.ShouldBe(expected.Eth1Data); -// actual.Graffiti.ShouldBe(expected.Graffiti); -// actual.ProposerSlashings.Count.ShouldBe(expected.ProposerSlashings.Count); -// actual.AttesterSlashings.Count.ShouldBe(expected.AttesterSlashings.Count); -// actual.Attestations.Count.ShouldBe(expected.Attestations.Count); -// actual.Deposits.Count.ShouldBe(expected.Deposits.Count); -// actual.VoluntaryExits.Count.ShouldBe(expected.VoluntaryExits.Count); - -// actual.AttesterSlashings.ShouldBe(expected.AttesterSlashings); -// actual.ProposerSlashings.ShouldBe(expected.ProposerSlashings); -// actual.Attestations.ShouldBe(expected.Attestations); -// actual.Deposits.ShouldBe(expected.Deposits); -// actual.VoluntaryExits.ShouldBe(expected.VoluntaryExits); -// } - -// private void AssertBeaconBlockEqual(BeaconBlock expected, BeaconBlock actual) -// { -// actual.Slot.ShouldBe(expected.Slot); -// actual.ParentRoot.ShouldBe(expected.ParentRoot); -// actual.StateRoot.ShouldBe(expected.StateRoot); - -// AssertBeaconBlockBodyEqual(expected.Body, actual.Body); -// } - -// public void AssertBeaconStateEqual(BeaconState expected, BeaconState actual) -// { -// actual.GenesisTime.ShouldBe(expected.GenesisTime); -// actual.Slot.ShouldBe(expected.Slot); -// actual.Fork.ShouldBe(expected.Fork); -// actual.LatestBlockHeader.ShouldBe(expected.LatestBlockHeader); -// actual.BlockRoots.Count.ShouldBe(expected.BlockRoots?.Count ?? 0); -// actual.StateRoots.Count.ShouldBe(expected.StateRoots?.Count ?? 0); -// actual.HistoricalRoots.Count.ShouldBe(expected.HistoricalRoots?.Count ?? 0); -// actual.Eth1Data.ShouldBe(expected.Eth1Data); -// actual.Eth1DataVotes.Count.ShouldBe(expected.Eth1DataVotes?.Count ?? 0); -// actual.Eth1DepositIndex.ShouldBe(expected.Eth1DepositIndex); -// actual.Validators.Count.ShouldBe(expected.Validators?.Count ?? 0); -// actual.Balances.Count.ShouldBe(expected.Balances?.Count ?? 0); -// actual.RandaoMixes.Count.ShouldBe(expected.RandaoMixes?.Count ?? 0); -// actual.Slashings.Count.ShouldBe(expected.Slashings?.Count ?? 0); -// actual.PreviousEpochAttestations.Count.ShouldBe(expected.PreviousEpochAttestations?.Count ?? 0); -// actual.CurrentEpochAttestations.Count.ShouldBe(expected.CurrentEpochAttestations?.Count ?? 0); -// //expected.JustificationBits.Count.ShouldBe(actual.JustificationBits.Count); -// actual.PreviousJustifiedCheckpoint.ShouldBe(expected.PreviousJustifiedCheckpoint); -// actual.CurrentJustifiedCheckpoint.ShouldBe(expected.CurrentJustifiedCheckpoint); -// actual.FinalizedCheckpoint.ShouldBe(expected.FinalizedCheckpoint); -// } -// } -//} diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/Crypto/Ssz.Root.cs b/src/Nethermind/Nethermind.Serialization.Ssz/Crypto/Ssz.Root.cs index 782dec6d669..92308a77518 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz/Crypto/Ssz.Root.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz/Crypto/Ssz.Root.cs @@ -54,6 +54,8 @@ public static Root DecodeRoot(ReadOnlySpan span) return new Root(span); } + + public static Root[] DecodeRoots(ReadOnlySpan span) { if (span.Length == 0) diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/MiscDependencies/Ssz.Bytes32.cs b/src/Nethermind/Nethermind.Serialization.Ssz/MiscDependencies/Ssz.Bytes32.cs index b83e902dc15..e562ce13c1d 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz/MiscDependencies/Ssz.Bytes32.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz/MiscDependencies/Ssz.Bytes32.cs @@ -12,7 +12,7 @@ public static partial class Ssz { public const int Bytes32Length = Bytes32.Length; - public static ReadOnlySpan DecodeBytes(ReadOnlySpan span) + public static byte[] DecodeBytes(ReadOnlySpan span) { return span.ToArray(); } diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.BasicTypes.cs b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.BasicTypes.cs index a18dcc8d18e..f95471e7864 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.BasicTypes.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.BasicTypes.cs @@ -11,52 +11,52 @@ namespace Nethermind.Serialization.Ssz; /// -/// https://github.com/ethereum/eth2.0-specs/blob/dev/specs/simple-serialize.md#simpleserialize-ssz +/// https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md /// public static partial class Ssz { [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Encode(Span span, byte[] value, ref int offset) + public static void Encode(Span span, byte[] value, ref int offset) { Encode(span.Slice(offset, value.Length), value); offset += value.Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Encode(Span span, int value, ref int offset) + public static void Encode(Span span, int value, ref int offset) { BinaryPrimitives.WriteInt32LittleEndian(span.Slice(offset, sizeof(int)), value); offset += sizeof(int); } - private static void Encode(Span span, uint value, ref int offset) + public static void Encode(Span span, uint value, ref int offset) { BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(offset, sizeof(uint)), value); offset += sizeof(uint); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Encode(Span span, ulong value, ref int offset) + public static void Encode(Span span, ulong value, ref int offset) { Encode(span.Slice(offset, sizeof(ulong)), value); offset += sizeof(ulong); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Encode(Span span, UInt256 value, ref int offset) + public static void Encode(Span span, UInt256 value, ref int offset) { Encode(span.Slice(offset, 32), value); offset += 32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Encode(Span span, bool value, ref int offset) + public static void Encode(Span span, bool value, ref int offset) { Encode(span.Slice(offset, 1), value); offset++; } - private static bool DecodeBool(Span span, ref int offset) + public static bool DecodeBool(Span span, ref int offset) { return span[offset++] == 1; } @@ -66,7 +66,7 @@ public static void Encode(Span span, byte value) span[0] = value; } - private static void Encode(Span span, byte value, ref int offset) + public static void Encode(Span span, byte value, ref int offset) { span[offset++] = value; } @@ -95,6 +95,12 @@ public static void Encode(Span span, ulong value) BinaryPrimitives.WriteUInt64LittleEndian(span, value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Encode(Span span, long value) + { + BinaryPrimitives.WriteInt64LittleEndian(span, value); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Encode(Span span, UInt128 value) { @@ -194,7 +200,7 @@ public static void Encode(Span span, Span value) MemoryMarshal.Cast(value).CopyTo(span); } - private static void Encode(Span span, Span value, ref int offset, ref int dynamicOffset) + public static void Encode(Span span, Span value, ref int offset, ref int dynamicOffset) { BinaryPrimitives.WriteInt32LittleEndian(span.Slice(offset, VarOffsetSize), dynamicOffset); offset += VarOffsetSize; @@ -277,7 +283,7 @@ public static ulong DecodeULong(ReadOnlySpan span) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong DecodeULong(ReadOnlySpan span, ref int offset) + public static ulong DecodeULong(ReadOnlySpan span, ref int offset) { ulong result = BinaryPrimitives.ReadUInt64LittleEndian(span.Slice(offset, sizeof(ulong))); offset += sizeof(ulong); @@ -335,7 +341,7 @@ public static UInt256[] DecodeUInts256(Span span) return result; } - private static byte[][] DecodeBytesArrays(ReadOnlySpan span, int itemsCount, int itemLength, ref int offset) + public static byte[][] DecodeBytesArrays(ReadOnlySpan span, int itemsCount, int itemLength, ref int offset) { byte[][] result = new byte[itemsCount][]; @@ -408,7 +414,7 @@ public static Span DecodeBools(Span span) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ThrowTargetLength(int targetLength, int expectedLength) + public static void ThrowTargetLength(int targetLength, int expectedLength) { Type type = typeof(T); throw new InvalidDataException( @@ -416,7 +422,7 @@ private static void ThrowTargetLength(int targetLength, int expectedLength) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ThrowSourceLength(int sourceLength, int expectedLength) + public static void ThrowSourceLength(int sourceLength, int expectedLength) { Type type = typeof(T); throw new InvalidDataException( @@ -424,7 +430,7 @@ private static void ThrowSourceLength(int sourceLength, int expectedLength) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ThrowInvalidSourceArrayLength(int sourceLength, int expectedItemLength) + public static void ThrowInvalidSourceArrayLength(int sourceLength, int expectedItemLength) { Type type = typeof(T); throw new InvalidDataException( diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Configuration.cs b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Configuration.cs deleted file mode 100644 index 8f9381b4941..00000000000 --- a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Configuration.cs +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -namespace Nethermind.Serialization.Ssz; - -public partial class Ssz -{ - public static int DepositContractTreeDepth { get; private set; } - private static int JustificationBitsLength; - public static ulong MaximumDepositContracts { get; private set; } - - public static uint MaxValidatorsPerCommittee { get; private set; } - - public static uint SlotsPerEpoch { get; private set; } - public static int SlotsPerEth1VotingPeriod { get; private set; } - public static int SlotsPerHistoricalRoot { get; private set; } - - public static int EpochsPerHistoricalVector { get; private set; } - public static int EpochsPerSlashingsVector { get; private set; } - public static ulong HistoricalRootsLimit { get; private set; } - public static ulong ValidatorRegistryLimit { get; private set; } - - public static uint MaxProposerSlashings { get; private set; } - public static uint MaxAttesterSlashings { get; private set; } - public static uint MaxAttestations { get; private set; } - public static uint MaxDeposits { get; private set; } - public static uint MaxVoluntaryExits { get; private set; } - - public static void Init(int depositContractTreeDepth, - int justificationBitsLength, - ulong maximumValidatorsPerCommittee, - ulong slotsPerEpoch, - ulong slotsPerEth1VotingPeriod, - ulong slotsPerHistoricalRoot, - ulong epochsPerHistoricalVector, - ulong epochsPerSlashingsVector, - ulong historicalRootsLimit, - ulong validatorRegistryLimit, - ulong maximumProposerSlashings, - ulong maximumAttesterSlashings, - ulong maximumAttestations, - ulong maximumDeposits, - ulong maximumVoluntaryExits - ) - { - DepositContractTreeDepth = depositContractTreeDepth; - JustificationBitsLength = justificationBitsLength; - MaxValidatorsPerCommittee = (uint)maximumValidatorsPerCommittee; - SlotsPerEpoch = (uint)slotsPerEpoch; - SlotsPerEth1VotingPeriod = (int)slotsPerEth1VotingPeriod; - SlotsPerHistoricalRoot = (int)slotsPerHistoricalRoot; - EpochsPerHistoricalVector = (int)epochsPerHistoricalVector; - EpochsPerSlashingsVector = (int)epochsPerSlashingsVector; - HistoricalRootsLimit = historicalRootsLimit; - ValidatorRegistryLimit = validatorRegistryLimit; - MaxProposerSlashings = (uint)maximumProposerSlashings; - MaxAttesterSlashings = (uint)maximumAttesterSlashings; - MaxAttestations = (uint)maximumAttestations; - MaxDeposits = (uint)maximumDeposits; - MaxVoluntaryExits = (uint)maximumVoluntaryExits; - - MaximumDepositContracts = (ulong)1 << depositContractTreeDepth; - } -} diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Containers.cs b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Containers.cs index b9539d7fe94..3055b6038a6 100644 --- a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Containers.cs +++ b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Containers.cs @@ -14,4 +14,5 @@ private static void DecodeDynamicOffset(ReadOnlySpan span, ref int offset, dynamicOffset = (int)DecodeUInt(span.Slice(offset, VarOffsetSize)); offset += sizeof(uint); } + } diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Decode.cs b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Decode.cs new file mode 100644 index 00000000000..6abf2cc1d5b --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Decode.cs @@ -0,0 +1,203 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Buffers.Binary; +using System.Collections; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Nethermind.Int256; + +namespace Nethermind.Serialization.Ssz; + +public static partial class Ssz +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decode(ReadOnlySpan span, out bool result) + { + result = span[0] != 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decode(ReadOnlySpan span, out byte result) + { + ValidateLength(span, sizeof(byte)); + + result = span[0]; + } + + public static void Decode(ReadOnlySpan span, out ushort result) + { + ValidateLength(span, sizeof(ushort)); + + result = BinaryPrimitives.ReadUInt16LittleEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decode(ReadOnlySpan span, out uint result) + { + ValidateLength(span, sizeof(uint)); + + result = BinaryPrimitives.ReadUInt32LittleEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decode(ReadOnlySpan span, out int result) + { + ValidateLength(span, sizeof(int)); + + result = BinaryPrimitives.ReadInt32LittleEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decode(ReadOnlySpan span, out ulong result) + { + ValidateLength(span, sizeof(ulong)); + + result = BinaryPrimitives.ReadUInt64LittleEndian(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Decode(ReadOnlySpan span, out long result) + { + ValidateLength(span, sizeof(long)); + + result = BinaryPrimitives.ReadInt64LittleEndian(span); + } + + public static void Decode(ReadOnlySpan span, out UInt128 result) + { + ValidateLength(span, 16); + + ulong s0 = BinaryPrimitives.ReadUInt64LittleEndian(span[..8]); + ulong s1 = BinaryPrimitives.ReadUInt64LittleEndian(span.Slice(8, 8)); + result = new UInt128(s0, s1); + } + + public static void Decode(ReadOnlySpan span, out UInt256 value) + { + ValidateLength(span, 32); + + value = new UInt256(span); + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + result = span; + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + ValidateArrayLength(span, sizeof(ushort)); + + result = MemoryMarshal.Cast(span); + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + ValidateArrayLength(span, sizeof(short)); + + result = MemoryMarshal.Cast(span); + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + ValidateArrayLength(span, sizeof(uint)); + + result = MemoryMarshal.Cast(span); + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + ValidateArrayLength(span, sizeof(int)); + + result = MemoryMarshal.Cast(span); + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + ValidateArrayLength(span, sizeof(ulong)); + + result = MemoryMarshal.Cast(span); + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + ValidateArrayLength(span, sizeof(long)); + + result = MemoryMarshal.Cast(span); + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + int typeSize = 16; + ValidateArrayLength(span, typeSize); + + UInt128[] array = new UInt128[span.Length / typeSize]; + + for (int i = 0; i < span.Length / typeSize; i++) + { + Decode(span.Slice(i * typeSize, typeSize), out array[i]); + } + + result = array; + } + + public static void Decode(ReadOnlySpan span, out ReadOnlySpan result) + { + int typeSize = 32; + ValidateArrayLength(span, typeSize); + + UInt256[] array = new UInt256[span.Length / typeSize]; + + for (int i = 0; i < span.Length / typeSize; i++) + { + Decode(span.Slice(i * typeSize, typeSize), out array[i]); + } + + result = array; + } + + public static void Decode(ReadOnlySpan span, int vectorLength, out BitArray vector) + { + BitArray value = new BitArray(span.ToArray()) + { + Length = vectorLength + }; + vector = value; + } + + public static void Decode(ReadOnlySpan span, out BitArray list) + { + BitArray value = new BitArray(span.ToArray()); + int length = value.Length - 1; + int lastByte = span[^1]; + int mask = 0x80; + while ((lastByte & mask) == 0 && mask > 0) + { + length--; + mask >>= 1; + } + value.Length = length; + list = value; + } + + private static void ValidateLength(ReadOnlySpan span, int expectedLength) + { + if (span.Length != expectedLength) + { + throw new InvalidDataException( + $"{nameof(DecodeByte)} expects input of length {expectedLength} and received {span.Length}"); + } + } + + private static void ValidateArrayLength(ReadOnlySpan span, int itemLength) + { + if (span.Length % itemLength != 0) + { + throw new InvalidDataException( + $"{nameof(DecodeUShorts)} expects input in multiples of {itemLength} and received {span.Length}"); + } + } +} diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Encode.cs b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Encode.cs new file mode 100644 index 00000000000..34d80555585 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.Ssz/Ssz.Encode.cs @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections; + +namespace Nethermind.Serialization.Ssz; + +public static partial class Ssz +{ + public static void Encode(Span span, BitArray? vector) + { + if (vector is null) + { + return; + } + int byteLength = (vector.Length + 7) / 8; + byte[] bytes = new byte[byteLength]; + vector.CopyTo(bytes, 0); + Encode(span, bytes); + } + + public static void Encode(Span span, BitArray? list, int limit) + { + if (list is null) + { + return; + } + int byteLength = (list.Length + 8) / 8; + byte[] bytes = new byte[byteLength]; + list.CopyTo(bytes, 0); + bytes[byteLength - 1] |= (byte)(1 << (list.Length % 8)); + Encode(span, bytes); + } +} diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/SszSerializableAttribute.cs b/src/Nethermind/Nethermind.Serialization.Ssz/SszSerializableAttribute.cs new file mode 100644 index 00000000000..89830705f1e --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.Ssz/SszSerializableAttribute.cs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; + +namespace Nethermind.Serialization.Ssz; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] +public class SszSerializableAttribute : Attribute; + +[AttributeUsage(AttributeTargets.Property)] +public class SszListAttribute(int limit) : Attribute +{ + public int Limit { get; } = limit; +} + +[AttributeUsage(AttributeTargets.Property)] +public class SszVectorAttribute(int length) : Attribute +{ + public int Length { get; } = length; +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/EncodingTest.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/EncodingTest.cs new file mode 100644 index 00000000000..627829e7bb1 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/EncodingTest.cs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Int256; +using NUnit.Framework; +using System.Linq; + +namespace Nethermind.Serialization.SszGenerator.Test; + +public class EncodingTest +{ + [Test] + public void Test_ComplexStructure_EncodingRoundTrip() + { + ComplexStruct test = new() + { + VariableC = new VariableC { Fixed1 = 2, Fixed2 = [1, 2, 3, 4] }, + Test2 = Enumerable.Range(0, 10).Select(i => (ulong)i).ToArray(), + FixedCVec = Enumerable.Range(0, 10).Select(i => new FixedC()).ToArray(), + VariableCVec = Enumerable.Range(0, 10).Select(i => new VariableC()).ToArray(), + Test2UnionVec = Enumerable.Range(0, 10).Select(i => new UnionTest3() + { + VariableC = new VariableC { Fixed1 = 2, Fixed2 = [1, 2, 3, 4] }, + Test2 = Enumerable.Range(0, 10).Select(i => (ulong)i).ToArray(), + FixedCVec = Enumerable.Range(0, 10).Select(i => new FixedC()).ToArray(), + VariableCVec = Enumerable.Range(0, 10).Select(i => new VariableC()).ToArray(), + BitVec = new System.Collections.BitArray(10), + }).ToArray(), + BitVec = new System.Collections.BitArray(10), + }; + + var encoded = SszEncoding.Encode(test); + SszEncoding.Merkleize(test, out UInt256 root); + SszEncoding.Decode(encoded, out ComplexStruct decodedTest); + + Assert.That(decodedTest.VariableC.Fixed1, Is.EqualTo(test.VariableC.Fixed1)); + Assert.That(decodedTest.VariableC.Fixed2, Is.EqualTo(test.VariableC.Fixed2)); + SszEncoding.Merkleize(test, out UInt256 decodedRoot); + Assert.That(root, Is.EqualTo(decodedRoot)); + } +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/Nethermind.Serialization.SszGenerator.Test.csproj b/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/Nethermind.Serialization.SszGenerator.Test.csproj new file mode 100644 index 00000000000..795e6710761 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/Nethermind.Serialization.SszGenerator.Test.csproj @@ -0,0 +1,32 @@ + + + + false + enable + false + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/SszTypes.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/SszTypes.cs new file mode 100644 index 00000000000..f1249c1ae66 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator.Test/SszTypes.cs @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Merkleization; +using Nethermind.Serialization.Ssz; +using System.Collections; +using System.ComponentModel; + +namespace Nethermind.Serialization.SszGenerator.Test +{ + [SszSerializable] + public struct ComplexStruct + { + public ulong Test1 { get; set; } + + [SszVector(10)] + public ulong[] Test2 { get; set; } + + [SszList(10)] + public ulong[] Test3 { get; set; } + public FixedC FixedC { get; set; } + public VariableC VariableC { get; set; } + + + [SszVector(10)] + public FixedC[] FixedCVec { get; set; } + + [SszList(10)] + public FixedC[] FixedCList { get; set; } + + + [SszVector(10)] + public VariableC[] VariableCVec { get; set; } + + [SszList(10)] + public VariableC[] VariableCList { get; set; } + + public UnionTest3 Test2Union { get; set; } + + [SszVector(10)] + public UnionTest3[]? Test2UnionVec { get; set; } + + [SszList(10)] + public UnionTest3[]? Test2UnionList { get; set; } + + [SszVector(10)] + public BitArray? BitVec { get; set; } + + [SszList(10)] + public BitArray? BitList2 { get; set; } + } + + [SszSerializable] + public struct FixedC + { + public ulong Fixed1 { get; set; } + public ulong Fixed2 { get; set; } + } + + [SszSerializable] + public struct VariableC + { + public ulong Fixed1 { get; set; } + + [SszList(10)] + public ulong[]? Fixed2 { get; set; } + } + + //// Does not compile + //[SszSerializable] + //public struct NoProps + //{ + + //} + + [SszSerializable] + public struct UnionTest3 + { + public Test3Union Selector { get; set; } + public ulong Test1 { get; set; } + + [SszVector(10)] + public ulong[] Test2 { get; set; } + + [SszList(10)] + public ulong[] Test3 { get; set; } + public FixedC FixedC { get; set; } + public VariableC VariableC { get; set; } + + + [SszVector(10)] + public FixedC[] FixedCVec { get; set; } + + [SszList(10)] + public FixedC[] FixedCList { get; set; } + + + [SszVector(10)] + public VariableC[] VariableCVec { get; set; } + + [SszList(10)] + public VariableC[] VariableCList { get; set; } + + public Test2 Test2Union { get; set; } + + [SszVector(10)] + public Test2[]? Test2UnionVec { get; set; } + + [SszList(10)] + public Test2[]? Test2UnionList { get; set; } + + [SszVector(10)] + public BitArray? BitVec { get; set; } + + [SszList(10)] + public BitArray? BitList { get; set; } + } + + [SszSerializable] + public struct Test2 + { + public Test2() + { + int[] x = []; + Merkleizer merkleizer = new Merkleizer(Merkle.NextPowerOfTwoExponent(14)); + merkleizer.Feed(x); + } + + public Test2Union Selector { get; set; } + public long Type1 { get; set; } + public int Type2 { get; set; } + } + + public enum Test2Union : byte + { + None, + Type1, + Type2, + } + public enum Test3Union : byte + { + Test1, + Test2, + Test3, + FixedC, + VariableC, + FixedCVec, + FixedCList, + VariableCVec, + VariableCList, + Test2Union, + Test2UnionVec, + Test2UnionList, + BitVec, + BitList, + } +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Shipped.md b/src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Shipped.md new file mode 100644 index 00000000000..60b59dd99b4 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Shipped.md @@ -0,0 +1,3 @@ +; Shipped analyzer releases +; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Unshipped.md b/src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Unshipped.md new file mode 100644 index 00000000000..af79f7e195f --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/AnalyzerReleases.Unshipped.md @@ -0,0 +1,9 @@ +; Unshipped analyzer release +; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + +### New Rules + +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +SSZ001 | Design | Error | PropertyRequiredInSszTypeAnalyzer +SSZ002 | Design | Error | CollectionTypeAnalyzer diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/CollectionTypeAnalyzer.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/CollectionTypeAnalyzer.cs new file mode 100644 index 00000000000..3892a502d3f --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/CollectionTypeAnalyzer.cs @@ -0,0 +1,78 @@ +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public class CollectionTypeAnalyzer : DiagnosticAnalyzer +{ + public const string DiagnosticId = "SSZ002"; + private static readonly LocalizableString Title = "Property with a collection type should be marked as SszList or SszVector"; + private static readonly LocalizableString MessageFormat = "Property {0} should be marked as SszList or SszVector"; + private const string Category = "Design"; + + private static readonly DiagnosticDescriptor Rule = new(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true); + + public override ImmutableArray SupportedDiagnostics { get { return [Rule]; } } + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration); + } + + private static void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + TypeDeclarationSyntax typeDeclaration = (TypeDeclarationSyntax)context.Node; + + if (!typeDeclaration.AttributeLists.SelectMany(attrList => attrList.Attributes).Any(attr => attr.ToString() == "SszSerializable" || attr.ToString() == "SszSerializableAttribute")) + { + return; + } + + foreach (var property in typeDeclaration.Members.OfType() + .Where(prop => + prop.Modifiers.Any(SyntaxKind.PublicKeyword) && + prop.AccessorList?.Accessors.Any(a => a.Kind() == SyntaxKind.GetAccessorDeclaration && !a.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) == true && + prop.AccessorList?.Accessors.Any(a => a.Kind() == SyntaxKind.SetAccessorDeclaration && !a.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) == true)) + { + CheckProperty(context, property); + } + } + + private static void CheckProperty(SyntaxNodeAnalysisContext context, PropertyDeclarationSyntax propertyDeclaration) + { + static bool IsCollectionType(ITypeSymbol typeSymbol) + { + if (typeSymbol is INamedTypeSymbol namedTypeSymbol) + { + ImmutableArray interfaces = namedTypeSymbol.AllInterfaces; + return interfaces.Any(i => i.Name == "IEnumerable"); + } + + return false; + } + + ITypeSymbol? typeSymbol = context.SemanticModel.GetTypeInfo(propertyDeclaration.Type).Type; + + if (typeSymbol is not null && (typeSymbol is IArrayTypeSymbol || IsCollectionType(typeSymbol))) + { + bool hasRequiredAttribute = propertyDeclaration.AttributeLists + .SelectMany(attrList => attrList.Attributes) + .Any(attr => + { + var name = attr.Name.ToString(); + return name == "SszList" || name == "SszVector" || name == "SszListAttribute" || name == "SszVectorAttribute" || name == "BitArray"; + }); + + if (!hasRequiredAttribute) + { + var diagnostic = Diagnostic.Create(Rule, propertyDeclaration.GetLocation(), propertyDeclaration.Identifier.Text); + context.ReportDiagnostic(diagnostic); + } + } + } +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/PropertyRequiredInSszTypeAnalyzer.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/PropertyRequiredInSszTypeAnalyzer.cs new file mode 100644 index 00000000000..d99d1b13efc --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/PropertyRequiredInSszTypeAnalyzer.cs @@ -0,0 +1,49 @@ +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public class PropertyRequiredInSszTypeAnalyzer : DiagnosticAnalyzer +{ + public const string DiagnosticId = "SSZ001"; + private static readonly LocalizableString Title = "Class or struct marked with SszSerializable must have at least one public property with public getter and setter"; + private static readonly LocalizableString MessageFormat = "Type '{0}' is marked with SszSerializable, but does not have any public property with public getter and setter"; + private static readonly LocalizableString Description = "A class or struct marked with SszSerializable should have at least one public property with both a public getter and setter."; + private const string Category = "Design"; + + private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description); + + public override ImmutableArray SupportedDiagnostics { get { return [Rule]; } } + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration); + } + + private static void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + TypeDeclarationSyntax typeDeclaration = (TypeDeclarationSyntax)context.Node; + + if (!typeDeclaration.AttributeLists.SelectMany(attrList => attrList.Attributes).Any(attr => attr.ToString() == "SszSerializable" || attr.ToString() == "SszSerializableAttribute")) + { + return; + } + + bool hasValidProperty = typeDeclaration.Members.OfType() + .Any(prop => + prop.Modifiers.Any(SyntaxKind.PublicKeyword) && + prop.AccessorList?.Accessors.Any(a => a.Kind() == SyntaxKind.GetAccessorDeclaration && !a.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) == true && + prop.AccessorList?.Accessors.Any(a => a.Kind() == SyntaxKind.SetAccessorDeclaration && !a.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) == true); + + if (!hasValidProperty) + { + Diagnostic diagnostic = Diagnostic.Create(Rule, typeDeclaration.Identifier.GetLocation(), typeDeclaration.Identifier.Text); + context.ReportDiagnostic(diagnostic); + } + } +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/SszDiagnosticAnalyzer.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/SszDiagnosticAnalyzer.cs new file mode 100644 index 00000000000..83c0418577f --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/Analyzers/SszDiagnosticAnalyzer.cs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections; + +public abstract class SszDiagnosticAnalyzer : DiagnosticAnalyzer +{ + protected static string[] SszSerializableAttributeNames = ["SszSerializable", "SszSerializableAttribute"]; + protected static string[] SszCollectionAttributeNames = ["SszVector", "SszList", "SszListAttribute", "SszVectorAttribute"]; + + protected static bool IsSerializableType(TypeDeclarationSyntax type) => + type.AttributeLists.SelectMany(attrList => attrList.Attributes).Any(attr => SszSerializableAttributeNames.Contains(attr.ToString())); + + protected static bool IsCollectionType(ITypeSymbol typeSymbol) => + typeSymbol is IArrayTypeSymbol || (typeSymbol is INamedTypeSymbol namedTypeSymbol + && (namedTypeSymbol.Name == nameof(BitArray) || namedTypeSymbol.AllInterfaces.Any(i => i.Name == nameof(IEnumerable)))); + + protected static bool IsPropertyMarkedWithCollectionAttribute(PropertyDeclarationSyntax property) => + property.AttributeLists.SelectMany(attrList => attrList.Attributes).Any(attr => SszCollectionAttributeNames.Contains(attr.Name.ToString())); + + public static bool IsPublicGetSetProperty(PropertyDeclarationSyntax property) => + property.Modifiers.Any(SyntaxKind.PublicKeyword) && + property.AccessorList?.Accessors.Any(a => a.Kind() == SyntaxKind.GetAccessorDeclaration && !a.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) == true && + property.AccessorList?.Accessors.Any(a => a.Kind() == SyntaxKind.SetAccessorDeclaration && !a.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) == true; +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/Attributes.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/Attributes.cs new file mode 100644 index 00000000000..8adab610e01 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/Attributes.cs @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Serialization.Ssz; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] +public class SszSerializableAttribute(bool isCollectionItself = false) : Attribute +{ + public bool IsCollectionItself { get; } = isCollectionItself; +} + +[AttributeUsage(AttributeTargets.Property)] +public class SszListAttribute(int limit) : Attribute +{ + public int Limit { get; } = limit; +} + +[AttributeUsage(AttributeTargets.Property)] +public class SszVectorAttribute(int length) : Attribute +{ + public int Length { get; } = length; +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/IsExternalInit.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/IsExternalInit.cs new file mode 100644 index 00000000000..21a4f119416 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/IsExternalInit.cs @@ -0,0 +1,12 @@ +namespace System.Runtime.CompilerServices; + +// .NET standard 2.0 needs these types to allow modern C# features + +internal static class IsExternalInit; + +public class RequiredMemberAttribute : Attribute; + +public class CompilerFeatureRequiredAttribute : Attribute +{ + public CompilerFeatureRequiredAttribute(string name) { } +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/Kind.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/Kind.cs new file mode 100644 index 00000000000..4aa2de67057 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/Kind.cs @@ -0,0 +1,16 @@ +public enum Kind +{ + None = 0x0, + Basic = 0x1, + Container = 0x2, + + Vector = 0x4, + List = 0x8, + + BitVector = 0x10, + BitList = 0x20, + + Union = 0x40, + + Collection = Vector | List, +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/Nethermind.Serialization.SszGenerator.csproj b/src/Nethermind/Nethermind.Serialization.SszGenerator/Nethermind.Serialization.SszGenerator.csproj new file mode 100644 index 00000000000..ae6ab740113 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/Nethermind.Serialization.SszGenerator.csproj @@ -0,0 +1,19 @@ + + + Library + netstandard2.0 + enable + enable + latest + true + true + Nethermind.Generated.Ssz + true + Generated + + + + + + + \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/Properties/launchSettings.json b/src/Nethermind/Nethermind.Serialization.SszGenerator/Properties/launchSettings.json new file mode 100644 index 00000000000..2d2d49cf6be --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Generate SSZ for tests": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\Nethermind.Serialization.SszGenerator.Test\\Nethermind.Serialization.SszGenerator.Test.csproj" + }, + "Generate SSZ for Nethermind.Network.Discovery": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\Nethermind.Network.Discovery\\Nethermind.Network.Discovery.csproj" + } + } +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/README.md b/src/Nethermind/Nethermind.Serialization.SszGenerator/README.md new file mode 100644 index 00000000000..2b073b15570 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/README.md @@ -0,0 +1,75 @@ +# SSZ Encoders generator + +Generates static encoding/decoding/merkleization methods for SSZ types. + +Allows to: +- Encode +- Decode +- Merkleize + +Supports vectors, lists, bitvectors, bitlists, unions, etc. + +## Usage + +- Add reference to the generator + +```xml + +``` + +- Output of the generation will appear under Project/Dependencies/Analyzers/Nethermind.Serialization.SszGenerator/SszGenerator. +- Partial static class SszEncoding will contain all the methods. + + +## Examples + +### Container with marked collections + +```csharp + +[SszSerializable] +public struct MyClass +{ + public ulong Test1 { get; set; } + + [SszVector(10)] + public ulong[] Test2 { get; set; } + + [SszList(10)] + public ulong[] Test3 { get; set; } +} + +... +MyClass instance = new(); +SszEncoding.Merkleize(instance, out UInt256 root); +byte[] encoded = SszEncoding.Encode(instance); +SszEncoding.Decode(encoded, out decodedInstance); +``` + + +### Union + +```csharp +[SszSerializable] +public struct MyUnion +{ + public MyUnionEnum Selector { get; set; } + + public ulong Test1 { get; set; } + + [SszVector(10)] + public ulong[] Test2 { get; set; } + + [SszList(10)] + public ulong[] Test3 { get; set; } +} + +public enum MyUnionEnum +{ + Test1, + Test2, + Test3 +} +``` + +More examples in Nethermind.Serialization.SszGenerator.Test project. diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/SszGenerator.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/SszGenerator.cs new file mode 100644 index 00000000000..4811bc571d1 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/SszGenerator.cs @@ -0,0 +1,673 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using System.Text; +using System.Text.RegularExpressions; + +[Generator] +public partial class SszGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + IncrementalValuesProvider<(SszType, List)?> classDeclarations = context.SyntaxProvider + .CreateSyntaxProvider( + predicate: (syntaxNode, _) => IsClassWithAttribute(syntaxNode), + transform: (context, _) => GetClassWithAttribute(context)) + .Where(classNode => classNode is not null); + + context.RegisterSourceOutput(classDeclarations, (spc, decl) => + { + if (decl is null) + { + return; + } + var generatedCode = GenerateClassCode(decl.Value.Item1, decl.Value.Item2); + spc.AddSource($"Serialization.SszEncoding.{decl.Value.Item1.Name}.cs", SourceText.From(generatedCode, Encoding.UTF8)); + }); + } + + private static bool IsClassWithAttribute(SyntaxNode syntaxNode) + { + return syntaxNode is TypeDeclarationSyntax classDeclaration && + classDeclaration.AttributeLists.Any(x => x.Attributes.Any()); + } + + private static (SszType, List)? GetClassWithAttribute(GeneratorSyntaxContext context) + { + TypeDeclarationSyntax classDeclaration = (TypeDeclarationSyntax)context.Node; + foreach (AttributeListSyntax attributeList in classDeclaration.AttributeLists) + { + foreach (AttributeSyntax attribute in attributeList.Attributes) + { + IMethodSymbol? methodSymbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol as IMethodSymbol; + if (methodSymbol is not null && methodSymbol.ContainingType.ToString() == "Nethermind.Serialization.Ssz.SszSerializableAttribute") + { + var foundTypes = new List(SszType.BasicTypes); + return (SszType.From(context.SemanticModel, foundTypes, (ITypeSymbol)context.SemanticModel.GetDeclaredSymbol(classDeclaration)!), foundTypes); + } + } + } + return null; + } + + const string Whitespace = "/**/"; + static readonly Regex OpeningWhiteSpaceRegex = new("{/(\\n\\s+)+\\n/"); + static readonly Regex ClosingWhiteSpaceRegex = new("/(\\s+\\n)+ }/"); + public static string FixWhitespace(string data) => OpeningWhiteSpaceRegex.Replace( + ClosingWhiteSpaceRegex.Replace( + string.Join("\n", data.Split('\n').Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Contains(Whitespace) ? "" : x)), + " }"), + "{\n" + ); + public static string Shift(int tabCount, string data) => string.Empty.PadLeft(4 * tabCount) + data; + public static string Shift(int tabCount, IEnumerable data, string? end = null) => string.Join("\n", data.Select(d => Shift(tabCount, d))) + (end is null || !data.Any() ? "" : end); + + private static string VarName(string name) + { + if (string.IsNullOrEmpty(name)) return name; + + string lowerCased = name.Substring(0, 1).ToLower() + name.Substring(1); + + return lowerCased == "data" || lowerCased == "container" || lowerCased.Contains("offset") ? $"_{lowerCased}" : lowerCased; + } + + private static string DynamicLength(SszType container, SszProperty m) + { + if ((m.Kind & (Kind.Collection | Kind.BitList)) != Kind.None && m.Type.Kind == Kind.Basic) + { + return $"(container.{m.Name} is not null ? {(m.Kind == Kind.BitList ? $"container.{m.Name}.Length / 8 + 1" : $"{m.Type.StaticLength} * container.{m.Name}.Count()")} : 0)"; + } + + return $"GetLength(container.{m.Name})"; + } + + private static string GenerateClassCode(SszType decl, List foundTypes) + { + try + { + List variables = decl.Members.Where(m => m.IsVariable).ToList(); + int encodeOffsetIndex = 0, encodeStaticOffset = 0; + int offsetIndex = 0, offset = 0; + string result = FixWhitespace(decl.IsSszListItself ? +$@"using Nethermind.Merkleization; +using System.Collections.Generic; +using System.Linq; +{string.Join("\n", foundTypes.Select(x => x.Namespace).Distinct().OrderBy(x => x).Where(x => !string.IsNullOrEmpty(x)).Select(n => $"using {n};"))} +{Whitespace} +using SszLib = Nethermind.Serialization.Ssz.Ssz; +{Whitespace} +namespace Nethermind.Serialization; +{Whitespace} +public partial class SszEncoding +{{ + public static int GetLength({decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return 0; + }")} +{Whitespace} + return {DynamicLength(decl, variables[0])}; + }} +{Whitespace} + public static int GetLength(ICollection<{decl.Name}>? container) + {{ + if(container is null) + {{ + return 0; + }} +{Whitespace} + int length = container.Count * {SszType.PointerLength}; + foreach({decl.Name} item in container) + {{ + length += GetLength(item); + }} +{Whitespace} + return length; + }} +{Whitespace} + public static byte[] Encode({decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return []; + }")} + byte[] buf = new byte[GetLength(container)]; + Encode(buf, container); + return buf; + }} +{Whitespace} + public static void Encode(Span data, {decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return; + }")} +{Whitespace} + if (container.{variables[0].Name} is not null) {(variables[0].HandledByStd ? "SszLib.Encode" : "Encode")}(data, container.{variables[0].Name}); + }} +{Whitespace} + public static byte[] Encode(ICollection<{decl.Name}>? items) + {{ + if (items is null) + {{ + return []; + }} + byte[] buf = new byte[GetLength(items)]; + Encode(buf, items); + return buf; + }} +{Whitespace} + public static void Encode(Span data, ICollection<{decl.Name}>? items) + {{ + if(items is null) return; +{Whitespace} + int offset = items.Count * {(SszType.PointerLength)}; + int itemOffset = 0; +{Whitespace} + foreach({decl.Name} item in items) + {{ + SszLib.Encode(data.Slice(itemOffset, {(SszType.PointerLength)}), offset); + itemOffset += {(SszType.PointerLength)}; + int length = GetLength(item); + Encode(data.Slice(offset, length), item); + offset += length; + }} + }} +{Whitespace} + public static void Decode(ReadOnlySpan data, out {decl.Name} container) + {{ + container = new(); +{Whitespace} + if (data.Length > 0) {{ {(variables[0].HandledByStd ? "SszLib.Decode" : "Decode")}(data, out {(variables[0].HandledByStd ? $"ReadOnlySpan<{variables[0].Type.Name}>" : $"{variables[0].Type.Name}[]")} {VarName(variables[0].Name)}); container.{variables[0].Name} = [ ..{VarName(variables[0].Name)}]; }} + }} +{Whitespace} + public static void Decode(ReadOnlySpan data, out {decl.Name}[] container) + {{ + if(data.Length is 0) + {{ + container = []; + return; + }} +{Whitespace} + {(decl.IsVariable ? $@"SszLib.Decode(data.Slice(0, 4), out int firstOffset); + int length = firstOffset / {SszType.PointerLength}" : $"int length = data.Length / {decl.StaticLength}")}; + container = new {decl.Name}[length]; +{Whitespace} + {(decl.IsVariable ? @$"int index = 0; + int offset = firstOffset; + for(int nextOffsetIndex = {SszType.PointerLength}; index < length - 1; index++, nextOffsetIndex += {SszType.PointerLength}) + {{ + SszLib.Decode(data.Slice(nextOffsetIndex, {SszType.PointerLength}), out int nextOffset); + Decode(data.Slice(offset, nextOffset - offset), out container[index]); + offset = nextOffset; + }} +{Whitespace} + Decode(data.Slice(offset), out container[index]);" : @$"int offset = 0; + for(int index = 0; index < length; index++) + {{ + Decode(data.Slice(offset, {decl.StaticLength}), out container[index]); + offset += {decl.StaticLength}; + }}")} + }} +{Whitespace} + public static void Merkleize({decl.Name}{(decl.IsStruct ? "" : "?")} container, out UInt256 root) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + root = 0; + return; + }")} + Merkleizer merkleizer = new Merkleizer(Merkle.NextPowerOfTwoExponent({decl.Members!.Length})); + {(variables[0].HandledByStd ? $"merkleizer.Feed(container.{variables[0].Name}, {variables[0].Limit});" : $"MerkleizeList(container.{variables[0].Name}, {variables[0].Limit}, out UInt256 {VarName(variables[0].Name)}Root); merkleizer.Feed({VarName(variables[0].Name)}Root);")} + merkleizer.CalculateRoot(out root); + }} +{Whitespace} + public static void MerkleizeVector(IList<{decl.Name}>? container, out UInt256 root) + {{ + if(container is null) + {{ + root = 0; + return; + }} +{Whitespace} + UInt256[] subRoots = new UInt256[container.Count]; + for(int i = 0; i < container.Count; i++) + {{ + Merkleize(container[i], out subRoots[i]); + }} +{Whitespace} + Merkle.Merkleize(out root, subRoots); + }} +{Whitespace} + public static void MerkleizeList(IList<{decl.Name}>? container, ulong limit, out UInt256 root) + {{ + if(container is null || container.Count is 0) + {{ + root = 0; + Merkle.MixIn(ref root, (int)limit); + return; + }} +{Whitespace} + MerkleizeVector(container, out root); + Merkle.MixIn(ref root, container.Count); + }} +}} +" : +decl.Kind == Kind.Container ? $@"using Nethermind.Merkleization; +using System.Collections.Generic; +using System.Linq; +{string.Join("\n", foundTypes.Select(x => x.Namespace).Distinct().OrderBy(x => x).Where(x => !string.IsNullOrEmpty(x)).Select(n => $"using {n};"))} +{Whitespace} +using SszLib = Nethermind.Serialization.Ssz.Ssz; +{Whitespace} +namespace Nethermind.Serialization; +{Whitespace} +public partial class SszEncoding +{{ + public static int GetLength({decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return 0; + }")} +{Whitespace} + return {decl.StaticLength}{(variables.Any() ? "" : ";")} +{Shift(4, variables.Select(m => $"+ {DynamicLength(decl, m)}"), ";")} + }} +{Whitespace} + public static int GetLength(ICollection<{decl.Name}>? container) + {{ + if(container is null) + {{ + return 0; + }} +{Whitespace} + {(decl.IsVariable ? @$"int length = container.Count * {SszType.PointerLength}; + foreach({decl.Name} item in container) + {{ + length += GetLength(item); + }} +{Whitespace} + return length;" : $"return container.Count * {(decl.StaticLength)};")} + }} +{Whitespace} + public static byte[] Encode({decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return []; + }")} + byte[] buf = new byte[GetLength(container)]; + Encode(buf, container); + return buf; + }} +{Whitespace} + public static void Encode(Span data, {decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return; + }")} +{Whitespace} +{Shift(2, variables.Select((_, i) => $"int offset{i + 1} = {(i == 0 ? decl.StaticLength : $"offset{i} + {DynamicLength(decl, variables[i - 1])}")};"))} +{Whitespace} +{Shift(2, decl.Members.Select(m => +{ + if (m.IsVariable) encodeOffsetIndex++; + string result = m.IsVariable ? $"SszLib.Encode(data.Slice({encodeStaticOffset}, 4), offset{encodeOffsetIndex});" + : m.HandledByStd ? $"SszLib.Encode(data.Slice({encodeStaticOffset}, {m.StaticLength}), container.{m.Name});" + : $"Encode(data.Slice({encodeStaticOffset}, {m.StaticLength}), container.{m.Name});"; + encodeStaticOffset += m.StaticLength; + return result; +}))} +{Whitespace} +{Shift(2, variables.Select((m, i) => (m.Type.IsStruct ? "" : $"if (container.{m.Name} is not null) ") + $"{(m.HandledByStd ? "SszLib.Encode" : "Encode")}(data.Slice(offset{i + 1}, {(i + 1 == variables.Count ? "data.Length" : $"offset{i + 2}")} - offset{i + 1}), container.{m.Name}{(m.Kind == Kind.BitList ? $", {m.Limit}" : "")});"))} + }} +{Whitespace} + public static byte[] Encode(ICollection<{decl.Name}>? items) + {{ + if (items is null) + {{ + return []; + }} + byte[] buf = new byte[GetLength(items)]; + Encode(buf, items); + return buf; + }} +{Whitespace} + public static void Encode(Span data, ICollection<{decl.Name}>? items) + {{ + if(items is null) return; +{Whitespace} + {(decl.IsVariable ? @$"int offset = items.Count * {(SszType.PointerLength)}; + int itemOffset = 0; +{Whitespace} + foreach({decl.Name} item in items) + {{ + SszLib.Encode(data.Slice(itemOffset, {(SszType.PointerLength)}), offset); + itemOffset += {(SszType.PointerLength)}; + int length = GetLength(item); + Encode(data.Slice(offset, length), item); + offset += length; + }}" : @$"int offset = 0; + foreach({decl.Name} item in items) + {{ + int length = GetLength(item); + Encode(data.Slice(offset, length), item); + offset += length; + }}")} + }} +{Whitespace} + public static void Decode(ReadOnlySpan data, out {decl.Name} container) + {{ + container = new(); +{Whitespace} +{Shift(2, decl.Members.Select(m => +{ + if (m.IsVariable) offsetIndex++; + string result = m.IsVariable ? $"SszLib.Decode(data.Slice({offset}, 4), out int offset{offsetIndex});" + : m.HandledByStd ? $"SszLib.Decode(data.Slice({offset}, {m.StaticLength}), out {(m.IsCollection ? $"ReadOnlySpan<{m.Type.Name}>" : m.Type.Name)} {VarName(m.Name)}); container.{m.Name} = {(m.IsCollection ? $"[ ..{VarName(m.Name)}]" : VarName(m.Name))};" + : $"Decode(data.Slice({offset}, {m.StaticLength}), out {(m.IsCollection ? $"{m.Type.Name}[]" : m.Type.Name)} {VarName(m.Name)}); container.{m.Name} = {(m.IsCollection ? $"[ ..{VarName(m.Name)}]" : VarName(m.Name))};"; + offset += m.StaticLength; + return result; +}))} +{Whitespace} +{Shift(2, variables.Select((m, i) => string.Format($"if ({(i + 1 == variables.Count ? "data.Length" : $"offset{i + 2}")} - offset{i + 1} > 0) {{{{ {{0}} }}}}", + $"{(m.HandledByStd ? "SszLib.Decode" : "Decode")}(data.Slice(offset{i + 1}, {(i + 1 == variables.Count ? "data.Length" : $"offset{i + 2}")} - offset{i + 1}), out {(m.IsCollection ? (m.HandledByStd ? $"ReadOnlySpan<{m.Type.Name}>" : $"{m.Type.Name}[]") : m.Type.Name)} {VarName(m.Name)}); container.{m.Name} = {(m.IsCollection ? $"[ ..{VarName(m.Name)}]" : VarName(m.Name))};")))} + }} +{Whitespace} + public static void Decode(ReadOnlySpan data, out {decl.Name}[] container) + {{ + if(data.Length is 0) + {{ + container = []; + return; + }} +{Whitespace} + {(decl.IsVariable ? $@"SszLib.Decode(data.Slice(0, 4), out int firstOffset); + int length = firstOffset / {SszType.PointerLength}" : $"int length = data.Length / {decl.StaticLength}")}; + container = new {decl.Name}[length]; +{Whitespace} + {(decl.IsVariable ? @$"int index = 0; + int offset = firstOffset; + for(int nextOffsetIndex = {SszType.PointerLength}; index < length - 1; index++, nextOffsetIndex += {SszType.PointerLength}) + {{ + SszLib.Decode(data.Slice(nextOffsetIndex, {SszType.PointerLength}), out int nextOffset); + Decode(data.Slice(offset, nextOffset - offset), out container[index]); + offset = nextOffset; + }} +{Whitespace} + Decode(data.Slice(offset), out container[index]);" : @$"int offset = 0; + for(int index = 0; index < length; index++) + {{ + Decode(data.Slice(offset, {decl.StaticLength}), out container[index]); + offset += {decl.StaticLength}; + }}")} + }} +{Whitespace} + public static void Merkleize({decl.Name}{(decl.IsStruct ? "" : "?")} container, out UInt256 root) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + root = 0; + return; + }")} + Merkleizer merkleizer = new Merkleizer(Merkle.NextPowerOfTwoExponent({decl.Members!.Length})); +{Shift(2, decl.Members.Select(m => + { + if (m.IsVariable) offsetIndex++; + string result = m.HandledByStd ? $"merkleizer.Feed(container.{m.Name}{(m.Kind == Kind.List || m.Kind == Kind.BitList ? $", {m.Limit}" : "")});" + : m.Kind == Kind.List ? $"MerkleizeList(container.{m.Name}, {m.Limit}, out UInt256 {VarName(m.Name)}Root); merkleizer.Feed({VarName(m.Name)}Root);" + : m.Kind == Kind.Vector ? $"MerkleizeVector(container.{m.Name}, out UInt256 {VarName(m.Name)}Root); merkleizer.Feed({VarName(m.Name)}Root);" + : $"Merkleize(container.{m.Name}, out UInt256 {VarName(m.Name)}Root); merkleizer.Feed({VarName(m.Name)}Root);"; + offset += m.StaticLength; + return result; + }))} + merkleizer.CalculateRoot(out root); + }} +{Whitespace} + public static void MerkleizeVector(IList<{decl.Name}>? container, out UInt256 root) + {{ + if(container is null) + {{ + root = 0; + return; + }} +{Whitespace} + UInt256[] subRoots = new UInt256[container.Count]; + for(int i = 0; i < container.Count; i++) + {{ + Merkleize(container[i], out subRoots[i]); + }} +{Whitespace} + Merkle.Merkleize(out root, subRoots); + }} +{Whitespace} + public static void MerkleizeList(IList<{decl.Name}>? container, ulong limit, out UInt256 root) + {{ + if(container is null || container.Count is 0) + {{ + root = 0; + Merkle.MixIn(ref root, (int)limit); + return; + }} +{Whitespace} + MerkleizeVector(container, out root); + Merkle.MixIn(ref root, container.Count); + }} +}} +" : +// Unions +$@"using Nethermind.Merkleization; +using System.Collections.Generic; +using System.Linq; +{string.Join("\n", foundTypes.Select(x => x.Namespace).Distinct().OrderBy(x => x).Where(x => !string.IsNullOrEmpty(x)).Select(n => $"using {n};"))} +{Whitespace} +using SszLib = Nethermind.Serialization.Ssz.Ssz; +{Whitespace} +namespace Nethermind.Serialization; +{Whitespace} +public partial class SszEncoding +{{ + public static int GetLength({decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return 0; + }")} + return 1 + container.Selector switch {{ +{Shift(3, decl.UnionMembers.Select(m => $"{decl.Selector!.Type.Name}.{m.Name} => {(m.IsVariable ? DynamicLength(decl, m) : m.StaticLength.ToString())},"))} + _ => 0, + }}; + }} +{Whitespace} + public static int GetLength(ICollection<{decl.Name}>? container) + {{ + if(container is null) + {{ + return 0; + }} +{Whitespace} + int length = container.Count * {SszType.PointerLength}; + foreach({decl.Name} item in container) + {{ + length += GetLength(item); + }} +{Whitespace} + return length; + }} +{Whitespace} + public static byte[] Encode({decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return []; + }")} + byte[] buf = new byte[GetLength(container)]; + Encode(buf, container); + return buf; + }} +{Whitespace} + public static void Encode(Span data, {decl.Name}{(decl.IsStruct ? "" : "?")} container) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + return; + }")} + SszLib.Encode(data.Slice(0, 1), (byte)container.Selector); + if(data.Length is 1) + {{ + return; + }} +{Whitespace} + switch(container.Selector) {{ +{Shift(3, decl.UnionMembers.Select(m => $"case {decl.Selector!.Type.Name}.{m.Name}: {(m.IsVariable ? $"{(m.HandledByStd ? "SszLib.Encode" : "Encode")}(data.Slice(1), container.{m.Name}{(m.Kind == Kind.BitList ? $", {m.Limit}" : "")});" + : m.HandledByStd ? $"SszLib.Encode(data.Slice(1), container.{m.Name});" + : $"Encode(data.Slice(1), container.{m.Name});")} break;"))} + }}; + }} +{Whitespace} + public static byte[] Encode(ICollection<{decl.Name}>? items) + {{ + if (items is null) + {{ + return []; + }} + byte[] buf = new byte[GetLength(items)]; + Encode(buf, items); + return buf; + }} +{Whitespace} + public static void Encode(Span data, ICollection<{decl.Name}>? items) + {{ + if(items is null) return; + int offset = items.Count * {(SszType.PointerLength)}; + int itemOffset = 0; + foreach({decl.Name} item in items) + {{ + SszLib.Encode(data.Slice(itemOffset, {(SszType.PointerLength)}), offset); + itemOffset += {(SszType.PointerLength)}; + int length = GetLength(item); + Encode(data.Slice(offset, length), item); + offset += length; + }} + }} +{Whitespace} + public static void Decode(ReadOnlySpan data, out {decl.Name}[] container) + {{ + if(data.Length is 0) + {{ + container = []; + return; + }} +{Whitespace} + SszLib.Decode(data.Slice(0, 4), out int firstOffset); + int length = firstOffset / {SszType.PointerLength}; + container = new {decl.Name}[length]; +{Whitespace} + int index = 0; + int offset = firstOffset; + for(int nextOffsetIndex = {SszType.PointerLength}; index < length - 1; index++, nextOffsetIndex += {SszType.PointerLength}) + {{ + SszLib.Decode(data.Slice(nextOffsetIndex, {SszType.PointerLength}), out int nextOffset); + Decode(data.Slice(offset, nextOffset - offset), out container[index]); + offset = nextOffset; + }} +{Whitespace} + Decode(data.Slice(offset), out container[index]); + }} +{Whitespace} + public static void Decode(ReadOnlySpan data, out {decl.Name} container) + {{ + container = new(); + container.Selector = ({decl.Selector!.Type.Name})data[0]; + switch(container.Selector) {{ +{Shift(3, decl.UnionMembers.Select(m => $"case {decl.Selector!.Type.Name}.{m.Name}: {(m.IsVariable ? $"{(m.HandledByStd ? "SszLib.Decode" : "Decode")}(data.Slice(1), out {(m.IsCollection ? (m.HandledByStd ? $"ReadOnlySpan<{m.Type.Name}>" : $"{m.Type.Name}[]") : m.Type.Name)} {VarName(m.Name)}); container.{m.Name} = {(m.IsCollection ? $"[ ..{VarName(m.Name)}]" : VarName(m.Name))};" + : m.HandledByStd ? $"SszLib.Decode(data.Slice(1), out {(m.IsCollection ? $"ReadOnlySpan<{m.Type.Name}>" : m.Type.Name)} {VarName(m.Name)}); container.{m.Name} = {(m.IsCollection ? $"[ ..{VarName(m.Name)}]" : VarName(m.Name))};" + : $"Decode(data.Slice(1), out {(m.IsCollection ? $"{m.Type.Name}[]" : m.Type.Name)} {VarName(m.Name)}); container.{m.Name} = {(m.IsCollection ? $"[ ..{VarName(m.Name)}]" : VarName(m.Name))};")} break;"))} + }}; + }} +{Whitespace} + public static void Merkleize({decl.Name}{(decl.IsStruct ? "" : "?")} container, out UInt256 root) + {{ + {(decl.IsStruct ? "" : @"if(container is null) + { + root = 0; + return; + }")} + Merkleizer merkleizer = new Merkleizer(Merkle.NextPowerOfTwoExponent({decl.Members!.Length})); + switch(container.Selector) {{ +{Shift(3, decl.UnionMembers.Select(m => $"case {decl.Selector!.Type.Name}.{m.Name}: {(m.HandledByStd ? $"merkleizer.Feed(container.{m.Name}{(m.Kind == Kind.List || m.Kind == Kind.BitList ? $", {m.Limit}" : "")});" + : m.Kind == Kind.List ? $"MerkleizeList(container.{m.Name}, {m.Limit}, out UInt256 {VarName(m.Name)}Root); merkleizer.Feed({VarName(m.Name)}Root);" + : m.Kind == Kind.Vector ? $"MerkleizeVector(container.{m.Name}, out UInt256 {VarName(m.Name)}Root); merkleizer.Feed({VarName(m.Name)}Root);" + : $"Merkleize(container.{m.Name}, out UInt256 {VarName(m.Name)}Root); merkleizer.Feed({VarName(m.Name)}Root);")} break;"))} + }}; +{Whitespace} + merkleizer.CalculateRoot(out root); + Merkle.MixIn(ref root, (byte)container.Selector); + }} +{Whitespace} + public static void MerkleizeVector(IList<{decl.Name}>? container, out UInt256 root) + {{ + if(container is null) + {{ + root = 0; + return; + }} +{Whitespace} + UInt256[] subRoots = new UInt256[container.Count]; + for(int i = 0; i < container.Count; i++) + {{ + Merkleize(container[i], out subRoots[i]); + }} +{Whitespace} + Merkle.Merkleize(out root, subRoots); + }} +{Whitespace} + public static void MerkleizeList(IList<{decl.Name}>? container, ulong limit, out UInt256 root) + {{ + if(container is null || container.Count is 0) + {{ + root = 0; + Merkle.MixIn(ref root, (int)limit); + return; + }} +{Whitespace} + MerkleizeVector(container, out root); + Merkle.MixIn(ref root, (int)limit); + }} +}} +"); +#if DEBUG +#pragma warning disable RS1035 // Allow console for debugging + Console.WriteLine(WithLineNumbers(result, false)); +#pragma warning restore RS1035 +#endif + return result; + } + catch (Exception e) + { + return $"/* Failed due to error: {e.Message}*/"; + } + } + +#if DEBUG + static string WithLineNumbers(string input, bool bypass = false) + { + if (bypass) return input; + + string[] lines = input.Split('\n'); + int lineNumberWidth = lines.Length.ToString().Length; + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < lines.Length; i++) + { + string lineNumber = (i + 1).ToString().PadLeft(lineNumberWidth); + sb.AppendLine($"{lineNumber}: {lines[i]}"); + } + + return sb.ToString(); + } +#endif +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/SszProperty.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/SszProperty.cs new file mode 100644 index 00000000000..1277e0b2805 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/SszProperty.cs @@ -0,0 +1,99 @@ +using Microsoft.CodeAnalysis; + +class SszProperty +{ + public override string ToString() + { + return $"prop({Kind},{Type},{Name},{(IsVariable ? "v" : "f")})"; + } + + public static SszProperty From(SemanticModel semanticModel, List types, IPropertySymbol prop) + { + ITypeSymbol? itemType = GetCollectionType(prop.Type, semanticModel.Compilation); + + SszType type = SszType.From(semanticModel, types, itemType ?? prop.Type); + + SszProperty result = new SszProperty { Name = prop.Name, Type = type }; + + if (itemType is not null || prop.Type.Name == "BitArray") + { + var vectorAttr = prop.GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name == "SszVectorAttribute"); + if (vectorAttr is not null) + { + result.Length = vectorAttr.ConstructorArguments.FirstOrDefault().Value as int? ?? 0; + } + var listAttr = prop.GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name == "SszListAttribute"); + if (listAttr is not null) + { + result.Limit = listAttr.ConstructorArguments.FirstOrDefault().Value as int? ?? 0; + } + } + + return result; + } + + private static ITypeSymbol? GetCollectionType(ITypeSymbol typeSymbol, Compilation compilation) + { + if (typeSymbol is IArrayTypeSymbol array) + { + return array.ElementType!; + } + + INamedTypeSymbol? ienumerableOfT = compilation.GetTypeByMetadataName("System.Collections.Generic.IList`1"); + INamedTypeSymbol? enumerable = typeSymbol.AllInterfaces.FirstOrDefault(i => SymbolEqualityComparer.Default.Equals(i.OriginalDefinition, ienumerableOfT)); + if (ienumerableOfT != null && enumerable is not null) + { + return enumerable.TypeArguments.First(); + } + + return null; + } + + + public required string Name { get; init; } + public required SszType Type { get; init; } + public Kind Kind + { + get + { + if (Limit is not null) + { + return Type.Name == "BitArray" ? Kind.BitList : Kind.List; + } + if (Length is not null) + { + return Type.Name == "BitArray" ? Kind.BitVector : Kind.Vector; + } + return Type.Kind; + } + } + + public bool HandledByStd => ((Kind & (Kind.Basic | Kind.BitVector | Kind.BitList)) != Kind.None) || (((Kind & (Kind.Vector | Kind.List)) != Kind.None) && Type.Kind == Kind.Basic); + public bool IsCollection => (Kind & Kind.Collection) != Kind.None; + + public bool IsVariable => (Kind & (Kind.List | Kind.BitList)) != Kind.None || Type.IsVariable; + + public int StaticLength + { + get + { + if (IsVariable) + { + return 4; + } + try + { + return Kind switch + { + Kind.Vector => Length!.Value * Type.StaticLength, + Kind.BitVector => (Length!.Value + 7) / 8, + _ => Type.StaticLength, + }; + } + catch { throw; } + } + } + + public int? Length { get; set; } + public int? Limit { get; set; } +} diff --git a/src/Nethermind/Nethermind.Serialization.SszGenerator/SszType.cs b/src/Nethermind/Nethermind.Serialization.SszGenerator/SszType.cs new file mode 100644 index 00000000000..f8b0c4b7de3 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.SszGenerator/SszType.cs @@ -0,0 +1,178 @@ +using Microsoft.CodeAnalysis; + +class SszType +{ + static SszType() + { + BasicTypes.Add(new SszType + { + Namespace = "System", + Name = "Byte", + Kind = Kind.Basic, + StaticLength = sizeof(byte), + }); + + BasicTypes.Add(new SszType + { + Namespace = "System", + Name = "UInt16", + Kind = Kind.Basic, + StaticLength = sizeof(ushort), + }); + + BasicTypes.Add(new SszType + { + Namespace = "System", + Name = "Int32", + Kind = Kind.Basic, + StaticLength = sizeof(int), + }); + + BasicTypes.Add(new SszType + { + Namespace = "System", + Name = "UInt32", + Kind = Kind.Basic, + StaticLength = sizeof(uint), + }); + + BasicTypes.Add(new SszType + { + Namespace = "System", + Name = "Int64", + Kind = Kind.Basic, + StaticLength = sizeof(long), + }); + + BasicTypes.Add(new SszType + { + Namespace = "System", + Name = "UInt64", + Kind = Kind.Basic, + StaticLength = sizeof(ulong), + }); + + BasicTypes.Add(new SszType + { + Namespace = "Nethermind.Int256", + Name = "UInt256", + Kind = Kind.Basic, + StaticLength = 32, + }); + BasicTypes.Add(new SszType + { + Namespace = "System", + Name = "Boolean", + Kind = Kind.Basic, + StaticLength = 1, + }); + + BasicTypes.Add(new SszType + { + Namespace = "System.Collections", + Name = "BitArray", + Kind = Kind.Basic, + }); + } + + public static List BasicTypes { get; set; } = []; + public required string Name { get; init; } + public required string? Namespace { get; init; } + public required Kind Kind { get; init; } + public SszProperty[]? Members { get; set; } = null; + + public bool IsStruct { get; set; } + + public bool HasNone { get; set; } + public IEnumerable? UnionMembers { get => Kind == Kind.Union ? Members.Where(x => x.Name != "Selector") : null; } + public SszProperty? Selector { get => Members.FirstOrDefault(x => x.Name == "Selector"); } + + private int? length = null; + + public SszType? EnumType { get; set; } + public int StaticLength { get => length ?? Members.Sum(x => x.StaticLength); set => length = value; } + + public bool IsVariable => Members is not null && Members.Any(x => x.IsVariable) || Kind is Kind.Union; + + public bool IsSszListItself { get; private set; } + + + public const int PointerLength = 4; + + internal static SszType From(SemanticModel semanticModel, List types, ITypeSymbol type) + { + string? @namespace = GetNamespace(type); + string name = GetTypeName(type); + + SszType? existingType = types.FirstOrDefault(t => t.Name == name && t.Namespace == @namespace); + if (existingType is not null) + { + return existingType; + } + + INamedTypeSymbol? enumType = (type as INamedTypeSymbol)?.EnumUnderlyingType; + + SszType result = new SszType + { + Namespace = @namespace, + Name = name, + Kind = type.GetMembers().OfType().Any(x => x.Name == "Selector" && x.Type.TypeKind == TypeKind.Enum) ? Kind.Union : enumType is not null ? Kind.Basic : Kind.Container, + }; + types.Add(result); + + if (enumType is not null) + { + result.EnumType = BasicTypes.First(x => x.Name == enumType.Name); + result.StaticLength = result.EnumType.StaticLength; + result.HasNone = (type as INamedTypeSymbol)?.MemberNames.Contains("None") == true; + } + + result.Members = result.Kind switch + { + Kind.Container or Kind.Union => type.GetMembers().OfType() + .Where(p => p.GetMethod is not null && p.SetMethod is not null && p.GetMethod.DeclaredAccessibility == Accessibility.Public && p.SetMethod.DeclaredAccessibility == Accessibility.Public) + .Select(prop => SszProperty.From(semanticModel, types, prop)).ToArray() ?? [], + _ => null, + }; + + if (result.Kind == Kind.Union) + { + result.HasNone = result.Members.Any(x => x.Name == "Selector" && x.Type.HasNone); + } + + if ((result.Kind & (Kind.Container | Kind.Union)) != Kind.None && type.TypeKind == TypeKind.Struct) + { + result.IsStruct = true; + } + + if (result.Kind is Kind.Container && result.Members is { Length: 1 } && result.Members[0] is { Kind: Kind.List, HandledByStd: true }) + { + result.IsSszListItself = GetIsCollectionItselfValue(type); + } + + return result; + } + + private static string? GetNamespace(ITypeSymbol syntaxNode) + { + return syntaxNode.ContainingNamespace?.ToString(); + } + + private static string GetTypeName(ITypeSymbol syntaxNode) + { + return string.IsNullOrEmpty(syntaxNode.ContainingNamespace?.ToString()) ? syntaxNode.ToString() : syntaxNode.Name.Replace(syntaxNode.ContainingNamespace!.ToString() + ".", ""); + } + public override string ToString() + { + return $"type({Kind},{Name},{(IsVariable ? "v" : "f")})"; + } + + private static bool GetIsCollectionItselfValue(ITypeSymbol typeSymbol) + { + object? attrValue = typeSymbol + .GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name == "SszSerializableAttribute")? + .ConstructorArguments.FirstOrDefault().Value; + + return attrValue is not null && (bool)attrValue; + } +} diff --git a/src/Nethermind/Nethermind.Shutter.Test/ShutterApiSimulator.cs b/src/Nethermind/Nethermind.Shutter.Test/ShutterApiSimulator.cs index 68616f48c68..d2377ef466e 100644 --- a/src/Nethermind/Nethermind.Shutter.Test/ShutterApiSimulator.cs +++ b/src/Nethermind/Nethermind.Shutter.Test/ShutterApiSimulator.cs @@ -1,6 +1,4 @@ -// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only - using System; using System.Collections.Generic; using System.IO.Abstractions; @@ -21,9 +19,7 @@ using Nethermind.Shutter.Config; using Nethermind.State; using NSubstitute; - namespace Nethermind.Shutter.Test; - public class ShutterApiSimulator( ShutterEventSimulator eventSimulator, IAbiEncoder abiEncoder, @@ -73,7 +69,6 @@ public void InsertShutterReceipts(Block block, in LogEntry[] logs) { var receipts = new TxReceipt[logs.Length]; block.Header.Bloom = new(logs); - // one log per receipt for (int i = 0; i < logs.Length; i++) { diff --git a/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj b/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj index f659070d3d2..1f75b9ac946 100644 --- a/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj +++ b/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj @@ -1,4 +1,4 @@ - + true diff --git a/src/Nethermind/Nethermind.Shutter/SlotDecryptionIdentites.cs b/src/Nethermind/Nethermind.Shutter/SlotDecryptionIdentites.cs new file mode 100644 index 00000000000..52dfbf69fdd --- /dev/null +++ b/src/Nethermind/Nethermind.Shutter/SlotDecryptionIdentites.cs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Serialization.Ssz; +using System.Collections.Generic; + +namespace Nethermind.Shutter; + +[SszSerializable] +public struct SlotDecryptionIdentites +{ + public ulong InstanceID { get; set; } + public ulong Eon { get; set; } + public ulong Slot { get; set; } + public ulong TxPointer { get; set; } + + [SszList(1024)] + public List IdentityPreimages { get; set; } +} + +[SszSerializable] +public struct IdentityPreimage(byte[] data) +{ + [SszVector(52)] + public byte[] Data { get; set; } = data; +} diff --git a/src/Nethermind/Nethermind.sln b/src/Nethermind/Nethermind.sln index 642d8487108..ab30ee6e7ed 100644 --- a/src/Nethermind/Nethermind.sln +++ b/src/Nethermind/Nethermind.sln @@ -229,6 +229,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter", "Nethe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter.Test", "Nethermind.Shutter.Test\Nethermind.Shutter.Test.csproj", "{CEA1C413-A96C-4339-AC1C-839B603DECC8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator", "Nethermind.Serialization.SszGenerator\Nethermind.Serialization.SszGenerator.csproj", "{F2F02874-8DF2-4434-A5F7-3418F24E1E56}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator.Test", "Nethermind.Serialization.SszGenerator.Test\Nethermind.Serialization.SszGenerator.Test.csproj", "{E11DA65F-7F52-40DA-BBF4-E6E90932EB68}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -635,6 +639,14 @@ Global {CEA1C413-A96C-4339-AC1C-839B603DECC8}.Debug|Any CPU.Build.0 = Debug|Any CPU {CEA1C413-A96C-4339-AC1C-839B603DECC8}.Release|Any CPU.ActiveCfg = Release|Any CPU {CEA1C413-A96C-4339-AC1C-839B603DECC8}.Release|Any CPU.Build.0 = Release|Any CPU + {F2F02874-8DF2-4434-A5F7-3418F24E1E56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2F02874-8DF2-4434-A5F7-3418F24E1E56}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2F02874-8DF2-4434-A5F7-3418F24E1E56}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2F02874-8DF2-4434-A5F7-3418F24E1E56}.Release|Any CPU.Build.0 = Release|Any CPU + {E11DA65F-7F52-40DA-BBF4-E6E90932EB68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E11DA65F-7F52-40DA-BBF4-E6E90932EB68}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E11DA65F-7F52-40DA-BBF4-E6E90932EB68}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E11DA65F-7F52-40DA-BBF4-E6E90932EB68}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -695,6 +707,7 @@ Global {E1E7BEFC-52C0-49ED-B0A7-CB8C3250D120} = {4019B82F-1104-4D2C-9F96-05FD7D3575E8} {89311B58-AF36-4956-883D-54531BC1D5A3} = {78BED57D-720E-4E6C-ABA2-397B73B494F9} {6528010D-7DCE-4935-9785-5270FF515F3E} = {89311B58-AF36-4956-883D-54531BC1D5A3} + {E11DA65F-7F52-40DA-BBF4-E6E90932EB68} = {4019B82F-1104-4D2C-9F96-05FD7D3575E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {092CA5E3-6180-4ED7-A3CB-9B57FAC2AA85} diff --git a/src/bench_precompiles b/src/bench_precompiles index c1089350ef0..a55fd2fb4a7 160000 --- a/src/bench_precompiles +++ b/src/bench_precompiles @@ -1 +1 @@ -Subproject commit c1089350ef0daa3f0bd437ce9d1626de973f9a93 +Subproject commit a55fd2fb4a7d28bfa5851a7aada4489c4a470951 From 1424688625b6cbaf2ba430f513d4a3213a550a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Chodo=C5=82a?= <43241881+kamilchodola@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:51:36 +0100 Subject: [PATCH 088/113] Revert removed admin_prune method in interface (#8026) --- .../Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs index f9a338e95db..fe1e99aedfd 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs @@ -62,6 +62,12 @@ ResultWrapper admin_peers( IsImplemented = false)] ResultWrapper admin_setSolc(); + [JsonRpcMethod(Description = "Runs full pruning if enabled.", + EdgeCaseHint = "", + ExampleResponse = "\"Starting\"", + IsImplemented = true)] + ResultWrapper admin_prune(); + [JsonRpcMethod(Description = "True if state root for the block is available", EdgeCaseHint = "", ExampleResponse = "\"Starting\"", From a04df32ab92bad3e35bec076a77e044128c25c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Moraczy=C5=84ski?= Date: Wed, 8 Jan 2025 16:25:23 +0100 Subject: [PATCH 089/113] Add eest to hive simulators (#8028) --- .github/workflows/hive-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/hive-tests.yml b/.github/workflows/hive-tests.yml index 942c9ac24e2..b0cb65f2a5f 100644 --- a/.github/workflows/hive-tests.yml +++ b/.github/workflows/hive-tests.yml @@ -16,7 +16,7 @@ on: - ethereum/consensus - ethereum/engine - ethereum/graphql - - ethereum/pyspec + - ethereum/eest - ethereum/rpc - ethereum/rpc-compat - ethereum/sync From cf4225098534ce66cd53dd616e811e0d1aae8b8f Mon Sep 17 00:00:00 2001 From: Ahmad Bitar <33181301+smartprogrammer93@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:25:28 +0300 Subject: [PATCH 090/113] fix memory expansion to support up to uint.max instead of int.max (#8030) --- src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs b/src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs index ddec0280779..a8cfef56914 100644 --- a/src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs +++ b/src/Nethermind/Nethermind.Evm/EvmPooledMemory.cs @@ -300,7 +300,7 @@ public static long Div32Ceiling(in UInt256 length, out bool outOfGas) result++; } - if (result > int.MaxValue) + if (result > uint.MaxValue) { outOfGas = true; return 0; From e809703f1a52070fc22983a76730c0b3907cbfe4 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel <31224949+emlautarom1@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:21:21 -0300 Subject: [PATCH 091/113] Move `Test` projects to proper solution folder (#8032) --- src/Nethermind/Nethermind.sln | 39 +++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/Nethermind/Nethermind.sln b/src/Nethermind/Nethermind.sln index ab30ee6e7ed..c5d64fec321 100644 --- a/src/Nethermind/Nethermind.sln +++ b/src/Nethermind/Nethermind.sln @@ -212,8 +212,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution nuget.config = nuget.config EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Optimism.Test", "Nethermind.Optimism.Test\Nethermind.Optimism.Test.csproj", "{2438958D-46EA-4A7E-B89F-29E069DA0CCA}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Signer", "Signer", "{89311B58-AF36-4956-883D-54531BC1D5A3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.ExternalSigner.Plugin", "Nethermind.ExternalSigner.Plugin\Nethermind.ExternalSigner.Plugin.csproj", "{6528010D-7DCE-4935-9785-5270FF515F3E}" @@ -223,16 +221,18 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flasbots.Test", "Nethermind.Flashbots.Test\Nethermind.Flasbots.Test.csproj", "{370C4088-0DB9-401A-872F-E72E3272AB54}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Taiko", "Nethermind.Taiko\Nethermind.Taiko.csproj", "{B4070433-328E-40E6-B89A-6554F015694C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.Taiko.Test", "Nethermind.Taiko.Test\Nethermind.Taiko.Test.csproj", "{3E097797-F8D5-4BB5-B544-C78FF0A14986}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter", "Nethermind.Shutter\Nethermind.Shutter.csproj", "{F38037D2-98EA-4263-887A-4B383635F605}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter.Test", "Nethermind.Shutter.Test\Nethermind.Shutter.Test.csproj", "{CEA1C413-A96C-4339-AC1C-839B603DECC8}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator", "Nethermind.Serialization.SszGenerator\Nethermind.Serialization.SszGenerator.csproj", "{F2F02874-8DF2-4434-A5F7-3418F24E1E56}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator.Test", "Nethermind.Serialization.SszGenerator.Test\Nethermind.Serialization.SszGenerator.Test.csproj", "{E11DA65F-7F52-40DA-BBF4-E6E90932EB68}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Taiko.Test", "Nethermind.Taiko.Test\Nethermind.Taiko.Test.csproj", "{B1CE6CBC-D85B-4631-A9F3-437ADB1FB049}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter.Test", "Nethermind.Shutter.Test\Nethermind.Shutter.Test.csproj", "{B068C72F-8B77-474E-A58C-5B929096FEF3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Optimism.Test", "Nethermind.Optimism.Test\Nethermind.Optimism.Test.csproj", "{DC983CEF-BA18-45DE-9AEB-AB9B459655BC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -607,10 +607,6 @@ Global {AD09FBCB-5496-499B-9129-B6D139A65B6F}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD09FBCB-5496-499B-9129-B6D139A65B6F}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD09FBCB-5496-499B-9129-B6D139A65B6F}.Release|Any CPU.Build.0 = Release|Any CPU - {2438958D-46EA-4A7E-B89F-29E069DA0CCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2438958D-46EA-4A7E-B89F-29E069DA0CCA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2438958D-46EA-4A7E-B89F-29E069DA0CCA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2438958D-46EA-4A7E-B89F-29E069DA0CCA}.Release|Any CPU.Build.0 = Release|Any CPU {6528010D-7DCE-4935-9785-5270FF515F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6528010D-7DCE-4935-9785-5270FF515F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU {6528010D-7DCE-4935-9785-5270FF515F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -627,18 +623,10 @@ Global {B4070433-328E-40E6-B89A-6554F015694C}.Debug|Any CPU.Build.0 = Debug|Any CPU {B4070433-328E-40E6-B89A-6554F015694C}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4070433-328E-40E6-B89A-6554F015694C}.Release|Any CPU.Build.0 = Release|Any CPU - {3E097797-F8D5-4BB5-B544-C78FF0A14986}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E097797-F8D5-4BB5-B544-C78FF0A14986}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E097797-F8D5-4BB5-B544-C78FF0A14986}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E097797-F8D5-4BB5-B544-C78FF0A14986}.Release|Any CPU.Build.0 = Release|Any CPU {F38037D2-98EA-4263-887A-4B383635F605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F38037D2-98EA-4263-887A-4B383635F605}.Debug|Any CPU.Build.0 = Debug|Any CPU {F38037D2-98EA-4263-887A-4B383635F605}.Release|Any CPU.ActiveCfg = Release|Any CPU {F38037D2-98EA-4263-887A-4B383635F605}.Release|Any CPU.Build.0 = Release|Any CPU - {CEA1C413-A96C-4339-AC1C-839B603DECC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CEA1C413-A96C-4339-AC1C-839B603DECC8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CEA1C413-A96C-4339-AC1C-839B603DECC8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CEA1C413-A96C-4339-AC1C-839B603DECC8}.Release|Any CPU.Build.0 = Release|Any CPU {F2F02874-8DF2-4434-A5F7-3418F24E1E56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2F02874-8DF2-4434-A5F7-3418F24E1E56}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2F02874-8DF2-4434-A5F7-3418F24E1E56}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -647,6 +635,18 @@ Global {E11DA65F-7F52-40DA-BBF4-E6E90932EB68}.Debug|Any CPU.Build.0 = Debug|Any CPU {E11DA65F-7F52-40DA-BBF4-E6E90932EB68}.Release|Any CPU.ActiveCfg = Release|Any CPU {E11DA65F-7F52-40DA-BBF4-E6E90932EB68}.Release|Any CPU.Build.0 = Release|Any CPU + {B1CE6CBC-D85B-4631-A9F3-437ADB1FB049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1CE6CBC-D85B-4631-A9F3-437ADB1FB049}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1CE6CBC-D85B-4631-A9F3-437ADB1FB049}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1CE6CBC-D85B-4631-A9F3-437ADB1FB049}.Release|Any CPU.Build.0 = Release|Any CPU + {B068C72F-8B77-474E-A58C-5B929096FEF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B068C72F-8B77-474E-A58C-5B929096FEF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B068C72F-8B77-474E-A58C-5B929096FEF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B068C72F-8B77-474E-A58C-5B929096FEF3}.Release|Any CPU.Build.0 = Release|Any CPU + {DC983CEF-BA18-45DE-9AEB-AB9B459655BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC983CEF-BA18-45DE-9AEB-AB9B459655BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC983CEF-BA18-45DE-9AEB-AB9B459655BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC983CEF-BA18-45DE-9AEB-AB9B459655BC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -708,6 +708,9 @@ Global {89311B58-AF36-4956-883D-54531BC1D5A3} = {78BED57D-720E-4E6C-ABA2-397B73B494F9} {6528010D-7DCE-4935-9785-5270FF515F3E} = {89311B58-AF36-4956-883D-54531BC1D5A3} {E11DA65F-7F52-40DA-BBF4-E6E90932EB68} = {4019B82F-1104-4D2C-9F96-05FD7D3575E8} + {B1CE6CBC-D85B-4631-A9F3-437ADB1FB049} = {4019B82F-1104-4D2C-9F96-05FD7D3575E8} + {B068C72F-8B77-474E-A58C-5B929096FEF3} = {4019B82F-1104-4D2C-9F96-05FD7D3575E8} + {DC983CEF-BA18-45DE-9AEB-AB9B459655BC} = {4019B82F-1104-4D2C-9F96-05FD7D3575E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {092CA5E3-6180-4ED7-A3CB-9B57FAC2AA85} From 55420825646d6346595267f63d0714d377fe1b43 Mon Sep 17 00:00:00 2001 From: Damian Orzechowski <114909782+damian-orzechowski@users.noreply.github.com> Date: Thu, 9 Jan 2025 21:21:01 +0100 Subject: [PATCH 092/113] Change more children derivation on snap sync (#8034) --- .../SnapSync/RecreateStateFromAccountRangesTests.cs | 13 ++++++------- .../SnapSync/SnapProviderHelper.cs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs index 5e74e84aca6..702775aa9de 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/RecreateStateFromAccountRangesTests.cs @@ -8,7 +8,6 @@ using System.Linq; using Autofac; using FluentAssertions; -using Nethermind.Blockchain.Synchronization; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; @@ -325,19 +324,19 @@ bool HasMoreChildren(ValueHash256 limitHash) } HasMoreChildren(TestItem.Tree.AccountsWithPaths[1].Path).Should().BeFalse(); - HasMoreChildren(TestItem.Tree.AccountsWithPaths[2].Path).Should().BeFalse(); + HasMoreChildren(TestItem.Tree.AccountsWithPaths[2].Path).Should().BeTrue(); //expect leaves exactly at limit path to be included HasMoreChildren(TestItem.Tree.AccountsWithPaths[3].Path).Should().BeTrue(); HasMoreChildren(TestItem.Tree.AccountsWithPaths[4].Path).Should().BeTrue(); - UInt256 between2and3 = new UInt256(TestItem.Tree.AccountsWithPaths[1].Path.Bytes, true); - between2and3 += 5; + UInt256 between1and2 = new UInt256(TestItem.Tree.AccountsWithPaths[1].Path.Bytes, true); + between1and2 += 5; - HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); + HasMoreChildren(new Hash256(between1and2.ToBigEndian())).Should().BeFalse(); - between2and3 = new UInt256(TestItem.Tree.AccountsWithPaths[2].Path.Bytes, true); + UInt256 between2and3 = new UInt256(TestItem.Tree.AccountsWithPaths[2].Path.Bytes, true); between2and3 -= 1; - HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeFalse(); + HasMoreChildren(new Hash256(between2and3.ToBigEndian())).Should().BeTrue(); } [Test] diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index eba604c428d..3e234fbef46 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -229,7 +229,7 @@ private static (AddRangeResult result, List<(TrieNode, TreePath)> sortedBoundary { bool hasKeccak = node.GetChildHashAsValueKeccak(ci, out ValueHash256 childKeccak); - moreChildrenToRight |= hasKeccak && (ci > right && (ci < limit || noLimit)); + moreChildrenToRight |= hasKeccak && (ci > right && (ci <= limit || noLimit)); if (ci >= left && ci <= right) { From b50c5d9ac0f0e8cdd16a05ecf19e0bd8e5618267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Chodo=C5=82a?= <43241881+kamilchodola@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:27:53 +0100 Subject: [PATCH 093/113] Add TxLookupLimit 0 for all missing archive nodes configs (#8039) --- .../Nethermind.Runner/configs/base-mainnet_archive.json | 3 +++ .../Nethermind.Runner/configs/base-sepolia_archive.json | 3 +++ .../Nethermind.Runner/configs/energyweb_archive.json | 6 +++--- .../Nethermind.Runner/configs/joc-mainnet_archive.json | 3 +++ .../Nethermind.Runner/configs/joc-testnet_archive.json | 3 +++ .../Nethermind.Runner/configs/linea-mainnet_archive.json | 3 +++ .../Nethermind.Runner/configs/linea-sepolia_archive.json | 3 +++ .../Nethermind.Runner/configs/op-mainnet_archive.json | 3 +++ .../Nethermind.Runner/configs/op-sepolia_archive.json | 3 +++ .../Nethermind.Runner/configs/poacore_archive.json | 1 - 10 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json index fc76030b98e..2f73de68079 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet_archive.json @@ -13,6 +13,9 @@ "Discovery": { "DiscoveryVersion": "V5" }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json b/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json index 16b69d12124..6d090627d4c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia_archive.json @@ -13,6 +13,9 @@ "Discovery": { "DiscoveryVersion": "V5" }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json b/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json index 9c997527266..3c86ed31113 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb_archive.json @@ -28,12 +28,12 @@ "Mining": { "MinGasPrice": 1 }, - "Pruning": { - "Mode": "None" - }, "Receipt": { "TxLookupLimit": 0 }, + "Pruning": { + "Mode": "None" + }, "Blocks": { "GasToken": "EWT" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json index fa99f295699..fcec01bbc2c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet_archive.json @@ -13,6 +13,9 @@ "DownloadBodiesInFastSync": false, "DownloadReceiptsInFastSync": false }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json index 88bae2152c4..ba3a38d8106 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet_archive.json @@ -13,6 +13,9 @@ "DownloadBodiesInFastSync": false, "DownloadReceiptsInFastSync": false }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json index e78a635b82d..4296b4f3177 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-mainnet_archive.json @@ -9,6 +9,9 @@ "Merge": { "Enabled": false }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json index 183a68a68aa..ceabce7c394 100644 --- a/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/linea-sepolia_archive.json @@ -9,6 +9,9 @@ "Merge": { "Enabled": false }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json b/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json index 98ab3b32baf..ee967c698d7 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet_archive.json @@ -18,6 +18,9 @@ "Discovery": { "DiscoveryVersion": "V5" }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json b/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json index 0723d0fe554..185badcd5bc 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia_archive.json @@ -13,6 +13,9 @@ "Discovery": { "DiscoveryVersion": "V5" }, + "Receipt": { + "TxLookupLimit": 0 + }, "Pruning": { "Mode": "None" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json b/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json index eb54c50b673..e1d5e8e7f96 100644 --- a/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json +++ b/src/Nethermind/Nethermind.Runner/configs/poacore_archive.json @@ -18,7 +18,6 @@ }, "Receipt": { "TxLookupLimit": 0 - }, "Bloom": { "IndexLevelBucketSizes": [ 16, 16, 16, 16 ] From bb2e4a71fea4609633f72bc9d2880db1159304fa Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Sat, 11 Jan 2025 15:22:44 +0530 Subject: [PATCH 094/113] address few PR comments --- .../Nethermind.Flashbots/Flashbots.cs | 4 ++-- .../Nethermind.Flashbots/FlashbotsConfig.cs | 2 ++ .../ValidateBuilderSubmissionHandler.cs | 21 ++++++++----------- .../Nethermind.Flashbots/IFlashbotsConfig.cs | 10 ++++++++- .../Nethermind.JsonRpc/IJsonRpcConfig.cs | 9 -------- .../Nethermind.JsonRpc/JsonRpcConfig.cs | 1 - .../Modules/Eth/EthRpcModule.cs | 4 ++-- .../MergeHeaderValidator.cs | 6 ------ 8 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index 1fdfff9721a..33b42e61a0a 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -30,7 +30,7 @@ public Task InitRpcModules() ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = new ReadOnlyTxProcessingEnvFactory( _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), - _api.SpecProvider, + _api.SpecProvider ?? throw new ArgumentNullException(nameof(_api.SpecProvider)), _api.LogManager ); @@ -48,7 +48,7 @@ public Task InitRpcModules() ArgumentNullException.ThrowIfNull(_api.RpcModuleProvider); _api.RpcModuleProvider.RegisterBounded(flashbotsRpcModule, - _jsonRpcConfig.EthModuleConcurrentInstances ?? Environment.ProcessorCount, _jsonRpcConfig.Timeout); + _flashbotsConfig.FlashbotsModuleConcurrentInstances ?? Environment.ProcessorCount, _jsonRpcConfig.Timeout); return Task.CompletedTask; } diff --git a/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs index 363483a383d..9ffa795c2cb 100644 --- a/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/FlashbotsConfig.cs @@ -12,4 +12,6 @@ public class FlashbotsConfig : IFlashbotsConfig public bool EnablePreWarmer { get; set; } = true; public bool EnableValidation { get; set; } = false; + + public int? FlashbotsModuleConcurrentInstances { get; set; } = null; } diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 803ce11c543..aec53e81550 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -45,8 +45,6 @@ public class ValidateSubmissionHandler private readonly IFlashbotsConfig _flashbotsConfig; - private readonly IReceiptStorage _receiptStorage = new InMemoryReceiptStorage(); - private readonly ILogManager _logManager; private readonly ISpecProvider _specProvider; @@ -85,7 +83,8 @@ public Task> ValidateSubmission(BuilderBlockValid string payloadStr = $"BuilderBlock: {payload}"; - _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length}"); + if (_logger.IsInfo) + _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length}"); if (!payload.TryGetBlock(out Block? block)) { @@ -255,7 +254,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected if (ValidateProposerPayment(expectedProfit, useBalanceDiffProfit, feeRecipientBalanceAfter, amtBeforeOrWithdrawn)) return true; - if (!ValidateProcessedBlock(block, feeRecipient, expectedProfit, blockReceiptsTracer.TxReceipts.ToArray(), out error)) + if (!ValidateProcessedBlock(block, feeRecipient, expectedProfit, [.. blockReceiptsTracer.TxReceipts], out error)) { return false; } @@ -283,11 +282,11 @@ private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHead return false; } - // if (!_blockTree.IsBetterThanHead(block.Header)) - // { - // error = $"Block {block.Header.Hash} is not better than head"; - // return false; - // } + if (!_blockTree.IsBetterThanHead(block.Header)) + { + error = $"Block {block.Header.Hash} is not better than head"; + return false; + } long calculatedGasLimit = GetGasLimit(parentHeader, registerGasLimit); @@ -343,8 +342,6 @@ private bool ValidateProposerPayment(UInt256 expectedProfit, bool useBalanceDiff private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, UInt256 expectedProfit, TxReceipt[] receipts, out string? error) { - // TxReceipt[] receipts = processedBlock.Hash != null ? _receiptStorage.Get(processedBlock.Hash) : []; - if (receipts.Length == 0) { error = "No proposer payment receipt"; @@ -417,7 +414,7 @@ private BlockProcessor CreateBlockProcessor(IWorldState stateProvider, ITransact new Consensus.Rewards.RewardCalculator(_specProvider), new BlockProcessor.BlockValidationTransactionsExecutor(transactionProcessor, stateProvider), stateProvider, - _receiptStorage, + NullReceiptStorage.Instance, transactionProcessor, new BeaconBlockRootHandler(transactionProcessor, stateProvider), new BlockhashStore(_specProvider, stateProvider), diff --git a/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs index 7142d3f0182..11cf99d2238 100644 --- a/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs @@ -16,9 +16,17 @@ public interface IFlashbotsConfig : IConfig [ConfigItem(Description = "If set to true, withdrawals to the fee recipient are excluded from the balance delta", DefaultValue = "false")] public bool ExcludeWithdrawals { get; set; } - [ConfigItem(Description = "If set to true, the pre-warmer will be enabled", DefaultValue = "false")] + [ConfigItem(Description = "If set to true, the pre-warmer will be enabled", DefaultValue = "true")] public bool EnablePreWarmer { get; set; } [ConfigItem(Description = "If set to true, the validation will be enabled", DefaultValue = "false")] public bool EnableValidation { get; set; } + + [ConfigItem( + Description = """ + The number of concurrent instances for non-sharable calls: + - `flashbots_validateBuilderSubmissionV3` + This limits the load on the CPU and I/O to reasonable levels. If the limit is exceeded, HTTP 503 is returned along with the JSON-RPC error. Defaults to the number of logical processors. + """)] + int? FlashbotsModuleConcurrentInstances { get; set; } } diff --git a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs index 832a68b842c..b9389ec4ccd 100644 --- a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs @@ -128,15 +128,6 @@ public interface IJsonRpcConfig : IConfig """)] int? EthModuleConcurrentInstances { get; set; } - - [ConfigItem( - Description = """ - The number of concurrent instances for non-sharable calls: - - `flashbots_validateBuilderSubmissionV3` - This limits the load on the CPU and I/O to reasonable levels. If the limit is exceeded, HTTP 503 is returned along with the JSON-RPC error. Defaults to the number of logical processors. - """)] - int? FlashbotsModuleConcurrentInstances { get; set; } - [ConfigItem(Description = "The path to the JWT secret file required for the Engine API authentication.", DefaultValue = "null")] public string JwtSecretFile { get; set; } diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs index b8c7ec0d489..7bd2761f14a 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs @@ -47,7 +47,6 @@ public string[] EnabledModules public long? MaxRequestBodySize { get; set; } = 30000000; public int MaxLogsPerResponse { get; set; } = 20_000; public int? EthModuleConcurrentInstances { get; set; } = null; - public int? FlashbotsModuleConcurrentInstances { get; set; } = null; public string JwtSecretFile { get; set; } = null; public bool UnsecureDevNoRpcAuthentication { get; set; } public int? MaxLoggedRequestParametersCharacters { get; set; } = null; diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index 3af1a71c3da..e62b851e883 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -404,9 +404,9 @@ public ResultWrapper eth_getBlockByNumber(BlockParameter blockParam return ResultWrapper.Success(null); } - IByteBuffer buffer = PooledByteBufferAllocator.Default.Buffer(TxDecoder.Instance.GetLength(transaction, RlpBehaviors.SkipTypedWrapping)); + IByteBuffer buffer = PooledByteBufferAllocator.Default.Buffer(TxDecoder.Instance.GetLength(transaction, RlpBehaviors.None)); using NettyRlpStream stream = new(buffer); - TxDecoder.Instance.Encode(stream, transaction, rlpBehaviors: RlpBehaviors.SkipTypedWrapping); + TxDecoder.Instance.Encode(stream, transaction); return ResultWrapper.Success(buffer.AsSpan().ToHexString(false)); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs index dc0a832f64b..ba2ffebab83 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs @@ -43,12 +43,6 @@ public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUn } public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) { - BlockHeader? currentHeader; - if (header.Hash != null) - { - currentHeader = _blockTree.FindHeader(header.Hash, BlockTreeLookupOptions.None); - } - error = null; return _poSSwitcher.IsPostMerge(header) ? ValidateTheMergeChecks(header) && base.Validate(header, parent, isUncle, out error) From 3c3c117d4a6da096748bf75479d50981fb239b19 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 6 Feb 2025 21:33:41 +0530 Subject: [PATCH 095/113] Add endpoint to support rBuilder payload (#8160) --- .../Nethermind.Flashbots/Data/BidTrace.cs | 50 ++++++---- .../Data/BuilderBlockValidationRequest.cs | 11 ++- .../Nethermind.Flashbots/Data/Message.cs | 46 ++++++++++ .../Data/RBuilderBlockValidationRequest.cs | 50 ++++++++++ .../Data/RExecutionPayloadV3.cs | 91 +++++++++++++++++++ .../Data/SubmitBlockRequest.cs | 4 +- .../Modules/Flashbots/FlashbotsRpcModule.cs | 17 +++- .../Modules/Flashbots/IFlashbotsRpcModule.cs | 6 ++ 8 files changed, 253 insertions(+), 22 deletions(-) create mode 100644 src/Nethermind/Nethermind.Flashbots/Data/Message.cs create mode 100644 src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs create mode 100644 src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs index 8fddcb0d205..073a8b8370e 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs @@ -7,23 +7,37 @@ namespace Nethermind.Flashbots.Data; -public class BidTrace( - ulong slot, - Hash256 blockHash, - PublicKey builderPublicKey, - PublicKey proposerPublicKey, - Address proposerFeeRecipient, - long gasLimit, - long gasUsed, - UInt256 value) +public class BidTrace { - public ulong Slot { get; } = slot; - public required Hash256 ParentHash { get; set; } - public Hash256 BlockHash { get; } = blockHash; - public PublicKey BuilderPublicKey { get; } = builderPublicKey; - public PublicKey ProposerPublicKey { get; } = proposerPublicKey; - public Address ProposerFeeRecipient { get; } = proposerFeeRecipient; - public long GasLimit { get; } = gasLimit; - public long GasUsed { get; } = gasUsed; - public UInt256 Value { get; } = value; + public ulong Slot { get; } + public Hash256 ParentHash { get; } + public Hash256 BlockHash { get; } + public PublicKey BuilderPublicKey { get; } + public PublicKey ProposerPublicKey { get; } + public Address ProposerFeeRecipient { get; } + public long GasLimit { get; } + public long GasUsed { get; } + public UInt256 Value { get; } + + public BidTrace( + ulong slot, + Hash256 parentHash, + Hash256 blockHash, + PublicKey builderPublicKey, + PublicKey proposerPublicKey, + Address proposerFeeRecipient, + long gasLimit, + long gasUsed, + UInt256 value) + { + Slot = slot; + ParentHash = parentHash; + BlockHash = blockHash; + BuilderPublicKey = builderPublicKey; + ProposerPublicKey = proposerPublicKey; + ProposerFeeRecipient = proposerFeeRecipient; + GasLimit = gasLimit; + GasUsed = gasUsed; + Value = value; + } } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 66463d74ffc..3285afc563b 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -8,16 +8,23 @@ namespace Nethermind.Flashbots.Data; public class BuilderBlockValidationRequest { + public BuilderBlockValidationRequest(Hash256 parentBeaconBlockRoot, long registerGasLimit, SubmitBlockRequest blockRequest) + { + ParentBeaconBlockRoot = parentBeaconBlockRoot; + RegisterGasLimit = registerGasLimit; + BlockRequest = blockRequest; + } + /// /// The block hash of the parent beacon block. /// /// [JsonRequired] - public required Hash256 ParentBeaconBlockRoot { get; set; } + public Hash256 ParentBeaconBlockRoot { get; set; } [JsonRequired] public long RegisterGasLimit { get; set; } [JsonRequired] - public required SubmitBlockRequest BlockRequest { get; set; } + public SubmitBlockRequest BlockRequest { get; set; } } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/Message.cs b/src/Nethermind/Nethermind.Flashbots/Data/Message.cs new file mode 100644 index 00000000000..9246b5319b4 --- /dev/null +++ b/src/Nethermind/Nethermind.Flashbots/Data/Message.cs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Int256; + +namespace Nethermind.Flashbots.Data; + +public class Message( + ulong slot, + Hash256 parent_hash, + Hash256 block_hash, + PublicKey builder_pubkey, + PublicKey proposer_pubkey, + Address proposer_fee_recipient, + long gas_limit, + long gas_used, + UInt256 value) +{ + public ulong slot { get; } = slot; + public required Hash256 parent_hash { get; set; } = parent_hash; + public Hash256 block_hash { get; } = block_hash; + public PublicKey builder_pubkey { get; } = builder_pubkey; + public PublicKey proposer_pubkey { get; } = proposer_pubkey; + public Address proposer_fee_recipient { get; } = proposer_fee_recipient; + public long gas_limit { get; } = gas_limit; + public long gas_used { get; } = gas_used; + public UInt256 value { get; } = value; + + public BidTrace ToBidTrace() + { + return new BidTrace( + slot, + parent_hash, + block_hash, + builder_pubkey, + proposer_pubkey, + proposer_fee_recipient, + gas_limit, + gas_used, + value + ); + } +} + diff --git a/src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs new file mode 100644 index 00000000000..4d80db37bc0 --- /dev/null +++ b/src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Text.Json.Serialization; +using Nethermind.Core.Crypto; +using Nethermind.Merge.Plugin.Data; + +namespace Nethermind.Flashbots.Data; + +public class RBuilderBlockValidationRequest +{ + public RBuilderBlockValidationRequest( + Message message, + RExecutionPayloadV3 execution_payload, + BlobsBundleV1 blobs_bundle, + byte[] signature, + long registered_gas_limit, + Hash256 withdrawals_root, + Hash256 parent_beacon_block_root) + { + this.message = message; + this.execution_payload = execution_payload; + this.blobs_bundle = blobs_bundle; + this.signature = signature; + this.registered_gas_limit = registered_gas_limit; + this.withdrawals_root = withdrawals_root; + this.parent_beacon_block_root = parent_beacon_block_root; + } + + [JsonRequired] + public Message message { get; set; } + + [JsonRequired] + public RExecutionPayloadV3 execution_payload { get; set; } + + [JsonRequired] + public BlobsBundleV1 blobs_bundle { get; set; } + + [JsonRequired] + public byte[] signature { get; set; } + + [JsonRequired] + public long registered_gas_limit { get; set; } + + [JsonRequired] + public Hash256 withdrawals_root { get; set; } + + [JsonRequired] + public Hash256 parent_beacon_block_root { get; set; } +} diff --git a/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs new file mode 100644 index 00000000000..239e05705d7 --- /dev/null +++ b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Int256; +using Nethermind.Merge.Plugin.Data; + +public class RExecutionPayloadV3 +{ + public Hash256 parent_hash { get; set; } + public Address fee_recipient { get; set; } + public Hash256 state_root { get; set; } + public Hash256 receipts_root { get; set; } + public Bloom logs_bloom { get; set; } + public Hash256 prev_randao { get; set; } + public long block_number { get; set; } + public long gas_limit { get; set; } + public long gas_used { get; set; } + public ulong timestamp { get; set; } + public byte[] extra_data { get; set; } + public UInt256 base_fee_per_gas { get; set; } + public Hash256 block_hash { get; set; } + public byte[][] transactions { get; set; } + public Withdrawal[]? withdrawals { get; set; } + public ulong? blob_gas_used { get; set; } + public ulong? excess_blob_gas { get; set; } + + public ExecutionPayloadV3 ToExecutionPayloadV3() + { + return new ExecutionPayloadV3 + { + ParentHash = parent_hash, + FeeRecipient = fee_recipient, + StateRoot = state_root, + ReceiptsRoot = receipts_root, + LogsBloom = logs_bloom, + PrevRandao = prev_randao, + BlockNumber = block_number, + GasLimit = gas_limit, + GasUsed = gas_used, + Timestamp = timestamp, + ExtraData = extra_data, + BaseFeePerGas = base_fee_per_gas, + BlockHash = block_hash, + Transactions = transactions, + Withdrawals = withdrawals, + BlobGasUsed = blob_gas_used, + ExcessBlobGas = excess_blob_gas + }; + } + + public RExecutionPayloadV3( + Hash256 parent_hash, + Address fee_recipient, + Hash256 state_root, + Hash256 receipts_root, + Bloom logs_bloom, + Hash256 prev_randao, + long block_number, + long gas_limit, + long gas_used, + ulong timestamp, + byte[] extra_data, + UInt256 base_fee_per_gas, + Hash256 block_hash, + byte[][] transactions, + Withdrawal[]? withdrawals, + ulong? blob_gas_used, + ulong? excess_blob_gas + ) + { + this.parent_hash = parent_hash; + this.fee_recipient = fee_recipient; + this.state_root = state_root; + this.receipts_root = receipts_root; + this.logs_bloom = logs_bloom; + this.prev_randao = prev_randao; + this.block_number = block_number; + this.gas_limit = gas_limit; + this.gas_used = gas_used; + this.timestamp = timestamp; + this.extra_data = extra_data; + this.base_fee_per_gas = base_fee_per_gas; + this.block_hash = block_hash; + this.transactions = transactions; + this.withdrawals = withdrawals; + this.blob_gas_used = blob_gas_used; + this.excess_blob_gas = excess_blob_gas; + } +} diff --git a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs index 6e7cc6d783c..f46c9743f4d 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs @@ -10,13 +10,15 @@ public class SubmitBlockRequest private readonly ExecutionPayloadV3 _executionPayload; private readonly BlobsBundleV1 _blobsBundle; - public SubmitBlockRequest(ExecutionPayloadV3 executionPayload, BlobsBundleV1 blobsBundle, BidTrace message) + public SubmitBlockRequest(ExecutionPayloadV3 executionPayload, BlobsBundleV1 blobsBundle, BidTrace message, byte[] signature) { _executionPayload = executionPayload; _blobsBundle = blobsBundle; Message = message; + Signature = signature; } public ExecutionPayloadV3 ExecutionPayload => _executionPayload; public BlobsBundleV1 BlobsBundle => _blobsBundle; public BidTrace Message { get; } + public byte[] Signature { get; } } diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs index 8f10a21fd5d..dc7570a44a0 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs @@ -2,10 +2,10 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; -using Nethermind.Core.Crypto; using Nethermind.Flashbots.Data; using Nethermind.Flashbots.Handlers; using Nethermind.JsonRpc; +using Nethermind.Merge.Plugin.Data; namespace Nethermind.Flashbots.Modules.Flashbots; @@ -21,4 +21,19 @@ public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => _validateSubmissionHandler.ValidateSubmission(@params); + Task> IFlashbotsRpcModule.flashbots_validateRBuilderSubmissionV3(RBuilderBlockValidationRequest @params) + { + ExecutionPayloadV3 executionPayload = @params.execution_payload.ToExecutionPayloadV3(); + BuilderBlockValidationRequest builderBlockValidationRequest = new BuilderBlockValidationRequest( + @params.parent_beacon_block_root, + @params.registered_gas_limit, + new SubmitBlockRequest( + executionPayload, + @params.blobs_bundle, + @params.message.ToBidTrace(), + @params.signature + ) + ); + return _validateSubmissionHandler.ValidateSubmission(builderBlockValidationRequest); + } } diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs index b81da13fb39..b0fdad2ab06 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -16,4 +16,10 @@ public interface IFlashbotsRpcModule : IRpcModule IsSharable = false, IsImplemented = true)] Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); + + [JsonRpcMethod( + Description = " validate the builder submissions as received by a relay", + IsSharable = false, + IsImplemented = true)] + Task> flashbots_validateRBuilderSubmissionV3(RBuilderBlockValidationRequest @params); } From 7d92d68348ca5ac6d6fa8be8a820acd0bfa2109e Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 6 Feb 2025 22:13:59 +0530 Subject: [PATCH 096/113] change casing of the parameters --- .../FlashbotsModuleTests.Setup.cs | 61 +++++++++++++++++-- .../FlashbotsModuleTests.cs | 58 ++---------------- .../Nethermind.Flashbots/Data/BidTrace.cs | 37 ++++++++--- .../Data/BuilderBlockValidationRequest.cs | 9 ++- .../Data/SubmitBlockRequest.cs | 25 +++++--- .../ValidateBuilderSubmissionHandler.cs | 8 +-- .../Modules/Flashbots/FlashbotsRpcModule.cs | 3 +- .../EngineModuleTests.Setup.cs | 1 - 8 files changed, 115 insertions(+), 87 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs index 228c76801e0..5fee8da4025 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; @@ -11,11 +14,13 @@ using Nethermind.Consensus.Validators; using Nethermind.Consensus.Withdrawals; using Nethermind.Core; +using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test.Blockchain; using Nethermind.Crypto; using Nethermind.Db; +using Nethermind.Evm.Tracing; using Nethermind.Flashbots; using Nethermind.Flashbots.Handlers; using Nethermind.Flashbots.Modules.Flashbots; @@ -124,7 +129,7 @@ protected override IBlockProcessor CreateBlockProcessor() { BlockValidator = CreateBlockValidator(); WithdrawalProcessor = new WithdrawalProcessor(State, LogManager); - IBlockProcessor prcessor = new BlockProcessor( + IBlockProcessor processor = new BlockProcessor( SpecProvider, BlockValidator, NoBlockRewards.Instance, @@ -135,10 +140,11 @@ protected override IBlockProcessor CreateBlockProcessor() new BeaconBlockRootHandler(TxProcessor, State), new BlockhashStore(SpecProvider, State), LogManager, - WithdrawalProcessor + WithdrawalProcessor, + preWarmer: CreateBlockCachePreWarmer() ); - return prcessor; + return new TestBlockProcessorInterceptor(processor); } protected IBlockValidator CreateBlockValidator() @@ -165,7 +171,7 @@ protected IBlockValidator CreateBlockValidator() protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) { - TestBlockchain chain = await base.Build(specProvider, initialValues); + TestBlockchain chain = await base.Build(specProvider, initialValues, false); return chain; } @@ -174,3 +180,50 @@ public async Task Build(ISpecProvider? specProvider = null) } } + +public class TestBlockProcessorInterceptor : IBlockProcessor +{ + private readonly IBlockProcessor _blockProcessorImplementation; + public Exception? ExceptionToThrow { get; set; } + + public TestBlockProcessorInterceptor(IBlockProcessor baseBlockProcessor) + { + _blockProcessorImplementation = baseBlockProcessor; + } + + public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, ProcessingOptions processingOptions, + IBlockTracer blockTracer) + { + + if (ExceptionToThrow is not null) + { + throw ExceptionToThrow; + } + + return _blockProcessorImplementation.Process(newBranchStateRoot, suggestedBlocks, processingOptions, blockTracer); + } + + public event EventHandler? BlocksProcessing + { + add => _blockProcessorImplementation.BlocksProcessing += value; + remove => _blockProcessorImplementation.BlocksProcessing -= value; + } + + public event EventHandler? BlockProcessing + { + add => _blockProcessorImplementation.BlockProcessing += value; + remove => _blockProcessorImplementation.BlockProcessing -= value; + } + + public event EventHandler? BlockProcessed + { + add => _blockProcessorImplementation.BlockProcessed += value; + remove => _blockProcessorImplementation.BlockProcessed -= value; + } + + public event EventHandler? TransactionProcessed + { + add => _blockProcessorImplementation.TransactionProcessed += value; + remove => _blockProcessorImplementation.TransactionProcessed -= value; + } +} diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index 654ebb5d1b7..87d97d6d736 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -3,7 +3,6 @@ using System; using System.Threading.Tasks; -using FluentAssertions; using Nethermind.Consensus.Processing; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -12,8 +11,6 @@ using Nethermind.Core.Test.Builders; using Nethermind.Flashbots.Modules.Flashbots; using Nethermind.Int256; -using Nethermind.JsonRpc; -using Nethermind.JsonRpc.Test; using Nethermind.Merge.Plugin.Data; using Nethermind.Specs.Forks; using Nethermind.State; @@ -30,14 +27,15 @@ public partial class FlashbotsModuleTests public virtual async Task TestValidateBuilderSubmissionV3() { using MergeTestBlockChain chain = await CreateBlockChain(releaseSpec: Cancun.Instance); - ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = chain.CreateReadOnlyTxProcessingEnv(); - IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnv); + ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = chain.CreateReadOnlyTxProcessingEnvFactory(); + IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnvFactory); + BlockHeader currentHeader = chain.BlockTree.Head.Header; IWorldState State = chain.State; UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); - Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(new Address("0x16")).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(TestKeysAndAddress.TestBuilderAddr).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; chain.TxPool.SubmitTx(tx1, TxPool.TxHandlingOptions.None); Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2 * TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; @@ -56,44 +54,6 @@ public virtual async Task TestValidateBuilderSubmissionV3() ulong timestamp = Timestamper.UnixTime.Seconds; Hash256 prevRandao = Keccak.Zero; - var payloadAttrs = new - { - timestamp = timestamp.ToHexString(true), - prevRandao, - suggestedFeeRecipient = TestKeysAndAddress.TestAddr.ToString(), - withdrawals, - parentBeaconBLockRoot = Keccak.Zero - }; - - string?[] @params = new string?[] - { - chain.JsonSerializer.Serialize(new { - headBlockHash = currentHeader.Hash.ToString(), - safeBlockHash = currentHeader.Hash.ToString(), - finalizedBlockHash = currentHeader.Hash.ToString(), - }), chain.JsonSerializer.Serialize(payloadAttrs) - }; - string expectedPayloadId = "0x774c6aff527bbc68"; - - string response = await RpcTest.TestSerializedRequest(rpc, "engine_forkchoiceUpdatedV3", @params!); - JsonRpcSuccessResponse? successResponse = chain.JsonSerializer.Deserialize(response); - - successResponse.Should().NotBeNull(); - response.Should().Be(chain.JsonSerializer.Serialize(new JsonRpcSuccessResponse - { - Id = successResponse.Id, - Result = new ForkchoiceUpdatedV1Result - { - PayloadId = expectedPayloadId, - PayloadStatus = new PayloadStatusV1 - { - LatestValidHash = new("0xd7e58364f16b4a329b959b166f9c32323cb135669335db5dadd0344568f8dc9a"), - Status = PayloadStatus.Valid, - ValidationError = null - } - } - })); - Hash256 expectedBlockHash = new("0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26"); string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; @@ -126,15 +86,5 @@ public virtual async Task TestValidateBuilderSubmissionV3() ); GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block)); - - response = await RpcTest.TestSerializedRequest(rpc, "engine_getPayloadV3", expectedPayloadId); - successResponse = chain.JsonSerializer.Deserialize(response); - - successResponse.Should().NotBeNull(); - response.Should().Be(chain.JsonSerializer.Serialize(new JsonRpcSuccessResponse - { - Id = successResponse.Id, - Result = expectedPayload - })); } } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs index 073a8b8370e..e27ca437a8a 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BidTrace.cs @@ -7,17 +7,36 @@ namespace Nethermind.Flashbots.Data; +using System.Text.Json.Serialization; + public class BidTrace { - public ulong Slot { get; } - public Hash256 ParentHash { get; } - public Hash256 BlockHash { get; } - public PublicKey BuilderPublicKey { get; } - public PublicKey ProposerPublicKey { get; } - public Address ProposerFeeRecipient { get; } - public long GasLimit { get; } - public long GasUsed { get; } - public UInt256 Value { get; } + [JsonPropertyName("slot")] + public ulong Slot { get; set; } + + [JsonPropertyName("parent_hash")] + public Hash256 ParentHash { get; set; } + + [JsonPropertyName("block_hash")] + public Hash256 BlockHash { get; set; } + + [JsonPropertyName("builder_public_key")] + public PublicKey BuilderPublicKey { get; set; } + + [JsonPropertyName("proposer_public_key")] + public PublicKey ProposerPublicKey { get; set; } + + [JsonPropertyName("proposer_fee_recipient")] + public Address ProposerFeeRecipient { get; set; } + + [JsonPropertyName("gas_limit")] + public long GasLimit { get; set; } + + [JsonPropertyName("gas_used")] + public long GasUsed { get; set; } + + [JsonPropertyName("value")] + public UInt256 Value { get; set; } public BidTrace( ulong slot, diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 3285afc563b..0f5eac56910 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -8,10 +8,10 @@ namespace Nethermind.Flashbots.Data; public class BuilderBlockValidationRequest { - public BuilderBlockValidationRequest(Hash256 parentBeaconBlockRoot, long registerGasLimit, SubmitBlockRequest blockRequest) + public BuilderBlockValidationRequest(Hash256 parentBeaconBlockRoot, long registeredGasLimit, SubmitBlockRequest blockRequest) { ParentBeaconBlockRoot = parentBeaconBlockRoot; - RegisterGasLimit = registerGasLimit; + RegisteredGasLimit = registeredGasLimit; BlockRequest = blockRequest; } @@ -20,11 +20,14 @@ public BuilderBlockValidationRequest(Hash256 parentBeaconBlockRoot, long registe /// /// [JsonRequired] + [JsonPropertyName("parent_beacon_block_root")] public Hash256 ParentBeaconBlockRoot { get; set; } [JsonRequired] - public long RegisterGasLimit { get; set; } + [JsonPropertyName("registered_gas_limit")] + public long RegisteredGasLimit { get; set; } [JsonRequired] + [JsonPropertyName("block_request")] public SubmitBlockRequest BlockRequest { get; set; } } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs index f46c9743f4d..b9bb5cd0058 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs @@ -1,24 +1,29 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Text.Json.Serialization; using Nethermind.Merge.Plugin.Data; namespace Nethermind.Flashbots.Data; public class SubmitBlockRequest { - private readonly ExecutionPayloadV3 _executionPayload; - private readonly BlobsBundleV1 _blobsBundle; - - public SubmitBlockRequest(ExecutionPayloadV3 executionPayload, BlobsBundleV1 blobsBundle, BidTrace message, byte[] signature) + public SubmitBlockRequest(RExecutionPayloadV3 executionPayload, BlobsBundleV1 blobsBundle, BidTrace message, byte[] signature) { - _executionPayload = executionPayload; - _blobsBundle = blobsBundle; + ExecutionPayload = executionPayload; + BlobsBundle = blobsBundle; Message = message; Signature = signature; } - public ExecutionPayloadV3 ExecutionPayload => _executionPayload; - public BlobsBundleV1 BlobsBundle => _blobsBundle; - public BidTrace Message { get; } - public byte[] Signature { get; } + [JsonPropertyName("execution_payload")] + public RExecutionPayloadV3 ExecutionPayload { get; set; } + + [JsonPropertyName("blobs_bundle")] + public BlobsBundleV1 BlobsBundle { get; set; } + + [JsonPropertyName("message")] + public BidTrace Message { get; set; } + + [JsonPropertyName("signature")] + public byte[] Signature { get; set; } } diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index aec53e81550..157b0573679 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -69,7 +69,7 @@ public ValidateSubmissionHandler( public Task> ValidateSubmission(BuilderBlockValidationRequest request) { - ExecutionPayloadV3 payload = request.BlockRequest.ExecutionPayload; + ExecutionPayloadV3 payload = request.BlockRequest.ExecutionPayload.ToExecutionPayloadV3(); if (request.ParentBeaconBlockRoot is null) { @@ -92,7 +92,7 @@ public Task> ValidateSubmission(BuilderBlockValid return FlashbotsResult.Invalid($"Block {payload} coud not be parsed as a block"); } - if (block is not null && !ValidateBlock(block, request.BlockRequest.Message, request.RegisterGasLimit, out string? error)) + if (block is not null && !ValidateBlock(block, request.BlockRequest.Message, request.RegisteredGasLimit, out string? error)) { if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}. Error: {error}"); return FlashbotsResult.Invalid(error ?? "Block validation failed"); @@ -108,7 +108,7 @@ public Task> ValidateSubmission(BuilderBlockValid return FlashbotsResult.Valid(); } - private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, out string? error) + private bool ValidateBlock(Block block, BidTrace message, long registeredGasLimit, out string? error) { error = null; @@ -139,7 +139,7 @@ private bool ValidateBlock(Block block, BidTrace message, long registerGasLimit, Address feeRecipient = message.ProposerFeeRecipient; UInt256 expectedProfit = message.Value; - if (!ValidatePayload(block, feeRecipient, expectedProfit, registerGasLimit, _flashbotsConfig.UseBalanceDiffProfit, _flashbotsConfig.ExcludeWithdrawals, out error)) + if (!ValidatePayload(block, feeRecipient, expectedProfit, registeredGasLimit, _flashbotsConfig.UseBalanceDiffProfit, _flashbotsConfig.ExcludeWithdrawals, out error)) { return false; } diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs index dc7570a44a0..b752f997205 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs @@ -23,12 +23,11 @@ Task> IFlashbotsRpcModule.flashbots_validateBuild Task> IFlashbotsRpcModule.flashbots_validateRBuilderSubmissionV3(RBuilderBlockValidationRequest @params) { - ExecutionPayloadV3 executionPayload = @params.execution_payload.ToExecutionPayloadV3(); BuilderBlockValidationRequest builderBlockValidationRequest = new BuilderBlockValidationRequest( @params.parent_beacon_block_root, @params.registered_gas_limit, new SubmitBlockRequest( - executionPayload, + @params.execution_payload, @params.blobs_bundle, @params.message.ToBidTrace(), @params.signature diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index 5c8be744150..4fa8b8e6811 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -38,7 +38,6 @@ using Nethermind.Specs.ChainSpecStyle; using Nethermind.Specs.Forks; using Nethermind.Synchronization; -using Nethermind.Synchronization.FastBlocks; using Nethermind.Synchronization.ParallelSync; using Nethermind.Synchronization.Peers; using NSubstitute; From 54791c38c909648716b054bf16e50aa9d34a406b Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 6 Feb 2025 22:21:47 +0530 Subject: [PATCH 097/113] apply rubo suggestions --- .../Nethermind.Flashbots/IFlashbotsConfig.cs | 11 +++++------ src/tests | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs index 11cf99d2238..2faaa530ea6 100644 --- a/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs +++ b/src/Nethermind/Nethermind.Flashbots/IFlashbotsConfig.cs @@ -10,22 +10,21 @@ public interface IFlashbotsConfig : IConfig [ConfigItem(Description = "Whether to enable the Flashbots endpoints.", DefaultValue = "false")] bool Enabled { get; set; } - [ConfigItem(Description = "If set to true, proposer payment is calculated as a balance difference of the fee recipient", DefaultValue = "false")] + [ConfigItem(Description = "Whether to calculate the proposer payment as a balance difference of the fee recipient.", DefaultValue = "false")] public bool UseBalanceDiffProfit { get; set; } - [ConfigItem(Description = "If set to true, withdrawals to the fee recipient are excluded from the balance delta", DefaultValue = "false")] + [ConfigItem(Description = "Whether to exclude the withdrawals to the fee recipient from the balance difference.", DefaultValue = "false")] public bool ExcludeWithdrawals { get; set; } - [ConfigItem(Description = "If set to true, the pre-warmer will be enabled", DefaultValue = "true")] + [ConfigItem(Description = "Whether to enable the pre-warmer.", DefaultValue = "true")] public bool EnablePreWarmer { get; set; } - [ConfigItem(Description = "If set to true, the validation will be enabled", DefaultValue = "false")] + [ConfigItem(Description = "Whether to enable validation.", DefaultValue = "false")] public bool EnableValidation { get; set; } [ConfigItem( Description = """ - The number of concurrent instances for non-sharable calls: - - `flashbots_validateBuilderSubmissionV3` + The number of concurrent instances for non-sharable calls for `flashbots_validateBuilderSubmissionV3` This limits the load on the CPU and I/O to reasonable levels. If the limit is exceeded, HTTP 503 is returned along with the JSON-RPC error. Defaults to the number of logical processors. """)] int? FlashbotsModuleConcurrentInstances { get; set; } diff --git a/src/tests b/src/tests index ae4791077e8..8c215d6b56f 160000 --- a/src/tests +++ b/src/tests @@ -1 +1 @@ -Subproject commit ae4791077e8fcf716136e70fe8392f1a1f1495fb +Subproject commit 8c215d6b56fed36501d04c165093357f102de2ac From 554a2296de682eaa46256100e88ab4083c9743cc Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 6 Feb 2025 22:27:37 +0530 Subject: [PATCH 098/113] revert bench precompiles --- src/bench_precompiles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bench_precompiles b/src/bench_precompiles index c1089350ef0..a55fd2fb4a7 160000 --- a/src/bench_precompiles +++ b/src/bench_precompiles @@ -1 +1 @@ -Subproject commit c1089350ef0daa3f0bd437ce9d1626de973f9a93 +Subproject commit a55fd2fb4a7d28bfa5851a7aada4489c4a470951 From a3ea5b8ea6e9c7f52b32323b027b815dad192c8a Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 6 Feb 2025 22:29:11 +0530 Subject: [PATCH 099/113] revert tests submodule --- src/tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests b/src/tests index 8c215d6b56f..ae4791077e8 160000 --- a/src/tests +++ b/src/tests @@ -1 +1 @@ -Subproject commit 8c215d6b56fed36501d04c165093357f102de2ac +Subproject commit ae4791077e8fcf716136e70fe8392f1a1f1495fb From 73317a409dfaaca6a91a13d78cc46f4b26ba7708 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 7 Feb 2025 00:09:13 +0530 Subject: [PATCH 100/113] add tests --- .../FlashbotsModuleTests.cs | 128 ++++++++++++++++++ .../Nethermind.Flashbots/Data/Message.cs | 2 +- .../Data/RExecutionPayloadV3.cs | 20 +++ 3 files changed, 149 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index 87d97d6d736..ab8ae4c215d 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -3,14 +3,18 @@ using System; using System.Threading.Tasks; +using FluentAssertions; using Nethermind.Consensus.Processing; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; +using Nethermind.Flashbots.Data; using Nethermind.Flashbots.Modules.Flashbots; using Nethermind.Int256; +using Nethermind.JsonRpc; +using Nethermind.JsonRpc.Test; using Nethermind.Merge.Plugin.Data; using Nethermind.Specs.Forks; using Nethermind.State; @@ -86,5 +90,129 @@ public virtual async Task TestValidateBuilderSubmissionV3() ); GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block)); + + BuilderBlockValidationRequest BlockRequest = new( + new Hash256("0x0000000000000000000000000000000000000000000000000000000000000042"), + block.Header.GasLimit, + new SubmitBlockRequest( + new RExecutionPayloadV3(ExecutionPayloadV3.Create(block)), + expectedPayload.BlobsBundle, + new BidTrace( + 0, block.Header.ParentHash, + block.Header.Hash, + TestKeysAndAddress.TestBuilderKey.PublicKey, + TestKeysAndAddress.TestValidatorKey.PublicKey, + TestKeysAndAddress.TestBuilderAddr, + block.Header.GasLimit, + block.Header.GasUsed, + new UInt256(132912184722469) + ), + [] + ) + ); + + ResultWrapper result = await rpc.flashbots_validateBuilderSubmissionV3(BlockRequest); + result.Should().NotBeNull(); + + Assert.That(result.Result, Is.EqualTo(Result.Success)); + // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); + + string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateBuilderSubmissionV3", BlockRequest); + JsonRpcSuccessResponse? jsonResponse = chain.JsonSerializer.Deserialize(response); + jsonResponse.Should().NotBeNull(); + } + + [Test] + public virtual async Task TestValidateRBuilderSubmissionV3() + { + using MergeTestBlockChain chain = await CreateBlockChain(releaseSpec: Cancun.Instance); + ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = chain.CreateReadOnlyTxProcessingEnvFactory(); + IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnvFactory); + + BlockHeader currentHeader = chain.BlockTree.Head.Header; + IWorldState State = chain.State; + + UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); + + Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(TestKeysAndAddress.TestBuilderAddr).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + chain.TxPool.SubmitTx(tx1, TxPool.TxHandlingOptions.None); + + Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2 * TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + chain.TxPool.SubmitTx(tx2, TxPool.TxHandlingOptions.None); + + UInt256 baseFee = BaseFeeCalculator.Calculate(currentHeader, chain.SpecProvider.GetFinalSpec()); + + Transaction tx3 = Build.A.Transaction.WithNonce(nonce + 2).WithValue(10).WithGasLimit(21000).WithValue(baseFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; + chain.TxPool.SubmitTx(tx3, TxPool.TxHandlingOptions.None); + + Withdrawal[] withdrawals = [ + Build.A.Withdrawal.WithIndex(0).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject, + Build.A.Withdrawal.WithIndex(1).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject + ]; + + ulong timestamp = Timestamper.UnixTime.Seconds; + Hash256 prevRandao = Keccak.Zero; + + Hash256 expectedBlockHash = new("0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26"); + string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; + + Block block = new( + new( + currentHeader.Hash, + Keccak.OfAnEmptySequenceRlp, + TestKeysAndAddress.TestAddr, + UInt256.Zero, + 1, + chain.BlockTree.Head!.GasLimit, + timestamp, + Bytes.FromHexString("0x4e65746865726d696e64") // Nethermind + ) + { + BlobGasUsed = 0, + ExcessBlobGas = 0, + BaseFeePerGas = 0, + Bloom = Bloom.Empty, + GasUsed = 0, + Hash = expectedBlockHash, + MixHash = prevRandao, + ParentBeaconBlockRoot = Keccak.Zero, + ReceiptsRoot = chain.BlockTree.Head!.ReceiptsRoot!, + StateRoot = new(stateRoot), + }, + Array.Empty(), + Array.Empty(), + withdrawals + ); + + GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block)); + + RBuilderBlockValidationRequest BlockRequest = new( + new Message( + 0, block.Header.ParentHash, + block.Header.Hash, + TestKeysAndAddress.TestBuilderKey.PublicKey, + TestKeysAndAddress.TestValidatorKey.PublicKey, + TestKeysAndAddress.TestBuilderAddr, + block.Header.GasLimit, + block.Header.GasUsed, + new UInt256(132912184722469) + ), + new RExecutionPayloadV3(ExecutionPayloadV3.Create(block)), + expectedPayload.BlobsBundle, + [], + block.Header.GasLimit, + block.WithdrawalsRoot, + new Hash256("0x0000000000000000000000000000000000000000000000000000000000000042") + ); + + ResultWrapper result = await rpc.flashbots_validateRBuilderSubmissionV3(BlockRequest); + result.Should().NotBeNull(); + + Assert.That(result.Result, Is.EqualTo(Result.Success)); + // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); + + string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateRBuilderSubmissionV3", BlockRequest); + JsonRpcSuccessResponse? jsonResponse = chain.JsonSerializer.Deserialize(response); + jsonResponse.Should().NotBeNull(); } } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/Message.cs b/src/Nethermind/Nethermind.Flashbots/Data/Message.cs index 9246b5319b4..47ed8f9988c 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/Message.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/Message.cs @@ -19,7 +19,7 @@ public class Message( UInt256 value) { public ulong slot { get; } = slot; - public required Hash256 parent_hash { get; set; } = parent_hash; + public Hash256 parent_hash { get; set; } = parent_hash; public Hash256 block_hash { get; } = block_hash; public PublicKey builder_pubkey { get; } = builder_pubkey; public PublicKey proposer_pubkey { get; } = proposer_pubkey; diff --git a/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs index 239e05705d7..01ba5c2cee9 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs @@ -26,6 +26,26 @@ public class RExecutionPayloadV3 public ulong? blob_gas_used { get; set; } public ulong? excess_blob_gas { get; set; } + public RExecutionPayloadV3(ExecutionPayloadV3 executionPayloadV3) + { + parent_hash = executionPayloadV3.ParentHash; + fee_recipient = executionPayloadV3.FeeRecipient; + state_root = executionPayloadV3.StateRoot; + receipts_root = executionPayloadV3.ReceiptsRoot; + logs_bloom = executionPayloadV3.LogsBloom; + prev_randao = executionPayloadV3.PrevRandao; + block_number = executionPayloadV3.BlockNumber; + gas_limit = executionPayloadV3.GasLimit; + gas_used = executionPayloadV3.GasUsed; + timestamp = executionPayloadV3.Timestamp; + extra_data = executionPayloadV3.ExtraData; + base_fee_per_gas = executionPayloadV3.BaseFeePerGas; + block_hash = executionPayloadV3.BlockHash; + transactions = executionPayloadV3.Transactions; + withdrawals = executionPayloadV3.Withdrawals; + blob_gas_used = executionPayloadV3.BlobGasUsed; + excess_blob_gas = executionPayloadV3.ExcessBlobGas; + } public ExecutionPayloadV3 ToExecutionPayloadV3() { return new ExecutionPayloadV3 From 8b508993cbdff836d672b80dc91a1898223537ce Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 7 Feb 2025 00:16:59 +0530 Subject: [PATCH 101/113] add tests --- .../FlashbotsModuleTests.cs | 122 ++++++------------ .../ValidateBuilderSubmissionHandler.cs | 6 +- 2 files changed, 39 insertions(+), 89 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index ab8ae4c215d..be669d4e04c 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -34,60 +34,7 @@ public virtual async Task TestValidateBuilderSubmissionV3() ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = chain.CreateReadOnlyTxProcessingEnvFactory(); IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnvFactory); - BlockHeader currentHeader = chain.BlockTree.Head.Header; - IWorldState State = chain.State; - - UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); - - Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(TestKeysAndAddress.TestBuilderAddr).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; - chain.TxPool.SubmitTx(tx1, TxPool.TxHandlingOptions.None); - - Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2 * TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; - chain.TxPool.SubmitTx(tx2, TxPool.TxHandlingOptions.None); - - UInt256 baseFee = BaseFeeCalculator.Calculate(currentHeader, chain.SpecProvider.GetFinalSpec()); - - Transaction tx3 = Build.A.Transaction.WithNonce(nonce + 2).WithValue(10).WithGasLimit(21000).WithValue(baseFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; - chain.TxPool.SubmitTx(tx3, TxPool.TxHandlingOptions.None); - - Withdrawal[] withdrawals = [ - Build.A.Withdrawal.WithIndex(0).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject, - Build.A.Withdrawal.WithIndex(1).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject - ]; - - ulong timestamp = Timestamper.UnixTime.Seconds; - Hash256 prevRandao = Keccak.Zero; - - Hash256 expectedBlockHash = new("0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26"); - string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; - - Block block = new( - new( - currentHeader.Hash, - Keccak.OfAnEmptySequenceRlp, - TestKeysAndAddress.TestAddr, - UInt256.Zero, - 1, - chain.BlockTree.Head!.GasLimit, - timestamp, - Bytes.FromHexString("0x4e65746865726d696e64") // Nethermind - ) - { - BlobGasUsed = 0, - ExcessBlobGas = 0, - BaseFeePerGas = 0, - Bloom = Bloom.Empty, - GasUsed = 0, - Hash = expectedBlockHash, - MixHash = prevRandao, - ParentBeaconBlockRoot = Keccak.Zero, - ReceiptsRoot = chain.BlockTree.Head!.ReceiptsRoot!, - StateRoot = new(stateRoot), - }, - Array.Empty(), - Array.Empty(), - withdrawals - ); + Block block = CreateBlock(chain); GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block)); @@ -129,6 +76,40 @@ public virtual async Task TestValidateRBuilderSubmissionV3() ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = chain.CreateReadOnlyTxProcessingEnvFactory(); IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnvFactory); + Block block = CreateBlock(chain); + + RBuilderBlockValidationRequest BlockRequest = new( + new Message( + 0, block.Header.ParentHash, + block.Header.Hash, + TestKeysAndAddress.TestBuilderKey.PublicKey, + TestKeysAndAddress.TestValidatorKey.PublicKey, + TestKeysAndAddress.TestBuilderAddr, + block.Header.GasLimit, + block.Header.GasUsed, + new UInt256(132912184722469) + ), + new RExecutionPayloadV3(ExecutionPayloadV3.Create(block)), + new BlobsBundleV1(block), + [], + block.Header.GasLimit, + block.WithdrawalsRoot, + new Hash256("0x0000000000000000000000000000000000000000000000000000000000000042") + ); + + ResultWrapper result = await rpc.flashbots_validateRBuilderSubmissionV3(BlockRequest); + result.Should().NotBeNull(); + + Assert.That(result.Result, Is.EqualTo(Result.Success)); + // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); + + string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateRBuilderSubmissionV3", BlockRequest); + JsonRpcSuccessResponse? jsonResponse = chain.JsonSerializer.Deserialize(response); + jsonResponse.Should().NotBeNull(); + } + + private Block CreateBlock(MergeTestBlockChain chain) + { BlockHeader currentHeader = chain.BlockTree.Head.Header; IWorldState State = chain.State; @@ -156,7 +137,7 @@ public virtual async Task TestValidateRBuilderSubmissionV3() Hash256 expectedBlockHash = new("0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26"); string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; - Block block = new( + return new( new( currentHeader.Hash, Keccak.OfAnEmptySequenceRlp, @@ -183,36 +164,5 @@ public virtual async Task TestValidateRBuilderSubmissionV3() Array.Empty(), withdrawals ); - - GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block)); - - RBuilderBlockValidationRequest BlockRequest = new( - new Message( - 0, block.Header.ParentHash, - block.Header.Hash, - TestKeysAndAddress.TestBuilderKey.PublicKey, - TestKeysAndAddress.TestValidatorKey.PublicKey, - TestKeysAndAddress.TestBuilderAddr, - block.Header.GasLimit, - block.Header.GasUsed, - new UInt256(132912184722469) - ), - new RExecutionPayloadV3(ExecutionPayloadV3.Create(block)), - expectedPayload.BlobsBundle, - [], - block.Header.GasLimit, - block.WithdrawalsRoot, - new Hash256("0x0000000000000000000000000000000000000000000000000000000000000042") - ); - - ResultWrapper result = await rpc.flashbots_validateRBuilderSubmissionV3(BlockRequest); - result.Should().NotBeNull(); - - Assert.That(result.Result, Is.EqualTo(Result.Success)); - // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); - - string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateRBuilderSubmissionV3", BlockRequest); - JsonRpcSuccessResponse? jsonResponse = chain.JsonSerializer.Deserialize(response); - jsonResponse.Should().NotBeNull(); } } diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 157b0573679..bb2fdda8625 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -254,7 +254,7 @@ private bool ValidatePayload(Block block, Address feeRecipient, UInt256 expected if (ValidateProposerPayment(expectedProfit, useBalanceDiffProfit, feeRecipientBalanceAfter, amtBeforeOrWithdrawn)) return true; - if (!ValidateProcessedBlock(block, feeRecipient, expectedProfit, [.. blockReceiptsTracer.TxReceipts], out error)) + if (!ValidateProcessedBlock(block, feeRecipient, expectedProfit, blockReceiptsTracer.TxReceipts, out error)) { return false; } @@ -340,9 +340,9 @@ private bool ValidateProposerPayment(UInt256 expectedProfit, bool useBalanceDiff return false; } - private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, UInt256 expectedProfit, TxReceipt[] receipts, out string? error) + private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, UInt256 expectedProfit, IReadOnlyList receipts, out string? error) { - if (receipts.Length == 0) + if (receipts.Count == 0) { error = "No proposer payment receipt"; return false; From f453326ecc38b21c5f5e592ce9378788d5cea92d Mon Sep 17 00:00:00 2001 From: mralj Date: Sat, 8 Feb 2025 22:29:23 +0100 Subject: [PATCH 102/113] RExecutionPayloadV3 Json bugfix --- .../Nethermind.Flashbots/Data/RExecutionPayloadV3.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs index 01ba5c2cee9..ebf383baca0 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Text.Json.Serialization; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -70,6 +71,8 @@ public ExecutionPayloadV3 ToExecutionPayloadV3() }; } + + [JsonConstructor] public RExecutionPayloadV3( Hash256 parent_hash, Address fee_recipient, From 87e0ad87b9f1e814e12857fb88dc6f24868ca0b1 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Tue, 11 Feb 2025 12:23:31 +0530 Subject: [PATCH 103/113] remove redundant endpoint --- .../FlashbotsModuleTests.cs | 49 ++---------------- .../Data/BuilderBlockValidationRequest.cs | 43 ++++++++++++---- .../Nethermind.Flashbots/Data/Message.cs | 46 ----------------- .../Data/RBuilderBlockValidationRequest.cs | 50 ------------------- .../Data/SubmitBlockRequest.cs | 29 ----------- .../ValidateBuilderSubmissionHandler.cs | 8 +-- .../Modules/Flashbots/FlashbotsRpcModule.cs | 15 ------ .../Modules/Flashbots/IFlashbotsRpcModule.cs | 6 --- 8 files changed, 40 insertions(+), 206 deletions(-) delete mode 100644 src/Nethermind/Nethermind.Flashbots/Data/Message.cs delete mode 100644 src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs delete mode 100644 src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index be669d4e04c..9260b886b7d 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -39,47 +39,7 @@ public virtual async Task TestValidateBuilderSubmissionV3() GetPayloadV3Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block)); BuilderBlockValidationRequest BlockRequest = new( - new Hash256("0x0000000000000000000000000000000000000000000000000000000000000042"), - block.Header.GasLimit, - new SubmitBlockRequest( - new RExecutionPayloadV3(ExecutionPayloadV3.Create(block)), - expectedPayload.BlobsBundle, - new BidTrace( - 0, block.Header.ParentHash, - block.Header.Hash, - TestKeysAndAddress.TestBuilderKey.PublicKey, - TestKeysAndAddress.TestValidatorKey.PublicKey, - TestKeysAndAddress.TestBuilderAddr, - block.Header.GasLimit, - block.Header.GasUsed, - new UInt256(132912184722469) - ), - [] - ) - ); - - ResultWrapper result = await rpc.flashbots_validateBuilderSubmissionV3(BlockRequest); - result.Should().NotBeNull(); - - Assert.That(result.Result, Is.EqualTo(Result.Success)); - // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); - - string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateBuilderSubmissionV3", BlockRequest); - JsonRpcSuccessResponse? jsonResponse = chain.JsonSerializer.Deserialize(response); - jsonResponse.Should().NotBeNull(); - } - - [Test] - public virtual async Task TestValidateRBuilderSubmissionV3() - { - using MergeTestBlockChain chain = await CreateBlockChain(releaseSpec: Cancun.Instance); - ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = chain.CreateReadOnlyTxProcessingEnvFactory(); - IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnvFactory); - - Block block = CreateBlock(chain); - - RBuilderBlockValidationRequest BlockRequest = new( - new Message( + new BidTrace( 0, block.Header.ParentHash, block.Header.Hash, TestKeysAndAddress.TestBuilderKey.PublicKey, @@ -90,20 +50,19 @@ public virtual async Task TestValidateRBuilderSubmissionV3() new UInt256(132912184722469) ), new RExecutionPayloadV3(ExecutionPayloadV3.Create(block)), - new BlobsBundleV1(block), + expectedPayload.BlobsBundle, [], block.Header.GasLimit, - block.WithdrawalsRoot, new Hash256("0x0000000000000000000000000000000000000000000000000000000000000042") ); - ResultWrapper result = await rpc.flashbots_validateRBuilderSubmissionV3(BlockRequest); + ResultWrapper result = await rpc.flashbots_validateBuilderSubmissionV3(BlockRequest); result.Should().NotBeNull(); Assert.That(result.Result, Is.EqualTo(Result.Success)); // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); - string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateRBuilderSubmissionV3", BlockRequest); + string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateBuilderSubmissionV3", BlockRequest); JsonRpcSuccessResponse? jsonResponse = chain.JsonSerializer.Deserialize(response); jsonResponse.Should().NotBeNull(); } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs index 0f5eac56910..496ec5b74e3 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BuilderBlockValidationRequest.cs @@ -3,31 +3,52 @@ using System.Text.Json.Serialization; using Nethermind.Core.Crypto; +using Nethermind.Merge.Plugin.Data; namespace Nethermind.Flashbots.Data; public class BuilderBlockValidationRequest { - public BuilderBlockValidationRequest(Hash256 parentBeaconBlockRoot, long registeredGasLimit, SubmitBlockRequest blockRequest) + public BuilderBlockValidationRequest( + BidTrace message, + RExecutionPayloadV3 executionPayload, + BlobsBundleV1 blobsBundle, + byte[] signature, + long registeredGasLimit, + Hash256 parentBeaconBlockRoot) { - ParentBeaconBlockRoot = parentBeaconBlockRoot; + Message = message; + ExecutionPayload = executionPayload; + BlobsBundle = blobsBundle; + Signature = signature; RegisteredGasLimit = registeredGasLimit; - BlockRequest = blockRequest; + ParentBeaconBlockRoot = parentBeaconBlockRoot; } - /// - /// The block hash of the parent beacon block. - /// - /// [JsonRequired] - [JsonPropertyName("parent_beacon_block_root")] - public Hash256 ParentBeaconBlockRoot { get; set; } + [JsonPropertyName("message")] + public BidTrace Message { get; set; } + + [JsonRequired] + [JsonPropertyName("execution_payload")] + public RExecutionPayloadV3 ExecutionPayload { get; set; } + + [JsonRequired] + [JsonPropertyName("blobs_bundle")] + public BlobsBundleV1 BlobsBundle { get; set; } + + [JsonPropertyName("signature")] + public byte[] Signature { get; set; } [JsonRequired] [JsonPropertyName("registered_gas_limit")] public long RegisteredGasLimit { get; set; } + /// + /// The block hash of the parent beacon block. + /// + /// [JsonRequired] - [JsonPropertyName("block_request")] - public SubmitBlockRequest BlockRequest { get; set; } + [JsonPropertyName("parent_beacon_block_root")] + public Hash256 ParentBeaconBlockRoot { get; set; } } diff --git a/src/Nethermind/Nethermind.Flashbots/Data/Message.cs b/src/Nethermind/Nethermind.Flashbots/Data/Message.cs deleted file mode 100644 index 47ed8f9988c..00000000000 --- a/src/Nethermind/Nethermind.Flashbots/Data/Message.cs +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using Nethermind.Core; -using Nethermind.Core.Crypto; -using Nethermind.Int256; - -namespace Nethermind.Flashbots.Data; - -public class Message( - ulong slot, - Hash256 parent_hash, - Hash256 block_hash, - PublicKey builder_pubkey, - PublicKey proposer_pubkey, - Address proposer_fee_recipient, - long gas_limit, - long gas_used, - UInt256 value) -{ - public ulong slot { get; } = slot; - public Hash256 parent_hash { get; set; } = parent_hash; - public Hash256 block_hash { get; } = block_hash; - public PublicKey builder_pubkey { get; } = builder_pubkey; - public PublicKey proposer_pubkey { get; } = proposer_pubkey; - public Address proposer_fee_recipient { get; } = proposer_fee_recipient; - public long gas_limit { get; } = gas_limit; - public long gas_used { get; } = gas_used; - public UInt256 value { get; } = value; - - public BidTrace ToBidTrace() - { - return new BidTrace( - slot, - parent_hash, - block_hash, - builder_pubkey, - proposer_pubkey, - proposer_fee_recipient, - gas_limit, - gas_used, - value - ); - } -} - diff --git a/src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs deleted file mode 100644 index 4d80db37bc0..00000000000 --- a/src/Nethermind/Nethermind.Flashbots/Data/RBuilderBlockValidationRequest.cs +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System.Text.Json.Serialization; -using Nethermind.Core.Crypto; -using Nethermind.Merge.Plugin.Data; - -namespace Nethermind.Flashbots.Data; - -public class RBuilderBlockValidationRequest -{ - public RBuilderBlockValidationRequest( - Message message, - RExecutionPayloadV3 execution_payload, - BlobsBundleV1 blobs_bundle, - byte[] signature, - long registered_gas_limit, - Hash256 withdrawals_root, - Hash256 parent_beacon_block_root) - { - this.message = message; - this.execution_payload = execution_payload; - this.blobs_bundle = blobs_bundle; - this.signature = signature; - this.registered_gas_limit = registered_gas_limit; - this.withdrawals_root = withdrawals_root; - this.parent_beacon_block_root = parent_beacon_block_root; - } - - [JsonRequired] - public Message message { get; set; } - - [JsonRequired] - public RExecutionPayloadV3 execution_payload { get; set; } - - [JsonRequired] - public BlobsBundleV1 blobs_bundle { get; set; } - - [JsonRequired] - public byte[] signature { get; set; } - - [JsonRequired] - public long registered_gas_limit { get; set; } - - [JsonRequired] - public Hash256 withdrawals_root { get; set; } - - [JsonRequired] - public Hash256 parent_beacon_block_root { get; set; } -} diff --git a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs b/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs deleted file mode 100644 index b9bb5cd0058..00000000000 --- a/src/Nethermind/Nethermind.Flashbots/Data/SubmitBlockRequest.cs +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System.Text.Json.Serialization; -using Nethermind.Merge.Plugin.Data; - -namespace Nethermind.Flashbots.Data; - -public class SubmitBlockRequest -{ - public SubmitBlockRequest(RExecutionPayloadV3 executionPayload, BlobsBundleV1 blobsBundle, BidTrace message, byte[] signature) - { - ExecutionPayload = executionPayload; - BlobsBundle = blobsBundle; - Message = message; - Signature = signature; - } - [JsonPropertyName("execution_payload")] - public RExecutionPayloadV3 ExecutionPayload { get; set; } - - [JsonPropertyName("blobs_bundle")] - public BlobsBundleV1 BlobsBundle { get; set; } - - [JsonPropertyName("message")] - public BidTrace Message { get; set; } - - [JsonPropertyName("signature")] - public byte[] Signature { get; set; } -} diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index bb2fdda8625..a35f5c3d0eb 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -69,7 +69,7 @@ public ValidateSubmissionHandler( public Task> ValidateSubmission(BuilderBlockValidationRequest request) { - ExecutionPayloadV3 payload = request.BlockRequest.ExecutionPayload.ToExecutionPayloadV3(); + ExecutionPayloadV3 payload = request.ExecutionPayload.ToExecutionPayloadV3(); if (request.ParentBeaconBlockRoot is null) { @@ -79,12 +79,12 @@ public Task> ValidateSubmission(BuilderBlockValid payload.ParentBeaconBlockRoot = new Hash256(request.ParentBeaconBlockRoot); - BlobsBundleV1 blobsBundle = request.BlockRequest.BlobsBundle; + BlobsBundleV1 blobsBundle = request.BlobsBundle; string payloadStr = $"BuilderBlock: {payload}"; if (_logger.IsInfo) - _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length}"); + _logger.Info($"blobs bundle blobs {blobsBundle.Blobs.Length} commits {blobsBundle.Commitments.Length} proofs {blobsBundle.Proofs.Length} commitments"); if (!payload.TryGetBlock(out Block? block)) { @@ -92,7 +92,7 @@ public Task> ValidateSubmission(BuilderBlockValid return FlashbotsResult.Invalid($"Block {payload} coud not be parsed as a block"); } - if (block is not null && !ValidateBlock(block, request.BlockRequest.Message, request.RegisteredGasLimit, out string? error)) + if (block is not null && !ValidateBlock(block, request.Message, request.RegisteredGasLimit, out string? error)) { if (_logger.IsWarn) _logger.Warn($"Invalid block. Result of {payloadStr}. Error: {error}"); return FlashbotsResult.Invalid(error ?? "Block validation failed"); diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs index b752f997205..c17b9b34708 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/FlashbotsRpcModule.cs @@ -20,19 +20,4 @@ public FlashbotsRpcModule(ValidateSubmissionHandler validateSubmissionHandler) Task> IFlashbotsRpcModule.flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params) => _validateSubmissionHandler.ValidateSubmission(@params); - - Task> IFlashbotsRpcModule.flashbots_validateRBuilderSubmissionV3(RBuilderBlockValidationRequest @params) - { - BuilderBlockValidationRequest builderBlockValidationRequest = new BuilderBlockValidationRequest( - @params.parent_beacon_block_root, - @params.registered_gas_limit, - new SubmitBlockRequest( - @params.execution_payload, - @params.blobs_bundle, - @params.message.ToBidTrace(), - @params.signature - ) - ); - return _validateSubmissionHandler.ValidateSubmission(builderBlockValidationRequest); - } } diff --git a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs index b0fdad2ab06..b81da13fb39 100644 --- a/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs +++ b/src/Nethermind/Nethermind.Flashbots/Modules/Flashbots/IFlashbotsRpcModule.cs @@ -16,10 +16,4 @@ public interface IFlashbotsRpcModule : IRpcModule IsSharable = false, IsImplemented = true)] Task> flashbots_validateBuilderSubmissionV3(BuilderBlockValidationRequest @params); - - [JsonRpcMethod( - Description = " validate the builder submissions as received by a relay", - IsSharable = false, - IsImplemented = true)] - Task> flashbots_validateRBuilderSubmissionV3(RBuilderBlockValidationRequest @params); } From 75bf15eff03fb3685609a672c5b8c1d8adbe12ae Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Wed, 12 Feb 2025 23:59:06 +0530 Subject: [PATCH 104/113] fix withdrawals error --- .../FlashbotsModuleTests.cs | 4 +- .../Data/RExecutionPayloadV3.cs | 9 ++-- .../Nethermind.Flashbots/Data/RWithdrawal.cs | 46 +++++++++++++++++++ .../Nethermind.Runner/configs/holesky.json | 5 +- 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 src/Nethermind/Nethermind.Flashbots/Data/RWithdrawal.cs diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index 9260b886b7d..3a09f5cfae0 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -93,7 +93,7 @@ private Block CreateBlock(MergeTestBlockChain chain) ulong timestamp = Timestamper.UnixTime.Seconds; Hash256 prevRandao = Keccak.Zero; - Hash256 expectedBlockHash = new("0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26"); + Hash256 expectedBlockHash = new("0xf823a4118e778834c2d31e9199d9cd1323ed62f0d14268efe5b9518f7157a17e"); string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; return new( @@ -119,7 +119,7 @@ private Block CreateBlock(MergeTestBlockChain chain) ReceiptsRoot = chain.BlockTree.Head!.ReceiptsRoot!, StateRoot = new(stateRoot), }, - Array.Empty(), + [tx1, tx2, tx3], Array.Empty(), withdrawals ); diff --git a/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs index ebf383baca0..f4a2820cb2c 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/RExecutionPayloadV3.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Text.Json.Serialization; +using System.Linq; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -23,7 +24,7 @@ public class RExecutionPayloadV3 public UInt256 base_fee_per_gas { get; set; } public Hash256 block_hash { get; set; } public byte[][] transactions { get; set; } - public Withdrawal[]? withdrawals { get; set; } + public RWithdrawal[]? withdrawals { get; set; } public ulong? blob_gas_used { get; set; } public ulong? excess_blob_gas { get; set; } @@ -43,7 +44,7 @@ public RExecutionPayloadV3(ExecutionPayloadV3 executionPayloadV3) base_fee_per_gas = executionPayloadV3.BaseFeePerGas; block_hash = executionPayloadV3.BlockHash; transactions = executionPayloadV3.Transactions; - withdrawals = executionPayloadV3.Withdrawals; + withdrawals = executionPayloadV3.Withdrawals?.Select(w => new RWithdrawal(w)).ToArray(); blob_gas_used = executionPayloadV3.BlobGasUsed; excess_blob_gas = executionPayloadV3.ExcessBlobGas; } @@ -65,7 +66,7 @@ public ExecutionPayloadV3 ToExecutionPayloadV3() BaseFeePerGas = base_fee_per_gas, BlockHash = block_hash, Transactions = transactions, - Withdrawals = withdrawals, + Withdrawals = withdrawals?.Select(w => w.ToWithdrawal()).ToArray(), BlobGasUsed = blob_gas_used, ExcessBlobGas = excess_blob_gas }; @@ -88,7 +89,7 @@ public RExecutionPayloadV3( UInt256 base_fee_per_gas, Hash256 block_hash, byte[][] transactions, - Withdrawal[]? withdrawals, + RWithdrawal[]? withdrawals, ulong? blob_gas_used, ulong? excess_blob_gas ) diff --git a/src/Nethermind/Nethermind.Flashbots/Data/RWithdrawal.cs b/src/Nethermind/Nethermind.Flashbots/Data/RWithdrawal.cs new file mode 100644 index 00000000000..79d7e42241e --- /dev/null +++ b/src/Nethermind/Nethermind.Flashbots/Data/RWithdrawal.cs @@ -0,0 +1,46 @@ +using System.Text.Json.Serialization; +using Nethermind.Core; +using Nethermind.Int256; + +public class RWithdrawal +{ + public ulong index { get; set; } + public ulong validator_index { get; set; } + public Address address { get; set; } + + [JsonPropertyName("amount")] + public ulong amount_in_gwei { get; set; } + + public RWithdrawal(Withdrawal withdrawal) + { + index = withdrawal.Index; + validator_index = withdrawal.ValidatorIndex; + address = withdrawal.Address; + amount_in_gwei = withdrawal.AmountInGwei; + } + + public Withdrawal ToWithdrawal() + { + return new Withdrawal + { + Index = index, + ValidatorIndex = validator_index, + Address = address, + AmountInGwei = amount_in_gwei + }; + } + + [JsonConstructor] + public RWithdrawal( + ulong index, + ulong validator_index, + Address address, + ulong amount_in_gwei + ) + { + this.index = index; + this.validator_index = validator_index; + this.address = address; + this.amount_in_gwei = amount_in_gwei; + } +} diff --git a/src/Nethermind/Nethermind.Runner/configs/holesky.json b/src/Nethermind/Nethermind.Runner/configs/holesky.json index 27101434088..b9090f318c6 100644 --- a/src/Nethermind/Nethermind.Runner/configs/holesky.json +++ b/src/Nethermind/Nethermind.Runner/configs/holesky.json @@ -27,7 +27,10 @@ "Port": 8545, "EngineHost": "127.0.0.1", "EnginePort": 8551, - "EngineEnabledModules": "net,eth,subscribe,engine,web3,client" + "EngineEnabledModules": "net,eth,subscribe,engine,web3,client,flashbots" + }, + "Flasbots": { + "Enabled": true }, "Merge": { "Enabled": true From 1236dced33f16077b580f56d1ba2b7a392a710fc Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 13 Feb 2025 00:14:16 +0530 Subject: [PATCH 105/113] add flashbots solution --- src/Nethermind/Nethermind.slnx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Nethermind/Nethermind.slnx b/src/Nethermind/Nethermind.slnx index 7889f4fee9e..fc27e847f2b 100644 --- a/src/Nethermind/Nethermind.slnx +++ b/src/Nethermind/Nethermind.slnx @@ -18,6 +18,10 @@ + + + + From cf015752d41c4167eed428434eb77863e5a46443 Mon Sep 17 00:00:00 2001 From: mralj Date: Thu, 13 Feb 2025 16:55:15 +0100 Subject: [PATCH 106/113] validation bugfixes --- .../Handlers/ValidateBuilderSubmissionHandler.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index a35f5c3d0eb..4617d1521da 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -282,9 +282,9 @@ private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHead return false; } - if (!_blockTree.IsBetterThanHead(block.Header)) + if (block.Header.Number <= _blockTree.Head?.Number) { - error = $"Block {block.Header.Hash} is not better than head"; + error = $"Block {block.Header.Number} is not better than head {_blockTree.Head?.Number}"; return false; } @@ -384,9 +384,9 @@ private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, return false; } - if (paymentTx.GasPrice != processedBlock.BaseFeePerGas) + if (paymentTx.MaxFeePerGas != processedBlock.BaseFeePerGas) { - error = "Malformed proposer payment, gas price not equal to base fee"; + error = "Malformed proposer payment, max fee per gas not equal to block base fee per gas"; return false; } @@ -396,11 +396,6 @@ private bool ValidateProcessedBlock(Block processedBlock, Address feeRecipient, return false; } - if (paymentTx.MaxFeePerGas != processedBlock.BaseFeePerGas) - { - error = "Malformed proposer payment, max fee per gas not equal to block base fee per gas"; - return false; - } error = null; return true; From 700872b4936ec239668f6c2519a7f748f41b8159 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Thu, 13 Feb 2025 11:31:08 +0530 Subject: [PATCH 107/113] update solution --- src/Nethermind/Nethermind.slnx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.slnx b/src/Nethermind/Nethermind.slnx index fc27e847f2b..94e32d1e56a 100644 --- a/src/Nethermind/Nethermind.slnx +++ b/src/Nethermind/Nethermind.slnx @@ -20,7 +20,7 @@ - + From fed4ed251d0896e68469c635e0cd4f490b0593ba Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 14 Feb 2025 17:00:10 +0530 Subject: [PATCH 108/113] fix fail cases --- nethermind.sln | 1028 +++++++++++++++++ .../FlashbotsModuleTests.Setup.cs | 2 +- .../FlashbotsModuleTests.cs | 2 +- ...sproj => Nethermind.Flashbots.Test.csproj} | 0 .../Data/BlockValidationResult.cs | 2 +- src/Nethermind/Nethermind.slnx | 2 +- 6 files changed, 1032 insertions(+), 4 deletions(-) create mode 100644 nethermind.sln rename src/Nethermind/Nethermind.Flashbots.Test/{Nethermind.Flasbots.Test.csproj => Nethermind.Flashbots.Test.csproj} (100%) diff --git a/nethermind.sln b/nethermind.sln new file mode 100644 index 00000000000..0d864d5a0fe --- /dev/null +++ b/nethermind.sln @@ -0,0 +1,1028 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{07C2787E-EAC7-C090-1BA3-A61EC2A24D84}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SendBlobs", "tools\SendBlobs\SendBlobs.csproj", "{1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Tools.Kute", "tools\Nethermind.Tools.Kute\Nethermind.Tools.Kute.csproj", "{2A14DF20-5AB3-1179-FC14-9080EA92BEB6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchemaGenerator", "tools\SchemaGenerator\SchemaGenerator.csproj", "{1014F3DD-0BE0-D671-9FD8-9856A8079ED2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TxParser", "tools\TxParser\TxParser.csproj", "{D329680A-AD3B-E6C7-7233-126E58F9E849}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HiveConsensusWorkflowGenerator", "tools\HiveConsensusWorkflowGenerator\HiveConsensusWorkflowGenerator.csproj", "{1C232EA2-92C2-B4A7-2A45-C8737833D336}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Evm", "tools\Evm\Evm.csproj", "{17F916F3-6AE7-3919-6783-41A493640905}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocGen", "tools\DocGen\DocGen.csproj", "{7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HiveCompare", "tools\HiveCompare\HiveCompare.csproj", "{ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Nethermind", "Nethermind", "{FBCB8DBD-CDF2-6977-D18F-5F93DC702250}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Stats", "src\Nethermind\Nethermind.Network.Stats\Nethermind.Network.Stats.csproj", "{B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Pyspec.Test", "src\Nethermind\Ethereum.Blockchain.Pyspec.Test\Ethereum.Blockchain.Pyspec.Test.csproj", "{BED99755-9E24-3619-2001-B8CEAC9A0162}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.Plugin.Test", "src\Nethermind\Nethermind.Merge.Plugin.Test\Nethermind.Merge.Plugin.Test.csproj", "{AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.HexPrefix.Test", "src\Nethermind\Ethereum.HexPrefix.Test\Ethereum.HexPrefix.Test.csproj", "{55B87E2E-B2C5-0727-32DB-B763F3A0DF64}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Difficulty.Test", "src\Nethermind\Ethereum.Difficulty.Test\Ethereum.Difficulty.Test.csproj", "{9AD734C0-4406-86B8-7A07-AF402C4BC872}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Taiko", "src\Nethermind\Nethermind.Taiko\Nethermind.Taiko.csproj", "{75168EF2-3375-63A0-8189-C73C353BCBBA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Cli.Test", "src\Nethermind\Nethermind.Cli.Test\Nethermind.Cli.Test.csproj", "{88022C29-F01F-F535-C955-266A5717AAA7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.TxPool", "src\Nethermind\Nethermind.TxPool\Nethermind.TxPool.csproj", "{3B3D25CF-720F-2BBC-082D-A631E11F3110}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db.Rocks", "src\Nethermind\Nethermind.Db.Rocks\Nethermind.Db.Rocks.csproj", "{44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Init", "src\Nethermind\Nethermind.Init\Nethermind.Init.csproj", "{3A2A1313-1831-EFA6-55AB-63849438C2F6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Synchronization", "src\Nethermind\Nethermind.Synchronization\Nethermind.Synchronization.csproj", "{C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Test", "src\Nethermind\Nethermind.Network.Test\Nethermind.Network.Test.csproj", "{A7441955-29AB-E120-B317-283D764FCC32}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flashbots", "src\Nethermind\Nethermind.Flashbots\Nethermind.Flashbots.csproj", "{C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flashbots.Test", "src\Nethermind\Nethermind.Flashbots.Test\Nethermind.Flashbots.Test.csproj", "{09251FE2-4416-153E-5E74-DAB63C4ECE64}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Basic.Test", "src\Nethermind\Ethereum.Basic.Test\Ethereum.Basic.Test.csproj", "{78B156EC-E3B6-C57D-9590-225D80F3580F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging.Microsoft", "src\Nethermind\Nethermind.Logging.Microsoft\Nethermind.Logging.Microsoft.csproj", "{E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Test.Base", "src\Nethermind\Ethereum.Test.Base\Ethereum.Test.Base.csproj", "{9620BCE5-17BE-6D11-84F6-444EAE405CFB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Cli", "src\Nethermind\Nethermind.Cli\Nethermind.Cli.csproj", "{360F1ABD-E146-A345-E84B-8A116CDB7E09}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.KeyStore.Test", "src\Nethermind\Ethereum.KeyStore.Test\Ethereum.KeyStore.Test.csproj", "{94337465-6C6A-E8C6-0240-4AAEF5F1DB59}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Facade", "src\Nethermind\Nethermind.Facade\Nethermind.Facade.csproj", "{4B7F5DB5-7915-076F-8215-FF2C7582E01B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Synchronization.Test", "src\Nethermind\Nethermind.Synchronization.Test\Nethermind.Synchronization.Test.csproj", "{775903B4-09D4-4B2C-1404-BD5FCEEE494E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Seq", "src\Nethermind\Nethermind.Seq\Nethermind.Seq.csproj", "{225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Specs.Test", "src\Nethermind\Nethermind.Specs.Test\Nethermind.Specs.Test.csproj", "{8567273B-1AE0-F3D0-85BD-70A1E8F5A790}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Blockchain.Test.Runner", "src\Nethermind\Nethermind.Blockchain.Test.Runner\Nethermind.Blockchain.Test.Runner.csproj", "{8E7A44D0-9E4D-BA3D-4C59-D602789529E1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.ExternalSigner.Plugin", "src\Nethermind\Nethermind.ExternalSigner.Plugin\Nethermind.ExternalSigner.Plugin.csproj", "{B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.Test", "src\Nethermind\Nethermind.JsonRpc.Test\Nethermind.JsonRpc.Test.csproj", "{B57166AD-FBF2-E511-63E6-BD4F293E3246}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Core", "src\Nethermind\Nethermind.Core\Nethermind.Core.csproj", "{A25B49E8-A1E2-08EB-90AD-95245686E358}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Dns", "src\Nethermind\Nethermind.Network.Dns\Nethermind.Network.Dns.csproj", "{C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator.Test", "src\Nethermind\Nethermind.Serialization.SszGenerator.Test\Nethermind.Serialization.SszGenerator.Test.csproj", "{6329D269-4E17-3139-CF5D-EBD992B71872}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator", "src\Nethermind\Nethermind.Serialization.SszGenerator\Nethermind.Serialization.SszGenerator.csproj", "{29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.HealthChecks", "src\Nethermind\Nethermind.HealthChecks\Nethermind.HealthChecks.csproj", "{BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Legacy.Test", "src\Nethermind\Ethereum.Blockchain.Legacy.Test\Ethereum.Blockchain.Legacy.Test.csproj", "{7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network", "src\Nethermind\Nethermind.Network\Nethermind.Network.csproj", "{7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Runner", "src\Nethermind\Nethermind.Runner\Nethermind.Runner.csproj", "{456816E9-79F5-A888-6A7F-FCAA00467883}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc", "src\Nethermind\Nethermind.JsonRpc\Nethermind.JsonRpc.csproj", "{4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Grpc", "src\Nethermind\Nethermind.Grpc\Nethermind.Grpc.csproj", "{5962CFA9-CF7F-7789-1582-69D09A4A0FD2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db.Rpc", "src\Nethermind\Nethermind.Db.Rpc\Nethermind.Db.Rpc.csproj", "{68E54CD1-B46E-7D40-A474-C2C8F013370B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.PerfTest", "src\Nethermind\Nethermind.PerfTest\Nethermind.PerfTest.csproj", "{9AB29652-ED65-E8EF-2E5B-A03CE514A10A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Config", "src\Nethermind\Nethermind.Config\Nethermind.Config.csproj", "{D154BF10-9EE8-F073-F612-439DEA9180B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Overseer.Test", "src\Nethermind\Nethermind.Overseer.Test\Nethermind.Overseer.Test.csproj", "{D31F4868-30A7-8B09-C07C-4F9258780385}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.TraceStore.Test", "src\Nethermind\Nethermind.JsonRpc.TraceStore.Test\Nethermind.JsonRpc.TraceStore.Test.csproj", "{A8846A27-965F-3743-7869-431B907D82C0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Optimism.Test", "src\Nethermind\Nethermind.Optimism.Test\Nethermind.Optimism.Test.csproj", "{B3C4059A-D7EC-2E83-900D-E47A259529CC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Api.Test", "src\Nethermind\Nethermind.Api.Test\Nethermind.Api.Test.csproj", "{8C96A8BB-30D6-F809-9986-0E54A630CE99}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Abi.Test", "src\Nethermind\Ethereum.Abi.Test\Ethereum.Abi.Test.csproj", "{E5254223-630A-4FCA-89F4-191E00B749D9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus", "src\Nethermind\Nethermind.Consensus\Nethermind.Consensus.csproj", "{5E1BDE6B-0FEB-F517-B482-7C752DD9D423}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Monitoring.Test", "src\Nethermind\Nethermind.Monitoring.Test\Nethermind.Monitoring.Test.csproj", "{EFB878C7-A53F-DB6F-4DB4-4C198F205F05}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merkleization", "src\Nethermind\Nethermind.Merkleization\Nethermind.Merkleization.csproj", "{5E3DD2DD-63E4-9617-51AD-BE7466B4F867}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Dns.Test", "src\Nethermind\Nethermind.Network.Dns.Test\Nethermind.Network.Dns.Test.csproj", "{5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Era1", "src\Nethermind\Nethermind.Era1\Nethermind.Era1.csproj", "{708142F8-D31F-2590-74CF-1CB6356373EB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.Ethash", "src\Nethermind\Nethermind.Consensus.Ethash\Nethermind.Consensus.Ethash.csproj", "{EE10DB5B-4BFB-2694-56C7-AA734D9998DE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Sockets.Test", "src\Nethermind\Nethermind.Sockets.Test\Nethermind.Sockets.Test.csproj", "{EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Sockets", "src\Nethermind\Nethermind.Sockets\Nethermind.Sockets.csproj", "{4E6AA273-973F-C518-09DE-0B32F1013D10}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Benchmark", "src\Nethermind\Nethermind.Benchmark\Nethermind.Benchmark.csproj", "{5F0D46F0-3751-F3B5-299D-3A5E96078D2E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.EthereumTests.Benchmark", "src\Nethermind\Nethermind.EthereumTests.Benchmark\Nethermind.EthereumTests.Benchmark.csproj", "{C23508FE-F0DD-D646-A330-179199A8C2F9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Rlp", "src\Nethermind\Nethermind.Serialization.Rlp\Nethermind.Serialization.Rlp.csproj", "{86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.EthStats.Test", "src\Nethermind\Nethermind.EthStats.Test\Nethermind.EthStats.Test.csproj", "{6587AB0F-0ACF-1281-5AEF-3BA3E639A969}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Ssz.Test", "src\Nethermind\Nethermind.Serialization.Ssz.Test\Nethermind.Serialization.Ssz.Test.csproj", "{215F234F-E057-6B91-E0E4-D92776FC15B4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging.NLog", "src\Nethermind\Nethermind.Logging.NLog\Nethermind.Logging.NLog.csproj", "{5E096865-7E69-538A-6E99-F3F0F699CF2A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.TxPool.Test", "src\Nethermind\Nethermind.TxPool.Test\Nethermind.TxPool.Test.csproj", "{CFDE18B2-7A61-5037-2C32-EFEED4F63364}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Crypto", "src\Nethermind\Nethermind.Crypto\Nethermind.Crypto.csproj", "{C8082A2D-57EA-055F-A87C-45023FCFD3F6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.Clique", "src\Nethermind\Nethermind.Consensus.Clique\Nethermind.Consensus.Clique.csproj", "{A3525B69-C2B0-0CE9-1F86-61CDD9889216}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.PoW.Test", "src\Nethermind\Ethereum.PoW.Test\Ethereum.PoW.Test.csproj", "{61DE83D6-6284-D448-E008-7039ED5E5BC0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Core.Test", "src\Nethermind\Nethermind.Core.Test\Nethermind.Core.Test.csproj", "{9C00290D-F421-9468-9833-4FFCDD2EFE8C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Runner.Test", "src\Nethermind\Nethermind.Runner.Test\Nethermind.Runner.Test.csproj", "{7351A2A2-E03C-39D3-F575-6D2755A23CC5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Transition.Test", "src\Nethermind\Ethereum.Transition.Test\Ethereum.Transition.Test.csproj", "{E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Rlp.Test", "src\Nethermind\Ethereum.Rlp.Test\Ethereum.Rlp.Test.csproj", "{D7A91A55-0BFA-5077-D80E-1F47396E1C6A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.Test", "src\Nethermind\Nethermind.Consensus.Test\Nethermind.Consensus.Test.csproj", "{02552470-3D09-742C-15A0-03448C7B176A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Hive.Test", "src\Nethermind\Nethermind.Hive.Test\Nethermind.Hive.Test.csproj", "{B16A32BE-D56A-9E9C-749D-4E242789DE8D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Ssz", "src\Nethermind\Nethermind.Serialization.Ssz\Nethermind.Serialization.Ssz.csproj", "{3A3A938B-6B9B-BF6B-3430-8FCFE598934D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.UPnP.Plugin", "src\Nethermind\Nethermind.UPnP.Plugin\Nethermind.UPnP.Plugin.csproj", "{1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.State.Test", "src\Nethermind\Nethermind.State.Test\Nethermind.State.Test.csproj", "{B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.EthStats", "src\Nethermind\Nethermind.EthStats\Nethermind.EthStats.csproj", "{5F7B6686-4642-015C-A57F-3B6B19133FC6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging", "src\Nethermind\Nethermind.Logging\Nethermind.Logging.csproj", "{68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db", "src\Nethermind\Nethermind.Db\Nethermind.Db.csproj", "{93FCD064-F7CF-A864-AF81-7B0279D2FE26}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Json", "src\Nethermind\Nethermind.Serialization.Json\Nethermind.Serialization.Json.csproj", "{4404C7F6-5CC2-4976-9303-F15492311054}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Block.Legacy.Test", "src\Nethermind\Ethereum.Blockchain.Block.Legacy.Test\Ethereum.Blockchain.Block.Legacy.Test.csproj", "{40180EE9-83E1-5D11-C54B-B4EC49CF99F5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Blockchain", "src\Nethermind\Nethermind.Blockchain\Nethermind.Blockchain.csproj", "{C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.VM.Test", "src\Nethermind\Ethereum.VM.Test\Ethereum.VM.Test.csproj", "{768E99B5-13ED-FD75-6F50-C405A8775290}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.KeyAddress.Test", "src\Nethermind\Ethereum.KeyAddress.Test\Ethereum.KeyAddress.Test.csproj", "{68B12BA0-2B85-6085-3732-D180558B0A30}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Trie", "src\Nethermind\Nethermind.Trie\Nethermind.Trie.csproj", "{CFE88035-0880-AD6F-D44C-077C99BDA355}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.KeyStore.Test", "src\Nethermind\Nethermind.KeyStore.Test\Nethermind.KeyStore.Test.csproj", "{BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Evm.Test", "src\Nethermind\Nethermind.Evm.Test\Nethermind.Evm.Test.csproj", "{7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.AuRa", "src\Nethermind\Nethermind.Merge.AuRa\Nethermind.Merge.AuRa.csproj", "{BF1F4B6C-CB98-C09E-5557-E99D03A86A22}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter", "src\Nethermind\Nethermind.Shutter\Nethermind.Shutter.csproj", "{6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.AuRa", "src\Nethermind\Nethermind.Consensus.AuRa\Nethermind.Consensus.AuRa.csproj", "{D3640F80-32DA-60DA-71A0-597803DD445D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Clique.Test", "src\Nethermind\Nethermind.Clique.Test\Nethermind.Clique.Test.csproj", "{7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.TraceStore", "src\Nethermind\Nethermind.JsonRpc.TraceStore\Nethermind.JsonRpc.TraceStore.csproj", "{A0856948-B184-BAE9-A350-7D0356997560}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Block.Test", "src\Nethermind\Ethereum.Blockchain.Block.Test\Ethereum.Blockchain.Block.Test.csproj", "{B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Analytics", "src\Nethermind\Nethermind.Analytics\Nethermind.Analytics.csproj", "{FBD86DBD-0A64-99A1-E878-47DD4C531AC5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Config.Test", "src\Nethermind\Nethermind.Config.Test\Nethermind.Config.Test.csproj", "{8449212A-9AC0-1C23-9419-1704158E7FF6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Discovery.Test", "src\Nethermind\Nethermind.Network.Discovery.Test\Nethermind.Network.Discovery.Test.csproj", "{27567BB5-7E42-3103-ABAB-EE445E03396B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.HealthChecks.Test", "src\Nethermind\Nethermind.HealthChecks.Test\Nethermind.HealthChecks.Test.csproj", "{BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.AuRa.Test", "src\Nethermind\Nethermind.AuRa.Test\Nethermind.AuRa.Test.csproj", "{E64D52DF-C601-E477-27FC-3198FA90777E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Contract", "src\Nethermind\Nethermind.Network.Contract\Nethermind.Network.Contract.csproj", "{B765E74F-BDF8-CBB7-1D12-40038265E480}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Ethash.Test", "src\Nethermind\Nethermind.Ethash.Test\Nethermind.Ethash.Test.csproj", "{238511B1-0953-42E1-2665-03075F55B4C9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Trie.Benchmark", "src\Nethermind\Nethermind.Trie.Benchmark\Nethermind.Trie.Benchmark.csproj", "{49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Era1.Test", "src\Nethermind\Nethermind.Era.Test\Nethermind.Era1.Test.csproj", "{1769A2A8-3156-9348-12BF-CFEF8253810B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Test.Runner", "src\Nethermind\Nethermind.Test.Runner\Nethermind.Test.Runner.csproj", "{0B694916-575C-00C4-9F31-8CB2A7BB6A83}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Trie.Test", "src\Nethermind\Ethereum.Trie.Test\Ethereum.Trie.Test.csproj", "{DF706532-E516-E7E3-A823-29DDF30A0D96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Discovery", "src\Nethermind\Nethermind.Network.Discovery\Nethermind.Network.Discovery.csproj", "{0C632D98-F35E-CF99-ADB5-D9828968BEBA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Precompiles.Benchmark", "src\Nethermind\Nethermind.Precompiles.Benchmark\Nethermind.Precompiles.Benchmark.csproj", "{E4D3743E-EFF0-9493-9F35-92D4F3408988}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Wallet.Test", "src\Nethermind\Nethermind.Wallet.Test\Nethermind.Wallet.Test.csproj", "{DFE4C60B-C995-4805-9E8A-FA271DA09F50}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Hive", "src\Nethermind\Nethermind.Hive\Nethermind.Hive.csproj", "{E0F37FA3-A10A-347C-0188-D7C3473413CE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.AuRa.Test", "src\Nethermind\Nethermind.Merge.AuRa.Test\Nethermind.Merge.AuRa.Test.csproj", "{75D6DE58-7A99-17D2-F6AD-6530795A1246}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Test", "src\Nethermind\Ethereum.Blockchain.Test\Ethereum.Blockchain.Test.csproj", "{9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Benchmark.Runner", "src\Nethermind\Nethermind.Benchmark.Runner\Nethermind.Benchmark.Runner.csproj", "{67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.State", "src\Nethermind\Nethermind.State\Nethermind.State.csproj", "{B4228F0C-BBD4-119D-17C0-51DAC508639A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.Plugin", "src\Nethermind\Nethermind.Merge.Plugin\Nethermind.Merge.Plugin.csproj", "{AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Transaction.Test", "src\Nethermind\Ethereum.Transaction.Test\Ethereum.Transaction.Test.csproj", "{9F1D5A80-2432-664A-6B6E-5840074FE627}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Blockchain.Test", "src\Nethermind\Nethermind.Blockchain.Test\Nethermind.Blockchain.Test.csproj", "{4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Mining.Test", "src\Nethermind\Nethermind.Mining.Test\Nethermind.Mining.Test.csproj", "{625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Tools.GasHistorian", "src\Nethermind\Nethermind.Tools.GasHistorian\Nethermind.Tools.GasHistorian.csproj", "{90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Wallet", "src\Nethermind\Nethermind.Wallet\Nethermind.Wallet.csproj", "{727DD935-998F-9913-8FBD-FE4A5B432128}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.Benchmark", "src\Nethermind\Nethermind.JsonRpc.Benchmark\Nethermind.JsonRpc.Benchmark.csproj", "{DA14FF81-99FE-473B-494D-C9B24CADF75F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Monitoring", "src\Nethermind\Nethermind.Monitoring\Nethermind.Monitoring.csproj", "{6172CFDC-4569-72AE-E6BD-8E78C823663C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Evm", "src\Nethermind\Nethermind.Evm\Nethermind.Evm.csproj", "{E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Api", "src\Nethermind\Nethermind.Api\Nethermind.Api.csproj", "{457256C7-C69D-CB30-B416-A1D2251589CE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Abi.Test", "src\Nethermind\Nethermind.Abi.Test\Nethermind.Abi.Test.csproj", "{3D6B5FC5-8F10-2423-957F-AD16AAAFD095}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Evm.Benchmark", "src\Nethermind\Nethermind.Evm.Benchmark\Nethermind.Evm.Benchmark.csproj", "{8E42DE0F-D93C-1031-9934-C82692D0FBD1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.State.Test.Runner.Test", "src\Nethermind\Nethermind.State.Test.Runner.Test\Nethermind.State.Test.Runner.Test.csproj", "{5DC94B97-BB49-E636-DA76-837BC3E45CAC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Optimism", "src\Nethermind\Nethermind.Optimism\Nethermind.Optimism.csproj", "{42506E08-3D7E-93FC-870F-2D4E534B1082}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Enr", "src\Nethermind\Nethermind.Network.Enr\Nethermind.Network.Enr.csproj", "{4C6EB51E-F0D8-6394-1828-8E542204F9BF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging.NLog.Test", "src\Nethermind\Nethermind.Logging.NLog.Test\Nethermind.Logging.NLog.Test.csproj", "{525682E4-E7EF-CDB3-54BA-15A5FAF76C20}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db.Test", "src\Nethermind\Nethermind.Db.Test\Nethermind.Db.Test.csproj", "{35B76447-4D36-699C-7CC9-DFD02E9F5D1F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Benchmark", "src\Nethermind\Nethermind.Network.Benchmark\Nethermind.Network.Benchmark.csproj", "{0893E83F-92C8-B58B-800D-F13CEEEF0DC5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Abi", "src\Nethermind\Nethermind.Abi\Nethermind.Abi.csproj", "{6D933A4A-780F-8549-1800-E2F343480EDF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.KeyStore", "src\Nethermind\Nethermind.KeyStore\Nethermind.KeyStore.csproj", "{715C0753-B773-9A0B-10D0-33849C0F3E4E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Facade.Test", "src\Nethermind\Nethermind.Facade.Test\Nethermind.Facade.Test.csproj", "{1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Specs", "src\Nethermind\Nethermind.Specs\Nethermind.Specs.csproj", "{B3E8FD8D-CBA4-0436-C845-FE02743185E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Taiko.Test", "src\Nethermind\Nethermind.Taiko.Test\Nethermind.Taiko.Test.csproj", "{768B75FC-7160-A313-FE51-2CBC8653D220}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter.Test", "src\Nethermind\Nethermind.Shutter.Test\Nethermind.Shutter.Test.csproj", "{5EDAB414-D5C7-C371-0072-E4B830BD9323}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Enr.Test", "src\Nethermind\Nethermind.Network.Enr.Test\Nethermind.Network.Enr.Test.csproj", "{3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Trie.Test", "src\Nethermind\Nethermind.Trie.Test\Nethermind.Trie.Test.csproj", "{8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Init.Snapshot", "src\Nethermind\Nethermind.Init.Snapshot\Nethermind.Init.Snapshot.csproj", "{440A73BE-3FBC-C528-5525-9DAACD46A20E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.ReferenceAssemblies", "src\Nethermind\Nethermind.ReferenceAssemblies\Nethermind.ReferenceAssemblies.csproj", "{224021DB-7DE8-D6BF-518A-CF72484B86DA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Release|Any CPU.Build.0 = Release|Any CPU + {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Release|Any CPU.Build.0 = Release|Any CPU + {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Release|Any CPU.Build.0 = Release|Any CPU + {D329680A-AD3B-E6C7-7233-126E58F9E849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D329680A-AD3B-E6C7-7233-126E58F9E849}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D329680A-AD3B-E6C7-7233-126E58F9E849}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D329680A-AD3B-E6C7-7233-126E58F9E849}.Release|Any CPU.Build.0 = Release|Any CPU + {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Release|Any CPU.Build.0 = Release|Any CPU + {17F916F3-6AE7-3919-6783-41A493640905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17F916F3-6AE7-3919-6783-41A493640905}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17F916F3-6AE7-3919-6783-41A493640905}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17F916F3-6AE7-3919-6783-41A493640905}.Release|Any CPU.Build.0 = Release|Any CPU + {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Release|Any CPU.Build.0 = Release|Any CPU + {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Release|Any CPU.Build.0 = Release|Any CPU + {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Release|Any CPU.Build.0 = Release|Any CPU + {BED99755-9E24-3619-2001-B8CEAC9A0162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BED99755-9E24-3619-2001-B8CEAC9A0162}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BED99755-9E24-3619-2001-B8CEAC9A0162}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BED99755-9E24-3619-2001-B8CEAC9A0162}.Release|Any CPU.Build.0 = Release|Any CPU + {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Release|Any CPU.Build.0 = Release|Any CPU + {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Release|Any CPU.Build.0 = Release|Any CPU + {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Release|Any CPU.Build.0 = Release|Any CPU + {75168EF2-3375-63A0-8189-C73C353BCBBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75168EF2-3375-63A0-8189-C73C353BCBBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75168EF2-3375-63A0-8189-C73C353BCBBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75168EF2-3375-63A0-8189-C73C353BCBBA}.Release|Any CPU.Build.0 = Release|Any CPU + {88022C29-F01F-F535-C955-266A5717AAA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88022C29-F01F-F535-C955-266A5717AAA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88022C29-F01F-F535-C955-266A5717AAA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88022C29-F01F-F535-C955-266A5717AAA7}.Release|Any CPU.Build.0 = Release|Any CPU + {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Release|Any CPU.Build.0 = Release|Any CPU + {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Release|Any CPU.Build.0 = Release|Any CPU + {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Release|Any CPU.Build.0 = Release|Any CPU + {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Release|Any CPU.Build.0 = Release|Any CPU + {A7441955-29AB-E120-B317-283D764FCC32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7441955-29AB-E120-B317-283D764FCC32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7441955-29AB-E120-B317-283D764FCC32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7441955-29AB-E120-B317-283D764FCC32}.Release|Any CPU.Build.0 = Release|Any CPU + {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Release|Any CPU.Build.0 = Release|Any CPU + {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Release|Any CPU.Build.0 = Release|Any CPU + {78B156EC-E3B6-C57D-9590-225D80F3580F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78B156EC-E3B6-C57D-9590-225D80F3580F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78B156EC-E3B6-C57D-9590-225D80F3580F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78B156EC-E3B6-C57D-9590-225D80F3580F}.Release|Any CPU.Build.0 = Release|Any CPU + {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Release|Any CPU.Build.0 = Release|Any CPU + {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Release|Any CPU.Build.0 = Release|Any CPU + {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Release|Any CPU.Build.0 = Release|Any CPU + {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Release|Any CPU.Build.0 = Release|Any CPU + {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Release|Any CPU.Build.0 = Release|Any CPU + {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Release|Any CPU.Build.0 = Release|Any CPU + {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Release|Any CPU.Build.0 = Release|Any CPU + {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Release|Any CPU.Build.0 = Release|Any CPU + {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Release|Any CPU.Build.0 = Release|Any CPU + {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Release|Any CPU.Build.0 = Release|Any CPU + {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Release|Any CPU.Build.0 = Release|Any CPU + {A25B49E8-A1E2-08EB-90AD-95245686E358}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A25B49E8-A1E2-08EB-90AD-95245686E358}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A25B49E8-A1E2-08EB-90AD-95245686E358}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A25B49E8-A1E2-08EB-90AD-95245686E358}.Release|Any CPU.Build.0 = Release|Any CPU + {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Release|Any CPU.Build.0 = Release|Any CPU + {6329D269-4E17-3139-CF5D-EBD992B71872}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6329D269-4E17-3139-CF5D-EBD992B71872}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6329D269-4E17-3139-CF5D-EBD992B71872}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6329D269-4E17-3139-CF5D-EBD992B71872}.Release|Any CPU.Build.0 = Release|Any CPU + {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Release|Any CPU.Build.0 = Release|Any CPU + {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Release|Any CPU.Build.0 = Release|Any CPU + {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Release|Any CPU.Build.0 = Release|Any CPU + {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Release|Any CPU.Build.0 = Release|Any CPU + {456816E9-79F5-A888-6A7F-FCAA00467883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {456816E9-79F5-A888-6A7F-FCAA00467883}.Debug|Any CPU.Build.0 = Debug|Any CPU + {456816E9-79F5-A888-6A7F-FCAA00467883}.Release|Any CPU.ActiveCfg = Release|Any CPU + {456816E9-79F5-A888-6A7F-FCAA00467883}.Release|Any CPU.Build.0 = Release|Any CPU + {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Release|Any CPU.Build.0 = Release|Any CPU + {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Release|Any CPU.Build.0 = Release|Any CPU + {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Release|Any CPU.Build.0 = Release|Any CPU + {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Release|Any CPU.Build.0 = Release|Any CPU + {D154BF10-9EE8-F073-F612-439DEA9180B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D154BF10-9EE8-F073-F612-439DEA9180B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D154BF10-9EE8-F073-F612-439DEA9180B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D154BF10-9EE8-F073-F612-439DEA9180B2}.Release|Any CPU.Build.0 = Release|Any CPU + {D31F4868-30A7-8B09-C07C-4F9258780385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D31F4868-30A7-8B09-C07C-4F9258780385}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D31F4868-30A7-8B09-C07C-4F9258780385}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D31F4868-30A7-8B09-C07C-4F9258780385}.Release|Any CPU.Build.0 = Release|Any CPU + {A8846A27-965F-3743-7869-431B907D82C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8846A27-965F-3743-7869-431B907D82C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8846A27-965F-3743-7869-431B907D82C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8846A27-965F-3743-7869-431B907D82C0}.Release|Any CPU.Build.0 = Release|Any CPU + {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Release|Any CPU.Build.0 = Release|Any CPU + {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Release|Any CPU.Build.0 = Release|Any CPU + {E5254223-630A-4FCA-89F4-191E00B749D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5254223-630A-4FCA-89F4-191E00B749D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5254223-630A-4FCA-89F4-191E00B749D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5254223-630A-4FCA-89F4-191E00B749D9}.Release|Any CPU.Build.0 = Release|Any CPU + {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Release|Any CPU.Build.0 = Release|Any CPU + {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Release|Any CPU.Build.0 = Release|Any CPU + {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Release|Any CPU.Build.0 = Release|Any CPU + {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Release|Any CPU.Build.0 = Release|Any CPU + {708142F8-D31F-2590-74CF-1CB6356373EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {708142F8-D31F-2590-74CF-1CB6356373EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {708142F8-D31F-2590-74CF-1CB6356373EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {708142F8-D31F-2590-74CF-1CB6356373EB}.Release|Any CPU.Build.0 = Release|Any CPU + {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Release|Any CPU.Build.0 = Release|Any CPU + {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Release|Any CPU.Build.0 = Release|Any CPU + {4E6AA273-973F-C518-09DE-0B32F1013D10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E6AA273-973F-C518-09DE-0B32F1013D10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E6AA273-973F-C518-09DE-0B32F1013D10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E6AA273-973F-C518-09DE-0B32F1013D10}.Release|Any CPU.Build.0 = Release|Any CPU + {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Release|Any CPU.Build.0 = Release|Any CPU + {C23508FE-F0DD-D646-A330-179199A8C2F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C23508FE-F0DD-D646-A330-179199A8C2F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C23508FE-F0DD-D646-A330-179199A8C2F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C23508FE-F0DD-D646-A330-179199A8C2F9}.Release|Any CPU.Build.0 = Release|Any CPU + {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Release|Any CPU.Build.0 = Release|Any CPU + {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Release|Any CPU.Build.0 = Release|Any CPU + {215F234F-E057-6B91-E0E4-D92776FC15B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {215F234F-E057-6B91-E0E4-D92776FC15B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {215F234F-E057-6B91-E0E4-D92776FC15B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {215F234F-E057-6B91-E0E4-D92776FC15B4}.Release|Any CPU.Build.0 = Release|Any CPU + {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Release|Any CPU.Build.0 = Release|Any CPU + {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Release|Any CPU.Build.0 = Release|Any CPU + {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Release|Any CPU.Build.0 = Release|Any CPU + {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Release|Any CPU.Build.0 = Release|Any CPU + {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Release|Any CPU.Build.0 = Release|Any CPU + {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Release|Any CPU.Build.0 = Release|Any CPU + {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Release|Any CPU.Build.0 = Release|Any CPU + {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Release|Any CPU.Build.0 = Release|Any CPU + {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Release|Any CPU.Build.0 = Release|Any CPU + {02552470-3D09-742C-15A0-03448C7B176A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02552470-3D09-742C-15A0-03448C7B176A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02552470-3D09-742C-15A0-03448C7B176A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02552470-3D09-742C-15A0-03448C7B176A}.Release|Any CPU.Build.0 = Release|Any CPU + {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Release|Any CPU.Build.0 = Release|Any CPU + {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Release|Any CPU.Build.0 = Release|Any CPU + {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Release|Any CPU.Build.0 = Release|Any CPU + {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Release|Any CPU.Build.0 = Release|Any CPU + {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Release|Any CPU.Build.0 = Release|Any CPU + {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Release|Any CPU.Build.0 = Release|Any CPU + {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Release|Any CPU.Build.0 = Release|Any CPU + {4404C7F6-5CC2-4976-9303-F15492311054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4404C7F6-5CC2-4976-9303-F15492311054}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4404C7F6-5CC2-4976-9303-F15492311054}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4404C7F6-5CC2-4976-9303-F15492311054}.Release|Any CPU.Build.0 = Release|Any CPU + {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Release|Any CPU.Build.0 = Release|Any CPU + {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Release|Any CPU.Build.0 = Release|Any CPU + {768E99B5-13ED-FD75-6F50-C405A8775290}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {768E99B5-13ED-FD75-6F50-C405A8775290}.Debug|Any CPU.Build.0 = Debug|Any CPU + {768E99B5-13ED-FD75-6F50-C405A8775290}.Release|Any CPU.ActiveCfg = Release|Any CPU + {768E99B5-13ED-FD75-6F50-C405A8775290}.Release|Any CPU.Build.0 = Release|Any CPU + {68B12BA0-2B85-6085-3732-D180558B0A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68B12BA0-2B85-6085-3732-D180558B0A30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68B12BA0-2B85-6085-3732-D180558B0A30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68B12BA0-2B85-6085-3732-D180558B0A30}.Release|Any CPU.Build.0 = Release|Any CPU + {CFE88035-0880-AD6F-D44C-077C99BDA355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFE88035-0880-AD6F-D44C-077C99BDA355}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFE88035-0880-AD6F-D44C-077C99BDA355}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFE88035-0880-AD6F-D44C-077C99BDA355}.Release|Any CPU.Build.0 = Release|Any CPU + {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Release|Any CPU.Build.0 = Release|Any CPU + {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Release|Any CPU.Build.0 = Release|Any CPU + {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Release|Any CPU.Build.0 = Release|Any CPU + {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Release|Any CPU.Build.0 = Release|Any CPU + {D3640F80-32DA-60DA-71A0-597803DD445D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3640F80-32DA-60DA-71A0-597803DD445D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3640F80-32DA-60DA-71A0-597803DD445D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3640F80-32DA-60DA-71A0-597803DD445D}.Release|Any CPU.Build.0 = Release|Any CPU + {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Release|Any CPU.Build.0 = Release|Any CPU + {A0856948-B184-BAE9-A350-7D0356997560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0856948-B184-BAE9-A350-7D0356997560}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0856948-B184-BAE9-A350-7D0356997560}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0856948-B184-BAE9-A350-7D0356997560}.Release|Any CPU.Build.0 = Release|Any CPU + {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Release|Any CPU.Build.0 = Release|Any CPU + {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Release|Any CPU.Build.0 = Release|Any CPU + {8449212A-9AC0-1C23-9419-1704158E7FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8449212A-9AC0-1C23-9419-1704158E7FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8449212A-9AC0-1C23-9419-1704158E7FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8449212A-9AC0-1C23-9419-1704158E7FF6}.Release|Any CPU.Build.0 = Release|Any CPU + {27567BB5-7E42-3103-ABAB-EE445E03396B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27567BB5-7E42-3103-ABAB-EE445E03396B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27567BB5-7E42-3103-ABAB-EE445E03396B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27567BB5-7E42-3103-ABAB-EE445E03396B}.Release|Any CPU.Build.0 = Release|Any CPU + {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Release|Any CPU.Build.0 = Release|Any CPU + {E64D52DF-C601-E477-27FC-3198FA90777E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E64D52DF-C601-E477-27FC-3198FA90777E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E64D52DF-C601-E477-27FC-3198FA90777E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E64D52DF-C601-E477-27FC-3198FA90777E}.Release|Any CPU.Build.0 = Release|Any CPU + {B765E74F-BDF8-CBB7-1D12-40038265E480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B765E74F-BDF8-CBB7-1D12-40038265E480}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B765E74F-BDF8-CBB7-1D12-40038265E480}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B765E74F-BDF8-CBB7-1D12-40038265E480}.Release|Any CPU.Build.0 = Release|Any CPU + {238511B1-0953-42E1-2665-03075F55B4C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {238511B1-0953-42E1-2665-03075F55B4C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {238511B1-0953-42E1-2665-03075F55B4C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {238511B1-0953-42E1-2665-03075F55B4C9}.Release|Any CPU.Build.0 = Release|Any CPU + {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Release|Any CPU.Build.0 = Release|Any CPU + {1769A2A8-3156-9348-12BF-CFEF8253810B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1769A2A8-3156-9348-12BF-CFEF8253810B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1769A2A8-3156-9348-12BF-CFEF8253810B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1769A2A8-3156-9348-12BF-CFEF8253810B}.Release|Any CPU.Build.0 = Release|Any CPU + {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Release|Any CPU.Build.0 = Release|Any CPU + {DF706532-E516-E7E3-A823-29DDF30A0D96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF706532-E516-E7E3-A823-29DDF30A0D96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF706532-E516-E7E3-A823-29DDF30A0D96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF706532-E516-E7E3-A823-29DDF30A0D96}.Release|Any CPU.Build.0 = Release|Any CPU + {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Release|Any CPU.Build.0 = Release|Any CPU + {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Release|Any CPU.Build.0 = Release|Any CPU + {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Release|Any CPU.Build.0 = Release|Any CPU + {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Release|Any CPU.Build.0 = Release|Any CPU + {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Release|Any CPU.Build.0 = Release|Any CPU + {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Release|Any CPU.Build.0 = Release|Any CPU + {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Release|Any CPU.Build.0 = Release|Any CPU + {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Release|Any CPU.Build.0 = Release|Any CPU + {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Release|Any CPU.Build.0 = Release|Any CPU + {9F1D5A80-2432-664A-6B6E-5840074FE627}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F1D5A80-2432-664A-6B6E-5840074FE627}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F1D5A80-2432-664A-6B6E-5840074FE627}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F1D5A80-2432-664A-6B6E-5840074FE627}.Release|Any CPU.Build.0 = Release|Any CPU + {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Release|Any CPU.Build.0 = Release|Any CPU + {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Release|Any CPU.Build.0 = Release|Any CPU + {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Release|Any CPU.Build.0 = Release|Any CPU + {727DD935-998F-9913-8FBD-FE4A5B432128}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {727DD935-998F-9913-8FBD-FE4A5B432128}.Debug|Any CPU.Build.0 = Debug|Any CPU + {727DD935-998F-9913-8FBD-FE4A5B432128}.Release|Any CPU.ActiveCfg = Release|Any CPU + {727DD935-998F-9913-8FBD-FE4A5B432128}.Release|Any CPU.Build.0 = Release|Any CPU + {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Release|Any CPU.Build.0 = Release|Any CPU + {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Release|Any CPU.Build.0 = Release|Any CPU + {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Release|Any CPU.Build.0 = Release|Any CPU + {457256C7-C69D-CB30-B416-A1D2251589CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {457256C7-C69D-CB30-B416-A1D2251589CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {457256C7-C69D-CB30-B416-A1D2251589CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {457256C7-C69D-CB30-B416-A1D2251589CE}.Release|Any CPU.Build.0 = Release|Any CPU + {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Release|Any CPU.Build.0 = Release|Any CPU + {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Release|Any CPU.Build.0 = Release|Any CPU + {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Release|Any CPU.Build.0 = Release|Any CPU + {42506E08-3D7E-93FC-870F-2D4E534B1082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42506E08-3D7E-93FC-870F-2D4E534B1082}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42506E08-3D7E-93FC-870F-2D4E534B1082}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42506E08-3D7E-93FC-870F-2D4E534B1082}.Release|Any CPU.Build.0 = Release|Any CPU + {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Release|Any CPU.Build.0 = Release|Any CPU + {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Release|Any CPU.Build.0 = Release|Any CPU + {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Release|Any CPU.Build.0 = Release|Any CPU + {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Release|Any CPU.Build.0 = Release|Any CPU + {6D933A4A-780F-8549-1800-E2F343480EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D933A4A-780F-8549-1800-E2F343480EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D933A4A-780F-8549-1800-E2F343480EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D933A4A-780F-8549-1800-E2F343480EDF}.Release|Any CPU.Build.0 = Release|Any CPU + {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Release|Any CPU.Build.0 = Release|Any CPU + {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Release|Any CPU.Build.0 = Release|Any CPU + {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Release|Any CPU.Build.0 = Release|Any CPU + {768B75FC-7160-A313-FE51-2CBC8653D220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {768B75FC-7160-A313-FE51-2CBC8653D220}.Debug|Any CPU.Build.0 = Debug|Any CPU + {768B75FC-7160-A313-FE51-2CBC8653D220}.Release|Any CPU.ActiveCfg = Release|Any CPU + {768B75FC-7160-A313-FE51-2CBC8653D220}.Release|Any CPU.Build.0 = Release|Any CPU + {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Release|Any CPU.Build.0 = Release|Any CPU + {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Release|Any CPU.Build.0 = Release|Any CPU + {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Release|Any CPU.Build.0 = Release|Any CPU + {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Release|Any CPU.Build.0 = Release|Any CPU + {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {2A14DF20-5AB3-1179-FC14-9080EA92BEB6} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {1014F3DD-0BE0-D671-9FD8-9856A8079ED2} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {D329680A-AD3B-E6C7-7233-126E58F9E849} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {1C232EA2-92C2-B4A7-2A45-C8737833D336} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {17F916F3-6AE7-3919-6783-41A493640905} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} + {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {BED99755-9E24-3619-2001-B8CEAC9A0162} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {55B87E2E-B2C5-0727-32DB-B763F3A0DF64} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {9AD734C0-4406-86B8-7A07-AF402C4BC872} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {75168EF2-3375-63A0-8189-C73C353BCBBA} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {88022C29-F01F-F535-C955-266A5717AAA7} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {3B3D25CF-720F-2BBC-082D-A631E11F3110} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {3A2A1313-1831-EFA6-55AB-63849438C2F6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {A7441955-29AB-E120-B317-283D764FCC32} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {09251FE2-4416-153E-5E74-DAB63C4ECE64} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {78B156EC-E3B6-C57D-9590-225D80F3580F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {9620BCE5-17BE-6D11-84F6-444EAE405CFB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {360F1ABD-E146-A345-E84B-8A116CDB7E09} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {94337465-6C6A-E8C6-0240-4AAEF5F1DB59} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {4B7F5DB5-7915-076F-8215-FF2C7582E01B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {775903B4-09D4-4B2C-1404-BD5FCEEE494E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {8567273B-1AE0-F3D0-85BD-70A1E8F5A790} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {8E7A44D0-9E4D-BA3D-4C59-D602789529E1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B57166AD-FBF2-E511-63E6-BD4F293E3246} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {A25B49E8-A1E2-08EB-90AD-95245686E358} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {6329D269-4E17-3139-CF5D-EBD992B71872} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {456816E9-79F5-A888-6A7F-FCAA00467883} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5962CFA9-CF7F-7789-1582-69D09A4A0FD2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {68E54CD1-B46E-7D40-A474-C2C8F013370B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {9AB29652-ED65-E8EF-2E5B-A03CE514A10A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {D154BF10-9EE8-F073-F612-439DEA9180B2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {D31F4868-30A7-8B09-C07C-4F9258780385} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {A8846A27-965F-3743-7869-431B907D82C0} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B3C4059A-D7EC-2E83-900D-E47A259529CC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {8C96A8BB-30D6-F809-9986-0E54A630CE99} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {E5254223-630A-4FCA-89F4-191E00B749D9} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5E1BDE6B-0FEB-F517-B482-7C752DD9D423} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {EFB878C7-A53F-DB6F-4DB4-4C198F205F05} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5E3DD2DD-63E4-9617-51AD-BE7466B4F867} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {708142F8-D31F-2590-74CF-1CB6356373EB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {EE10DB5B-4BFB-2694-56C7-AA734D9998DE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {4E6AA273-973F-C518-09DE-0B32F1013D10} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5F0D46F0-3751-F3B5-299D-3A5E96078D2E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {C23508FE-F0DD-D646-A330-179199A8C2F9} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {6587AB0F-0ACF-1281-5AEF-3BA3E639A969} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {215F234F-E057-6B91-E0E4-D92776FC15B4} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5E096865-7E69-538A-6E99-F3F0F699CF2A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {CFDE18B2-7A61-5037-2C32-EFEED4F63364} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {C8082A2D-57EA-055F-A87C-45023FCFD3F6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {A3525B69-C2B0-0CE9-1F86-61CDD9889216} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {61DE83D6-6284-D448-E008-7039ED5E5BC0} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {9C00290D-F421-9468-9833-4FFCDD2EFE8C} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {7351A2A2-E03C-39D3-F575-6D2755A23CC5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {D7A91A55-0BFA-5077-D80E-1F47396E1C6A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {02552470-3D09-742C-15A0-03448C7B176A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B16A32BE-D56A-9E9C-749D-4E242789DE8D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {3A3A938B-6B9B-BF6B-3430-8FCFE598934D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5F7B6686-4642-015C-A57F-3B6B19133FC6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {93FCD064-F7CF-A864-AF81-7B0279D2FE26} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {4404C7F6-5CC2-4976-9303-F15492311054} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {40180EE9-83E1-5D11-C54B-B4EC49CF99F5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {768E99B5-13ED-FD75-6F50-C405A8775290} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {68B12BA0-2B85-6085-3732-D180558B0A30} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {CFE88035-0880-AD6F-D44C-077C99BDA355} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {BF1F4B6C-CB98-C09E-5557-E99D03A86A22} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {D3640F80-32DA-60DA-71A0-597803DD445D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {A0856948-B184-BAE9-A350-7D0356997560} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {FBD86DBD-0A64-99A1-E878-47DD4C531AC5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {8449212A-9AC0-1C23-9419-1704158E7FF6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {27567BB5-7E42-3103-ABAB-EE445E03396B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {E64D52DF-C601-E477-27FC-3198FA90777E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B765E74F-BDF8-CBB7-1D12-40038265E480} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {238511B1-0953-42E1-2665-03075F55B4C9} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {1769A2A8-3156-9348-12BF-CFEF8253810B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {0B694916-575C-00C4-9F31-8CB2A7BB6A83} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {DF706532-E516-E7E3-A823-29DDF30A0D96} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {0C632D98-F35E-CF99-ADB5-D9828968BEBA} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {E4D3743E-EFF0-9493-9F35-92D4F3408988} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {DFE4C60B-C995-4805-9E8A-FA271DA09F50} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {E0F37FA3-A10A-347C-0188-D7C3473413CE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {75D6DE58-7A99-17D2-F6AD-6530795A1246} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B4228F0C-BBD4-119D-17C0-51DAC508639A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {9F1D5A80-2432-664A-6B6E-5840074FE627} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {727DD935-998F-9913-8FBD-FE4A5B432128} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {DA14FF81-99FE-473B-494D-C9B24CADF75F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {6172CFDC-4569-72AE-E6BD-8E78C823663C} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {457256C7-C69D-CB30-B416-A1D2251589CE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {3D6B5FC5-8F10-2423-957F-AD16AAAFD095} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {8E42DE0F-D93C-1031-9934-C82692D0FBD1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5DC94B97-BB49-E636-DA76-837BC3E45CAC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {42506E08-3D7E-93FC-870F-2D4E534B1082} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {4C6EB51E-F0D8-6394-1828-8E542204F9BF} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {525682E4-E7EF-CDB3-54BA-15A5FAF76C20} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {35B76447-4D36-699C-7CC9-DFD02E9F5D1F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {0893E83F-92C8-B58B-800D-F13CEEEF0DC5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {6D933A4A-780F-8549-1800-E2F343480EDF} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {715C0753-B773-9A0B-10D0-33849C0F3E4E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {B3E8FD8D-CBA4-0436-C845-FE02743185E5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {768B75FC-7160-A313-FE51-2CBC8653D220} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {5EDAB414-D5C7-C371-0072-E4B830BD9323} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {440A73BE-3FBC-C528-5525-9DAACD46A20E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + {224021DB-7DE8-D6BF-518A-CF72484B86DA} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F033E9E3-6C80-4B3B-98A3-62F97328FDDA} + EndGlobalSection +EndGlobal diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs index 5fee8da4025..621e0786c44 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -32,7 +32,7 @@ using Nethermind.Specs.Forks; using NUnit.Framework; -namespace Nethermind.Flasbots.Test; +namespace Nethermind.Flashbots.Test; public partial class FlashbotsModuleTests { diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index 3a09f5cfae0..bd6a9b5d176 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -20,7 +20,7 @@ using Nethermind.State; using NUnit.Framework; -namespace Nethermind.Flasbots.Test; +namespace Nethermind.Flashbots.Test; public partial class FlashbotsModuleTests { diff --git a/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj b/src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flashbots.Test.csproj similarity index 100% rename from src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flasbots.Test.csproj rename to src/Nethermind/Nethermind.Flashbots.Test/Nethermind.Flashbots.Test.csproj diff --git a/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs index 1a0eae8d723..e44fe6b629d 100644 --- a/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs +++ b/src/Nethermind/Nethermind.Flashbots/Data/BlockValidationResult.cs @@ -14,7 +14,7 @@ public class FlashbotsResult public static ResultWrapper Invalid(string error) { - return ResultWrapper.Success(new FlashbotsResult + return ResultWrapper.Fail(error, new FlashbotsResult { Status = FlashbotsStatus.Invalid, ValidationError = error diff --git a/src/Nethermind/Nethermind.slnx b/src/Nethermind/Nethermind.slnx index 94e32d1e56a..71425b0a26d 100644 --- a/src/Nethermind/Nethermind.slnx +++ b/src/Nethermind/Nethermind.slnx @@ -19,8 +19,8 @@ - + From 5787334e852e7fe147228b2732ac169f3df331ba Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 14 Feb 2025 17:05:22 +0530 Subject: [PATCH 109/113] remove sln file --- nethermind.sln | 1028 ----------------- .../ValidateBuilderSubmissionHandler.cs | 5 + 2 files changed, 5 insertions(+), 1028 deletions(-) delete mode 100644 nethermind.sln diff --git a/nethermind.sln b/nethermind.sln deleted file mode 100644 index 0d864d5a0fe..00000000000 --- a/nethermind.sln +++ /dev/null @@ -1,1028 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.2.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{07C2787E-EAC7-C090-1BA3-A61EC2A24D84}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SendBlobs", "tools\SendBlobs\SendBlobs.csproj", "{1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Tools.Kute", "tools\Nethermind.Tools.Kute\Nethermind.Tools.Kute.csproj", "{2A14DF20-5AB3-1179-FC14-9080EA92BEB6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchemaGenerator", "tools\SchemaGenerator\SchemaGenerator.csproj", "{1014F3DD-0BE0-D671-9FD8-9856A8079ED2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TxParser", "tools\TxParser\TxParser.csproj", "{D329680A-AD3B-E6C7-7233-126E58F9E849}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HiveConsensusWorkflowGenerator", "tools\HiveConsensusWorkflowGenerator\HiveConsensusWorkflowGenerator.csproj", "{1C232EA2-92C2-B4A7-2A45-C8737833D336}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Evm", "tools\Evm\Evm.csproj", "{17F916F3-6AE7-3919-6783-41A493640905}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocGen", "tools\DocGen\DocGen.csproj", "{7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HiveCompare", "tools\HiveCompare\HiveCompare.csproj", "{ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Nethermind", "Nethermind", "{FBCB8DBD-CDF2-6977-D18F-5F93DC702250}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Stats", "src\Nethermind\Nethermind.Network.Stats\Nethermind.Network.Stats.csproj", "{B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Pyspec.Test", "src\Nethermind\Ethereum.Blockchain.Pyspec.Test\Ethereum.Blockchain.Pyspec.Test.csproj", "{BED99755-9E24-3619-2001-B8CEAC9A0162}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.Plugin.Test", "src\Nethermind\Nethermind.Merge.Plugin.Test\Nethermind.Merge.Plugin.Test.csproj", "{AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.HexPrefix.Test", "src\Nethermind\Ethereum.HexPrefix.Test\Ethereum.HexPrefix.Test.csproj", "{55B87E2E-B2C5-0727-32DB-B763F3A0DF64}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Difficulty.Test", "src\Nethermind\Ethereum.Difficulty.Test\Ethereum.Difficulty.Test.csproj", "{9AD734C0-4406-86B8-7A07-AF402C4BC872}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Taiko", "src\Nethermind\Nethermind.Taiko\Nethermind.Taiko.csproj", "{75168EF2-3375-63A0-8189-C73C353BCBBA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Cli.Test", "src\Nethermind\Nethermind.Cli.Test\Nethermind.Cli.Test.csproj", "{88022C29-F01F-F535-C955-266A5717AAA7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.TxPool", "src\Nethermind\Nethermind.TxPool\Nethermind.TxPool.csproj", "{3B3D25CF-720F-2BBC-082D-A631E11F3110}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db.Rocks", "src\Nethermind\Nethermind.Db.Rocks\Nethermind.Db.Rocks.csproj", "{44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Init", "src\Nethermind\Nethermind.Init\Nethermind.Init.csproj", "{3A2A1313-1831-EFA6-55AB-63849438C2F6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Synchronization", "src\Nethermind\Nethermind.Synchronization\Nethermind.Synchronization.csproj", "{C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Test", "src\Nethermind\Nethermind.Network.Test\Nethermind.Network.Test.csproj", "{A7441955-29AB-E120-B317-283D764FCC32}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flashbots", "src\Nethermind\Nethermind.Flashbots\Nethermind.Flashbots.csproj", "{C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Flashbots.Test", "src\Nethermind\Nethermind.Flashbots.Test\Nethermind.Flashbots.Test.csproj", "{09251FE2-4416-153E-5E74-DAB63C4ECE64}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Basic.Test", "src\Nethermind\Ethereum.Basic.Test\Ethereum.Basic.Test.csproj", "{78B156EC-E3B6-C57D-9590-225D80F3580F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging.Microsoft", "src\Nethermind\Nethermind.Logging.Microsoft\Nethermind.Logging.Microsoft.csproj", "{E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Test.Base", "src\Nethermind\Ethereum.Test.Base\Ethereum.Test.Base.csproj", "{9620BCE5-17BE-6D11-84F6-444EAE405CFB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Cli", "src\Nethermind\Nethermind.Cli\Nethermind.Cli.csproj", "{360F1ABD-E146-A345-E84B-8A116CDB7E09}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.KeyStore.Test", "src\Nethermind\Ethereum.KeyStore.Test\Ethereum.KeyStore.Test.csproj", "{94337465-6C6A-E8C6-0240-4AAEF5F1DB59}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Facade", "src\Nethermind\Nethermind.Facade\Nethermind.Facade.csproj", "{4B7F5DB5-7915-076F-8215-FF2C7582E01B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Synchronization.Test", "src\Nethermind\Nethermind.Synchronization.Test\Nethermind.Synchronization.Test.csproj", "{775903B4-09D4-4B2C-1404-BD5FCEEE494E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Seq", "src\Nethermind\Nethermind.Seq\Nethermind.Seq.csproj", "{225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Specs.Test", "src\Nethermind\Nethermind.Specs.Test\Nethermind.Specs.Test.csproj", "{8567273B-1AE0-F3D0-85BD-70A1E8F5A790}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Blockchain.Test.Runner", "src\Nethermind\Nethermind.Blockchain.Test.Runner\Nethermind.Blockchain.Test.Runner.csproj", "{8E7A44D0-9E4D-BA3D-4C59-D602789529E1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.ExternalSigner.Plugin", "src\Nethermind\Nethermind.ExternalSigner.Plugin\Nethermind.ExternalSigner.Plugin.csproj", "{B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.Test", "src\Nethermind\Nethermind.JsonRpc.Test\Nethermind.JsonRpc.Test.csproj", "{B57166AD-FBF2-E511-63E6-BD4F293E3246}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Core", "src\Nethermind\Nethermind.Core\Nethermind.Core.csproj", "{A25B49E8-A1E2-08EB-90AD-95245686E358}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Dns", "src\Nethermind\Nethermind.Network.Dns\Nethermind.Network.Dns.csproj", "{C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator.Test", "src\Nethermind\Nethermind.Serialization.SszGenerator.Test\Nethermind.Serialization.SszGenerator.Test.csproj", "{6329D269-4E17-3139-CF5D-EBD992B71872}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.SszGenerator", "src\Nethermind\Nethermind.Serialization.SszGenerator\Nethermind.Serialization.SszGenerator.csproj", "{29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.HealthChecks", "src\Nethermind\Nethermind.HealthChecks\Nethermind.HealthChecks.csproj", "{BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Legacy.Test", "src\Nethermind\Ethereum.Blockchain.Legacy.Test\Ethereum.Blockchain.Legacy.Test.csproj", "{7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network", "src\Nethermind\Nethermind.Network\Nethermind.Network.csproj", "{7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Runner", "src\Nethermind\Nethermind.Runner\Nethermind.Runner.csproj", "{456816E9-79F5-A888-6A7F-FCAA00467883}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc", "src\Nethermind\Nethermind.JsonRpc\Nethermind.JsonRpc.csproj", "{4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Grpc", "src\Nethermind\Nethermind.Grpc\Nethermind.Grpc.csproj", "{5962CFA9-CF7F-7789-1582-69D09A4A0FD2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db.Rpc", "src\Nethermind\Nethermind.Db.Rpc\Nethermind.Db.Rpc.csproj", "{68E54CD1-B46E-7D40-A474-C2C8F013370B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.PerfTest", "src\Nethermind\Nethermind.PerfTest\Nethermind.PerfTest.csproj", "{9AB29652-ED65-E8EF-2E5B-A03CE514A10A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Config", "src\Nethermind\Nethermind.Config\Nethermind.Config.csproj", "{D154BF10-9EE8-F073-F612-439DEA9180B2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Overseer.Test", "src\Nethermind\Nethermind.Overseer.Test\Nethermind.Overseer.Test.csproj", "{D31F4868-30A7-8B09-C07C-4F9258780385}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.TraceStore.Test", "src\Nethermind\Nethermind.JsonRpc.TraceStore.Test\Nethermind.JsonRpc.TraceStore.Test.csproj", "{A8846A27-965F-3743-7869-431B907D82C0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Optimism.Test", "src\Nethermind\Nethermind.Optimism.Test\Nethermind.Optimism.Test.csproj", "{B3C4059A-D7EC-2E83-900D-E47A259529CC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Api.Test", "src\Nethermind\Nethermind.Api.Test\Nethermind.Api.Test.csproj", "{8C96A8BB-30D6-F809-9986-0E54A630CE99}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Abi.Test", "src\Nethermind\Ethereum.Abi.Test\Ethereum.Abi.Test.csproj", "{E5254223-630A-4FCA-89F4-191E00B749D9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus", "src\Nethermind\Nethermind.Consensus\Nethermind.Consensus.csproj", "{5E1BDE6B-0FEB-F517-B482-7C752DD9D423}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Monitoring.Test", "src\Nethermind\Nethermind.Monitoring.Test\Nethermind.Monitoring.Test.csproj", "{EFB878C7-A53F-DB6F-4DB4-4C198F205F05}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merkleization", "src\Nethermind\Nethermind.Merkleization\Nethermind.Merkleization.csproj", "{5E3DD2DD-63E4-9617-51AD-BE7466B4F867}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Dns.Test", "src\Nethermind\Nethermind.Network.Dns.Test\Nethermind.Network.Dns.Test.csproj", "{5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Era1", "src\Nethermind\Nethermind.Era1\Nethermind.Era1.csproj", "{708142F8-D31F-2590-74CF-1CB6356373EB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.Ethash", "src\Nethermind\Nethermind.Consensus.Ethash\Nethermind.Consensus.Ethash.csproj", "{EE10DB5B-4BFB-2694-56C7-AA734D9998DE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Sockets.Test", "src\Nethermind\Nethermind.Sockets.Test\Nethermind.Sockets.Test.csproj", "{EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Sockets", "src\Nethermind\Nethermind.Sockets\Nethermind.Sockets.csproj", "{4E6AA273-973F-C518-09DE-0B32F1013D10}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Benchmark", "src\Nethermind\Nethermind.Benchmark\Nethermind.Benchmark.csproj", "{5F0D46F0-3751-F3B5-299D-3A5E96078D2E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.EthereumTests.Benchmark", "src\Nethermind\Nethermind.EthereumTests.Benchmark\Nethermind.EthereumTests.Benchmark.csproj", "{C23508FE-F0DD-D646-A330-179199A8C2F9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Rlp", "src\Nethermind\Nethermind.Serialization.Rlp\Nethermind.Serialization.Rlp.csproj", "{86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.EthStats.Test", "src\Nethermind\Nethermind.EthStats.Test\Nethermind.EthStats.Test.csproj", "{6587AB0F-0ACF-1281-5AEF-3BA3E639A969}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Ssz.Test", "src\Nethermind\Nethermind.Serialization.Ssz.Test\Nethermind.Serialization.Ssz.Test.csproj", "{215F234F-E057-6B91-E0E4-D92776FC15B4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging.NLog", "src\Nethermind\Nethermind.Logging.NLog\Nethermind.Logging.NLog.csproj", "{5E096865-7E69-538A-6E99-F3F0F699CF2A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.TxPool.Test", "src\Nethermind\Nethermind.TxPool.Test\Nethermind.TxPool.Test.csproj", "{CFDE18B2-7A61-5037-2C32-EFEED4F63364}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Crypto", "src\Nethermind\Nethermind.Crypto\Nethermind.Crypto.csproj", "{C8082A2D-57EA-055F-A87C-45023FCFD3F6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.Clique", "src\Nethermind\Nethermind.Consensus.Clique\Nethermind.Consensus.Clique.csproj", "{A3525B69-C2B0-0CE9-1F86-61CDD9889216}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.PoW.Test", "src\Nethermind\Ethereum.PoW.Test\Ethereum.PoW.Test.csproj", "{61DE83D6-6284-D448-E008-7039ED5E5BC0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Core.Test", "src\Nethermind\Nethermind.Core.Test\Nethermind.Core.Test.csproj", "{9C00290D-F421-9468-9833-4FFCDD2EFE8C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Runner.Test", "src\Nethermind\Nethermind.Runner.Test\Nethermind.Runner.Test.csproj", "{7351A2A2-E03C-39D3-F575-6D2755A23CC5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Transition.Test", "src\Nethermind\Ethereum.Transition.Test\Ethereum.Transition.Test.csproj", "{E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Rlp.Test", "src\Nethermind\Ethereum.Rlp.Test\Ethereum.Rlp.Test.csproj", "{D7A91A55-0BFA-5077-D80E-1F47396E1C6A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.Test", "src\Nethermind\Nethermind.Consensus.Test\Nethermind.Consensus.Test.csproj", "{02552470-3D09-742C-15A0-03448C7B176A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Hive.Test", "src\Nethermind\Nethermind.Hive.Test\Nethermind.Hive.Test.csproj", "{B16A32BE-D56A-9E9C-749D-4E242789DE8D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Ssz", "src\Nethermind\Nethermind.Serialization.Ssz\Nethermind.Serialization.Ssz.csproj", "{3A3A938B-6B9B-BF6B-3430-8FCFE598934D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.UPnP.Plugin", "src\Nethermind\Nethermind.UPnP.Plugin\Nethermind.UPnP.Plugin.csproj", "{1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.State.Test", "src\Nethermind\Nethermind.State.Test\Nethermind.State.Test.csproj", "{B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.EthStats", "src\Nethermind\Nethermind.EthStats\Nethermind.EthStats.csproj", "{5F7B6686-4642-015C-A57F-3B6B19133FC6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging", "src\Nethermind\Nethermind.Logging\Nethermind.Logging.csproj", "{68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db", "src\Nethermind\Nethermind.Db\Nethermind.Db.csproj", "{93FCD064-F7CF-A864-AF81-7B0279D2FE26}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Serialization.Json", "src\Nethermind\Nethermind.Serialization.Json\Nethermind.Serialization.Json.csproj", "{4404C7F6-5CC2-4976-9303-F15492311054}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Block.Legacy.Test", "src\Nethermind\Ethereum.Blockchain.Block.Legacy.Test\Ethereum.Blockchain.Block.Legacy.Test.csproj", "{40180EE9-83E1-5D11-C54B-B4EC49CF99F5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Blockchain", "src\Nethermind\Nethermind.Blockchain\Nethermind.Blockchain.csproj", "{C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.VM.Test", "src\Nethermind\Ethereum.VM.Test\Ethereum.VM.Test.csproj", "{768E99B5-13ED-FD75-6F50-C405A8775290}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.KeyAddress.Test", "src\Nethermind\Ethereum.KeyAddress.Test\Ethereum.KeyAddress.Test.csproj", "{68B12BA0-2B85-6085-3732-D180558B0A30}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Trie", "src\Nethermind\Nethermind.Trie\Nethermind.Trie.csproj", "{CFE88035-0880-AD6F-D44C-077C99BDA355}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.KeyStore.Test", "src\Nethermind\Nethermind.KeyStore.Test\Nethermind.KeyStore.Test.csproj", "{BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Evm.Test", "src\Nethermind\Nethermind.Evm.Test\Nethermind.Evm.Test.csproj", "{7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.AuRa", "src\Nethermind\Nethermind.Merge.AuRa\Nethermind.Merge.AuRa.csproj", "{BF1F4B6C-CB98-C09E-5557-E99D03A86A22}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter", "src\Nethermind\Nethermind.Shutter\Nethermind.Shutter.csproj", "{6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Consensus.AuRa", "src\Nethermind\Nethermind.Consensus.AuRa\Nethermind.Consensus.AuRa.csproj", "{D3640F80-32DA-60DA-71A0-597803DD445D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Clique.Test", "src\Nethermind\Nethermind.Clique.Test\Nethermind.Clique.Test.csproj", "{7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.TraceStore", "src\Nethermind\Nethermind.JsonRpc.TraceStore\Nethermind.JsonRpc.TraceStore.csproj", "{A0856948-B184-BAE9-A350-7D0356997560}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Block.Test", "src\Nethermind\Ethereum.Blockchain.Block.Test\Ethereum.Blockchain.Block.Test.csproj", "{B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Analytics", "src\Nethermind\Nethermind.Analytics\Nethermind.Analytics.csproj", "{FBD86DBD-0A64-99A1-E878-47DD4C531AC5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Config.Test", "src\Nethermind\Nethermind.Config.Test\Nethermind.Config.Test.csproj", "{8449212A-9AC0-1C23-9419-1704158E7FF6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Discovery.Test", "src\Nethermind\Nethermind.Network.Discovery.Test\Nethermind.Network.Discovery.Test.csproj", "{27567BB5-7E42-3103-ABAB-EE445E03396B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.HealthChecks.Test", "src\Nethermind\Nethermind.HealthChecks.Test\Nethermind.HealthChecks.Test.csproj", "{BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.AuRa.Test", "src\Nethermind\Nethermind.AuRa.Test\Nethermind.AuRa.Test.csproj", "{E64D52DF-C601-E477-27FC-3198FA90777E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Contract", "src\Nethermind\Nethermind.Network.Contract\Nethermind.Network.Contract.csproj", "{B765E74F-BDF8-CBB7-1D12-40038265E480}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Ethash.Test", "src\Nethermind\Nethermind.Ethash.Test\Nethermind.Ethash.Test.csproj", "{238511B1-0953-42E1-2665-03075F55B4C9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Trie.Benchmark", "src\Nethermind\Nethermind.Trie.Benchmark\Nethermind.Trie.Benchmark.csproj", "{49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Era1.Test", "src\Nethermind\Nethermind.Era.Test\Nethermind.Era1.Test.csproj", "{1769A2A8-3156-9348-12BF-CFEF8253810B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Test.Runner", "src\Nethermind\Nethermind.Test.Runner\Nethermind.Test.Runner.csproj", "{0B694916-575C-00C4-9F31-8CB2A7BB6A83}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Trie.Test", "src\Nethermind\Ethereum.Trie.Test\Ethereum.Trie.Test.csproj", "{DF706532-E516-E7E3-A823-29DDF30A0D96}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Discovery", "src\Nethermind\Nethermind.Network.Discovery\Nethermind.Network.Discovery.csproj", "{0C632D98-F35E-CF99-ADB5-D9828968BEBA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Precompiles.Benchmark", "src\Nethermind\Nethermind.Precompiles.Benchmark\Nethermind.Precompiles.Benchmark.csproj", "{E4D3743E-EFF0-9493-9F35-92D4F3408988}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Wallet.Test", "src\Nethermind\Nethermind.Wallet.Test\Nethermind.Wallet.Test.csproj", "{DFE4C60B-C995-4805-9E8A-FA271DA09F50}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Hive", "src\Nethermind\Nethermind.Hive\Nethermind.Hive.csproj", "{E0F37FA3-A10A-347C-0188-D7C3473413CE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.AuRa.Test", "src\Nethermind\Nethermind.Merge.AuRa.Test\Nethermind.Merge.AuRa.Test.csproj", "{75D6DE58-7A99-17D2-F6AD-6530795A1246}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Blockchain.Test", "src\Nethermind\Ethereum.Blockchain.Test\Ethereum.Blockchain.Test.csproj", "{9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Benchmark.Runner", "src\Nethermind\Nethermind.Benchmark.Runner\Nethermind.Benchmark.Runner.csproj", "{67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.State", "src\Nethermind\Nethermind.State\Nethermind.State.csproj", "{B4228F0C-BBD4-119D-17C0-51DAC508639A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Merge.Plugin", "src\Nethermind\Nethermind.Merge.Plugin\Nethermind.Merge.Plugin.csproj", "{AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ethereum.Transaction.Test", "src\Nethermind\Ethereum.Transaction.Test\Ethereum.Transaction.Test.csproj", "{9F1D5A80-2432-664A-6B6E-5840074FE627}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Blockchain.Test", "src\Nethermind\Nethermind.Blockchain.Test\Nethermind.Blockchain.Test.csproj", "{4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Mining.Test", "src\Nethermind\Nethermind.Mining.Test\Nethermind.Mining.Test.csproj", "{625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Tools.GasHistorian", "src\Nethermind\Nethermind.Tools.GasHistorian\Nethermind.Tools.GasHistorian.csproj", "{90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Wallet", "src\Nethermind\Nethermind.Wallet\Nethermind.Wallet.csproj", "{727DD935-998F-9913-8FBD-FE4A5B432128}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.JsonRpc.Benchmark", "src\Nethermind\Nethermind.JsonRpc.Benchmark\Nethermind.JsonRpc.Benchmark.csproj", "{DA14FF81-99FE-473B-494D-C9B24CADF75F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Monitoring", "src\Nethermind\Nethermind.Monitoring\Nethermind.Monitoring.csproj", "{6172CFDC-4569-72AE-E6BD-8E78C823663C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Evm", "src\Nethermind\Nethermind.Evm\Nethermind.Evm.csproj", "{E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Api", "src\Nethermind\Nethermind.Api\Nethermind.Api.csproj", "{457256C7-C69D-CB30-B416-A1D2251589CE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Abi.Test", "src\Nethermind\Nethermind.Abi.Test\Nethermind.Abi.Test.csproj", "{3D6B5FC5-8F10-2423-957F-AD16AAAFD095}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Evm.Benchmark", "src\Nethermind\Nethermind.Evm.Benchmark\Nethermind.Evm.Benchmark.csproj", "{8E42DE0F-D93C-1031-9934-C82692D0FBD1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.State.Test.Runner.Test", "src\Nethermind\Nethermind.State.Test.Runner.Test\Nethermind.State.Test.Runner.Test.csproj", "{5DC94B97-BB49-E636-DA76-837BC3E45CAC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Optimism", "src\Nethermind\Nethermind.Optimism\Nethermind.Optimism.csproj", "{42506E08-3D7E-93FC-870F-2D4E534B1082}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Enr", "src\Nethermind\Nethermind.Network.Enr\Nethermind.Network.Enr.csproj", "{4C6EB51E-F0D8-6394-1828-8E542204F9BF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Logging.NLog.Test", "src\Nethermind\Nethermind.Logging.NLog.Test\Nethermind.Logging.NLog.Test.csproj", "{525682E4-E7EF-CDB3-54BA-15A5FAF76C20}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Db.Test", "src\Nethermind\Nethermind.Db.Test\Nethermind.Db.Test.csproj", "{35B76447-4D36-699C-7CC9-DFD02E9F5D1F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Benchmark", "src\Nethermind\Nethermind.Network.Benchmark\Nethermind.Network.Benchmark.csproj", "{0893E83F-92C8-B58B-800D-F13CEEEF0DC5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Abi", "src\Nethermind\Nethermind.Abi\Nethermind.Abi.csproj", "{6D933A4A-780F-8549-1800-E2F343480EDF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.KeyStore", "src\Nethermind\Nethermind.KeyStore\Nethermind.KeyStore.csproj", "{715C0753-B773-9A0B-10D0-33849C0F3E4E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Facade.Test", "src\Nethermind\Nethermind.Facade.Test\Nethermind.Facade.Test.csproj", "{1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Specs", "src\Nethermind\Nethermind.Specs\Nethermind.Specs.csproj", "{B3E8FD8D-CBA4-0436-C845-FE02743185E5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Taiko.Test", "src\Nethermind\Nethermind.Taiko.Test\Nethermind.Taiko.Test.csproj", "{768B75FC-7160-A313-FE51-2CBC8653D220}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Shutter.Test", "src\Nethermind\Nethermind.Shutter.Test\Nethermind.Shutter.Test.csproj", "{5EDAB414-D5C7-C371-0072-E4B830BD9323}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Network.Enr.Test", "src\Nethermind\Nethermind.Network.Enr.Test\Nethermind.Network.Enr.Test.csproj", "{3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Trie.Test", "src\Nethermind\Nethermind.Trie.Test\Nethermind.Trie.Test.csproj", "{8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Init.Snapshot", "src\Nethermind\Nethermind.Init.Snapshot\Nethermind.Init.Snapshot.csproj", "{440A73BE-3FBC-C528-5525-9DAACD46A20E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.ReferenceAssemblies", "src\Nethermind\Nethermind.ReferenceAssemblies\Nethermind.ReferenceAssemblies.csproj", "{224021DB-7DE8-D6BF-518A-CF72484B86DA}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555}.Release|Any CPU.Build.0 = Release|Any CPU - {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2A14DF20-5AB3-1179-FC14-9080EA92BEB6}.Release|Any CPU.Build.0 = Release|Any CPU - {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1014F3DD-0BE0-D671-9FD8-9856A8079ED2}.Release|Any CPU.Build.0 = Release|Any CPU - {D329680A-AD3B-E6C7-7233-126E58F9E849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D329680A-AD3B-E6C7-7233-126E58F9E849}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D329680A-AD3B-E6C7-7233-126E58F9E849}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D329680A-AD3B-E6C7-7233-126E58F9E849}.Release|Any CPU.Build.0 = Release|Any CPU - {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1C232EA2-92C2-B4A7-2A45-C8737833D336}.Release|Any CPU.Build.0 = Release|Any CPU - {17F916F3-6AE7-3919-6783-41A493640905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {17F916F3-6AE7-3919-6783-41A493640905}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17F916F3-6AE7-3919-6783-41A493640905}.Release|Any CPU.ActiveCfg = Release|Any CPU - {17F916F3-6AE7-3919-6783-41A493640905}.Release|Any CPU.Build.0 = Release|Any CPU - {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC}.Release|Any CPU.Build.0 = Release|Any CPU - {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3}.Release|Any CPU.Build.0 = Release|Any CPU - {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF}.Release|Any CPU.Build.0 = Release|Any CPU - {BED99755-9E24-3619-2001-B8CEAC9A0162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BED99755-9E24-3619-2001-B8CEAC9A0162}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BED99755-9E24-3619-2001-B8CEAC9A0162}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BED99755-9E24-3619-2001-B8CEAC9A0162}.Release|Any CPU.Build.0 = Release|Any CPU - {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E}.Release|Any CPU.Build.0 = Release|Any CPU - {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Debug|Any CPU.Build.0 = Debug|Any CPU - {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Release|Any CPU.ActiveCfg = Release|Any CPU - {55B87E2E-B2C5-0727-32DB-B763F3A0DF64}.Release|Any CPU.Build.0 = Release|Any CPU - {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9AD734C0-4406-86B8-7A07-AF402C4BC872}.Release|Any CPU.Build.0 = Release|Any CPU - {75168EF2-3375-63A0-8189-C73C353BCBBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {75168EF2-3375-63A0-8189-C73C353BCBBA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {75168EF2-3375-63A0-8189-C73C353BCBBA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {75168EF2-3375-63A0-8189-C73C353BCBBA}.Release|Any CPU.Build.0 = Release|Any CPU - {88022C29-F01F-F535-C955-266A5717AAA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {88022C29-F01F-F535-C955-266A5717AAA7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {88022C29-F01F-F535-C955-266A5717AAA7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {88022C29-F01F-F535-C955-266A5717AAA7}.Release|Any CPU.Build.0 = Release|Any CPU - {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B3D25CF-720F-2BBC-082D-A631E11F3110}.Release|Any CPU.Build.0 = Release|Any CPU - {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E}.Release|Any CPU.Build.0 = Release|Any CPU - {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3A2A1313-1831-EFA6-55AB-63849438C2F6}.Release|Any CPU.Build.0 = Release|Any CPU - {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1}.Release|Any CPU.Build.0 = Release|Any CPU - {A7441955-29AB-E120-B317-283D764FCC32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A7441955-29AB-E120-B317-283D764FCC32}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A7441955-29AB-E120-B317-283D764FCC32}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A7441955-29AB-E120-B317-283D764FCC32}.Release|Any CPU.Build.0 = Release|Any CPU - {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7}.Release|Any CPU.Build.0 = Release|Any CPU - {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Debug|Any CPU.Build.0 = Debug|Any CPU - {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Release|Any CPU.ActiveCfg = Release|Any CPU - {09251FE2-4416-153E-5E74-DAB63C4ECE64}.Release|Any CPU.Build.0 = Release|Any CPU - {78B156EC-E3B6-C57D-9590-225D80F3580F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {78B156EC-E3B6-C57D-9590-225D80F3580F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {78B156EC-E3B6-C57D-9590-225D80F3580F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {78B156EC-E3B6-C57D-9590-225D80F3580F}.Release|Any CPU.Build.0 = Release|Any CPU - {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E}.Release|Any CPU.Build.0 = Release|Any CPU - {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9620BCE5-17BE-6D11-84F6-444EAE405CFB}.Release|Any CPU.Build.0 = Release|Any CPU - {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Debug|Any CPU.Build.0 = Debug|Any CPU - {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Release|Any CPU.ActiveCfg = Release|Any CPU - {360F1ABD-E146-A345-E84B-8A116CDB7E09}.Release|Any CPU.Build.0 = Release|Any CPU - {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Debug|Any CPU.Build.0 = Debug|Any CPU - {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Release|Any CPU.ActiveCfg = Release|Any CPU - {94337465-6C6A-E8C6-0240-4AAEF5F1DB59}.Release|Any CPU.Build.0 = Release|Any CPU - {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4B7F5DB5-7915-076F-8215-FF2C7582E01B}.Release|Any CPU.Build.0 = Release|Any CPU - {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {775903B4-09D4-4B2C-1404-BD5FCEEE494E}.Release|Any CPU.Build.0 = Release|Any CPU - {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB}.Release|Any CPU.Build.0 = Release|Any CPU - {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8567273B-1AE0-F3D0-85BD-70A1E8F5A790}.Release|Any CPU.Build.0 = Release|Any CPU - {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E7A44D0-9E4D-BA3D-4C59-D602789529E1}.Release|Any CPU.Build.0 = Release|Any CPU - {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB}.Release|Any CPU.Build.0 = Release|Any CPU - {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B57166AD-FBF2-E511-63E6-BD4F293E3246}.Release|Any CPU.Build.0 = Release|Any CPU - {A25B49E8-A1E2-08EB-90AD-95245686E358}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A25B49E8-A1E2-08EB-90AD-95245686E358}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A25B49E8-A1E2-08EB-90AD-95245686E358}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A25B49E8-A1E2-08EB-90AD-95245686E358}.Release|Any CPU.Build.0 = Release|Any CPU - {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3}.Release|Any CPU.Build.0 = Release|Any CPU - {6329D269-4E17-3139-CF5D-EBD992B71872}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6329D269-4E17-3139-CF5D-EBD992B71872}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6329D269-4E17-3139-CF5D-EBD992B71872}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6329D269-4E17-3139-CF5D-EBD992B71872}.Release|Any CPU.Build.0 = Release|Any CPU - {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2}.Release|Any CPU.Build.0 = Release|Any CPU - {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18}.Release|Any CPU.Build.0 = Release|Any CPU - {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F}.Release|Any CPU.Build.0 = Release|Any CPU - {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913}.Release|Any CPU.Build.0 = Release|Any CPU - {456816E9-79F5-A888-6A7F-FCAA00467883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {456816E9-79F5-A888-6A7F-FCAA00467883}.Debug|Any CPU.Build.0 = Debug|Any CPU - {456816E9-79F5-A888-6A7F-FCAA00467883}.Release|Any CPU.ActiveCfg = Release|Any CPU - {456816E9-79F5-A888-6A7F-FCAA00467883}.Release|Any CPU.Build.0 = Release|Any CPU - {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE}.Release|Any CPU.Build.0 = Release|Any CPU - {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5962CFA9-CF7F-7789-1582-69D09A4A0FD2}.Release|Any CPU.Build.0 = Release|Any CPU - {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68E54CD1-B46E-7D40-A474-C2C8F013370B}.Release|Any CPU.Build.0 = Release|Any CPU - {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9AB29652-ED65-E8EF-2E5B-A03CE514A10A}.Release|Any CPU.Build.0 = Release|Any CPU - {D154BF10-9EE8-F073-F612-439DEA9180B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D154BF10-9EE8-F073-F612-439DEA9180B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D154BF10-9EE8-F073-F612-439DEA9180B2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D154BF10-9EE8-F073-F612-439DEA9180B2}.Release|Any CPU.Build.0 = Release|Any CPU - {D31F4868-30A7-8B09-C07C-4F9258780385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D31F4868-30A7-8B09-C07C-4F9258780385}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D31F4868-30A7-8B09-C07C-4F9258780385}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D31F4868-30A7-8B09-C07C-4F9258780385}.Release|Any CPU.Build.0 = Release|Any CPU - {A8846A27-965F-3743-7869-431B907D82C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8846A27-965F-3743-7869-431B907D82C0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8846A27-965F-3743-7869-431B907D82C0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8846A27-965F-3743-7869-431B907D82C0}.Release|Any CPU.Build.0 = Release|Any CPU - {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B3C4059A-D7EC-2E83-900D-E47A259529CC}.Release|Any CPU.Build.0 = Release|Any CPU - {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C96A8BB-30D6-F809-9986-0E54A630CE99}.Release|Any CPU.Build.0 = Release|Any CPU - {E5254223-630A-4FCA-89F4-191E00B749D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E5254223-630A-4FCA-89F4-191E00B749D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5254223-630A-4FCA-89F4-191E00B749D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E5254223-630A-4FCA-89F4-191E00B749D9}.Release|Any CPU.Build.0 = Release|Any CPU - {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E1BDE6B-0FEB-F517-B482-7C752DD9D423}.Release|Any CPU.Build.0 = Release|Any CPU - {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EFB878C7-A53F-DB6F-4DB4-4C198F205F05}.Release|Any CPU.Build.0 = Release|Any CPU - {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E3DD2DD-63E4-9617-51AD-BE7466B4F867}.Release|Any CPU.Build.0 = Release|Any CPU - {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2}.Release|Any CPU.Build.0 = Release|Any CPU - {708142F8-D31F-2590-74CF-1CB6356373EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {708142F8-D31F-2590-74CF-1CB6356373EB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {708142F8-D31F-2590-74CF-1CB6356373EB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {708142F8-D31F-2590-74CF-1CB6356373EB}.Release|Any CPU.Build.0 = Release|Any CPU - {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EE10DB5B-4BFB-2694-56C7-AA734D9998DE}.Release|Any CPU.Build.0 = Release|Any CPU - {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7}.Release|Any CPU.Build.0 = Release|Any CPU - {4E6AA273-973F-C518-09DE-0B32F1013D10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4E6AA273-973F-C518-09DE-0B32F1013D10}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4E6AA273-973F-C518-09DE-0B32F1013D10}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4E6AA273-973F-C518-09DE-0B32F1013D10}.Release|Any CPU.Build.0 = Release|Any CPU - {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F0D46F0-3751-F3B5-299D-3A5E96078D2E}.Release|Any CPU.Build.0 = Release|Any CPU - {C23508FE-F0DD-D646-A330-179199A8C2F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C23508FE-F0DD-D646-A330-179199A8C2F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C23508FE-F0DD-D646-A330-179199A8C2F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C23508FE-F0DD-D646-A330-179199A8C2F9}.Release|Any CPU.Build.0 = Release|Any CPU - {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27}.Release|Any CPU.Build.0 = Release|Any CPU - {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6587AB0F-0ACF-1281-5AEF-3BA3E639A969}.Release|Any CPU.Build.0 = Release|Any CPU - {215F234F-E057-6B91-E0E4-D92776FC15B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {215F234F-E057-6B91-E0E4-D92776FC15B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {215F234F-E057-6B91-E0E4-D92776FC15B4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {215F234F-E057-6B91-E0E4-D92776FC15B4}.Release|Any CPU.Build.0 = Release|Any CPU - {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E096865-7E69-538A-6E99-F3F0F699CF2A}.Release|Any CPU.Build.0 = Release|Any CPU - {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CFDE18B2-7A61-5037-2C32-EFEED4F63364}.Release|Any CPU.Build.0 = Release|Any CPU - {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C8082A2D-57EA-055F-A87C-45023FCFD3F6}.Release|Any CPU.Build.0 = Release|Any CPU - {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A3525B69-C2B0-0CE9-1F86-61CDD9889216}.Release|Any CPU.Build.0 = Release|Any CPU - {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {61DE83D6-6284-D448-E008-7039ED5E5BC0}.Release|Any CPU.Build.0 = Release|Any CPU - {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C00290D-F421-9468-9833-4FFCDD2EFE8C}.Release|Any CPU.Build.0 = Release|Any CPU - {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7351A2A2-E03C-39D3-F575-6D2755A23CC5}.Release|Any CPU.Build.0 = Release|Any CPU - {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6}.Release|Any CPU.Build.0 = Release|Any CPU - {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7A91A55-0BFA-5077-D80E-1F47396E1C6A}.Release|Any CPU.Build.0 = Release|Any CPU - {02552470-3D09-742C-15A0-03448C7B176A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {02552470-3D09-742C-15A0-03448C7B176A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {02552470-3D09-742C-15A0-03448C7B176A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {02552470-3D09-742C-15A0-03448C7B176A}.Release|Any CPU.Build.0 = Release|Any CPU - {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B16A32BE-D56A-9E9C-749D-4E242789DE8D}.Release|Any CPU.Build.0 = Release|Any CPU - {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3A3A938B-6B9B-BF6B-3430-8FCFE598934D}.Release|Any CPU.Build.0 = Release|Any CPU - {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1}.Release|Any CPU.Build.0 = Release|Any CPU - {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2}.Release|Any CPU.Build.0 = Release|Any CPU - {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F7B6686-4642-015C-A57F-3B6B19133FC6}.Release|Any CPU.Build.0 = Release|Any CPU - {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC}.Release|Any CPU.Build.0 = Release|Any CPU - {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93FCD064-F7CF-A864-AF81-7B0279D2FE26}.Release|Any CPU.Build.0 = Release|Any CPU - {4404C7F6-5CC2-4976-9303-F15492311054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4404C7F6-5CC2-4976-9303-F15492311054}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4404C7F6-5CC2-4976-9303-F15492311054}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4404C7F6-5CC2-4976-9303-F15492311054}.Release|Any CPU.Build.0 = Release|Any CPU - {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {40180EE9-83E1-5D11-C54B-B4EC49CF99F5}.Release|Any CPU.Build.0 = Release|Any CPU - {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A}.Release|Any CPU.Build.0 = Release|Any CPU - {768E99B5-13ED-FD75-6F50-C405A8775290}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {768E99B5-13ED-FD75-6F50-C405A8775290}.Debug|Any CPU.Build.0 = Debug|Any CPU - {768E99B5-13ED-FD75-6F50-C405A8775290}.Release|Any CPU.ActiveCfg = Release|Any CPU - {768E99B5-13ED-FD75-6F50-C405A8775290}.Release|Any CPU.Build.0 = Release|Any CPU - {68B12BA0-2B85-6085-3732-D180558B0A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68B12BA0-2B85-6085-3732-D180558B0A30}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68B12BA0-2B85-6085-3732-D180558B0A30}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68B12BA0-2B85-6085-3732-D180558B0A30}.Release|Any CPU.Build.0 = Release|Any CPU - {CFE88035-0880-AD6F-D44C-077C99BDA355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CFE88035-0880-AD6F-D44C-077C99BDA355}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CFE88035-0880-AD6F-D44C-077C99BDA355}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CFE88035-0880-AD6F-D44C-077C99BDA355}.Release|Any CPU.Build.0 = Release|Any CPU - {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01}.Release|Any CPU.Build.0 = Release|Any CPU - {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A}.Release|Any CPU.Build.0 = Release|Any CPU - {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BF1F4B6C-CB98-C09E-5557-E99D03A86A22}.Release|Any CPU.Build.0 = Release|Any CPU - {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4}.Release|Any CPU.Build.0 = Release|Any CPU - {D3640F80-32DA-60DA-71A0-597803DD445D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3640F80-32DA-60DA-71A0-597803DD445D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3640F80-32DA-60DA-71A0-597803DD445D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3640F80-32DA-60DA-71A0-597803DD445D}.Release|Any CPU.Build.0 = Release|Any CPU - {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A}.Release|Any CPU.Build.0 = Release|Any CPU - {A0856948-B184-BAE9-A350-7D0356997560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0856948-B184-BAE9-A350-7D0356997560}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0856948-B184-BAE9-A350-7D0356997560}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0856948-B184-BAE9-A350-7D0356997560}.Release|Any CPU.Build.0 = Release|Any CPU - {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B}.Release|Any CPU.Build.0 = Release|Any CPU - {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FBD86DBD-0A64-99A1-E878-47DD4C531AC5}.Release|Any CPU.Build.0 = Release|Any CPU - {8449212A-9AC0-1C23-9419-1704158E7FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8449212A-9AC0-1C23-9419-1704158E7FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8449212A-9AC0-1C23-9419-1704158E7FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8449212A-9AC0-1C23-9419-1704158E7FF6}.Release|Any CPU.Build.0 = Release|Any CPU - {27567BB5-7E42-3103-ABAB-EE445E03396B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27567BB5-7E42-3103-ABAB-EE445E03396B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27567BB5-7E42-3103-ABAB-EE445E03396B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27567BB5-7E42-3103-ABAB-EE445E03396B}.Release|Any CPU.Build.0 = Release|Any CPU - {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB}.Release|Any CPU.Build.0 = Release|Any CPU - {E64D52DF-C601-E477-27FC-3198FA90777E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E64D52DF-C601-E477-27FC-3198FA90777E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E64D52DF-C601-E477-27FC-3198FA90777E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E64D52DF-C601-E477-27FC-3198FA90777E}.Release|Any CPU.Build.0 = Release|Any CPU - {B765E74F-BDF8-CBB7-1D12-40038265E480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B765E74F-BDF8-CBB7-1D12-40038265E480}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B765E74F-BDF8-CBB7-1D12-40038265E480}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B765E74F-BDF8-CBB7-1D12-40038265E480}.Release|Any CPU.Build.0 = Release|Any CPU - {238511B1-0953-42E1-2665-03075F55B4C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {238511B1-0953-42E1-2665-03075F55B4C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {238511B1-0953-42E1-2665-03075F55B4C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {238511B1-0953-42E1-2665-03075F55B4C9}.Release|Any CPU.Build.0 = Release|Any CPU - {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE}.Release|Any CPU.Build.0 = Release|Any CPU - {1769A2A8-3156-9348-12BF-CFEF8253810B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1769A2A8-3156-9348-12BF-CFEF8253810B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1769A2A8-3156-9348-12BF-CFEF8253810B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1769A2A8-3156-9348-12BF-CFEF8253810B}.Release|Any CPU.Build.0 = Release|Any CPU - {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0B694916-575C-00C4-9F31-8CB2A7BB6A83}.Release|Any CPU.Build.0 = Release|Any CPU - {DF706532-E516-E7E3-A823-29DDF30A0D96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF706532-E516-E7E3-A823-29DDF30A0D96}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF706532-E516-E7E3-A823-29DDF30A0D96}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF706532-E516-E7E3-A823-29DDF30A0D96}.Release|Any CPU.Build.0 = Release|Any CPU - {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0C632D98-F35E-CF99-ADB5-D9828968BEBA}.Release|Any CPU.Build.0 = Release|Any CPU - {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4D3743E-EFF0-9493-9F35-92D4F3408988}.Release|Any CPU.Build.0 = Release|Any CPU - {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DFE4C60B-C995-4805-9E8A-FA271DA09F50}.Release|Any CPU.Build.0 = Release|Any CPU - {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E0F37FA3-A10A-347C-0188-D7C3473413CE}.Release|Any CPU.Build.0 = Release|Any CPU - {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Debug|Any CPU.Build.0 = Debug|Any CPU - {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Release|Any CPU.ActiveCfg = Release|Any CPU - {75D6DE58-7A99-17D2-F6AD-6530795A1246}.Release|Any CPU.Build.0 = Release|Any CPU - {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0}.Release|Any CPU.Build.0 = Release|Any CPU - {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8}.Release|Any CPU.Build.0 = Release|Any CPU - {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B4228F0C-BBD4-119D-17C0-51DAC508639A}.Release|Any CPU.Build.0 = Release|Any CPU - {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE}.Release|Any CPU.Build.0 = Release|Any CPU - {9F1D5A80-2432-664A-6B6E-5840074FE627}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9F1D5A80-2432-664A-6B6E-5840074FE627}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9F1D5A80-2432-664A-6B6E-5840074FE627}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9F1D5A80-2432-664A-6B6E-5840074FE627}.Release|Any CPU.Build.0 = Release|Any CPU - {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095}.Release|Any CPU.Build.0 = Release|Any CPU - {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE}.Release|Any CPU.Build.0 = Release|Any CPU - {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D}.Release|Any CPU.Build.0 = Release|Any CPU - {727DD935-998F-9913-8FBD-FE4A5B432128}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {727DD935-998F-9913-8FBD-FE4A5B432128}.Debug|Any CPU.Build.0 = Debug|Any CPU - {727DD935-998F-9913-8FBD-FE4A5B432128}.Release|Any CPU.ActiveCfg = Release|Any CPU - {727DD935-998F-9913-8FBD-FE4A5B432128}.Release|Any CPU.Build.0 = Release|Any CPU - {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DA14FF81-99FE-473B-494D-C9B24CADF75F}.Release|Any CPU.Build.0 = Release|Any CPU - {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6172CFDC-4569-72AE-E6BD-8E78C823663C}.Release|Any CPU.Build.0 = Release|Any CPU - {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD}.Release|Any CPU.Build.0 = Release|Any CPU - {457256C7-C69D-CB30-B416-A1D2251589CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {457256C7-C69D-CB30-B416-A1D2251589CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {457256C7-C69D-CB30-B416-A1D2251589CE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {457256C7-C69D-CB30-B416-A1D2251589CE}.Release|Any CPU.Build.0 = Release|Any CPU - {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3D6B5FC5-8F10-2423-957F-AD16AAAFD095}.Release|Any CPU.Build.0 = Release|Any CPU - {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E42DE0F-D93C-1031-9934-C82692D0FBD1}.Release|Any CPU.Build.0 = Release|Any CPU - {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5DC94B97-BB49-E636-DA76-837BC3E45CAC}.Release|Any CPU.Build.0 = Release|Any CPU - {42506E08-3D7E-93FC-870F-2D4E534B1082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42506E08-3D7E-93FC-870F-2D4E534B1082}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42506E08-3D7E-93FC-870F-2D4E534B1082}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42506E08-3D7E-93FC-870F-2D4E534B1082}.Release|Any CPU.Build.0 = Release|Any CPU - {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C6EB51E-F0D8-6394-1828-8E542204F9BF}.Release|Any CPU.Build.0 = Release|Any CPU - {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Debug|Any CPU.Build.0 = Debug|Any CPU - {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Release|Any CPU.ActiveCfg = Release|Any CPU - {525682E4-E7EF-CDB3-54BA-15A5FAF76C20}.Release|Any CPU.Build.0 = Release|Any CPU - {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {35B76447-4D36-699C-7CC9-DFD02E9F5D1F}.Release|Any CPU.Build.0 = Release|Any CPU - {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0893E83F-92C8-B58B-800D-F13CEEEF0DC5}.Release|Any CPU.Build.0 = Release|Any CPU - {6D933A4A-780F-8549-1800-E2F343480EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6D933A4A-780F-8549-1800-E2F343480EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6D933A4A-780F-8549-1800-E2F343480EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6D933A4A-780F-8549-1800-E2F343480EDF}.Release|Any CPU.Build.0 = Release|Any CPU - {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {715C0753-B773-9A0B-10D0-33849C0F3E4E}.Release|Any CPU.Build.0 = Release|Any CPU - {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC}.Release|Any CPU.Build.0 = Release|Any CPU - {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B3E8FD8D-CBA4-0436-C845-FE02743185E5}.Release|Any CPU.Build.0 = Release|Any CPU - {768B75FC-7160-A313-FE51-2CBC8653D220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {768B75FC-7160-A313-FE51-2CBC8653D220}.Debug|Any CPU.Build.0 = Debug|Any CPU - {768B75FC-7160-A313-FE51-2CBC8653D220}.Release|Any CPU.ActiveCfg = Release|Any CPU - {768B75FC-7160-A313-FE51-2CBC8653D220}.Release|Any CPU.Build.0 = Release|Any CPU - {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5EDAB414-D5C7-C371-0072-E4B830BD9323}.Release|Any CPU.Build.0 = Release|Any CPU - {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A}.Release|Any CPU.Build.0 = Release|Any CPU - {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E}.Release|Any CPU.Build.0 = Release|Any CPU - {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {440A73BE-3FBC-C528-5525-9DAACD46A20E}.Release|Any CPU.Build.0 = Release|Any CPU - {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {224021DB-7DE8-D6BF-518A-CF72484B86DA}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {1B7ECFD9-BE5D-0D1E-1D37-D32D064ED555} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {2A14DF20-5AB3-1179-FC14-9080EA92BEB6} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {1014F3DD-0BE0-D671-9FD8-9856A8079ED2} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {D329680A-AD3B-E6C7-7233-126E58F9E849} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {1C232EA2-92C2-B4A7-2A45-C8737833D336} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {17F916F3-6AE7-3919-6783-41A493640905} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {7BE0E0DB-8690-5EF9-3850-D9F963ACA2CC} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {ED9E7E0B-F427-5E63-4714-DEE3BA5BB6F3} = {07C2787E-EAC7-C090-1BA3-A61EC2A24D84} - {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {B04919A0-AAE2-B19C-510C-47A0F6F2A2CF} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {BED99755-9E24-3619-2001-B8CEAC9A0162} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {AAD08A18-3633-D9ED-D7ED-E21398FEEC9E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {55B87E2E-B2C5-0727-32DB-B763F3A0DF64} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {9AD734C0-4406-86B8-7A07-AF402C4BC872} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {75168EF2-3375-63A0-8189-C73C353BCBBA} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {88022C29-F01F-F535-C955-266A5717AAA7} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {3B3D25CF-720F-2BBC-082D-A631E11F3110} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {44B6CBE5-CE0B-B340-32A6-8A7A4E8B3E5E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {3A2A1313-1831-EFA6-55AB-63849438C2F6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {C9605351-FFFC-3C08-536C-0E6D7FF8E3E1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {A7441955-29AB-E120-B317-283D764FCC32} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {C7800CB2-A20F-AD1F-26F9-BFBB79444AB7} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {09251FE2-4416-153E-5E74-DAB63C4ECE64} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {78B156EC-E3B6-C57D-9590-225D80F3580F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {E2EAC1B9-0D62-2F3F-93EC-32FF54881A5E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {9620BCE5-17BE-6D11-84F6-444EAE405CFB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {360F1ABD-E146-A345-E84B-8A116CDB7E09} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {94337465-6C6A-E8C6-0240-4AAEF5F1DB59} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {4B7F5DB5-7915-076F-8215-FF2C7582E01B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {775903B4-09D4-4B2C-1404-BD5FCEEE494E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {225AEDBE-A716-7BE8-985F-2B95C1B1DAEB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {8567273B-1AE0-F3D0-85BD-70A1E8F5A790} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {8E7A44D0-9E4D-BA3D-4C59-D602789529E1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B2CD5C68-9C0E-1A23-9BED-6A9F6B588CCB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B57166AD-FBF2-E511-63E6-BD4F293E3246} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {A25B49E8-A1E2-08EB-90AD-95245686E358} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {C63A6F56-F3BB-5498-43F7-3AC6EADAFFE3} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {6329D269-4E17-3139-CF5D-EBD992B71872} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {29C4EE8E-9B44-B86B-CC77-69F7BF4EE7E2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {BC5973AF-BBE7-C9B7-BFDD-50AC1791DC18} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {7DC09A9C-66CF-7E91-0C8D-8837AC2CD45F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {7A0014A3-8EE5-7EF6-D6E2-E2A21D8C3913} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {456816E9-79F5-A888-6A7F-FCAA00467883} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {4D578E4A-FEB5-9A18-1CE7-C509AF15DBBE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5962CFA9-CF7F-7789-1582-69D09A4A0FD2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {68E54CD1-B46E-7D40-A474-C2C8F013370B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {9AB29652-ED65-E8EF-2E5B-A03CE514A10A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {D154BF10-9EE8-F073-F612-439DEA9180B2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {D31F4868-30A7-8B09-C07C-4F9258780385} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {A8846A27-965F-3743-7869-431B907D82C0} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B3C4059A-D7EC-2E83-900D-E47A259529CC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {8C96A8BB-30D6-F809-9986-0E54A630CE99} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {E5254223-630A-4FCA-89F4-191E00B749D9} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5E1BDE6B-0FEB-F517-B482-7C752DD9D423} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {EFB878C7-A53F-DB6F-4DB4-4C198F205F05} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5E3DD2DD-63E4-9617-51AD-BE7466B4F867} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5847C513-37B3-F70B-3AB7-D2E33F7D8DA2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {708142F8-D31F-2590-74CF-1CB6356373EB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {EE10DB5B-4BFB-2694-56C7-AA734D9998DE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {EEFAF207-DCC9-F2B3-5AB9-36D1DE6DF8B7} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {4E6AA273-973F-C518-09DE-0B32F1013D10} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5F0D46F0-3751-F3B5-299D-3A5E96078D2E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {C23508FE-F0DD-D646-A330-179199A8C2F9} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {86BEDF9F-4F25-6EC0-4D0E-103E3485DE27} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {6587AB0F-0ACF-1281-5AEF-3BA3E639A969} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {215F234F-E057-6B91-E0E4-D92776FC15B4} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5E096865-7E69-538A-6E99-F3F0F699CF2A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {CFDE18B2-7A61-5037-2C32-EFEED4F63364} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {C8082A2D-57EA-055F-A87C-45023FCFD3F6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {A3525B69-C2B0-0CE9-1F86-61CDD9889216} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {61DE83D6-6284-D448-E008-7039ED5E5BC0} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {9C00290D-F421-9468-9833-4FFCDD2EFE8C} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {7351A2A2-E03C-39D3-F575-6D2755A23CC5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {E8556F3C-C41E-8112-EE7D-5B074CE2EDC6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {D7A91A55-0BFA-5077-D80E-1F47396E1C6A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {02552470-3D09-742C-15A0-03448C7B176A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B16A32BE-D56A-9E9C-749D-4E242789DE8D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {3A3A938B-6B9B-BF6B-3430-8FCFE598934D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {1EC1FCAE-762F-0185-186F-62B1AE8DDFA1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B5337686-41E6-7BA6-71A1-F4F1FABEA6D2} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5F7B6686-4642-015C-A57F-3B6B19133FC6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {68F8F775-6C70-5B24-8C07-6A0B7D4CB8AC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {93FCD064-F7CF-A864-AF81-7B0279D2FE26} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {4404C7F6-5CC2-4976-9303-F15492311054} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {40180EE9-83E1-5D11-C54B-B4EC49CF99F5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {C694008E-E386-ACD8-0DFF-0BDA5A99ED4A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {768E99B5-13ED-FD75-6F50-C405A8775290} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {68B12BA0-2B85-6085-3732-D180558B0A30} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {CFE88035-0880-AD6F-D44C-077C99BDA355} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {BA266543-4B0A-7FA2-05E9-DD26C9D9BF01} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {7F0CD4C7-C362-BEC9-1863-1C490F4EAF1A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {BF1F4B6C-CB98-C09E-5557-E99D03A86A22} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {6B778BE1-DF03-DCDC-2AA8-EF7F2DAA54D4} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {D3640F80-32DA-60DA-71A0-597803DD445D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {7CC9CB54-BD17-C67B-689C-DDB4BDA77A1A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {A0856948-B184-BAE9-A350-7D0356997560} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B5A7A3FE-372A-387C-9E3D-7FD86D59A60B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {FBD86DBD-0A64-99A1-E878-47DD4C531AC5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {8449212A-9AC0-1C23-9419-1704158E7FF6} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {27567BB5-7E42-3103-ABAB-EE445E03396B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {BAE7BDB0-2B4F-E9A9-C6D9-930EB11AADBB} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {E64D52DF-C601-E477-27FC-3198FA90777E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B765E74F-BDF8-CBB7-1D12-40038265E480} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {238511B1-0953-42E1-2665-03075F55B4C9} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {49B4BC81-EF44-17AB-BF05-D4C7AC487DEE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {1769A2A8-3156-9348-12BF-CFEF8253810B} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {0B694916-575C-00C4-9F31-8CB2A7BB6A83} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {DF706532-E516-E7E3-A823-29DDF30A0D96} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {0C632D98-F35E-CF99-ADB5-D9828968BEBA} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {E4D3743E-EFF0-9493-9F35-92D4F3408988} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {DFE4C60B-C995-4805-9E8A-FA271DA09F50} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {E0F37FA3-A10A-347C-0188-D7C3473413CE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {75D6DE58-7A99-17D2-F6AD-6530795A1246} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {9DE6F509-32E2-8A35-DA06-42F03B4CCCB0} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {67B41B28-C7A7-EF7B-F15B-EDBB60755CA8} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B4228F0C-BBD4-119D-17C0-51DAC508639A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {AA14F2AD-3E07-1951-1DE0-02D3FF0A47DE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {9F1D5A80-2432-664A-6B6E-5840074FE627} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {4A3A6DB4-1A19-AFA3-F925-C1A1A5AD0095} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {625C049B-B9FF-BEC6-B5AB-C50544F1BEEE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {90DA9361-D1ED-4DF0-FBF9-3A7B8FAD811D} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {727DD935-998F-9913-8FBD-FE4A5B432128} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {DA14FF81-99FE-473B-494D-C9B24CADF75F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {6172CFDC-4569-72AE-E6BD-8E78C823663C} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {E131277E-1BE6-A8BE-E41B-D3CFA23C21CD} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {457256C7-C69D-CB30-B416-A1D2251589CE} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {3D6B5FC5-8F10-2423-957F-AD16AAAFD095} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {8E42DE0F-D93C-1031-9934-C82692D0FBD1} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5DC94B97-BB49-E636-DA76-837BC3E45CAC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {42506E08-3D7E-93FC-870F-2D4E534B1082} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {4C6EB51E-F0D8-6394-1828-8E542204F9BF} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {525682E4-E7EF-CDB3-54BA-15A5FAF76C20} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {35B76447-4D36-699C-7CC9-DFD02E9F5D1F} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {0893E83F-92C8-B58B-800D-F13CEEEF0DC5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {6D933A4A-780F-8549-1800-E2F343480EDF} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {715C0753-B773-9A0B-10D0-33849C0F3E4E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {1D3394C5-4891-5EFC-04E5-F77F17A1B0AC} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {B3E8FD8D-CBA4-0436-C845-FE02743185E5} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {768B75FC-7160-A313-FE51-2CBC8653D220} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {5EDAB414-D5C7-C371-0072-E4B830BD9323} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {3DB99F46-2EF8-C0C4-EA68-A0615C19DA9A} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {8F853ACE-C534-4C8B-4F53-8AE7CDC2BE4E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {440A73BE-3FBC-C528-5525-9DAACD46A20E} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - {224021DB-7DE8-D6BF-518A-CF72484B86DA} = {FBCB8DBD-CDF2-6977-D18F-5F93DC702250} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {F033E9E3-6C80-4B3B-98A3-62F97328FDDA} - EndGlobalSection -EndGlobal diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 4617d1521da..908dc543aed 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -288,6 +288,11 @@ private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHead return false; } + if( block.Header.TotalDifficulty != null && !_blockTree.IsBetterThanHead(block.Header)){ + error = $"Block {block.Header.Hash} is not better than head {_blockTree.Head?.Hash}"; + return false; + } + long calculatedGasLimit = GetGasLimit(parentHeader, registerGasLimit); if (calculatedGasLimit != block.Header.GasLimit) From 3d983cb5a15fdb30598f9be83792f4aae9300cd5 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 14 Feb 2025 17:22:03 +0530 Subject: [PATCH 110/113] format files --- .../Handlers/ValidateBuilderSubmissionHandler.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs index 908dc543aed..1b189728521 100644 --- a/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs +++ b/src/Nethermind/Nethermind.Flashbots/Handlers/ValidateBuilderSubmissionHandler.cs @@ -288,7 +288,8 @@ private bool ValidateBlockMetadata(Block block, long registerGasLimit, BlockHead return false; } - if( block.Header.TotalDifficulty != null && !_blockTree.IsBetterThanHead(block.Header)){ + if (block.Header.TotalDifficulty != null && !_blockTree.IsBetterThanHead(block.Header)) + { error = $"Block {block.Header.Hash} is not better than head {_blockTree.Head?.Hash}"; return false; } From ad624447f6979745713fbecf77024a8951368c1e Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 17 Feb 2025 13:19:58 +0530 Subject: [PATCH 111/113] add filter logging json RPC endpoint --- .../Nethermind.Flashbots.Test/FlashbotsModuleTests.cs | 8 ++++---- src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index bd6a9b5d176..0714fd90983 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -59,7 +59,7 @@ public virtual async Task TestValidateBuilderSubmissionV3() ResultWrapper result = await rpc.flashbots_validateBuilderSubmissionV3(BlockRequest); result.Should().NotBeNull(); - Assert.That(result.Result, Is.EqualTo(Result.Success)); + // Assert.That(result.Result, Is.EqualTo(Result.Success)); // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateBuilderSubmissionV3", BlockRequest); @@ -71,7 +71,7 @@ private Block CreateBlock(MergeTestBlockChain chain) { BlockHeader currentHeader = chain.BlockTree.Head.Header; IWorldState State = chain.State; - + State.CreateAccount(TestKeysAndAddress.TestAddr, TestKeysAndAddress.TestBalance); UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(TestKeysAndAddress.TestBuilderAddr).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; @@ -93,7 +93,7 @@ private Block CreateBlock(MergeTestBlockChain chain) ulong timestamp = Timestamper.UnixTime.Seconds; Hash256 prevRandao = Keccak.Zero; - Hash256 expectedBlockHash = new("0xf823a4118e778834c2d31e9199d9cd1323ed62f0d14268efe5b9518f7157a17e"); + Hash256 expectedBlockHash = new("0xd8f631517e9f336a3c13997786e874e17e7859fc95eddc1359226c0b8d71a307"); string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; return new( @@ -104,7 +104,7 @@ private Block CreateBlock(MergeTestBlockChain chain) UInt256.Zero, 1, chain.BlockTree.Head!.GasLimit, - timestamp, + currentHeader.Timestamp + 12, Bytes.FromHexString("0x4e65746865726d696e64") // Nethermind ) { diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs index 7bd2761f14a..3ce4ed4cbfc 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs @@ -56,7 +56,8 @@ public string[] EnabledModules "engine_newPayloadV2", "engine_newPayloadV3", "engine_forkchoiceUpdatedV1", - "engine_forkchoiceUpdatedV2" + "engine_forkchoiceUpdatedV2", + "flashbots_validateBuilderSubmissionV3" }; public string EngineHost { get; set; } = "127.0.0.1"; public int? EnginePort { get; set; } = null; From ef29584c30514fbb4790173e1eb201472a959fc6 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 17 Feb 2025 13:29:53 +0530 Subject: [PATCH 112/113] fix failing tests --- src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs index b9389ec4ccd..f48eda1fff3 100644 --- a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs @@ -141,7 +141,7 @@ public interface IJsonRpcConfig : IConfig [ConfigItem( Description = "An array of the method names not to log.", - DefaultValue = "[engine_newPayloadV1,engine_newPayloadV2,engine_newPayloadV3,engine_forkchoiceUpdatedV1,engine_forkchoiceUpdatedV2]")] + DefaultValue = "[engine_newPayloadV1,engine_newPayloadV2,engine_newPayloadV3,engine_forkchoiceUpdatedV1,engine_forkchoiceUpdatedV2,flashbots_validateBuilderSubmissionV3]")] public string[]? MethodsLoggingFiltering { get; set; } [ConfigItem(Description = "The Engine API host.", DefaultValue = "127.0.0.1")] From 42e1af36eb123fc6a64f99e66f0bab057700ae56 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Mon, 17 Feb 2025 19:18:30 +0530 Subject: [PATCH 113/113] refactor tests --- .../FlashbotsModuleTests.Setup.cs | 185 ++---------------- .../FlashbotsModuleTests.cs | 27 +-- .../Nethermind.Flashbots/Flashbots.cs | 3 +- 3 files changed, 28 insertions(+), 187 deletions(-) diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs index 621e0786c44..bc9cf08be4c 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.Setup.cs @@ -1,36 +1,19 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; -using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; -using Nethermind.Blockchain.BeaconBlockRoot; -using Nethermind.Blockchain.Blocks; -using Nethermind.Blockchain.Synchronization; -using Nethermind.Consensus; -using Nethermind.Consensus.Processing; -using Nethermind.Consensus.Rewards; -using Nethermind.Consensus.Validators; -using Nethermind.Consensus.Withdrawals; using Nethermind.Core; -using Nethermind.Core.Crypto; -using Nethermind.Core.Extensions; -using Nethermind.Core.Specs; -using Nethermind.Core.Test.Blockchain; using Nethermind.Crypto; -using Nethermind.Db; -using Nethermind.Evm.Tracing; -using Nethermind.Flashbots; using Nethermind.Flashbots.Handlers; using Nethermind.Flashbots.Modules.Flashbots; using Nethermind.Int256; -using Nethermind.Logging; -using Nethermind.Merge.Plugin; -using Nethermind.Specs; -using Nethermind.Specs.ChainSpecStyle; -using Nethermind.Specs.Forks; using NUnit.Framework; +using Nethermind.Merge.Plugin.Test; +using Nethermind.Specs.Forks; +using Nethermind.Specs; +using Nethermind.Consensus.Processing; +using Nethermind.Core.Specs; +using Nethermind.Core.Extensions; namespace Nethermind.Flashbots.Test; @@ -67,20 +50,22 @@ public TestKeyAndAddress() } } - protected virtual MergeTestBlockChain CreateBaseBlockChain( - IFlashbotsConfig flashbotsConfig, - ILogManager? logManager = null) + public ReadOnlyTxProcessingEnvFactory CreateReadOnlyTxProcessingEnvFactory(EngineModuleTests.MergeTestBlockchain chain) { - return new MergeTestBlockChain(flashbotsConfig, logManager); + ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = new( + chain.WorldStateManager, + chain.BlockTree, + chain.SpecProvider, + chain.LogManager + ); + return readOnlyTxProcessingEnvFactory; } - protected async Task CreateBlockChain( - IReleaseSpec? releaseSpec = null, - IFlashbotsConfig? flashbotsConfig = null, - ILogManager? logManager = null) - => await CreateBaseBlockChain(flashbotsConfig ?? new FlashbotsConfig(), logManager).Build(new TestSingleReleaseSpecProvider(releaseSpec ?? London.Instance)); + protected static async Task CreateBlockChain( + IReleaseSpec? releaseSpec = null) + => await new EngineModuleTests.MergeTestBlockchain().Build(new TestSingleReleaseSpecProvider(releaseSpec ?? London.Instance)); - private IFlashbotsRpcModule CreateFlashbotsModule(MergeTestBlockChain chain, ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory) + private IFlashbotsRpcModule CreateFlashbotsModule(EngineModuleTests.MergeTestBlockchain chain, ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory) { return new FlashbotsRpcModule( new ValidateSubmissionHandler( @@ -90,140 +75,8 @@ private IFlashbotsRpcModule CreateFlashbotsModule(MergeTestBlockChain chain, Rea readOnlyTxProcessingEnvFactory, chain.LogManager, chain.SpecProvider, - chain.FlashbotsConfig + new FlashbotsConfig() ) ); } - - public class MergeTestBlockChain : TestBlockchain - { - public IFlashbotsConfig FlashbotsConfig; - - public IMergeConfig MergeConfig; - - public IWithdrawalProcessor? WithdrawalProcessor { get; set; } - - public ReadOnlyTxProcessingEnvFactory ReadOnlyTxProcessingEnvFactory { get; set; } - - public MergeTestBlockChain(IFlashbotsConfig flashbotsConfig, ILogManager? logManager = null) - { - FlashbotsConfig = flashbotsConfig; - MergeConfig = new MergeConfig() { TerminalTotalDifficulty = "0" }; - LogManager = logManager ?? LogManager; - } - - public sealed override ILogManager LogManager { get; set; } = LimboLogs.Instance; - - public ReadOnlyTxProcessingEnvFactory CreateReadOnlyTxProcessingEnvFactory() - { - ReadOnlyTxProcessingEnvFactory = new ReadOnlyTxProcessingEnvFactory( - WorldStateManager, - BlockTree, - SpecProvider, - LogManager - ); - return ReadOnlyTxProcessingEnvFactory; - } - - protected override IBlockProcessor CreateBlockProcessor() - { - BlockValidator = CreateBlockValidator(); - WithdrawalProcessor = new WithdrawalProcessor(State, LogManager); - IBlockProcessor processor = new BlockProcessor( - SpecProvider, - BlockValidator, - NoBlockRewards.Instance, - new BlockProcessor.BlockValidationTransactionsExecutor(TxProcessor, State), - State, - ReceiptStorage, - TxProcessor, - new BeaconBlockRootHandler(TxProcessor, State), - new BlockhashStore(SpecProvider, State), - LogManager, - WithdrawalProcessor, - preWarmer: CreateBlockCachePreWarmer() - ); - - return new TestBlockProcessorInterceptor(processor); - } - - protected IBlockValidator CreateBlockValidator() - { - PoSSwitcher = new PoSSwitcher(MergeConfig, SyncConfig.Default, new MemDb(), BlockTree, SpecProvider, new ChainSpec() { Genesis = Core.Test.Builders.Build.A.Block.WithDifficulty(0).TestObject }, LogManager); - ISealValidator SealValidator = new MergeSealValidator(PoSSwitcher, Always.Valid); - HeaderValidator = new MergeHeaderValidator( - PoSSwitcher, - new HeaderValidator(BlockTree, SealValidator, SpecProvider, LogManager), - BlockTree, - SpecProvider, - SealValidator, - LogManager - ); - - return new BlockValidator( - new TxValidator(SpecProvider.ChainId), - HeaderValidator, - Always.Valid, - SpecProvider, - LogManager - ); - } - - protected override async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) - { - TestBlockchain chain = await base.Build(specProvider, initialValues, false); - return chain; - } - - public async Task Build(ISpecProvider? specProvider = null) => - (MergeTestBlockChain)await Build(specProvider, null); - - } -} - -public class TestBlockProcessorInterceptor : IBlockProcessor -{ - private readonly IBlockProcessor _blockProcessorImplementation; - public Exception? ExceptionToThrow { get; set; } - - public TestBlockProcessorInterceptor(IBlockProcessor baseBlockProcessor) - { - _blockProcessorImplementation = baseBlockProcessor; - } - - public Block[] Process(Hash256 newBranchStateRoot, List suggestedBlocks, ProcessingOptions processingOptions, - IBlockTracer blockTracer) - { - - if (ExceptionToThrow is not null) - { - throw ExceptionToThrow; - } - - return _blockProcessorImplementation.Process(newBranchStateRoot, suggestedBlocks, processingOptions, blockTracer); - } - - public event EventHandler? BlocksProcessing - { - add => _blockProcessorImplementation.BlocksProcessing += value; - remove => _blockProcessorImplementation.BlocksProcessing -= value; - } - - public event EventHandler? BlockProcessing - { - add => _blockProcessorImplementation.BlockProcessing += value; - remove => _blockProcessorImplementation.BlockProcessing -= value; - } - - public event EventHandler? BlockProcessed - { - add => _blockProcessorImplementation.BlockProcessed += value; - remove => _blockProcessorImplementation.BlockProcessed -= value; - } - - public event EventHandler? TransactionProcessed - { - add => _blockProcessorImplementation.TransactionProcessed += value; - remove => _blockProcessorImplementation.TransactionProcessed -= value; - } } diff --git a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs index 0714fd90983..11c02ce5b82 100644 --- a/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs +++ b/src/Nethermind/Nethermind.Flashbots.Test/FlashbotsModuleTests.cs @@ -16,6 +16,7 @@ using Nethermind.JsonRpc; using Nethermind.JsonRpc.Test; using Nethermind.Merge.Plugin.Data; +using Nethermind.Merge.Plugin.Test; using Nethermind.Specs.Forks; using Nethermind.State; using NUnit.Framework; @@ -30,8 +31,8 @@ public partial class FlashbotsModuleTests [Test] public virtual async Task TestValidateBuilderSubmissionV3() { - using MergeTestBlockChain chain = await CreateBlockChain(releaseSpec: Cancun.Instance); - ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = chain.CreateReadOnlyTxProcessingEnvFactory(); + using EngineModuleTests.MergeTestBlockchain chain = await CreateBlockChain(releaseSpec: Cancun.Instance); + ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = CreateReadOnlyTxProcessingEnvFactory(chain); IFlashbotsRpcModule rpc = CreateFlashbotsModule(chain, readOnlyTxProcessingEnvFactory); Block block = CreateBlock(chain); @@ -59,41 +60,29 @@ public virtual async Task TestValidateBuilderSubmissionV3() ResultWrapper result = await rpc.flashbots_validateBuilderSubmissionV3(BlockRequest); result.Should().NotBeNull(); - // Assert.That(result.Result, Is.EqualTo(Result.Success)); - // Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Valid)); + Assert.That(result.Result.Error, Is.EqualTo("No proposer payment receipt")); + Assert.That(result.Data.Status, Is.EqualTo(FlashbotsStatus.Invalid)); string response = await RpcTest.TestSerializedRequest(rpc, "flashbots_validateBuilderSubmissionV3", BlockRequest); JsonRpcSuccessResponse? jsonResponse = chain.JsonSerializer.Deserialize(response); jsonResponse.Should().NotBeNull(); } - private Block CreateBlock(MergeTestBlockChain chain) + private Block CreateBlock(EngineModuleTests.MergeTestBlockchain chain) { BlockHeader currentHeader = chain.BlockTree.Head.Header; IWorldState State = chain.State; State.CreateAccount(TestKeysAndAddress.TestAddr, TestKeysAndAddress.TestBalance); UInt256 nonce = State.GetNonce(TestKeysAndAddress.TestAddr); - Transaction tx1 = Build.A.Transaction.WithNonce(nonce).WithTo(TestKeysAndAddress.TestBuilderAddr).WithValue(10).WithGasLimit(21000).WithGasPrice(TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; - chain.TxPool.SubmitTx(tx1, TxPool.TxHandlingOptions.None); - - Transaction tx2 = Build.A.Transaction.WithNonce(nonce + 1).WithValue(0).WithGasLimit(1000000).WithGasPrice(2 * TestKeysAndAddress.BaseInitialFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; - chain.TxPool.SubmitTx(tx2, TxPool.TxHandlingOptions.None); - - UInt256 baseFee = BaseFeeCalculator.Calculate(currentHeader, chain.SpecProvider.GetFinalSpec()); - - Transaction tx3 = Build.A.Transaction.WithNonce(nonce + 2).WithValue(10).WithGasLimit(21000).WithValue(baseFee).Signed(TestKeysAndAddress.PrivateKey).TestObject; - chain.TxPool.SubmitTx(tx3, TxPool.TxHandlingOptions.None); - Withdrawal[] withdrawals = [ Build.A.Withdrawal.WithIndex(0).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject, Build.A.Withdrawal.WithIndex(1).WithValidatorIndex(1).WithAmount(100).WithRecipient(TestKeysAndAddress.TestAddr).TestObject ]; - ulong timestamp = Timestamper.UnixTime.Seconds; Hash256 prevRandao = Keccak.Zero; - Hash256 expectedBlockHash = new("0xd8f631517e9f336a3c13997786e874e17e7859fc95eddc1359226c0b8d71a307"); + Hash256 expectedBlockHash = new("0x479f7c9b7389e9ff3f443b99c3cd4b90f9b7feef5f41d714edb59de6b3e7ac02"); string stateRoot = "0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154"; return new( @@ -119,7 +108,7 @@ private Block CreateBlock(MergeTestBlockChain chain) ReceiptsRoot = chain.BlockTree.Head!.ReceiptsRoot!, StateRoot = new(stateRoot), }, - [tx1, tx2, tx3], + [], Array.Empty(), withdrawals ); diff --git a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs index 33b42e61a0a..73faf9165da 100644 --- a/src/Nethermind/Nethermind.Flashbots/Flashbots.cs +++ b/src/Nethermind/Nethermind.Flashbots/Flashbots.cs @@ -27,6 +27,7 @@ public class Flashbots : INethermindPlugin public string Author => "Nethermind"; public Task InitRpcModules() { + ArgumentNullException.ThrowIfNull(_api.RpcModuleProvider); ReadOnlyTxProcessingEnvFactory readOnlyTxProcessingEnvFactory = new ReadOnlyTxProcessingEnvFactory( _api.WorldStateManager ?? throw new ArgumentNullException(nameof(_api.WorldStateManager)), _api.BlockTree ?? throw new ArgumentNullException(nameof(_api.BlockTree)), @@ -45,8 +46,6 @@ public Task InitRpcModules() ); ModuleFactoryBase flashbotsRpcModule = new FlashbotsRpcModuleFactory(validateSubmissionHandler); - - ArgumentNullException.ThrowIfNull(_api.RpcModuleProvider); _api.RpcModuleProvider.RegisterBounded(flashbotsRpcModule, _flashbotsConfig.FlashbotsModuleConcurrentInstances ?? Environment.ProcessorCount, _jsonRpcConfig.Timeout);