diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs index 36e20ca3f925..2c5cb0302855 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/BlockValidatorTests.cs @@ -189,41 +189,44 @@ private static IEnumerable BadSuggestedBlocks() BlockHeader parent = Build.A.BlockHeader.TestObject; yield return new TestCaseData( - Build.A.Block.WithHeader(Build.A.BlockHeader.WithParent(parent).WithUnclesHash(Keccak.Zero).TestObject).TestObject, - parent, - Substitute.For(), - "InvalidUnclesHash"); + Build.A.Block.WithHeader(Build.A.BlockHeader.WithParent(parent).WithUnclesHash(Keccak.Zero).TestObject) + .TestObject, + parent, + Substitute.For(), + "InvalidUnclesHash"); yield return new TestCaseData( - Build.A.Block.WithHeader(Build.A.BlockHeader.WithParent(parent).WithTransactionsRoot(Keccak.Zero).TestObject).TestObject, - parent, - Substitute.For(), - "InvalidTxRoot"); + Build.A.Block + .WithHeader(Build.A.BlockHeader.WithParent(parent).WithTransactionsRoot(Keccak.Zero).TestObject) + .TestObject, + parent, + Substitute.For(), + "InvalidTxRoot"); yield return new TestCaseData( - Build.A.Block.WithBlobGasUsed(131072) - .WithParent(parent) - .WithExcessBlobGas(1) - .WithTransactions( - Build.A.Transaction.WithShardBlobTxTypeAndFields(1) - .WithMaxFeePerBlobGas(0) - .WithMaxFeePerGas(1000000) - .Signed() - .TestObject) - .TestObject, - parent, - new CustomSpecProvider(((ForkActivation)0, Cancun.Instance)), - "InsufficientMaxFeePerBlobGas"); + Build.A.Block.WithBlobGasUsed(131072) + .WithParent(parent) + .WithExcessBlobGas(1) + .WithTransactions( + Build.A.Transaction.WithShardBlobTxTypeAndFields(1) + .WithMaxFeePerBlobGas(0) + .WithMaxFeePerGas(1000000) + .Signed() + .TestObject) + .TestObject, + parent, + new CustomSpecProvider(((ForkActivation)0, Cancun.Instance)), + "InsufficientMaxFeePerBlobGas"); yield return new TestCaseData( - Build.A.Block.WithParent(parent).WithEncodedSize(Eip7934Constants.DefaultMaxRlpBlockSize + 1).TestObject, - parent, - new CustomSpecProvider(((ForkActivation)0, Osaka.Instance)), - "ExceededBlockSizeLimit"); + Build.A.Block.WithParent(parent).WithEncodedSize(Eip7934Constants.DefaultMaxRlpBlockSize + 1).TestObject, + parent, + new CustomSpecProvider(((ForkActivation)0, Osaka.Instance)), + "ExceededBlockSizeLimit"); } [TestCaseSource(nameof(BadSuggestedBlocks))] - public void ValidateSuggestedBlock_SuggestedBlockIsInvalid_CorrectErrorIsSet(Block suggestedBlock, BlockHeader? parent, ISpecProvider specProvider, string expectedError) + public void ValidateSuggestedBlock_SuggestedBlockIsInvalid_CorrectErrorIsSet(Block suggestedBlock, BlockHeader parent, ISpecProvider specProvider, string expectedError) { TxValidator txValidator = new(TestBlockchainIds.ChainId); BlockValidator sut = new(txValidator, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs index cd3bb86fafbb..0d386ee72497 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs @@ -24,13 +24,14 @@ public static bool Blob_gas_fields_should_be_set(IReleaseSpec spec, ulong? blobG HeaderValidator headerValidator = new(Substitute.For(), Always.Valid, specProvider, TestLogManager.Instance); BlockValidator blockValidator = new(Always.Valid, headerValidator, Always.Valid, specProvider, TestLogManager.Instance); BlockHeader parent = Build.A.BlockHeader.TestObject; - return blockValidator.ValidateSuggestedBlock(Build.A.Block - .WithBlobGasUsed(blobGasUsed) - .WithExcessBlobGas(excessBlobGas) - .WithWithdrawalsRoot(TestItem.KeccakA) - .WithWithdrawals(TestItem.WithdrawalA_1Eth) - .WithParent(parent) - .TestObject, + return blockValidator.ValidateSuggestedBlock( + Build.A.Block + .WithBlobGasUsed(blobGasUsed) + .WithExcessBlobGas(excessBlobGas) + .WithWithdrawalsRoot(TestItem.KeccakA) + .WithWithdrawals(TestItem.WithdrawalA_1Eth) + .WithParent(parent) + .TestObject, parent, out _); } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TestBlockValidator.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TestBlockValidator.cs index 7dd052f35068..8e6848942d95 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TestBlockValidator.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TestBlockValidator.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Nethermind.Consensus.Validators; @@ -9,62 +8,23 @@ namespace Nethermind.Blockchain.Test.Validators; -public class TestBlockValidator : IBlockValidator +public class TestBlockValidator(bool suggestedValidationResult = true) : IBlockValidator { public static TestBlockValidator AlwaysValid = new(); - public static TestBlockValidator NeverValid = new(false, false); - private readonly Queue _processedValidationResults = null!; private readonly Queue _suggestedValidationResults = null!; - private readonly bool? _alwaysSameResultForProcessed; - private readonly bool? _alwaysSameResultForSuggested; + private readonly bool? _alwaysSameResultForSuggested = suggestedValidationResult; - public TestBlockValidator(bool suggestedValidationResult = true, bool processedValidationResult = true) - { - _alwaysSameResultForSuggested = suggestedValidationResult; - _alwaysSameResultForProcessed = processedValidationResult; - } - - public TestBlockValidator(Queue suggestedValidationResults, Queue processedValidationResults) - { - _suggestedValidationResults = suggestedValidationResults ?? throw new ArgumentNullException(nameof(suggestedValidationResults)); - _processedValidationResults = processedValidationResults ?? throw new ArgumentNullException(nameof(processedValidationResults)); - } - - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error) + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, [NotNullWhen(false)] out string? error) => Validate(out error); + public bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error) => Validate(out error); + public bool ValidateSuggestedBlock(Block block, BlockHeader parent, [NotNullWhen(false)] out string? error, bool validateHashes = true) => Validate(out error); + public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, [NotNullWhen(false)] out string? error) => Validate(out error); + public bool ValidateWithdrawals(Block block, out string? error) => Validate(out error); + public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) => Validate(out error); + public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? error) => Validate(out error); + private bool Validate(out string? error) { var result = _alwaysSameResultForSuggested ?? _suggestedValidationResults.Dequeue(); error = result ? null : ""; return result; } - - public bool ValidateSuggestedBlock(Block block, BlockHeader? parent, [NotNullWhen(false)] out string? error, bool validateHashes = true) - { - error = null; - return _alwaysSameResultForSuggested ?? _suggestedValidationResults.Dequeue(); - } - - public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, [NotNullWhen(false)] out string? error) - { - error = null; - return _alwaysSameResultForProcessed ?? _processedValidationResults.Dequeue(); - } - - public bool ValidateWithdrawals(Block block, out string? error) - { - error = null; - - return _alwaysSameResultForSuggested ?? _suggestedValidationResults.Dequeue(); - } - - public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) - { - error = null; - return _alwaysSameResultForSuggested ?? _suggestedValidationResults.Dequeue(); - } - - public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? errorMessage) - { - errorMessage = null; - return _alwaysSameResultForSuggested ?? _suggestedValidationResults.Dequeue(); - } } diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealValidator.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealValidator.cs index 02460496e112..18315e3080da 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealValidator.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliqueSealValidator.cs @@ -8,24 +8,21 @@ namespace Nethermind.Consensus.Clique { - internal class CliqueSealValidator : ISealValidator + internal class CliqueSealValidator( + ICliqueConfig cliqueConfig, + ISnapshotManager snapshotManager, + ILogManager logManager) + : ISealValidator { - private readonly ICliqueConfig _cliqueConfig; - private readonly ISnapshotManager _snapshotManager; - private readonly ILogger _logger; - - public CliqueSealValidator(ICliqueConfig cliqueConfig, ISnapshotManager snapshotManager, ILogManager logManager) - { - _cliqueConfig = cliqueConfig ?? throw new ArgumentNullException(nameof(cliqueConfig)); - _snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager)); - _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - } + private readonly ICliqueConfig _cliqueConfig = cliqueConfig ?? throw new ArgumentNullException(nameof(cliqueConfig)); + private readonly ISnapshotManager _snapshotManager = snapshotManager ?? throw new ArgumentNullException(nameof(snapshotManager)); + private readonly ILogger _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); public bool ValidateParams(BlockHeader parent, BlockHeader header, bool isUncle = false) { long number = header.Number; // Retrieve the snapshot needed to validate this header and cache it - Snapshot snapshot = _snapshotManager.GetOrCreateSnapshot(number - 1, header.ParentHash); + Snapshot snapshot = _snapshotManager.GetOrCreateSnapshot(number - 1, header.ParentHash!); // Resolve the authorization key and check against signers header.Author ??= _snapshotManager.GetBlockSealer(header); Address signer = header.Author; diff --git a/src/Nethermind/Nethermind.Consensus/Validators/Always.cs b/src/Nethermind/Nethermind.Consensus/Validators/Always.cs new file mode 100644 index 000000000000..aa74ae0ba258 --- /dev/null +++ b/src/Nethermind/Nethermind.Consensus/Validators/Always.cs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using Nethermind.Core; +using Nethermind.Core.Specs; +using Nethermind.TxPool; + +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; + } + + // ReSharper disable once NotNullMemberIsNotInitialized + private static Always _valid; + + public static Always Valid => LazyInitializer.EnsureInitialized(ref _valid, static () => new Always(true)); + + // ReSharper disable once NotNullMemberIsNotInitialized + private static Always _invalid; + + public static Always Invalid => LazyInitializer.EnsureInitialized(ref _invalid, static () => new Always(false)); + + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, out string? error) => Validate(out error); + public bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error) => Validate(out error); + public bool ValidateParams(BlockHeader parent, BlockHeader header, bool isUncle = false) => Validate(out _); + public bool ValidateSeal(BlockHeader header, bool force) => Validate(out _); + public bool Validate(BlockHeader header, BlockHeader[] uncles) => Validate(out _); + public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => _validationResult; + public bool ValidateWithdrawals(Block block, out string? error) => Validate(out error); + public bool ValidateOrphanedBlock(Block block, out string? error) => Validate(out error); + public bool ValidateSuggestedBlock(Block block, BlockHeader parent, out string? error, bool validateHashes = true) => Validate(out error); + public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, out string? error) => Validate(out error); + public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? error) => Validate(out error); + + private bool Validate(out string? error) + { + error = _result ? null : "Always invalid."; + return _result; + } +} diff --git a/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs b/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs deleted file mode 100644 index e298f8a6bc74..000000000000 --- a/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using Nethermind.Core; -using Nethermind.Core.Specs; -using Nethermind.TxPool; - -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; - } - - // ReSharper disable once NotNullMemberIsNotInitialized - private static Always _valid; - - public static Always Valid - => LazyInitializer.EnsureInitialized(ref _valid, static () => new Always(true)); - - // ReSharper disable once NotNullMemberIsNotInitialized - private static Always _invalid; - - public static Always Invalid - => LazyInitializer.EnsureInitialized(ref _invalid, static () => new Always(false)); - - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) - { - error = null; - return _result; - } - - public bool Validate(BlockHeader header, bool isUncle, out string? error) - { - error = null; - return _result; - } - public bool ValidateParams(BlockHeader parent, BlockHeader header, bool isUncle = false) - { - return _result; - } - - public bool ValidateSeal(BlockHeader header, bool force) - { - return _result; - } - - public bool Validate(BlockHeader header, BlockHeader[] uncles) - { - return _result; - } - - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) - { - return _validationResult; - } - public bool ValidateWithdrawals(Block block, out string? error) - { - error = null; - - return _result; - } - - public bool ValidateOrphanedBlock(Block block, out string? error) - { - error = null; - return _result; - } - - public bool ValidateSuggestedBlock(Block block, BlockHeader? parent, out string? error, bool validateHashes = true) - { - error = null; - return _result; - } - - public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, out string? error) - { - error = null; - return _result; - } - - public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? errorMessage) - { - errorMessage = null; - return _result; - } -} diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs index 4b4682402901..17397d1a17d8 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Diagnostics.CodeAnalysis; using System.Text; using Nethermind.Blockchain; using Nethermind.Core; @@ -33,12 +34,11 @@ public class BlockValidator( private readonly BlockDecoder _blockDecoder = new(); private readonly ILogger _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle) => - _headerValidator.Validate(header, parent, isUncle, out _); - - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) => + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, out string? error) => _headerValidator.Validate(header, parent, isUncle, out error); + public bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error) => + _headerValidator.ValidateOrphaned(header, out error); /// /// Applies to blocks without parent /// @@ -48,14 +48,8 @@ public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out /// /// Parent may be absent during BeaconSync /// - public bool ValidateOrphanedBlock(Block block, out string? error) - { - if (!ValidateEip4844Fields(block, _specProvider.GetSpec(block.Header), out error)) - return false; - - error = null; - return true; - } + public bool ValidateOrphanedBlock(Block block, out string? error) => + ValidateBlock(block, null, out error); /// /// Suggested block validation runs basic checks that can be executed before going through the expensive EVM processing. @@ -67,28 +61,37 @@ public bool ValidateOrphanedBlock(Block block, out string? error) /// /// true if the is valid; otherwise, false. /// - public bool ValidateSuggestedBlock(Block block, BlockHeader? parent, out string? errorMessage, bool validateHashes = true) + public bool ValidateSuggestedBlock(Block block, BlockHeader parent, out string? errorMessage, bool validateHashes = true) => + ValidateBlock(block, parent, out errorMessage, validateHashes); + + private bool ValidateBlock(Block block, BlockHeader? parent, out string? errorMessage, bool validateHashes = true) where TOrphaned : struct, IFlag { IReleaseSpec spec = _specProvider.GetSpec(block.Header); + errorMessage = null; - int encodedSize = block.EncodedSize ?? _blockDecoder.GetLength(block, RlpBehaviors.None); - if (spec.IsEip7934Enabled && encodedSize > spec.Eip7934MaxRlpBlockSize) - { - if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} RLP encoded size of {encodedSize} bytes exceeds the max limit of {spec.Eip7934MaxRlpBlockSize} bytes"); - errorMessage = BlockErrorMessages.ExceededBlockSizeLimit(spec.Eip7934MaxRlpBlockSize); - return false; - } + return ValidateBlockSize(block, spec, ref errorMessage) && + ValidateTransactions(block, spec, ref errorMessage) && + ValidateEip4844Fields(block, spec, ref errorMessage) && + ValidateUncles(block, spec, validateHashes, ref errorMessage) && + ValidateHeader(block, parent, ref errorMessage) && + ValidateTxRootMatchesTxs(block, validateHashes, ref errorMessage) && + ValidateWithdrawals(block, spec, validateHashes, ref errorMessage); + } - if (!ValidateTransactions(block, spec, out errorMessage)) - { - return false; - } + private bool ValidateHeader(Block block, BlockHeader? parent, ref string? errorMessage) + where TOrphaned : struct, IFlag + { + bool blockHeaderValid = typeof(TOrphaned) == typeof(OffFlag) + ? parent is not null && _headerValidator.Validate(block.Header, parent, false, out errorMessage) + : parent is null && _headerValidator.ValidateOrphaned(block.Header, out errorMessage); - if (!ValidateEip4844Fields(block, spec, out errorMessage)) - { - return false; - } + if (_logger.IsDebug && !blockHeaderValid) _logger.Debug($"{Invalid(block)} Invalid header: {errorMessage}"); + + return blockHeaderValid; + } + private bool ValidateUncles(Block block, IReleaseSpec spec, bool validateHashes, ref string? errorMessage) + { if (spec.MaximumUncleCount < block.Uncles.Length) { if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Uncle count of {block.Uncles.Length} exceeds the max limit of {spec.MaximumUncleCount}"); @@ -110,24 +113,18 @@ public bool ValidateSuggestedBlock(Block block, BlockHeader? parent, out string? return false; } - bool blockHeaderValid = _headerValidator.Validate(block.Header, parent, false, out errorMessage); - if (!blockHeaderValid) - { - if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Invalid header"); - return false; - } + return true; + } - if (validateHashes) + private bool ValidateBlockSize(Block block, IReleaseSpec spec, ref string? errorMessage) + { + if (spec.IsEip7934Enabled) { - if (!ValidateTxRootMatchesTxs(block, out Hash256 txRoot)) - { - if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Transaction root hash mismatch: expected {block.Header.TxRoot}, got {txRoot}"); - errorMessage = BlockErrorMessages.InvalidTxRoot(block.Header.TxRoot!, txRoot); - return false; - } - - if (!ValidateWithdrawals(block, spec, out errorMessage)) + int encodedSize = block.EncodedSize ?? _blockDecoder.GetLength(block, RlpBehaviors.None); + if (encodedSize > spec.Eip7934MaxRlpBlockSize) { + if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} RLP encoded size of {encodedSize} bytes exceeds the max limit of {spec.Eip7934MaxRlpBlockSize} bytes"); + errorMessage = BlockErrorMessages.ExceededBlockSizeLimit(spec.Eip7934MaxRlpBlockSize); return false; } } @@ -231,46 +228,45 @@ public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, B return false; } - public bool ValidateWithdrawals(Block block, out string? error) => - ValidateWithdrawals(block, _specProvider.GetSpec(block.Header), out error); - - protected virtual bool ValidateWithdrawals(Block block, IReleaseSpec spec, out string? error) + public bool ValidateWithdrawals(Block block, out string? error) { - if (spec.WithdrawalsEnabled && block.Withdrawals is null) - { - error = BlockErrorMessages.MissingWithdrawals; - - if (_logger.IsWarn) _logger.Warn($"Withdrawals cannot be null in block {block.Hash} when EIP-4895 activated."); - - return false; - } - - if (!spec.WithdrawalsEnabled && block.Withdrawals is not null) - { - error = BlockErrorMessages.WithdrawalsNotEnabled; - - if (_logger.IsWarn) _logger.Warn($"Withdrawals must be null in block {block.Hash} when EIP-4895 not activated."); - - return false; - } + error = null; + return ValidateWithdrawals(block, _specProvider.GetSpec(block.Header), true, ref error); + } - if (block.Withdrawals is not null) + protected virtual bool ValidateWithdrawals(Block block, IReleaseSpec spec, bool validateHashes, ref string? error) + { + if (validateHashes) { - if (!ValidateWithdrawalsHashMatches(block, out Hash256 withdrawalsRoot)) + if (spec.WithdrawalsEnabled && block.Withdrawals is null) { - error = BlockErrorMessages.InvalidWithdrawalsRoot(block.Header.WithdrawalsRoot, withdrawalsRoot); - if (_logger.IsWarn) _logger.Warn($"Withdrawals root hash mismatch in block {block.ToString(Block.Format.FullHashAndNumber)}: expected {block.Header.WithdrawalsRoot}, got {withdrawalsRoot}"); + error = BlockErrorMessages.MissingWithdrawals; + if (_logger.IsWarn) _logger.Warn($"Withdrawals cannot be null in block {block.Hash} when EIP-4895 activated."); + return false; + } + if (!spec.WithdrawalsEnabled && block.Withdrawals is not null) + { + error = BlockErrorMessages.WithdrawalsNotEnabled; + if (_logger.IsWarn) _logger.Warn($"Withdrawals must be null in block {block.Hash} when EIP-4895 not activated."); return false; } - } - error = null; + if (block.Withdrawals is not null) + { + if (!ValidateWithdrawalsHashMatches(block, out Hash256 withdrawalsRoot)) + { + error = BlockErrorMessages.InvalidWithdrawalsRoot(block.Header.WithdrawalsRoot, withdrawalsRoot); + if (_logger.IsWarn) _logger.Warn($"Withdrawals root hash mismatch in block {block.ToString(Block.Format.FullHashAndNumber)}: expected {block.Header.WithdrawalsRoot}, got {withdrawalsRoot}"); + return false; + } + } + } return true; } - protected virtual bool ValidateTransactions(Block block, IReleaseSpec spec, out string? errorMessage) + protected virtual bool ValidateTransactions(Block block, IReleaseSpec spec, ref string? errorMessage) { Transaction[] transactions = block.Transactions; @@ -286,15 +282,14 @@ protected virtual bool ValidateTransactions(Block block, IReleaseSpec spec, out return false; } } - errorMessage = null; + return true; } - protected virtual bool ValidateEip4844Fields(Block block, IReleaseSpec spec, out string? error) + protected virtual bool ValidateEip4844Fields(Block block, IReleaseSpec spec, ref string? error) { if (!spec.IsEip4844Enabled) { - error = null; return true; } @@ -347,39 +342,47 @@ protected virtual bool ValidateEip4844Fields(Block block, IReleaseSpec spec, out return false; } - error = null; return true; } public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated) => ValidateBodyAgainstHeader(header, toBeValidated, out _); - public virtual bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, out string? errorMessage) + public virtual bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, out string? error) { if (!ValidateTxRootMatchesTxs(header, toBeValidated, out Hash256? txRoot)) { - errorMessage = BlockErrorMessages.InvalidTxRoot(header.TxRoot, txRoot); + error = BlockErrorMessages.InvalidTxRoot(header.TxRoot, txRoot); return false; } if (!ValidateUnclesHashMatches(header, toBeValidated, out _)) { - errorMessage = BlockErrorMessages.InvalidUnclesHash; + error = BlockErrorMessages.InvalidUnclesHash; return false; } if (!ValidateWithdrawalsHashMatches(header, toBeValidated, out Hash256? withdrawalsRoot)) { - errorMessage = BlockErrorMessages.InvalidWithdrawalsRoot(header.WithdrawalsRoot, withdrawalsRoot); + error = BlockErrorMessages.InvalidWithdrawalsRoot(header.WithdrawalsRoot, withdrawalsRoot); return false; } - errorMessage = null; + error = null; return true; } - public static bool ValidateTxRootMatchesTxs(Block block, out Hash256 txRoot) => - ValidateTxRootMatchesTxs(block.Header, block.Body, out txRoot); + private bool ValidateTxRootMatchesTxs(Block block, bool validateHashes, [NotNullWhen(false)] ref string? errorMessage) + { + if (validateHashes && !ValidateTxRootMatchesTxs(block.Header, block.Body, out Hash256 txRoot)) + { + if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Transaction root hash mismatch: expected {block.Header.TxRoot}, got {txRoot}"); + errorMessage = BlockErrorMessages.InvalidTxRoot(block.Header.TxRoot!, txRoot); + return false; + } + + return true; + } public static bool ValidateTxRootMatchesTxs(BlockHeader header, BlockBody body, out Hash256 txRoot) => (txRoot = TxTrie.CalculateRoot(body.Transactions)) == header.TxRoot; @@ -404,6 +407,5 @@ public static bool ValidateWithdrawalsHashMatches(BlockHeader header, BlockBody return (withdrawalsRoot = new WithdrawalTrie(body.Withdrawals).RootHash) == header.WithdrawalsRoot; } - private static string Invalid(Block block) => - $"Invalid block {block.ToString(Block.Format.FullHashAndNumber)}:"; + private static string Invalid(Block block) => $"Invalid block {block.ToString(Block.Format.FullHashAndNumber)}:"; } diff --git a/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs index dff4f5b91030..43322f640a7a 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Diagnostics.CodeAnalysis; using Nethermind.Blockchain; -using Nethermind.Blockchain.Find; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; @@ -16,28 +16,20 @@ namespace Nethermind.Consensus.Validators { - public class HeaderValidator : IHeaderValidator + public class HeaderValidator( + IBlockTree? blockTree, + ISealValidator? sealValidator, + ISpecProvider? specProvider, + ILogManager? logManager) + : IHeaderValidator { private static readonly byte[] DaoExtraData = Bytes.FromHexString("0x64616f2d686172642d666f726b"); - protected readonly ISealValidator _sealValidator; - protected readonly ISpecProvider _specProvider; - private readonly long? _daoBlockNumber; - protected readonly ILogger _logger; - private readonly IBlockTree _blockTree; - - public HeaderValidator( - IBlockTree? blockTree, - ISealValidator? sealValidator, - ISpecProvider? specProvider, - ILogManager? logManager) - { - _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); - _sealValidator = sealValidator ?? throw new ArgumentNullException(nameof(sealValidator)); - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _daoBlockNumber = specProvider.DaoBlockNumber; - } + protected readonly ISealValidator _sealValidator = sealValidator ?? throw new ArgumentNullException(nameof(sealValidator)); + protected readonly ISpecProvider _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + private readonly long? _daoBlockNumber = specProvider.DaoBlockNumber; + protected readonly ILogger _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); + private readonly IBlockTree _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); public static bool ValidateHash(BlockHeader header, out Hash256 actualHash) { @@ -54,7 +46,7 @@ private bool ValidateHash(BlockHeader header, ref string? error) if (!hashAsExpected) { if (_logger.IsWarn) _logger.Warn($"Invalid block header ({header.Hash}) - invalid block hash"); - error = BlockErrorMessages.InvalidHeaderHash(header.Hash, header.CalculateHash()); + error = BlockErrorMessages.InvalidHeaderHash(header.Hash!, header.CalculateHash()); return false; } @@ -66,42 +58,48 @@ private bool ValidateHash(BlockHeader header, ref string? error) /// /// BlockHeader to validate /// BlockHeader which is the parent of - /// True if uncle block, otherwise False + /// True if is an uncle block, otherwise False /// True if validation succeeds otherwise false - public virtual bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle = false) - { - return Validate(header, parent, isUncle, out _); - } + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle = false) => + Validate(header, parent, isUncle, out _); /// /// Note that this does not validate seal which is the responsibility of > /// /// BlockHeader to validate /// BlockHeader which is the parent of - /// True if uncle block, otherwise False + /// True if is an uncle block, otherwise False /// Detailed error message if validation fails, otherwise null. /// True if validation succeeds otherwise false - public virtual bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, out string? error) => + Validate(header, parent, isUncle, out error); + + protected virtual bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) where TOrphaned : struct, IFlag { IReleaseSpec spec; error = null; + bool orphaned = typeof(TOrphaned) == typeof(OnFlag); + parent = orphaned ? null : parent!; // bool gasLimitAboveAbsoluteMinimum = header.GasLimit >= 125000; // described in the YellowPaper but not followed return ValidateFieldLimit(header, ref error) - && ValidateHash(header, ref error) - && ValidateExtraData(header, parent, spec = _specProvider.GetSpec(header), isUncle, ref error) - && ValidateParent(header, parent, ref error) - && ValidateTotalDifficulty(parent!, header, ref error) - && ValidateSeal(header, parent, isUncle, ref error) - && ValidateGasUsed(header, ref error) - && ValidateGasLimitRange(header, parent, spec, ref error) - && ValidateTimestamp(header, parent, ref error) - && ValidateBlockNumber(header, parent, ref error) - && Validate1559(header, parent, spec, ref error) - && ValidateBlobGasFields(header, parent, spec, ref error) - && ValidateRequestsHash(header, spec, ref error); + && ValidateHash(header, ref error) + && ValidateExtraData(header, spec = _specProvider.GetSpec(header), isUncle, ref error) + && (orphaned || ValidateParent(header, parent, ref error)) + && (orphaned || ValidateTotalDifficulty(header, parent, ref error)) + && (orphaned || ValidateSeal(header, parent, isUncle, ref error)) + && ValidateGasUsed(header, ref error) + && (orphaned || ValidateGasLimitRange(header, parent, spec, ref error)) + && (orphaned || ValidateTimestamp(header, parent, ref error)) + && (orphaned || ValidateBlockNumber(header, parent, ref error)) + && (orphaned || Validate1559(header, parent, spec, ref error)) + && (orphaned || ValidateBlobGasFields(header, parent, spec, ref error)) + && ValidateRequestsHash(header, spec, ref error); } + public bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error) => + Validate(header, null, false, out error); + protected virtual bool ValidateRequestsHash(BlockHeader header, IReleaseSpec spec, ref string? error) { if (spec.RequestsEnabled) @@ -187,7 +185,7 @@ protected virtual bool ValidateParent(BlockHeader header, BlockHeader? parent, r } else if (parent.Hash != header.ParentHash) { - error = BlockErrorMessages.MismatchedParent(header.Hash, header.ParentHash, parent.Hash); + error = BlockErrorMessages.MismatchedParent(header.Hash!, header.ParentHash!, parent.Hash!); return false; } @@ -236,7 +234,7 @@ protected virtual bool ValidateFieldLimit(BlockHeader blockHeader, ref string? e } - protected virtual bool ValidateExtraData(BlockHeader header, BlockHeader? parent, IReleaseSpec spec, bool isUncle, ref string? error) + protected virtual bool ValidateExtraData(BlockHeader header, IReleaseSpec spec, bool isUncle, ref string? error) { bool extraDataValid = header.ExtraData.Length <= spec.MaximumExtraDataSize && (isUncle @@ -298,7 +296,7 @@ protected virtual bool ValidateTimestamp(BlockHeader header, BlockHeader parent, return timestampMoreThanAtParent; } - protected virtual bool ValidateTotalDifficulty(BlockHeader parent, BlockHeader header, ref string? error) + protected virtual bool ValidateTotalDifficulty(BlockHeader header, BlockHeader parent, ref string? error) { bool result = true; @@ -333,7 +331,7 @@ private bool ValidateGenesis(BlockHeader header) => header.Bloom is not null && header.ExtraData.Length <= _specProvider.GenesisSpec.MaximumExtraDataSize; - protected virtual bool ValidateBlobGasFields(BlockHeader header, BlockHeader parentHeader, IReleaseSpec spec, ref string? error) + protected virtual bool ValidateBlobGasFields(BlockHeader header, BlockHeader parent, IReleaseSpec spec, ref string? error) { if (spec.IsEip4844Enabled) { @@ -351,7 +349,7 @@ protected virtual bool ValidateBlobGasFields(BlockHeader header, BlockHeader par return false; } - ulong? expectedExcessBlobGas = BlobGasCalculator.CalculateExcessBlobGas(parentHeader, spec); + ulong? expectedExcessBlobGas = BlobGasCalculator.CalculateExcessBlobGas(parent, spec); if (header.ExcessBlobGas != expectedExcessBlobGas) { if (_logger.IsWarn) _logger.Warn($"ExcessBlobGas field is incorrect: {header.ExcessBlobGas}, should be {expectedExcessBlobGas}."); diff --git a/src/Nethermind/Nethermind.Consensus/Validators/IBlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/IBlockValidator.cs index 98fe6f7a23dc..974b2bac8865 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/IBlockValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/IBlockValidator.cs @@ -9,7 +9,7 @@ namespace Nethermind.Consensus.Validators; public interface IBlockValidator : IHeaderValidator, IWithdrawalValidator { bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error); - bool ValidateSuggestedBlock(Block block, BlockHeader? parent, [NotNullWhen(false)] out string? error, bool validateHashes = true); + bool ValidateSuggestedBlock(Block block, BlockHeader parent, [NotNullWhen(false)] out string? error, bool validateHashes = true); bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, [NotNullWhen(false)] out string? error); - bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? errorMessage); + bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? error); } diff --git a/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs index d380e41f7286..808d472d498f 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/IHeaderValidator.cs @@ -8,6 +8,7 @@ namespace Nethermind.Consensus.Validators { public interface IHeaderValidator { - bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error); + bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, [NotNullWhen(false)] out string? error); + bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error); } } diff --git a/src/Nethermind/Nethermind.Consensus/Validators/NeverValidBlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/NeverValidBlockValidator.cs deleted file mode 100644 index 08e9d67b89f6..000000000000 --- a/src/Nethermind/Nethermind.Consensus/Validators/NeverValidBlockValidator.cs +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System.Diagnostics.CodeAnalysis; -using Nethermind.Core; - -namespace Nethermind.Consensus.Validators -{ - public class NeverValidBlockValidator : IBlockValidator - { - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) - { - error = null; - return false; - } - - public bool Validate(BlockHeader header, bool isUncle, out string? error) - { - error = null; - return false; - } - - public bool ValidateWithdrawals(Block block, out string? error) - { - error = null; - return false; - } - - public bool ValidateOrphanedBlock(Block block, out string? error) - { - error = null; - return false; - } - - public bool ValidateSuggestedBlock(Block block, BlockHeader? parent, out string? error, bool validateHashes = true) - { - error = null; - return false; - } - - public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, out string? error) - { - error = null; - return false; - } - - public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? errorMessage) - { - errorMessage = null; - return false; - } - } -} diff --git a/src/Nethermind/Nethermind.Consensus/Validators/SimulateBlockValidatorProxy.cs b/src/Nethermind/Nethermind.Consensus/Validators/SimulateBlockValidatorProxy.cs index 3339916e218e..d75c84c39c8b 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/SimulateBlockValidatorProxy.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/SimulateBlockValidatorProxy.cs @@ -14,7 +14,7 @@ public bool ValidateWithdrawals(Block block, out string? error) => public bool ValidateOrphanedBlock(Block block, out string? error) => baseBlockValidator.ValidateOrphanedBlock(block, out error); - public bool ValidateSuggestedBlock(Block block, BlockHeader? parentHeader, out string? error, bool validateHashes = true) => + public bool ValidateSuggestedBlock(Block block, BlockHeader parentHeader, out string? error, bool validateHashes = true) => baseBlockValidator.ValidateSuggestedBlock(block, parentHeader, out error, validateHashes); public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, out string? error) @@ -23,9 +23,12 @@ public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, B return true; } - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) => + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, out string? error) => baseBlockValidator.Validate(header, parent, isUncle, out error); - public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? errorMessage) => - baseBlockValidator.ValidateBodyAgainstHeader(header, toBeValidated, out errorMessage); + public bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error) => + baseBlockValidator.ValidateOrphaned(header, out error); + + public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? error) => + baseBlockValidator.ValidateBodyAgainstHeader(header, toBeValidated, out error); } diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs index f08690c33818..a9e138cdb40d 100644 --- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs +++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs @@ -30,24 +30,31 @@ public BlockHeaderBuilder() DefaultDifficulty, 0, 4_000_000, 1_000_000, - new byte[] { 1, 2, 3 }); - TestObjectInternal.Bloom = Bloom.Empty; - TestObjectInternal.MixHash = Keccak.Compute("mix_hash"); - TestObjectInternal.Nonce = 1000; - TestObjectInternal.ReceiptsRoot = Keccak.EmptyTreeHash; - TestObjectInternal.StateRoot = Keccak.EmptyTreeHash; - TestObjectInternal.TxRoot = Keccak.EmptyTreeHash; + [1, 2, 3]) + { + Bloom = Bloom.Empty, + MixHash = Keccak.Compute("mix_hash"), + Nonce = 1000, + ReceiptsRoot = Keccak.EmptyTreeHash, + StateRoot = Keccak.EmptyTreeHash, + TxRoot = Keccak.EmptyTreeHash + }; } public BlockHeaderBuilder WithParent(BlockHeader parentHeader) { - if (parentHeader is null) return this; TestObjectInternal.ParentHash = parentHeader.Hash; TestObjectInternal.Number = parentHeader.Number + 1; TestObjectInternal.GasLimit = parentHeader.GasLimit; return this; } + public BlockHeaderBuilder WithParentOptional(BlockHeader? parentHeader) + { + if (parentHeader is not null) WithParent(parentHeader); + return this; + } + public BlockHeaderBuilder WithParentHash(Hash256 parentHash) { TestObjectInternal.ParentHash = parentHash; diff --git a/src/Nethermind/Nethermind.Core/TypeFlags.cs b/src/Nethermind/Nethermind.Core/TypeFlags.cs index 59f70354fb00..7454a835927c 100644 --- a/src/Nethermind/Nethermind.Core/TypeFlags.cs +++ b/src/Nethermind/Nethermind.Core/TypeFlags.cs @@ -6,17 +6,17 @@ namespace Nethermind.Core; /// /// Represents a flag interface that declares a static boolean property. /// By defining the property as static and using generic specialization at the JIT level, -/// any conditional checks (e.g. if-branches) can be elided (i.e., removed), as the compiler +/// any conditional checks (e.g. if-branches) can be elided (i.e., removed), as the compiler /// can resolve the static value at compile-time rather than needing to evaluate it at runtime. /// public interface IFlag { /// /// Gets a value indicating whether this flag is active. - /// The JIT can specialize the implementation based on the static type, + /// The JIT can specialize the implementation based on the static type, /// removing the need for run-time checks. /// - virtual static bool IsActive { get; } + static virtual bool IsActive { get; } } /// diff --git a/src/Nethermind/Nethermind.Hive/HiveRunner.cs b/src/Nethermind/Nethermind.Hive/HiveRunner.cs index d327ce08694e..4f8763713425 100644 --- a/src/Nethermind/Nethermind.Hive/HiveRunner.cs +++ b/src/Nethermind/Nethermind.Hive/HiveRunner.cs @@ -123,10 +123,8 @@ private async Task InitializeBlocks(string blocksDir, CancellationToken cancella parent = blockTree.Genesis; } - if (_logger.IsInfo) - _logger.Info( - $"HIVE Processing block file: {file} - {block.ToString(Block.Format.Short)}"); - await ProcessBlock(block, parent); + if (_logger.IsInfo) _logger.Info($"HIVE Processing block file: {file} - {block.ToString(Block.Format.Short)}"); + await ProcessBlock(block, parent!); parent = block.Header; } catch (RlpException e) @@ -170,7 +168,7 @@ private async Task InitializeChain(string chainFile) parent = blockTree.Genesis; } - await ProcessBlock(block, parent); + await ProcessBlock(block, parent!); parent = block.Header; } } @@ -191,7 +189,7 @@ private static async Task WaitForBlockProcessing(SemaphoreSlim semaphore) } } - private async Task ProcessBlock(Block block, BlockHeader? parent) + private async Task ProcessBlock(Block block, BlockHeader parent) { try { diff --git a/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs b/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs index af6fab483c95..9e949899e54a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidBlockInterceptor.cs @@ -18,7 +18,7 @@ public class InvalidBlockInterceptor( public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) => blockValidator.ValidateOrphanedBlock(block, out error); - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error) + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, [NotNullWhen(false)] out string? error) { bool result = blockValidator.Validate(header, parent, isUncle, out error); if (!result) @@ -35,7 +35,10 @@ public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [Not return result; } - public bool ValidateSuggestedBlock(Block block, BlockHeader? parent, [NotNullWhen(false)] out string? error, bool validateHashes = true) + public bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error) => + blockValidator.ValidateOrphaned(header, out error); + + public bool ValidateSuggestedBlock(Block block, BlockHeader parent, [NotNullWhen(false)] out string? error, bool validateHashes = true) { bool result = blockValidator.ValidateSuggestedBlock(block, parent, out error, validateHashes); if (!result) @@ -97,8 +100,8 @@ public bool ValidateWithdrawals(Block block, out string? error) return result; } - public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? errorMessage) => - blockValidator.ValidateBodyAgainstHeader(header, toBeValidated, out errorMessage); + public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? error) => + blockValidator.ValidateBodyAgainstHeader(header, toBeValidated, out error); private bool ShouldNotTrackInvalidation(Block block) => ShouldNotTrackInvalidation(block.Header) || diff --git a/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidHeaderInterceptor.cs b/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidHeaderInterceptor.cs index ccfd8ad3a898..e7a6f0dafb21 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidHeaderInterceptor.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/InvalidChainTracker/InvalidHeaderInterceptor.cs @@ -8,25 +8,17 @@ namespace Nethermind.Merge.Plugin.InvalidChainTracker; -public class InvalidHeaderInterceptor : IHeaderValidator +public class InvalidHeaderInterceptor( + IHeaderValidator headerValidator, + IInvalidChainTracker invalidChainTracker, + ILogManager logManager) + : IHeaderValidator { - private readonly IHeaderValidator _baseValidator; - private readonly IInvalidChainTracker _invalidChainTracker; - private readonly ILogger _logger; + private readonly ILogger _logger = logManager.GetClassLogger(); - public InvalidHeaderInterceptor( - IHeaderValidator headerValidator, - IInvalidChainTracker invalidChainTracker, - ILogManager logManager) + public bool Validate(BlockHeader header, BlockHeader parent, bool isUncle, [NotNullWhen(false)] out string? error) { - _baseValidator = headerValidator; - _invalidChainTracker = invalidChainTracker; - _logger = logManager.GetClassLogger(); - } - - 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.IsDebug) _logger.Debug($"Intercepted a bad header {header}"); @@ -35,14 +27,14 @@ 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; } - private static bool ShouldNotTrackInvalidation(BlockHeader header) - { - return !HeaderValidator.ValidateHash(header); - } + public bool ValidateOrphaned(BlockHeader header, [NotNullWhen(false)] out string? error) => + headerValidator.ValidateOrphaned(header, out error); + + private static bool ShouldNotTrackInvalidation(BlockHeader header) => !HeaderValidator.ValidateHash(header); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs index de155efb0d7a..fcd4bf923cfd 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeHeaderValidator.cs @@ -14,43 +14,32 @@ namespace Nethermind.Merge.Plugin { - public class MergeHeaderValidator : HeaderValidator + public class MergeHeaderValidator( + IPoSSwitcher poSSwitcher, + IHeaderValidator preMergeHeaderValidator, + IBlockTree blockTree, + ISpecProvider specProvider, + ISealValidator sealValidator, + ILogManager logManager) + : HeaderValidator(blockTree, sealValidator, specProvider, logManager) { // https://eips.ethereum.org/EIPS/eip-3675#constants private const int MaxExtraDataBytes = 32; - private readonly IPoSSwitcher _poSSwitcher; - private readonly IHeaderValidator _preMergeHeaderValidator; - private readonly IBlockTree _blockTree; - - public MergeHeaderValidator( - IPoSSwitcher poSSwitcher, - IHeaderValidator preMergeHeaderValidator, - IBlockTree blockTree, - ISpecProvider specProvider, - ISealValidator sealValidator, - ILogManager logManager) - : base(blockTree, sealValidator, specProvider, logManager) - { - _poSSwitcher = poSSwitcher; - _preMergeHeaderValidator = preMergeHeaderValidator; - _blockTree = blockTree; - } - - public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle = false) - { - return Validate(header, parent, isUncle, out _); - } - public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) + protected override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) { error = null; - return _poSSwitcher.IsPostMerge(header) - ? ValidateTheMergeChecks(header) && base.Validate(header, parent, isUncle, out error) - : ValidatePoWTotalDifficulty(header) && _preMergeHeaderValidator.Validate(header, parent, isUncle, out error); + return poSSwitcher.IsPostMerge(header) + ? ValidateTheMergeChecks(header) && base.Validate(header, parent, isUncle, out error) + : ValidatePoWTotalDifficulty(header) && ( + typeof(TOrphaned) == typeof(OnFlag) + ? preMergeHeaderValidator.ValidateOrphaned(header, out error) + : preMergeHeaderValidator.Validate(header, parent!, isUncle, out error) + ); } - protected override bool ValidateTotalDifficulty(BlockHeader parent, BlockHeader header, ref string? error) => - _poSSwitcher.IsPostMerge(header) || base.ValidateTotalDifficulty(parent, header, ref error); + protected override bool ValidateTotalDifficulty(BlockHeader header, BlockHeader parent, ref string? error) => + poSSwitcher.IsPostMerge(header) || base.ValidateTotalDifficulty(header, parent, ref error); private bool ValidatePoWTotalDifficulty(BlockHeader header) { @@ -65,9 +54,9 @@ private bool ValidatePoWTotalDifficulty(BlockHeader header) private bool ValidateTheMergeChecks(BlockHeader header) { - (bool IsTerminal, bool IsPostMerge) = _poSSwitcher.GetBlockConsensusInfo(header); - bool terminalTotalDifficultyChecks = ValidateTerminalTotalDifficultyChecks(header, IsTerminal); - bool valid = !IsPostMerge || + (bool isTerminal, bool isPostMerge) = poSSwitcher.GetBlockConsensusInfo(header); + bool terminalTotalDifficultyChecks = ValidateTerminalTotalDifficultyChecks(header, isTerminal); + bool valid = !isPostMerge || ValidateHeaderField(header, header.Difficulty, UInt256.Zero, nameof(header.Difficulty)) && ValidateHeaderField(header, header.Nonce, 0u, nameof(header.Nonce)) && ValidateHeaderField(header, header.UnclesHash, Keccak.OfAnEmptySequenceRlp, nameof(header.UnclesHash)); @@ -75,9 +64,9 @@ private bool ValidateTheMergeChecks(BlockHeader header) return terminalTotalDifficultyChecks && valid; } - protected override bool ValidateExtraData(BlockHeader header, BlockHeader? parent, IReleaseSpec spec, bool isUncle, ref string? error) + protected override bool ValidateExtraData(BlockHeader header, IReleaseSpec spec, bool isUncle, ref string? error) { - if (_poSSwitcher.IsPostMerge(header)) + if (poSSwitcher.IsPostMerge(header)) { if (header.ExtraData.Length > MaxExtraDataBytes) { @@ -89,12 +78,12 @@ protected override bool ValidateExtraData(BlockHeader header, BlockHeader? paren return true; } - return base.ValidateExtraData(header, parent, spec, isUncle, ref error); + return base.ValidateExtraData(header, spec, isUncle, ref error); } private bool ValidateTerminalTotalDifficultyChecks(BlockHeader header, bool isTerminal) { - if ((header.TotalDifficulty ?? 0) == 0 || _poSSwitcher.TerminalTotalDifficulty is null) + if ((header.TotalDifficulty ?? 0) == 0 || poSSwitcher.TerminalTotalDifficulty is null) { return true; } @@ -103,19 +92,19 @@ private bool ValidateTerminalTotalDifficultyChecks(BlockHeader header, bool isTe bool isPostMerge = header.IsPostMerge; if (!isPostMerge && !isTerminal) { - if (header.TotalDifficulty >= _poSSwitcher.TerminalTotalDifficulty) + if (header.TotalDifficulty >= poSSwitcher.TerminalTotalDifficulty) { isValid = false; } } - else if (header.TotalDifficulty < _poSSwitcher.TerminalTotalDifficulty) + else if (header.TotalDifficulty < poSSwitcher.TerminalTotalDifficulty) { isValid = false; } if (!isValid) { - if (_logger.IsWarn) _logger.Warn($"Invalid block header {header.ToString(BlockHeader.Format.Short)} - total difficulty is incorrect because of TTD, TerminalTotalDifficulty: {_poSSwitcher.TerminalTotalDifficulty}, IsPostMerge {header.IsPostMerge} IsTerminalBlock: {isTerminal}"); + if (_logger.IsWarn) _logger.Warn($"Invalid block header {header.ToString(BlockHeader.Format.Short)} - total difficulty is incorrect because of TTD, TerminalTotalDifficulty: {poSSwitcher.TerminalTotalDifficulty}, IsPostMerge {header.IsPostMerge} IsTerminalBlock: {isTerminal}"); } return isValid; @@ -125,7 +114,7 @@ private bool ValidateHeaderField(BlockHeader header, T value, T expected, str { if (!Equals(value, expected)) { - if (_logger.IsWarn) _logger.Warn($"Invalid block header {header.ToString(BlockHeader.Format.Full)} - the {name} is incorrect expected {expected}, got {value}. TransitionFinished: {_poSSwitcher.TransitionFinished}, TTD: {_specProvider.TerminalTotalDifficulty}, IsTerminal: {header.IsTerminalBlock(_specProvider)}"); + if (_logger.IsWarn) _logger.Warn($"Invalid block header {header.ToString(BlockHeader.Format.Full)} - the {name} is incorrect expected {expected}, got {value}. TransitionFinished: {poSSwitcher.TransitionFinished}, TTD: {_specProvider.TerminalTotalDifficulty}, IsTerminal: {header.IsTerminalBlock(_specProvider)}"); return false; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeSealValidator.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeSealValidator.cs index a6bb70927ded..4ffae3650a85 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeSealValidator.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeSealValidator.cs @@ -6,25 +6,17 @@ namespace Nethermind.Merge.Plugin; -public class MergeSealValidator : ISealValidator +public class MergeSealValidator( + IPoSSwitcher poSSwitcher, + ISealValidator preMergeSealValidator) + : ISealValidator { - private readonly IPoSSwitcher _poSSwitcher; - private readonly ISealValidator _preMergeSealValidator; - - public MergeSealValidator( - IPoSSwitcher poSSwitcher, - ISealValidator preMergeSealValidator - ) - { - _poSSwitcher = poSSwitcher; - _preMergeSealValidator = preMergeSealValidator; - } public bool ValidateParams(BlockHeader parent, BlockHeader header, bool isUncle) => - _poSSwitcher.IsPostMerge(header) || _preMergeSealValidator.ValidateParams(parent, header, isUncle); + poSSwitcher.IsPostMerge(header) || preMergeSealValidator.ValidateParams(parent, header, isUncle); public bool ValidateSeal(BlockHeader header, bool force) { - (bool isTerminal, bool isPostMerge) = _poSSwitcher.GetBlockConsensusInfo(header); - return isPostMerge || _preMergeSealValidator.ValidateSeal(header, force || isTerminal); + (bool isTerminal, bool isPostMerge) = poSSwitcher.GetBlockConsensusInfo(header); + return isPostMerge || preMergeSealValidator.ValidateSeal(header, force || isTerminal); } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockValidator.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockValidator.cs index 13bba69f006c..7574b2f1f7c9 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockValidator.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockValidator.cs @@ -38,30 +38,30 @@ public class OptimismBlockValidator( private const string NonNullWithdrawalsRootError = $"{nameof(BlockHeader.WithdrawalsRoot)} is not null"; - public override bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, out string? errorMessage) + public override bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, out string? error) { if (!ValidateTxRootMatchesTxs(header, toBeValidated, out Hash256? txRoot)) { - errorMessage = BlockErrorMessages.InvalidTxRoot(header.TxRoot!, txRoot); + error = BlockErrorMessages.InvalidTxRoot(header.TxRoot!, txRoot); return false; } if (!ValidateUnclesHashMatches(header, toBeValidated, out _)) { - errorMessage = BlockErrorMessages.InvalidUnclesHash; + error = BlockErrorMessages.InvalidUnclesHash; return false; } - if (!ValidateWithdrawals(header, toBeValidated, out errorMessage)) + if (!ValidateWithdrawals(header, toBeValidated, out error)) { return false; } - errorMessage = null; + error = null; return true; } - protected override bool ValidateWithdrawals(Block block, IReleaseSpec spec, out string? error) => + protected override bool ValidateWithdrawals(Block block, IReleaseSpec spec, bool validateHashes, ref string? error) => ValidateWithdrawals(block.Header, block.Body, out error); private bool ValidateWithdrawals(BlockHeader header, BlockBody body, out string? error) @@ -75,7 +75,7 @@ private bool ValidateWithdrawals(BlockHeader header, BlockBody body, out string? return false; } - if (header.WithdrawalsRoot == null) + if (header.WithdrawalsRoot is null) { error = MissingWithdrawalsRootError; return false; @@ -95,13 +95,10 @@ private bool ValidateWithdrawals(BlockHeader header, BlockBody body, out string? return false; } } - else + else if (header.WithdrawalsRoot is not null) { - if (header.WithdrawalsRoot != null) - { - error = NonNullWithdrawalsRootError; - return false; - } + error = NonNullWithdrawalsRootError; + return false; } error = null; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs b/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs index db9069b9adda..18d8845935b8 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs @@ -18,10 +18,10 @@ public class PreBedrockHeaderValidator( ISpecProvider? specProvider, ILogManager? logManager) : HeaderValidator(blockTree, sealValidator, specProvider, logManager) { - public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error) + protected override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) { error = null; - return ValidateParent(header, parent, ref error); + return typeof(TOrphaned) == typeof(OnFlag) || ValidateParent(header, parent, ref error); } } @@ -37,11 +37,11 @@ public class OptimismHeaderValidator( new PreBedrockHeaderValidator(blockTree, sealValidator, specProvider, logManager), blockTree, specProvider, sealValidator, logManager) { - public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) + protected override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) { if (specHelper.IsHolocene(header)) { - if (!header.TryDecodeEIP1559Parameters(out var parameters, out var decodeError)) + if (!header.TryDecodeEIP1559Parameters(out EIP1559Parameters parameters, out var decodeError)) { error = decodeError; return false; @@ -54,7 +54,7 @@ public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUn } } - return base.Validate(header, parent, isUncle, out error); + return base.Validate(header, parent, isUncle, out error); } protected override bool ValidateRequestsHash(BlockHeader header, IReleaseSpec spec, ref string? error) diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs index adf3689f0ed4..15b2e0b2cb5d 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs @@ -34,7 +34,6 @@ using NSubstitute; using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; -using System.Diagnostics.CodeAnalysis; using Autofac; using Autofac.Features.AttributeFilters; using Humanizer; @@ -655,161 +654,6 @@ public bool ValidateSeal(BlockHeader header, bool force) } } - private class SlowHeaderValidator : IBlockValidator - { - - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle) - { - Thread.Sleep(1000); - return true; - } - - public bool Validate(BlockHeader header, bool isUncle) - { - Thread.Sleep(1000); - return true; - } - - public bool ValidateSuggestedBlock(Block block) - { - Thread.Sleep(1000); - return true; - } - - public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock) - { - Thread.Sleep(1000); - return true; - } - - public bool ValidateWithdrawals(Block block, out string? error) - { - Thread.Sleep(1000); - error = string.Empty; - return true; - } - - public bool ValidateOrphanedBlock(Block block, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } - - public bool ValidateSuggestedBlock(Block block, BlockHeader? parent, [NotNullWhen(false)] out string? error, bool validateHashes = true) - { - Thread.Sleep(1000); - error = null; - return true; - } - - public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, Block suggestedBlock, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } - - public bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } - - public bool Validate(BlockHeader header, bool isUncle, [NotNullWhen(false)] out string? error) - { - Thread.Sleep(1000); - error = null; - return true; - } - - public bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBeValidated, [NotNullWhen(false)] out string? errorMessage) - { - Thread.Sleep(1000); - errorMessage = null; - return true; - } - } - - private class ThrowingPeer : ISyncPeer - { - public ThrowingPeer(long number, UInt256? totalDiff, Hash256? headHash = null) - { - HeadNumber = number; - TotalDifficulty = totalDiff ?? UInt256.MaxValue; - HeadHash = headHash ?? Keccak.Zero; - } - - public string Name => "Throwing"; - public string ClientId => "EX peer"; - public Node Node { get; } = null!; - public string ProtocolCode { get; } = null!; - public byte ProtocolVersion { get; } = default; - public Hash256 HeadHash { get; set; } - public long HeadNumber { get; set; } - public UInt256? TotalDifficulty { get; set; } - public bool IsInitialized { get; set; } - public bool IsPriority { get; set; } - - public void Disconnect(DisconnectReason reason, string details) - { - throw new NotImplementedException(); - } - - public Task GetBlockBodies(IReadOnlyList blockHashes, CancellationToken token) - { - throw new NotImplementedException(); - } - - public Task?> GetBlockHeaders(Hash256 blockHash, int maxBlocks, int skip, CancellationToken token) - { - throw new NotImplementedException(); - } - - public Task?> GetBlockHeaders(long number, int maxBlocks, int skip, CancellationToken token) - { - throw new Exception(); - } - - public Task GetHeadBlockHeader(Hash256? hash, CancellationToken token) - { - throw new NotImplementedException(); - } - - public void NotifyOfNewBlock(Block block, SendBlockMode mode) - { - throw new NotImplementedException(); - } - - public PublicKey Id => Node.Id; - - public void SendNewTransactions(IEnumerable txs, bool sendFullTx) - { - throw new NotImplementedException(); - } - - public Task> GetReceipts(IReadOnlyList blockHash, CancellationToken token) - { - throw new NotImplementedException(); - } - - public Task> GetNodeData(IReadOnlyList hashes, CancellationToken token) - { - throw new NotImplementedException(); - } - - public void RegisterSatelliteProtocol(string protocol, T protocolHandler) where T : class - { - throw new NotImplementedException(); - } - - public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) where T : class - { - throw new NotImplementedException(); - } - } - [Test] public async Task Flag_lesser_quality_on_body_download_failure() { diff --git a/src/Nethermind/Nethermind.Taiko/TaikoBlockValidator.cs b/src/Nethermind/Nethermind.Taiko/TaikoBlockValidator.cs index 73a923a3c8db..6fb161f78486 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoBlockValidator.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoBlockValidator.cs @@ -30,29 +30,22 @@ public class TaikoBlockValidator( private const long AnchorGasLimit = 250_000; private const long AnchorV3GasLimit = 1_000_000; - protected override bool ValidateEip4844Fields(Block block, IReleaseSpec spec, out string? error) - { - // No blob transactions are expected, covered by ValidateTransactions also - error = null; - return true; - } + protected override bool ValidateEip4844Fields(Block block, IReleaseSpec spec, ref string? error) => true; // No blob transactions are expected, covered by ValidateTransactions also - protected override bool ValidateTransactions(Block block, IReleaseSpec spec, out string? errorMessage) + protected override bool ValidateTransactions(Block block, IReleaseSpec spec, ref string? errorMessage) { if (block.IsGenesis) { - errorMessage = null; return true; } - if (block.Transactions.Length is not 0) + if (block.Transactions.Length is not 0 && !ValidateAnchorTransaction(block.Transactions[0], block, (ITaikoReleaseSpec)spec, out errorMessage)) { - if (!ValidateAnchorTransaction(block.Transactions[0], block, (ITaikoReleaseSpec)spec, out errorMessage)) - return false; + return false; } - // TaikoPlugin initializes the TxValidator with a Always.Valid validator - return base.ValidateTransactions(block, spec, out errorMessage); + // TaikoPlugin initializes the TxValidator with an Always.Valid validator + return base.ValidateTransactions(block, spec, ref errorMessage); } private bool ValidateAnchorTransaction(Transaction tx, Block block, ITaikoReleaseSpec spec, out string? errorMessage) diff --git a/src/Nethermind/Nethermind.Taiko/TaikoHeaderValidator.cs b/src/Nethermind/Nethermind.Taiko/TaikoHeaderValidator.cs index 10713e7e8423..0236e250e187 100644 --- a/src/Nethermind/Nethermind.Taiko/TaikoHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Taiko/TaikoHeaderValidator.cs @@ -35,7 +35,7 @@ protected override bool ValidateTimestamp(BlockHeader header, BlockHeader parent return true; } - protected override bool ValidateTotalDifficulty(BlockHeader parent, BlockHeader header, ref string? error) + protected override bool ValidateTotalDifficulty(BlockHeader header, BlockHeader parent, ref string? error) { if (header.Difficulty != 0 || header.TotalDifficulty != 0 && header.TotalDifficulty != null) { @@ -46,9 +46,5 @@ protected override bool ValidateTotalDifficulty(BlockHeader parent, BlockHeader return true; } - protected override bool ValidateBlobGasFields(BlockHeader header, BlockHeader parentHeader, IReleaseSpec spec, ref string? error) - { - // not validated in taiko-geth - return true; - } + protected override bool ValidateBlobGasFields(BlockHeader header, BlockHeader parent, IReleaseSpec spec, ref string? error) => true; // not validated in taiko-geth } diff --git a/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs b/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs index 65132800130c..f5267e2b0d22 100644 --- a/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs +++ b/src/Nethermind/Nethermind.Trie.Test/Pruning/TreeStoreTests.cs @@ -106,12 +106,12 @@ public async Task Flush_ShouldBeCalledOnEachPersist() using (var _ = fullTrieStore.BeginScope(baseBlock)) { pt.Set(TestItem.KeccakA.BytesToArray(), TestItem.Keccaks[i].BytesToArray()); - using (ICommitter? committer = fullTrieStore.BeginStateBlockCommit(i + 1, trieNode)) + using (fullTrieStore.BeginStateBlockCommit(i + 1, trieNode)) { pt.Commit(); } - baseBlock = Build.A.BlockHeader.WithParent(baseBlock).WithStateRoot(pt.RootHash).TestObject; + baseBlock = Build.A.BlockHeader.WithParentOptional(baseBlock).WithStateRoot(pt.RootHash).TestObject; } await Task.Yield(); fullTrieStore.WaitForPruning(); @@ -1079,12 +1079,12 @@ public Task Will_RePersist_PersistedReCommittedNode() topTree.Set(key1, [1, 2]); topTree.Set(key2, [4, (byte)(i % 4)]); - using (ICommitter committer = fullTrieStore.BeginStateBlockCommit(i, topTree.Root)) + using (fullTrieStore.BeginStateBlockCommit(i, topTree.Root)) { topTree.Commit(); } - baseBlock = Build.A.BlockHeader.WithParent(baseBlock).WithStateRoot(topTree.RootHash).TestObject; + baseBlock = Build.A.BlockHeader.WithParentOptional(baseBlock).WithStateRoot(topTree.RootHash).TestObject; } fullTrieStore.WaitForPruning(); diff --git a/src/Nethermind/Nethermind.Xdc.Test/XdcHeaderValidatorTests.cs b/src/Nethermind/Nethermind.Xdc.Test/XdcHeaderValidatorTests.cs index f2897ca400f8..a5b527164068 100644 --- a/src/Nethermind/Nethermind.Xdc.Test/XdcHeaderValidatorTests.cs +++ b/src/Nethermind/Nethermind.Xdc.Test/XdcHeaderValidatorTests.cs @@ -1,18 +1,15 @@ // SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using FluentAssertions; using Nethermind.Blockchain; using Nethermind.Consensus; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; -using Nethermind.Crypto; using Nethermind.Logging; using Nethermind.Xdc.Spec; using NSubstitute; -using NSubstitute.ExceptionExtensions; using NUnit.Framework; using System; using System.Collections.Generic; @@ -24,10 +21,11 @@ public class Tests [Test] public void Validate_NotAnXdcHeader_ThrowsArgumentException() { - var header = Build.A.BlockHeader.TestObject; + BlockHeader parent = Build.A.BlockHeader.TestObject; + BlockHeader header = Build.A.BlockHeader.WithParent(parent).TestObject; XdcHeaderValidator validator = new(Substitute.For(), Substitute.For(), Substitute.For(), Substitute.For()); - Assert.That(() => validator.Validate(header, null, false, out string? error), Throws.TypeOf()); + Assert.That(() => validator.Validate(header, parent, false, out _), Throws.TypeOf()); } public static IEnumerable HeaderTestCases() @@ -35,65 +33,36 @@ public static IEnumerable HeaderTestCases() XdcBlockHeaderBuilder blockHeaderBuilder = CreateValidHeader(); //Base control case - yield return new object[] - { - blockHeaderBuilder, - true - }; + yield return [blockHeaderBuilder, true]; //Missing block seal - blockHeaderBuilder = CreateValidHeader(); - blockHeaderBuilder.WithValidator(Array.Empty()); - yield return new object[] - { - blockHeaderBuilder, - false - }; + blockHeaderBuilder = CreateValidHeader().WithValidator([]); + yield return [blockHeaderBuilder, false]; //No consensus data blockHeaderBuilder = CreateValidHeader(); blockHeaderBuilder.WithExtraData([]); - yield return new object[] - { - blockHeaderBuilder, - false - }; + yield return [blockHeaderBuilder, false]; //Invalid nonce value blockHeaderBuilder = CreateValidHeader(); blockHeaderBuilder.WithNonce(XdcConstants.NonceDropVoteValue + 1); - yield return new object[] - { - blockHeaderBuilder, - false - }; + yield return [blockHeaderBuilder, false]; //Invalid nonce value blockHeaderBuilder = CreateValidHeader(); blockHeaderBuilder.WithNonce(XdcConstants.NonceAuthVoteValue - 1); - yield return new object[] - { - blockHeaderBuilder, - false - }; + yield return [blockHeaderBuilder, false]; //Invalid mix hash blockHeaderBuilder = CreateValidHeader(); blockHeaderBuilder.WithMixHash(Hash256.FromBytesWithPadding([0x01])); - yield return new object[] - { - blockHeaderBuilder, - false - }; + yield return [blockHeaderBuilder, false]; //Invalid uncles hash blockHeaderBuilder = CreateValidHeader(); blockHeaderBuilder.WithUnclesHash(Hash256.FromBytesWithPadding([0x01])); - yield return new object[] - { - blockHeaderBuilder, - false - }; + yield return [blockHeaderBuilder, false]; static XdcBlockHeaderBuilder CreateValidHeader() { @@ -123,6 +92,6 @@ public void Validate_HeaderWithDifferentValues_ReturnsExpected(XdcBlockHeaderBui specProvider.GetSpec(Arg.Any()).Returns(releaseSpec); XdcHeaderValidator validator = new(Substitute.For(), sealValidator, specProvider, Substitute.For()); - Assert.That(validator.Validate(headerBuilder.TestObject, headerParent, false, out string? error), Is.EqualTo(expected)); + Assert.That(validator.Validate(headerBuilder.TestObject, headerParent, false, out _), Is.EqualTo(expected)); } } diff --git a/src/Nethermind/Nethermind.Xdc/XdcHeaderValidator.cs b/src/Nethermind/Nethermind.Xdc/XdcHeaderValidator.cs index 8a3b3b6ca388..a27f13914255 100644 --- a/src/Nethermind/Nethermind.Xdc/XdcHeaderValidator.cs +++ b/src/Nethermind/Nethermind.Xdc/XdcHeaderValidator.cs @@ -9,24 +9,19 @@ using Nethermind.Core.Specs; using Nethermind.Crypto; using Nethermind.Logging; -using Nethermind.Xdc.Spec; using Nethermind.Xdc.Types; using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; namespace Nethermind.Xdc; public class XdcHeaderValidator(IBlockTree blockTree, ISealValidator sealValidator, ISpecProvider specProvider, ILogManager? logManager = null) : HeaderValidator(blockTree, sealValidator, specProvider, logManager) { - - public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) + protected override bool Validate(BlockHeader header, BlockHeader? parent, bool isUncle, out string? error) { if (header is not XdcBlockHeader xdcHeader) throw new ArgumentException($"Only type of {nameof(XdcBlockHeader)} is allowed, but got type {header.GetType().Name}.", nameof(header)); - if (xdcHeader.Validator == null || xdcHeader.Validator.Length == 0) + if (xdcHeader.Validator is null || xdcHeader.Validator.Length == 0) { error = "Validator field is required in XDC header."; return false; @@ -49,17 +44,17 @@ public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUn if (xdcHeader.MixHash != Hash256.Zero) { - error = $"Non-zero mix hash."; + error = "Non-zero mix hash."; return false; } if (xdcHeader.UnclesHash != Keccak.OfAnEmptySequenceRlp) { - error = $"Cannot contain uncles."; + error = "Cannot contain uncles."; return false; } - if (!base.Validate(header, parent, isUncle, out error)) + if (!base.Validate(header, parent, isUncle, out error)) { return false; } @@ -86,13 +81,10 @@ protected override bool ValidateSeal(BlockHeader header, BlockHeader parent, boo return true; } - protected override bool ValidateExtraData(BlockHeader header, BlockHeader? parent, IReleaseSpec spec, bool isUncle, ref string? error) - { - //Extra consensus data is validated in SealValidator - return true; - } + // Extra consensus data is validated in SealValidator + protected override bool ValidateExtraData(BlockHeader header, IReleaseSpec spec, bool isUncle, ref string? error) => true; - protected override bool ValidateTotalDifficulty(BlockHeader parent, BlockHeader header, ref string? error) + protected override bool ValidateTotalDifficulty(BlockHeader header, BlockHeader parent, ref string? error) { if (header.Difficulty != 1) {