diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs index 3f28d6257de..ed8a8906a48 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).AsBool().Should().BeFalse(); + txValidator.IsWellFormed(tx, null, MuirGlacier.Instance).AsBool().Should().BeFalse(); } private static byte CalculateV() => (byte)EthereumEcdsaExtensions.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).AsBool().Should().BeFalse(); + txValidator.IsWellFormed(tx, null, MuirGlacier.Instance).AsBool().Should().BeFalse(); } [Test, MaxTime(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).AsBool().Should().BeFalse(); + txValidator.IsWellFormed(tx, null, MuirGlacier.Instance).AsBool().Should().BeFalse(); } [Test, MaxTime(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).AsBool().Should().BeTrue(); + txValidator.IsWellFormed(tx, null, MuirGlacier.Instance).AsBool().Should().BeTrue(); } [Test, MaxTime(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).AsBool().Should().BeTrue(); + txValidator.IsWellFormed(tx, null, MuirGlacier.Instance).AsBool().Should().BeTrue(); } [MaxTime(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).AsBool().Should().Be(!validateChainId); + txValidator.IsWellFormed(tx, null, releaseSpec).AsBool().Should().Be(!validateChainId); } [MaxTime(Timeout.MaxTestTime)] @@ -161,7 +161,7 @@ public bool Before_eip_2930_has_to_be_legacy_tx(TxType txType, bool eip2930) tx.Type = txType; TxValidator txValidator = new(TestBlockchainIds.ChainId); - return txValidator.IsWellFormed(tx, eip2930 ? Berlin.Instance : MuirGlacier.Instance); + return txValidator.IsWellFormed(tx, null, eip2930 ? Berlin.Instance : MuirGlacier.Instance); } [MaxTime(Timeout.MaxTestTime)] @@ -192,7 +192,7 @@ public bool Before_eip_1559_has_to_be_legacy_or_access_list_tx(TxType txType, bo TxValidator txValidator = new(TestBlockchainIds.ChainId); IReleaseSpec releaseSpec = new ReleaseSpec() { IsEip2930Enabled = eip2930, IsEip1559Enabled = eip1559 }; - return txValidator.IsWellFormed(tx, releaseSpec); + return txValidator.IsWellFormed(tx, null, releaseSpec); } [MaxTime(Timeout.MaxTestTime)] @@ -216,7 +216,7 @@ public bool Chain_Id_required_for_non_legacy_transactions_after_Berlin(TxType tx tx.Type = txType; TxValidator txValidator = new(TestBlockchainIds.ChainId); - return txValidator.IsWellFormed(tx, Berlin.Instance); + return txValidator.IsWellFormed(tx, null, Berlin.Instance); } [MaxTime(Timeout.MaxTestTime)] @@ -247,7 +247,7 @@ public bool MaxFeePerGas_is_required_to_be_greater_than_MaxPriorityFeePerGas(TxT tx.Type = txType; TxValidator txValidator = new(TestBlockchainIds.ChainId); - return txValidator.IsWellFormed(tx, London.Instance); + return txValidator.IsWellFormed(tx, null, London.Instance); } [MaxTime(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).AsBool().Should().Be(expectedResult); + txValidator.IsWellFormed(tx, null, releaseSpec).AsBool().Should().Be(expectedResult); } //leading zeros in AccessList - expected to pass (real mainnet tx) @@ -312,7 +312,7 @@ public bool Incorrect_transactions_are_rejected(string rlp) { Transaction tx = Rlp.Decode(Bytes.FromHexString(rlp), RlpBehaviors.SkipTypedWrapping); TxValidator txValidator = new(BlockchainIds.Mainnet); - return txValidator.IsWellFormed(tx, London.Instance); + return txValidator.IsWellFormed(tx, null, London.Instance); } catch (Exception e) when (e is RlpException or ArgumentException) { @@ -345,8 +345,8 @@ public void ShardBlobTransactions_should_have_destination_set() .WithChainId(TestBlockchainIds.ChainId) .SignedAndResolved().TestObject; - Assert.That(txValidator.IsWellFormed(txWithoutTo, Cancun.Instance).AsBool(), Is.False); - Assert.That(txValidator.IsWellFormed(txWithTo, Cancun.Instance).AsBool()); + Assert.That(txValidator.IsWellFormed(txWithoutTo, null, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(txWithTo, null, Cancun.Instance).AsBool()); } [MaxTime(Timeout.MaxTestTime)] @@ -367,7 +367,7 @@ public bool MaxFeePerBlobGas_should_be_set_for_blob_tx_only(TxType txType, bool Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - return txValidator.IsWellFormed(tx, Cancun.Instance); + return txValidator.IsWellFormed(tx, null, Cancun.Instance); } [TestCaseSource(nameof(BlobVersionedHashInvalidTestCases))] @@ -384,14 +384,14 @@ public bool BlobVersionedHash_should_be_correct(byte[] hash) .SignedAndResolved().TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - return txValidator.IsWellFormed(tx, Cancun.Instance); + return txValidator.IsWellFormed(tx, null, Cancun.Instance); } [TestCaseSource(nameof(ShardBlobTxIncorrectTransactions))] public bool ShardBlobTransaction_fields_should_be_verified(Transaction tx) { TxValidator txValidator = new(TestBlockchainIds.ChainId); - return txValidator.IsWellFormed(tx, Cancun.Instance); + return txValidator.IsWellFormed(tx, null, Cancun.Instance); } [Test] @@ -405,7 +405,7 @@ public void IsWellFormed_NotBlobTxButMaxFeePerBlobGasIsSet_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -419,7 +419,7 @@ public void IsWellFormed_NotBlobTxButBlobVersionedHashesIsSet_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -436,7 +436,7 @@ public void IsWellFormed_BlobTxToIsNull_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] public void IsWellFormed_BlobTxHasMoreDataGasThanAllowed_ReturnFalse() @@ -452,7 +452,7 @@ public void IsWellFormed_BlobTxHasMoreDataGasThanAllowed_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -469,7 +469,7 @@ public void IsWellFormed_BlobTxHasNoBlobs_ReturnFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -486,7 +486,7 @@ public void IsWellFormed_BlobTxHasBlobOverTheSizeLimit_ReturnFalse() ((ShardBlobNetworkWrapper)tx.NetworkWrapper!).Blobs[0] = new byte[Ckzg.Ckzg.BytesPerBlob + 1]; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -503,7 +503,7 @@ public void IsWellFormed_BlobTxHasCommitmentOverTheSizeLimit_ReturnFalse() ((ShardBlobNetworkWrapper)tx.NetworkWrapper!).Commitments[0] = new byte[Ckzg.Ckzg.BytesPerCommitment + 1]; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -520,7 +520,7 @@ public void IsWellFormed_BlobTxHasProofOverTheSizeLimit_ReturnFalse() ((ShardBlobNetworkWrapper)tx.NetworkWrapper!).Proofs[0] = new byte[Ckzg.Ckzg.BytesPerProof + 1]; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Cancun.Instance).AsBool(), Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Cancun.Instance).AsBool(), Is.False); } [Test] @@ -540,7 +540,7 @@ public void IsWellFormed_CreateTxInSetCode_ReturnsFalse() Assert.Multiple(() => { - ValidationResult validationResult = txValidator.IsWellFormed(tx, Prague.Instance); + ValidationResult validationResult = txValidator.IsWellFormed(tx, null, Prague.Instance); Assert.That(validationResult.AsBool(), Is.False); Assert.That(validationResult.Error, Is.EqualTo(TxErrorMessages.NotAllowedCreateTransaction)); }); @@ -561,7 +561,7 @@ public void IsWellFormed_AuthorizationListTxInPragueSpec_ReturnsTrue() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Prague.Instance).AsBool, Is.True); + Assert.That(txValidator.IsWellFormed(tx, null, Prague.Instance).AsBool, Is.True); } [Test] @@ -579,7 +579,7 @@ public void IsWellFormed_EmptyAuthorizationList_ReturnsFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Prague.Instance).AsBool, Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Prague.Instance).AsBool, Is.False); } [Test] public void IsWellFormed_NullAuthorizationList_ReturnsFalse() @@ -596,7 +596,7 @@ public void IsWellFormed_NullAuthorizationList_ReturnsFalse() Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Prague.Instance).AsBool, Is.False); + Assert.That(txValidator.IsWellFormed(tx, null, Prague.Instance).AsBool, Is.False); } private static IEnumerable NonSetCodeTypes() => @@ -619,7 +619,7 @@ public void IsWellFormed_NonSetCodeTxHasAuthorizationList_ReturnsFalse(TxType ty Transaction tx = txBuilder.TestObject; TxValidator txValidator = new(TestBlockchainIds.ChainId); - Assert.That(txValidator.IsWellFormed(tx, Prague.Instance).Error, Is.EqualTo(TxErrorMessages.NotAllowedAuthorizationList)); + Assert.That(txValidator.IsWellFormed(tx, null, Prague.Instance).Error, Is.EqualTo(TxErrorMessages.NotAllowedAuthorizationList)); } 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 0550ac08ddb..7e72636a770 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/AlwaysValid.cs @@ -81,7 +81,7 @@ public bool Validate(BlockHeader header, BlockHeader[] uncles) return _result; } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) { return _validationResult; } diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs index 62f5c756cdf..08b093f0e85 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs @@ -282,7 +282,7 @@ protected virtual bool ValidateTransactions(Block block, IReleaseSpec spec, out { Transaction transaction = transactions[txIndex]; - ValidationResult isWellFormed = _txValidator.IsWellFormed(transaction, spec); + ValidationResult isWellFormed = _txValidator.IsWellFormed(transaction, block, spec); if (!isWellFormed) { if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Invalid transaction: {isWellFormed}"); diff --git a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs index b5db9fd9eef..be964d67f55 100644 --- a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs +++ b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs @@ -82,19 +82,19 @@ public TxValidator(ulong chainId) /// 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) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => _validators.TryGetByTxType(transaction.Type, out ITxValidator validator) - ? validator.IsWellFormed(transaction, releaseSpec) + ? validator.IsWellFormed(transaction, block, releaseSpec) : TxErrorMessages.InvalidTxType(releaseSpec.Name); } public sealed class CompositeTxValidator(List validators) : ITxValidator { - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) { foreach (ITxValidator validator in validators) { - ValidationResult isWellFormed = validator.IsWellFormed(transaction, releaseSpec); + ValidationResult isWellFormed = validator.IsWellFormed(transaction, block, releaseSpec); if (!isWellFormed) { return isWellFormed; @@ -110,7 +110,7 @@ public sealed class IntrinsicGasTxValidator : ITxValidator public static readonly IntrinsicGasTxValidator Instance = new(); private IntrinsicGasTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => // This is unnecessarily calculated twice - at validation and execution times. transaction.GasLimit < IntrinsicGasCalculator.Calculate(transaction, releaseSpec) ? TxErrorMessages.IntrinsicGasTooLow @@ -119,13 +119,13 @@ public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec relea public sealed class ReleaseSpecTxValidator(Func validate) : ITxValidator { - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => !validate(releaseSpec) ? TxErrorMessages.InvalidTxType(releaseSpec.Name) : ValidationResult.Success; } public sealed class ExpectedChainIdTxValidator(ulong chainId) : ITxValidator { - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction.ChainId != chainId ? TxErrorMessages.InvalidTxChainId(chainId, transaction.ChainId) : ValidationResult.Success; } @@ -134,7 +134,7 @@ public sealed class GasFieldsTxValidator : ITxValidator public static readonly GasFieldsTxValidator Instance = new(); private GasFieldsTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction.MaxFeePerGas < transaction.MaxPriorityFeePerGas ? TxErrorMessages.InvalidMaxPriorityFeePerGas : ValidationResult.Success; } @@ -143,7 +143,7 @@ public sealed class ContractSizeTxValidator : ITxValidator public static readonly ContractSizeTxValidator Instance = new(); private ContractSizeTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction.IsAboveInitCode(releaseSpec) ? TxErrorMessages.ContractSizeTooBig : ValidationResult.Success; } @@ -156,7 +156,7 @@ public sealed class NonBlobFieldsTxValidator : ITxValidator public static readonly NonBlobFieldsTxValidator Instance = new(); private NonBlobFieldsTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => transaction switch + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction switch { // Execution-payload version verification { MaxFeePerBlobGas: not null } => TxErrorMessages.NotAllowedMaxFeePerBlobGas, @@ -171,7 +171,7 @@ public sealed class NonSetCodeFieldsTxValidator : ITxValidator public static readonly NonSetCodeFieldsTxValidator Instance = new(); private NonSetCodeFieldsTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => transaction switch + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction switch { { AuthorizationList: not null } => TxErrorMessages.NotAllowedAuthorizationList, _ => ValidationResult.Success @@ -183,7 +183,7 @@ public sealed class BlobFieldsTxValidator : ITxValidator public static readonly BlobFieldsTxValidator Instance = new(); private BlobFieldsTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction switch { { To: null } => TxErrorMessages.TxMissingTo, @@ -225,7 +225,7 @@ public sealed class MempoolBlobTxValidator : ITxValidator public static readonly MempoolBlobTxValidator Instance = new(); private MempoolBlobTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) { int blobCount = transaction.BlobVersionedHashes!.Length; return transaction.NetworkWrapper is not ShardBlobNetworkWrapper wrapper ? ValidationResult.Success @@ -275,7 +275,7 @@ public abstract class BaseSignatureTxValidator : ITxValidator protected virtual ValidationResult ValidateChainId(Transaction transaction, IReleaseSpec releaseSpec) => releaseSpec.ValidateChainId ? TxErrorMessages.InvalidTxSignature : ValidationResult.Success; - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) { Signature? signature = transaction.Signature; if (signature is null) @@ -315,7 +315,7 @@ public sealed class NoContractCreationTxValidator : ITxValidator { public static readonly NoContractCreationTxValidator Instance = new(); private NoContractCreationTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction.IsContractCreation ? TxErrorMessages.NotAllowedCreateTransaction : ValidationResult.Success; } @@ -324,7 +324,7 @@ public sealed class AuthorizationListTxValidator : ITxValidator public static readonly AuthorizationListTxValidator Instance = new(); private AuthorizationListTxValidator() { } - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec) => + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) => transaction.AuthorizationList switch { null or { Length: 0 } => TxErrorMessages.MissingAuthorizationList, diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs index 7ed70774b64..9f2153e3b61 100644 --- a/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs +++ b/src/Nethermind/Nethermind.Core.Test/Builders/TransactionValidatorBuilder.cs @@ -36,8 +36,8 @@ public TransactionValidatorBuilder ThatAlwaysReturnsTrue protected override void BeforeReturn() { - TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any()).Returns(_always); - TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any()).Returns(_always); + TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any(), Arg.Any()).Returns(_always); + TestObjectInternal.IsWellFormed(Arg.Any(), Arg.Any(), Arg.Any()).Returns(_always); base.BeforeReturn(); } } diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs index 57953c0a226..6f5ea280f47 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs @@ -20,7 +20,7 @@ namespace Nethermind.Init.Steps { - [RunnerStepDependencies(typeof(InitTxTypesAndRlp), typeof(InitDatabase), typeof(MigrateConfigs), typeof(SetupKeyStore))] + [RunnerStepDependencies(typeof(InitTxTypesAndRlp), typeof(InitDatabase), typeof(MigrateConfigs), typeof(SetupKeyStore), typeof(InitTxTypesAndRlp))] public class InitializeBlockTree : IStep { private readonly IBasicApi _get; diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index e1c185d2aea..af52dcaf6b9 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -14,9 +14,11 @@ using Nethermind.Core; using Nethermind.Evm; using Nethermind.Evm.TransactionProcessing; +using Nethermind.Facade.Eth.RpcTransaction; using Nethermind.Init.Steps; using Nethermind.Merge.Plugin.InvalidChainTracker; using Nethermind.Optimism.Rpc; +using Nethermind.Serialization.Rlp.TxDecoders; using Nethermind.TxPool; namespace Nethermind.Optimism; @@ -36,6 +38,7 @@ protected override async Task InitBlockchain() await base.InitBlockchain(); api.RegisterTxType(new OptimismTxDecoder(), Always.Valid); + api.RegisterTxType(new OptimismLegacyTxDecoder(), Always.Valid); } protected override ITransactionProcessor CreateTransactionProcessor(CodeInfoRepository codeInfoRepository, VirtualMachine virtualMachine) diff --git a/src/Nethermind/Nethermind.Optimism/OptimismLegacyTxDecoder.cs b/src/Nethermind/Nethermind.Optimism/OptimismLegacyTxDecoder.cs new file mode 100644 index 00000000000..d8b1bd6efec --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/OptimismLegacyTxDecoder.cs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; +using Nethermind.Serialization.Rlp; +using Nethermind.Serialization.Rlp.TxDecoders; +using Nethermind.TxPool; + +namespace Nethermind.Optimism; + +public class OptimismLegacyTxDecoder : LegacyTxDecoder +{ + protected override Signature? DecodeSignature(ulong v, ReadOnlySpan rBytes, ReadOnlySpan sBytes, Signature? fallbackSignature = null, + RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + return base.DecodeSignature(v, rBytes, sBytes, fallbackSignature, rlpBehaviors | RlpBehaviors.AllowUnsigned); + } +} + +public class OptimismLegacyTxValidator(OptimismSpecHelper specHelper) : ITxValidator +{ + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec) + { + if (block is null || specHelper.IsBedrock(block.Header)) + { + return transaction.Signature is null ? new ValidationResult("Empty signature") : ValidationResult.Success; + } + + return ValidationResult.Success; + } +} diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index 277aadbbd25..e19d79eb953 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -24,12 +24,14 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Facade.Eth.RpcTransaction; using Nethermind.Merge.Plugin.Synchronization; using Nethermind.HealthChecks; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Serialization.Rlp; using Nethermind.Optimism.Rpc; +using Nethermind.Serialization.Rlp.TxDecoders; using Nethermind.Synchronization; namespace Nethermind.Optimism; @@ -84,6 +86,7 @@ public void InitTxTypesAndRlpDecoders(INethermindApi api) if (ShouldRunSteps(api)) { api.RegisterTxType(new OptimismTxDecoder(), Always.Valid); + api.RegisterTxType(new OptimismLegacyTxDecoder(), new OptimismLegacyTxValidator(((OptimismNethermindApi)api).SpecHelper!)); Rlp.RegisterDecoders(typeof(OptimismReceiptMessageDecoder).Assembly, true); } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/LegacyTxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/LegacyTxDecoder.cs index 3937f0c0ae2..99aba5bf70d 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/LegacyTxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/LegacyTxDecoder.cs @@ -7,7 +7,7 @@ namespace Nethermind.Serialization.Rlp.TxDecoders; -public sealed class LegacyTxDecoder(Func? transactionFactory = null) : BaseTxDecoder(TxType.Legacy, transactionFactory) where T : Transaction, new() +public class LegacyTxDecoder(Func? transactionFactory = null) : BaseTxDecoder(TxType.Legacy, transactionFactory) where T : Transaction, new() { private static bool IncludeSigChainIdHack(bool isEip155Enabled, ulong chainId) => isEip155Enabled && chainId != 0; diff --git a/src/Nethermind/Nethermind.Shutter/ShutterTxFilter.cs b/src/Nethermind/Nethermind.Shutter/ShutterTxFilter.cs index 8ca9fc7992b..1e492080af8 100644 --- a/src/Nethermind/Nethermind.Shutter/ShutterTxFilter.cs +++ b/src/Nethermind/Nethermind.Shutter/ShutterTxFilter.cs @@ -26,7 +26,7 @@ public AcceptTxResult IsAllowed(Transaction tx, BlockHeader parentHeader) } IReleaseSpec releaseSpec = specProvider.GetSpec(parentHeader); - ValidationResult wellFormed = _txValidator.IsWellFormed(tx, releaseSpec); + ValidationResult wellFormed = _txValidator.IsWellFormed(tx, null, releaseSpec); if (_logger.IsDebug && !wellFormed) _logger.Debug($"Decrypted Shutter transaction was not well-formed: {wellFormed}"); diff --git a/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs index 52f0753471d..984c7d1ff86 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/MalformedTxFilter.cs @@ -19,7 +19,7 @@ internal sealed class MalformedTxFilter( public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandlingOptions txHandlingOptions) { IReleaseSpec spec = specProvider.GetCurrentHeadSpec(); - if (!txValidator.IsWellFormed(tx, spec)) + if (!txValidator.IsWellFormed(tx, null, spec)) { Metrics.PendingTransactionsMalformed++; // It may happen that other nodes send us transactions that were signed for another chain or don't have enough gas. diff --git a/src/Nethermind/Nethermind.TxPool/ITxValidator.cs b/src/Nethermind/Nethermind.TxPool/ITxValidator.cs index 64c2075715f..b8678528e48 100644 --- a/src/Nethermind/Nethermind.TxPool/ITxValidator.cs +++ b/src/Nethermind/Nethermind.TxPool/ITxValidator.cs @@ -8,6 +8,6 @@ namespace Nethermind.TxPool { public interface ITxValidator { - public ValidationResult IsWellFormed(Transaction transaction, IReleaseSpec releaseSpec); + public ValidationResult IsWellFormed(Transaction transaction, Block? block, IReleaseSpec releaseSpec); } }