From d33add6f4768dcf08b287fda22ebdd1fcaad8a06 Mon Sep 17 00:00:00 2001 From: Rohit Ranjan Date: Fri, 16 Aug 2024 13:08:59 +0530 Subject: [PATCH 01/34] 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 02/34] 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 03/34] 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 04/34] 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 05/34] 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 06/34] 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 07/34] 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 08/34] 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 09/34] 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 10/34] 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 11/34] 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 12/34] 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 13/34] 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 14/34] 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 15/34] 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 16/34] 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 17/34] 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 18/34] 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 19/34] 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 20/34] 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 21/34] 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 22/34] 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 23/34] 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 24/34] 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 25/34] 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 26/34] 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 27/34] 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 28/34] 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 29/34] 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 30/34] 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 31/34] 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 32/34] 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 33/34] 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 34/34] 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!),