From d43b7d2955fd67dce6a99eea16df06abf0c72129 Mon Sep 17 00:00:00 2001 From: ak88 Date: Tue, 4 Feb 2025 23:41:23 +0100 Subject: [PATCH 01/15] start --- .../OnlyOneTxPerDelegatedAccountFilter.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index e45f477e245..ff9d67b75f8 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -22,6 +22,11 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl if (!spec.IsEip7702Enabled) return AcceptTxResult.Accepted; + if (tx.HasAuthorizationList && AuthorityHasPendingTx(tx.AuthorizationList)) + { + return AcceptTxResult.PendingDelegation; + } + if (pendingDelegations.HasPending(tx.SenderAddress!, tx.Nonce)) return AcceptTxResult.PendingDelegation; @@ -35,5 +40,16 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl } return AcceptTxResult.Accepted; } + private bool AuthorityHasPendingTx(AuthorizationTuple[] authorizations) + { + foreach (AuthorizationTuple authorization in authorizations) + { + if (!standardPool.BucketEmptyExcept(authorization.Authority!, (t) => t.Nonce == authorization.Nonce) + || !blobPool.BucketEmptyExcept(authorization.Authority!, (t) => t.Nonce == authorization.Nonce)) + { + + } + } + } } } From 8e723e0530340966e1565e6b2fea3aef24848510 Mon Sep 17 00:00:00 2001 From: ak88 Date: Wed, 5 Feb 2025 12:28:18 +0100 Subject: [PATCH 02/15] Dont allow if auth has pending tx --- .../Nethermind.TxPool/AcceptTxResult.cs | 5 +++++ .../OnlyOneTxPerDelegatedAccountFilter.cs | 16 +++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs index f707264a6d3..8e75632ad0e 100644 --- a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs +++ b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs @@ -105,6 +105,11 @@ namespace Nethermind.TxPool /// public static readonly AcceptTxResult PendingDelegation = new(18, nameof(PendingDelegation)); + /// + /// There is a pending transaction from a delegation in the tx pool already. + /// + public static readonly AcceptTxResult DelegatorHasPendingTx = new(19, nameof(DelegatorHasPendingTx)); + /// /// The node is syncing and cannot accept transactions at this time. /// diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index ff9d67b75f8..4aff7e28569 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -24,7 +24,7 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl if (tx.HasAuthorizationList && AuthorityHasPendingTx(tx.AuthorizationList)) { - return AcceptTxResult.PendingDelegation; + return AcceptTxResult.DelegatorHasPendingTx; } if (pendingDelegations.HasPending(tx.SenderAddress!, tx.Nonce)) @@ -32,7 +32,7 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl if (!codeInfoRepository.TryGetDelegation(worldState, tx.SenderAddress!, out _)) return AcceptTxResult.Accepted; - //Transactios from the same source can only be either blob transactions or other type + //Transactions from the same source can only be either blob transactions or other type if (tx.SupportsBlobs ? !blobPool.BucketEmptyExcept(tx.SenderAddress!, (t) => t.Nonce == tx.Nonce) : !standardPool.BucketEmptyExcept(tx.SenderAddress!, (t) => t.Nonce == tx.Nonce)) { @@ -40,16 +40,22 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl } return AcceptTxResult.Accepted; } + private bool AuthorityHasPendingTx(AuthorizationTuple[] authorizations) { foreach (AuthorizationTuple authorization in authorizations) { - if (!standardPool.BucketEmptyExcept(authorization.Authority!, (t) => t.Nonce == authorization.Nonce) - || !blobPool.BucketEmptyExcept(authorization.Authority!, (t) => t.Nonce == authorization.Nonce)) + if (authorization.Authority is null) { - + continue; + } + if (!standardPool.ContainsBucket(authorization.Authority!) + || !blobPool.ContainsBucket(authorization.Authority!)) + { + return true; } } + return false; } } } From 9a28213fbce6ae1c63909d2609a5618e0df7ef40 Mon Sep 17 00:00:00 2001 From: ak88 Date: Fri, 7 Feb 2025 00:42:53 +0100 Subject: [PATCH 03/15] self sponsored SetCode replacement --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 40 +++++++ .../Nethermind.TxPool.Test/TxPoolTests.cs | 107 +++++++++++++++++- .../Collections/DelegationPool.cs | 39 +++++++ .../OnlyOneTxPerDelegatedAccountFilter.cs | 19 +++- src/Nethermind/Nethermind.TxPool/TxPool.cs | 11 +- 5 files changed, 208 insertions(+), 8 deletions(-) create mode 100644 src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index b1751f03c23..34b3902a3f3 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -166,4 +166,44 @@ public void Accept_SenderHasPendingDelegation_ReturnsPendingDelegation() Assert.That(result, Is.EqualTo(AcceptTxResult.PendingDelegation)); } + + [TestCase(true)] + [TestCase(false)] + public void Accept_AuthorityHasPendingTransaction_ReturnsDelegatorHasPendingTx(bool useBlobPool) + { + IChainHeadSpecProvider headInfoProvider = Substitute.For(); + headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance); + TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For>(), NullLogManager.Instance); + TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); + OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), new()); + Transaction transaction; + if (useBlobPool) + { + transaction + = Build.A.Transaction + .WithShardBlobTxTypeAndFields() + .SignedAndResolved(TestItem.PrivateKeyA).TestObject; + blobPool.TryInsert(transaction.Hash, transaction, out _); + } + else + { + transaction + = Build.A.Transaction + .WithNonce(0) + .SignedAndResolved(TestItem.PrivateKeyA).TestObject; + standardPool.TryInsert(transaction.Hash, transaction, out _); + } + TxFilteringState state = new(); + EthereumEcdsa ecdsa = new EthereumEcdsa(0); + AuthorizationTuple authTuple = new AuthorizationTuple(0, TestItem.AddressB, 0, new Core.Crypto.Signature(0, 0, 27), TestItem.AddressA); + Transaction setCodeTx = Build.A.Transaction + .WithType(TxType.SetCode) + .WithAuthorizationCode(authTuple) + .SignedAndResolved(TestItem.PrivateKeyB) + .TestObject; + + AcceptTxResult setCodeTxResult = filter.Accept(setCodeTx, ref state, TxHandlingOptions.None); + + Assert.That(setCodeTxResult, Is.EqualTo(AcceptTxResult.DelegatorHasPendingTx)); + } } diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index b91e450f83b..77e56536256 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1748,7 +1748,7 @@ public void Should_correctly_add_tx_to_local_pool_when_underpaid([Values] TxType yield return ([.. Eip7702Constants.DelegationHeader, .. new byte[20]], AcceptTxResult.Accepted); } [TestCaseSource(nameof(CodeCases))] - public void SubmitTx_CodeIsNotDelegationAndDelegation_DelegationIsAccepted((byte[] code, AcceptTxResult expected) testCase) + public void Sender_account_has_delegation_and_normal_code((byte[] code, AcceptTxResult expected) testCase) { ISpecProvider specProvider = GetPragueSpecProvider(); TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 }; @@ -1810,7 +1810,7 @@ public void Delegated_account_can_only_have_one_tx() [TestCase(true)] [TestCase(false)] - public void Tx_with_pending_delegation_is_rejected_then_is_accepted_after_delegation_removal(bool withRemoval) + public void Tx_with_conflicting_pending_delegation_is_rejected_then_is_accepted_after_delegation_removal(bool withRemoval) { ISpecProvider specProvider = GetPragueSpecProvider(); TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 }; @@ -1859,6 +1859,109 @@ public void Tx_with_pending_delegation_is_rejected_then_is_accepted_after_delega } } + [TestCase(true)] + [TestCase(false)] + public void SetCode_tx_has_authority_with_pending_transaction_is_rejected_then_is_accepted_after_tx_removal(bool withRemoval) + { + ISpecProvider specProvider = GetPragueSpecProvider(); + TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 }; + _txPool = CreatePool(txPoolConfig, specProvider); + + PrivateKey signer = TestItem.PrivateKeyA; + _stateProvider.CreateAccount(signer.Address, UInt256.MaxValue); + + EthereumEcdsa ecdsa = new EthereumEcdsa(_specProvider.ChainId); + + Transaction firstTx = Build.A.Transaction + .WithNonce(0) + .WithType(TxType.EIP1559) + .WithMaxFeePerGas(9.GWei()) + .WithMaxPriorityFeePerGas(9.GWei()) + .WithGasLimit(GasCostOf.Transaction) + .WithTo(TestItem.AddressB) + .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + + AcceptTxResult result = _txPool.SubmitTx(firstTx, TxHandlingOptions.PersistentBroadcast); + result.Should().Be(AcceptTxResult.Accepted); + + Transaction secondTx = Build.A.Transaction + .WithNonce(0) + .WithType(TxType.SetCode) + .WithMaxFeePerGas(9.GWei()) + .WithMaxPriorityFeePerGas(9.GWei()) + .WithGasLimit(100_000) + .WithAuthorizationCode(ecdsa.Sign(signer, specProvider.ChainId, TestItem.AddressC, 0)) + .WithTo(TestItem.AddressB) + .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + + if (withRemoval) + { + _txPool.RemoveTransaction(firstTx.Hash); + + result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast); + + result.Should().Be(AcceptTxResult.Accepted); + } + else + { + result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast); + + result.Should().Be(AcceptTxResult.DelegatorHasPendingTx); + } + } + + [TestCase] + public void SetCode_tx_replament_can_replace_itself_and_remove_pending_delegation_restriction() + { + ISpecProvider specProvider = GetPragueSpecProvider(); + TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 }; + _txPool = CreatePool(txPoolConfig, specProvider); + + PrivateKey signer = TestItem.PrivateKeyA; + _stateProvider.CreateAccount(signer.Address, UInt256.MaxValue); + + EthereumEcdsa ecdsa = new EthereumEcdsa(_specProvider.ChainId); + + Transaction firstSetcodeTx = Build.A.Transaction + .WithNonce(0) + .WithType(TxType.SetCode) + .WithMaxFeePerGas(9.GWei()) + .WithMaxPriorityFeePerGas(9.GWei()) + .WithGasLimit(100_000) + .WithAuthorizationCode(ecdsa.Sign(signer, specProvider.ChainId, TestItem.AddressC, 0)) + .WithTo(TestItem.AddressB) + .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + + AcceptTxResult result = _txPool.SubmitTx(firstSetcodeTx, TxHandlingOptions.PersistentBroadcast); + result.Should().Be(AcceptTxResult.Accepted); + + Transaction replacementTx = Build.A.Transaction + .WithNonce(0) + .WithType(TxType.EIP1559) + .WithMaxFeePerGas(12.GWei()) + .WithMaxPriorityFeePerGas(12.GWei()) + .WithGasLimit(GasCostOf.Transaction) + .WithTo(TestItem.AddressB) + .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + + result = _txPool.SubmitTx(replacementTx, TxHandlingOptions.PersistentBroadcast); + + result.Should().Be(AcceptTxResult.Accepted); + + Transaction thirdTx = Build.A.Transaction + .WithNonce(1) + .WithType(TxType.EIP1559) + .WithMaxFeePerGas(9.GWei()) + .WithMaxPriorityFeePerGas(9.GWei()) + .WithGasLimit(GasCostOf.Transaction) + .WithTo(TestItem.AddressB) + .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + + result = _txPool.SubmitTx(thirdTx, TxHandlingOptions.PersistentBroadcast); + + result.Should().Be(AcceptTxResult.Accepted); + } + private IDictionary GetPeers(int limit = 100) { var peers = new Dictionary(); diff --git a/src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs new file mode 100644 index 00000000000..e4ba21b2086 --- /dev/null +++ b/src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Int256; +using Nethermind.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Nethermind.TxPool.Collections; +public class DelegationPool : SortedPool +{ + public DelegationPool(int capacity, IComparer comparer, ILogManager logManager) : base(capacity, comparer, logManager) + { + } + + protected override IComparer GetGroupComparer(IComparer comparer) + { + throw new NotImplementedException(); + } + + protected override UInt256 GetKey(Transaction value) + { + throw new NotImplementedException(); + } + + protected override IComparer GetUniqueComparer(IComparer comparer) + { + throw new NotImplementedException(); + } + + protected override AddressAsKey MapToGroup(Transaction value) + { + throw new NotImplementedException(); + } +} diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index 4aff7e28569..a4158741d9e 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -5,6 +5,7 @@ using Nethermind.State; using Nethermind.TxPool.Collections; using System.Collections.Concurrent; +using System.Linq; namespace Nethermind.TxPool.Filters { @@ -23,12 +24,21 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl return AcceptTxResult.Accepted; if (tx.HasAuthorizationList && AuthorityHasPendingTx(tx.AuthorizationList)) - { return AcceptTxResult.DelegatorHasPendingTx; - } if (pendingDelegations.HasPending(tx.SenderAddress!, tx.Nonce)) + { + Transaction[] userTxs = standardPool.GetSnapshot(); + //Check if the sender has a self-sponsored SetCode transaction with same nonce. + //If he does then this is a replacement tx and should be accepted + if (userTxs.Any(t => t.Nonce == tx.Nonce + && t.HasAuthorizationList + && t.AuthorizationList.Any(tuple => tuple.Authority == tx.SenderAddress))) + { + return AcceptTxResult.Accepted; + } return AcceptTxResult.PendingDelegation; + } if (!codeInfoRepository.TryGetDelegation(worldState, tx.SenderAddress!, out _)) return AcceptTxResult.Accepted; @@ -45,12 +55,13 @@ private bool AuthorityHasPendingTx(AuthorizationTuple[] authorizations) { foreach (AuthorizationTuple authorization in authorizations) { + //RecoverAuthorityFilter runs before so if a signature is null, it must be bad if (authorization.Authority is null) { continue; } - if (!standardPool.ContainsBucket(authorization.Authority!) - || !blobPool.ContainsBucket(authorization.Authority!)) + if (standardPool.ContainsBucket(authorization.Authority!) + || blobPool.ContainsBucket(authorization.Authority!)) { return true; } diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index 5bce5d6ac21..75cbec7a26d 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -120,6 +120,8 @@ public TxPool(IEthereumEcdsa ecdsa, TxPoolHeadChanged += _broadcaster.OnNewHead; _transactions = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, comparer, logManager); + _transactions.Removed += OnReplacedTx; + _blobTransactions = txPoolConfig.BlobsSupport.IsPersistentStorage() ? new PersistentBlobTxDistinctSortedPool(blobTxStorage, _txPoolConfig, comparer, logManager) : new BlobTxDistinctSortedPool(txPoolConfig.BlobsSupport == BlobsSupportMode.InMemory ? _txPoolConfig.InMemoryBlobPoolSize : 0, comparer, logManager); @@ -198,6 +200,10 @@ public bool TryGetBlobAndProof(byte[] blobVersionedHash, [NotNullWhen(true)] out byte[]? proof) => _blobTransactions.TryGetBlobAndProof(blobVersionedHash, out blob, out proof); + private void OnReplacedTx(object? sender, SortedPool.SortedPoolRemovedEventArgs args) + { + RemovePendingDelegations(args.Value); + } private void OnHeadChange(object? sender, BlockReplacementEventArgs e) { if (_headInfo.IsSyncing) return; @@ -460,7 +466,7 @@ private void AddPendingDelegations(Transaction tx) { if (tx.HasAuthorizationList) { - foreach (var auth in tx.AuthorizationList) + foreach (AuthorizationTuple auth in tx.AuthorizationList) { if (auth.Authority is not null) _pendingDelegations.IncrementDelegationCount(auth.Authority!, auth.Nonce); @@ -509,7 +515,7 @@ private AcceptTxResult AddCore(Transaction tx, ref TxFilteringState state, bool if (!inserted) { // it means it failed on adding to the pool - it is possible when new tx has the same sender - // and nonce as already existent tx and is not good enough to replace it + // and nonce as already eqxistent tx and is not good enough to replace it Metrics.PendingTransactionsPassedFiltersButCannotReplace++; return AcceptTxResult.ReplacementNotAllowed; } @@ -801,6 +807,7 @@ public void Dispose() _broadcaster.Dispose(); _headInfo.HeadChanged -= OnHeadChange; _headBlocksChannel.Writer.Complete(); + _transactions.Removed -= OnReplacedTx; } /// From fc13f46ef3ce027e7738bd7d62cedbdff0ae75a8 Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 12:22:42 +0100 Subject: [PATCH 04/15] Simplified filter --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 4 +- .../Nethermind.TxPool.Test/TxPoolTests.cs | 64 ++++++++++++++----- .../Nethermind.TxPool/AcceptTxResult.cs | 2 +- .../Collections/SortedPool.cs | 6 +- .../OnlyOneTxPerDelegatedAccountFilter.cs | 20 +++--- 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index 34b3902a3f3..93a99df7369 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -115,12 +115,12 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_R AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None); - Assert.That(result, Is.EqualTo(AcceptTxResult.MoreThanOneTxPerDelegatedAccount)); + Assert.That(result, Is.EqualTo(AcceptTxResult.OnlyExactNonceForDelegatedAccount)); } private static object[] EipActiveCases = { - new object[]{ true, AcceptTxResult.MoreThanOneTxPerDelegatedAccount }, + new object[]{ true, AcceptTxResult.OnlyExactNonceForDelegatedAccount }, new object[]{ false, AcceptTxResult.Accepted}, }; [TestCaseSource(nameof(EipActiveCases))] diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 77e56536256..3e038474d37 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1770,8 +1770,16 @@ public void Sender_account_has_delegation_and_normal_code((byte[] code, AcceptTx result.Should().Be(testCase.expected); } - [Test] - public void Delegated_account_can_only_have_one_tx() + private static IEnumerable DifferentOrderNonces() + { + yield return new object[] {0, 1, AcceptTxResult.Accepted, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; + yield return new object[] {2, 5, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; + yield return new object[] {1, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; + yield return new object[] {5, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; + } + + [TestCaseSource(nameof(DifferentOrderNonces))] + public void Delegated_account_can_only_have_one_tx_with_current_account_nonce(int firstNonce, int secondNonce, AcceptTxResult firstExpectation, AcceptTxResult secondExpectation) { ISpecProvider specProvider = GetPragueSpecProvider(); TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 }; @@ -1783,7 +1791,7 @@ public void Delegated_account_can_only_have_one_tx() _stateProvider.InsertCode(signer.Address, delegation.AsMemory(), Prague.Instance); Transaction firstTx = Build.A.Transaction - .WithNonce(0) + .WithNonce((UInt256)firstNonce) .WithType(TxType.EIP1559) .WithMaxFeePerGas(9.GWei()) .WithMaxPriorityFeePerGas(9.GWei()) @@ -1792,10 +1800,10 @@ public void Delegated_account_can_only_have_one_tx() .SignedAndResolved(_ethereumEcdsa, signer).TestObject; AcceptTxResult result = _txPool.SubmitTx(firstTx, TxHandlingOptions.PersistentBroadcast); - result.Should().Be(AcceptTxResult.Accepted); + result.Should().Be(firstExpectation); Transaction secondTx = Build.A.Transaction - .WithNonce(1) + .WithNonce((UInt256)secondNonce) .WithType(TxType.EIP1559) .WithMaxFeePerGas(9.GWei()) .WithMaxPriorityFeePerGas(9.GWei()) @@ -1805,7 +1813,7 @@ public void Delegated_account_can_only_have_one_tx() result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast); - result.Should().Be(AcceptTxResult.MoreThanOneTxPerDelegatedAccount); + result.Should().Be(secondExpectation); } [TestCase(true)] @@ -1817,7 +1825,9 @@ public void Tx_with_conflicting_pending_delegation_is_rejected_then_is_accepted_ _txPool = CreatePool(txPoolConfig, specProvider); PrivateKey signer = TestItem.PrivateKeyA; + PrivateKey sponsor = TestItem.PrivateKeyB; _stateProvider.CreateAccount(signer.Address, UInt256.MaxValue); + _stateProvider.CreateAccount(sponsor.Address, UInt256.MaxValue); EthereumEcdsa ecdsa = new EthereumEcdsa(_specProvider.ChainId); @@ -1829,7 +1839,7 @@ public void Tx_with_conflicting_pending_delegation_is_rejected_then_is_accepted_ .WithGasLimit(100_000) .WithAuthorizationCode(ecdsa.Sign(signer, specProvider.ChainId, TestItem.AddressC, 0)) .WithTo(TestItem.AddressB) - .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + .SignedAndResolved(_ethereumEcdsa, sponsor).TestObject; AcceptTxResult result = _txPool.SubmitTx(firstTx, TxHandlingOptions.PersistentBroadcast); result.Should().Be(AcceptTxResult.Accepted); @@ -1837,8 +1847,8 @@ public void Tx_with_conflicting_pending_delegation_is_rejected_then_is_accepted_ Transaction secondTx = Build.A.Transaction .WithNonce(0) .WithType(TxType.EIP1559) - .WithMaxFeePerGas(9.GWei()) - .WithMaxPriorityFeePerGas(9.GWei()) + .WithMaxFeePerGas(12.GWei()) + .WithMaxPriorityFeePerGas(12.GWei()) .WithGasLimit(GasCostOf.Transaction) .WithTo(TestItem.AddressB) .SignedAndResolved(_ethereumEcdsa, signer).TestObject; @@ -1910,16 +1920,40 @@ public void SetCode_tx_has_authority_with_pending_transaction_is_rejected_then_i } } - [TestCase] - public void SetCode_tx_replament_can_replace_itself_and_remove_pending_delegation_restriction() + private static IEnumerable SelfsponsoredSetCodeTxCases() + { + yield return new object[] + { + (IWorldState state, Address account, IReleaseSpec spec) => + { + state.CreateAccount(account, UInt256.MaxValue); + }, + AcceptTxResult.Accepted + }; + yield return new object[] + { + //Account is delegated so the last transaction should not be accepted + (IWorldState state, Address account, IReleaseSpec spec) => + { + state.CreateAccount(account, UInt256.MaxValue); + byte[] delegation = [..Eip7702Constants.DelegationHeader, ..TestItem.AddressB.Bytes]; + state.InsertCode(account, delegation, spec); + }, + AcceptTxResult.OnlyExactNonceForDelegatedAccount + }; + } + + + [TestCaseSource(nameof(SelfsponsoredSetCodeTxCases))] + public void Selfsponsored_SetCode_tx_replacement_can_replace_itself_and_remove_pending_delegation_restriction(Action accountSetup, AcceptTxResult lastExpectation) { ISpecProvider specProvider = GetPragueSpecProvider(); TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 }; _txPool = CreatePool(txPoolConfig, specProvider); PrivateKey signer = TestItem.PrivateKeyA; - _stateProvider.CreateAccount(signer.Address, UInt256.MaxValue); - + accountSetup(_stateProvider, signer.Address, Prague.Instance); + EthereumEcdsa ecdsa = new EthereumEcdsa(_specProvider.ChainId); Transaction firstSetcodeTx = Build.A.Transaction @@ -1954,12 +1988,12 @@ public void SetCode_tx_replament_can_replace_itself_and_remove_pending_delegatio .WithMaxFeePerGas(9.GWei()) .WithMaxPriorityFeePerGas(9.GWei()) .WithGasLimit(GasCostOf.Transaction) - .WithTo(TestItem.AddressB) + .WithTo(TestItem.AddressB) .SignedAndResolved(_ethereumEcdsa, signer).TestObject; result = _txPool.SubmitTx(thirdTx, TxHandlingOptions.PersistentBroadcast); - result.Should().Be(AcceptTxResult.Accepted); + result.Should().Be(lastExpectation); } private IDictionary GetPeers(int limit = 100) diff --git a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs index 8e75632ad0e..fe2e4133a39 100644 --- a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs +++ b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs @@ -98,7 +98,7 @@ namespace Nethermind.TxPool /// /// Only one tx is allowed per delegated account. /// - public static readonly AcceptTxResult MoreThanOneTxPerDelegatedAccount = new(17, nameof(MoreThanOneTxPerDelegatedAccount)); + public static readonly AcceptTxResult OnlyExactNonceForDelegatedAccount = new(17, nameof(OnlyExactNonceForDelegatedAccount)); /// /// There is a pending delegation in the tx pool already diff --git a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs index 49d9e53fad0..a17749b530b 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs @@ -530,12 +530,12 @@ public bool TryGetBucketsWorstValue(TGroupKey groupKey, out TValue? item) return false; } - public bool BucketEmptyExcept(TGroupKey groupKey, Func predicate) + public bool BucketAny(TGroupKey groupKey, Func predicate) { using var lockRelease = Lock.Acquire(); - if (_buckets.TryGetValue(groupKey, out EnhancedSortedSet? bucket) && bucket.Count > 0) + if (_buckets.TryGetValue(groupKey, out EnhancedSortedSet? bucket)) return bucket.Any(predicate); - return true; + return false; } protected void EnsureCapacity(int? expectedCapacity = null) diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index a4158741d9e..2818f5f569f 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -28,25 +28,23 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl if (pendingDelegations.HasPending(tx.SenderAddress!, tx.Nonce)) { - Transaction[] userTxs = standardPool.GetSnapshot(); //Check if the sender has a self-sponsored SetCode transaction with same nonce. //If he does then this is a replacement tx and should be accepted - if (userTxs.Any(t => t.Nonce == tx.Nonce - && t.HasAuthorizationList - && t.AuthorizationList.Any(tuple => tuple.Authority == tx.SenderAddress))) + if (!standardPool.BucketAny(tx.SenderAddress!, + t => t.Nonce == tx.Nonce + && t.HasAuthorizationList + && t.AuthorizationList.Any(tuple => tuple.Authority == tx.SenderAddress))) { - return AcceptTxResult.Accepted; + return AcceptTxResult.PendingDelegation; } - return AcceptTxResult.PendingDelegation; } if (!codeInfoRepository.TryGetDelegation(worldState, tx.SenderAddress!, out _)) return AcceptTxResult.Accepted; - //Transactions from the same source can only be either blob transactions or other type - if (tx.SupportsBlobs ? !blobPool.BucketEmptyExcept(tx.SenderAddress!, (t) => t.Nonce == tx.Nonce) - : !standardPool.BucketEmptyExcept(tx.SenderAddress!, (t) => t.Nonce == tx.Nonce)) + //If the account is delegated we only accept the next transaction nonce + if (state.SenderAccount.Nonce != tx.Nonce) { - return AcceptTxResult.MoreThanOneTxPerDelegatedAccount; + return AcceptTxResult.OnlyExactNonceForDelegatedAccount; } return AcceptTxResult.Accepted; } @@ -55,7 +53,7 @@ private bool AuthorityHasPendingTx(AuthorizationTuple[] authorizations) { foreach (AuthorizationTuple authorization in authorizations) { - //RecoverAuthorityFilter runs before so if a signature is null, it must be bad + //RecoverAuthorityFilter runs before this, so if a signature is null, we assume it is bad if (authorization.Authority is null) { continue; From d28594839b35ed2da22c1fef47a8766c9f8ec289 Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 12:24:32 +0100 Subject: [PATCH 05/15] format --- src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 3e038474d37..00a210fde9f 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1772,10 +1772,10 @@ public void Sender_account_has_delegation_and_normal_code((byte[] code, AcceptTx private static IEnumerable DifferentOrderNonces() { - yield return new object[] {0, 1, AcceptTxResult.Accepted, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; - yield return new object[] {2, 5, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; - yield return new object[] {1, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; - yield return new object[] {5, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; + yield return new object[] { 0, 1, AcceptTxResult.Accepted, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; + yield return new object[] { 2, 5, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; + yield return new object[] { 1, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; + yield return new object[] { 5, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; } [TestCaseSource(nameof(DifferentOrderNonces))] @@ -1953,7 +1953,7 @@ public void Selfsponsored_SetCode_tx_replacement_can_replace_itself_and_remove_p PrivateKey signer = TestItem.PrivateKeyA; accountSetup(_stateProvider, signer.Address, Prague.Instance); - + EthereumEcdsa ecdsa = new EthereumEcdsa(_specProvider.ChainId); Transaction firstSetcodeTx = Build.A.Transaction @@ -1988,7 +1988,7 @@ public void Selfsponsored_SetCode_tx_replacement_can_replace_itself_and_remove_p .WithMaxFeePerGas(9.GWei()) .WithMaxPriorityFeePerGas(9.GWei()) .WithGasLimit(GasCostOf.Transaction) - .WithTo(TestItem.AddressB) + .WithTo(TestItem.AddressB) .SignedAndResolved(_ethereumEcdsa, signer).TestObject; result = _txPool.SubmitTx(thirdTx, TxHandlingOptions.PersistentBroadcast); From 8bd30caf519e45022bf75fc8361305a0590c2bb6 Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 12:35:52 +0100 Subject: [PATCH 06/15] test fix --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index 93a99df7369..9ceefe8e7ff 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -59,7 +59,7 @@ public void Accept_SenderIsDelegatedWithNoTransactionsInPool_ReturnsAccepted() TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); Transaction transaction = Build.A.Transaction.SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; - TxFilteringState state = new(); + TxFilteringState state = new(transaction, stateProvider); AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None); @@ -85,7 +85,7 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithSameNonce_Return codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance); OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); Transaction transaction = Build.A.Transaction.SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; - TxFilteringState state = new(); + TxFilteringState state = new(transaction, stateProvider); AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None); @@ -110,8 +110,8 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_R byte[] code = [.. Eip7702Constants.DelegationHeader, .. TestItem.PrivateKeyA.Address.Bytes]; codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance); OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); - Transaction transaction = Build.A.Transaction.WithNonce(1).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; - TxFilteringState state = new(); + Transaction transaction = Build.A.Transaction.WithNonce(1).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; + TxFilteringState state = new(transaction, stateProvider); AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None); @@ -142,7 +142,7 @@ public void Accept_Eip7702IsNotActivated_ReturnsExpected(bool isActive, AcceptTx codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance); OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); Transaction transaction = Build.A.Transaction.WithNonce(1).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; - TxFilteringState state = new(); + TxFilteringState state = new(transaction, stateProvider); AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None); From 0f57db30964c4944c19725da67dc3b49968e1095 Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 12:41:04 +0100 Subject: [PATCH 07/15] remove nonce from DelegationCache --- .../Nethermind.TxPool/DelegationCache.cs | 34 ++++++------------- .../OnlyOneTxPerDelegatedAccountFilter.cs | 2 +- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool/DelegationCache.cs b/src/Nethermind/Nethermind.TxPool/DelegationCache.cs index f9a9be94475..1beba2074dc 100644 --- a/src/Nethermind/Nethermind.TxPool/DelegationCache.cs +++ b/src/Nethermind/Nethermind.TxPool/DelegationCache.cs @@ -14,28 +14,26 @@ namespace Nethermind.TxPool; internal sealed class DelegationCache { - private readonly ConcurrentDictionary _pendingDelegations = new(); + private readonly ConcurrentDictionary _pendingDelegations = new(); - public bool HasPending(AddressAsKey key, UInt256 nonce) + public bool HasPending(AddressAsKey key) { - return _pendingDelegations.ContainsKey(KeyMask(key, nonce)); + return _pendingDelegations.ContainsKey(key); } - public void DecrementDelegationCount(AddressAsKey key, UInt256 nonce) + public void DecrementDelegationCount(AddressAsKey key) { - InternalIncrement(key, nonce, false); + InternalIncrement(key, false); } - public void IncrementDelegationCount(AddressAsKey key, UInt256 nonce) + public void IncrementDelegationCount(AddressAsKey key) { - InternalIncrement(key, nonce, true); + InternalIncrement(key, true); } - private void InternalIncrement(AddressAsKey key, UInt256 nonce, bool increment) + private void InternalIncrement(AddressAsKey key, bool increment) { - UInt256 addressPlusNonce = KeyMask(key, nonce); - int value = increment ? 1 : -1; - var lastCount = _pendingDelegations.AddOrUpdate(addressPlusNonce, + var lastCount = _pendingDelegations.AddOrUpdate(key, (k) => { if (increment) @@ -47,18 +45,8 @@ private void InternalIncrement(AddressAsKey key, UInt256 nonce, bool increment) if (lastCount == 0) { //Remove() is threadsafe and only removes if the count is the same as the updated one - ((ICollection>)_pendingDelegations).Remove( - new KeyValuePair(addressPlusNonce, lastCount)); + ((ICollection>)_pendingDelegations).Remove( + new KeyValuePair(key, lastCount)); } } - - private static UInt256 KeyMask(AddressAsKey key, UInt256 nonce) - { - //A nonce cannot exceed 2^64-1 and an address is 20 bytes, so we can pack them together in one u256 - ref byte baseRef = ref key.Value.Bytes[0]; - return new UInt256(Unsafe.ReadUnaligned(ref baseRef), - Unsafe.ReadUnaligned(ref Unsafe.Add(ref baseRef, 8)), - Unsafe.ReadUnaligned(ref Unsafe.Add(ref baseRef, 16)), - nonce.u1); - } } diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index 2818f5f569f..8c77da4ae0a 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -26,7 +26,7 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl if (tx.HasAuthorizationList && AuthorityHasPendingTx(tx.AuthorizationList)) return AcceptTxResult.DelegatorHasPendingTx; - if (pendingDelegations.HasPending(tx.SenderAddress!, tx.Nonce)) + if (pendingDelegations.HasPending(tx.SenderAddress!)) { //Check if the sender has a self-sponsored SetCode transaction with same nonce. //If he does then this is a replacement tx and should be accepted From c6fa7f253d0e1567753601e0b268ba8a31e8b45e Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 12:42:50 +0100 Subject: [PATCH 08/15] remove nonce from DelegationCache --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 2 +- src/Nethermind/Nethermind.TxPool/TxPool.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index 9ceefe8e7ff..4c3ce7a9fff 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -157,7 +157,7 @@ public void Accept_SenderHasPendingDelegation_ReturnsPendingDelegation() TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For>(), NullLogManager.Instance); TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); DelegationCache pendingDelegations = new(); - pendingDelegations.IncrementDelegationCount(TestItem.AddressA, 0); + pendingDelegations.IncrementDelegationCount(TestItem.AddressA); OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), pendingDelegations); Transaction transaction = Build.A.Transaction.WithNonce(0).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(); diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index 75cbec7a26d..9252b6787ea 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -469,7 +469,7 @@ private void AddPendingDelegations(Transaction tx) foreach (AuthorizationTuple auth in tx.AuthorizationList) { if (auth.Authority is not null) - _pendingDelegations.IncrementDelegationCount(auth.Authority!, auth.Nonce); + _pendingDelegations.IncrementDelegationCount(auth.Authority!); } } } @@ -568,7 +568,7 @@ private void RemovePendingDelegations(Transaction transaction) foreach (var auth in transaction.AuthorizationList) { if (auth.Authority is not null) - _pendingDelegations.DecrementDelegationCount(auth.Authority!, auth.Nonce); + _pendingDelegations.DecrementDelegationCount(auth.Authority!); } } } From a9d046c8f323140e9f289dc0f23f6a9d01829fb5 Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 12:43:45 +0100 Subject: [PATCH 09/15] format --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index 4c3ce7a9fff..79051222c44 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -110,7 +110,7 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_R byte[] code = [.. Eip7702Constants.DelegationHeader, .. TestItem.PrivateKeyA.Address.Bytes]; codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance); OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); - Transaction transaction = Build.A.Transaction.WithNonce(1).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; + Transaction transaction = Build.A.Transaction.WithNonce(1).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(transaction, stateProvider); AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None); From 927b24176308d91bca02f02624ade656df2e99cb Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 15:03:50 +0100 Subject: [PATCH 10/15] Update src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs Co-authored-by: Lukasz Rozmej --- .../Filters/OnlyOneTxPerDelegatedAccountFilter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index 8c77da4ae0a..a147a941054 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -58,8 +58,8 @@ private bool AuthorityHasPendingTx(AuthorizationTuple[] authorizations) { continue; } - if (standardPool.ContainsBucket(authorization.Authority!) - || blobPool.ContainsBucket(authorization.Authority!)) + if (standardPool.ContainsBucket(authorization.Authority) + || blobPool.ContainsBucket(authorization.Authority)) { return true; } From 55409baa9c5f12a907b055158649104c6bce6b96 Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 15:08:24 +0100 Subject: [PATCH 11/15] cleanup and review comments --- .../Nethermind.TxPool.Test/TxPoolTests.cs | 27 ++++++++++--- .../Collections/DelegationPool.cs | 39 ------------------- .../Collections/SortedPool.cs | 5 +-- src/Nethermind/Nethermind.TxPool/TxPool.cs | 2 +- 4 files changed, 24 insertions(+), 49 deletions(-) delete mode 100644 src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index 00a210fde9f..e8120c9100d 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1920,18 +1920,33 @@ public void SetCode_tx_has_authority_with_pending_transaction_is_rejected_then_i } } - private static IEnumerable SelfsponsoredSetCodeTxCases() + private static IEnumerable SetCodeReplacedTxCases() { yield return new object[] { + //Not self sponsored + TestItem.PrivateKeyB, (IWorldState state, Address account, IReleaseSpec spec) => { state.CreateAccount(account, UInt256.MaxValue); + state.CreateAccount(TestItem.AddressB, UInt256.MaxValue); }, AcceptTxResult.Accepted }; yield return new object[] { + //Self sponsored + TestItem.PrivateKeyA, + (IWorldState state, Address account, IReleaseSpec spec) => + { + state.CreateAccount(account, UInt256.MaxValue); + }, + AcceptTxResult.Accepted + }; + yield return new object[] + { + //Self sponsored + TestItem.PrivateKeyA, //Account is delegated so the last transaction should not be accepted (IWorldState state, Address account, IReleaseSpec spec) => { @@ -1943,9 +1958,9 @@ private static IEnumerable SelfsponsoredSetCodeTxCases() }; } - - [TestCaseSource(nameof(SelfsponsoredSetCodeTxCases))] - public void Selfsponsored_SetCode_tx_replacement_can_replace_itself_and_remove_pending_delegation_restriction(Action accountSetup, AcceptTxResult lastExpectation) + [TestCaseSource(nameof(SetCodeReplacedTxCases))] + public void SetCode_tx_can_be_replaced_itself_and_remove_pending_delegation_restriction( + PrivateKey sponsor, Action accountSetup, AcceptTxResult lastExpectation) { ISpecProvider specProvider = GetPragueSpecProvider(); TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 }; @@ -1964,7 +1979,7 @@ public void Selfsponsored_SetCode_tx_replacement_can_replace_itself_and_remove_p .WithGasLimit(100_000) .WithAuthorizationCode(ecdsa.Sign(signer, specProvider.ChainId, TestItem.AddressC, 0)) .WithTo(TestItem.AddressB) - .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + .SignedAndResolved(_ethereumEcdsa, sponsor).TestObject; AcceptTxResult result = _txPool.SubmitTx(firstSetcodeTx, TxHandlingOptions.PersistentBroadcast); result.Should().Be(AcceptTxResult.Accepted); @@ -1976,7 +1991,7 @@ public void Selfsponsored_SetCode_tx_replacement_can_replace_itself_and_remove_p .WithMaxPriorityFeePerGas(12.GWei()) .WithGasLimit(GasCostOf.Transaction) .WithTo(TestItem.AddressB) - .SignedAndResolved(_ethereumEcdsa, signer).TestObject; + .SignedAndResolved(_ethereumEcdsa, sponsor).TestObject; result = _txPool.SubmitTx(replacementTx, TxHandlingOptions.PersistentBroadcast); diff --git a/src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs deleted file mode 100644 index e4ba21b2086..00000000000 --- a/src/Nethermind/Nethermind.TxPool/Collections/DelegationPool.cs +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using Nethermind.Core; -using Nethermind.Int256; -using Nethermind.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Nethermind.TxPool.Collections; -public class DelegationPool : SortedPool -{ - public DelegationPool(int capacity, IComparer comparer, ILogManager logManager) : base(capacity, comparer, logManager) - { - } - - protected override IComparer GetGroupComparer(IComparer comparer) - { - throw new NotImplementedException(); - } - - protected override UInt256 GetKey(Transaction value) - { - throw new NotImplementedException(); - } - - protected override IComparer GetUniqueComparer(IComparer comparer) - { - throw new NotImplementedException(); - } - - protected override AddressAsKey MapToGroup(Transaction value) - { - throw new NotImplementedException(); - } -} diff --git a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs index a17749b530b..2ea40b6ea77 100644 --- a/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs +++ b/src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs @@ -533,9 +533,8 @@ public bool TryGetBucketsWorstValue(TGroupKey groupKey, out TValue? item) public bool BucketAny(TGroupKey groupKey, Func predicate) { using var lockRelease = Lock.Acquire(); - if (_buckets.TryGetValue(groupKey, out EnhancedSortedSet? bucket)) - return bucket.Any(predicate); - return false; + return _buckets.TryGetValue(groupKey, out EnhancedSortedSet? bucket) + && bucket.Any(predicate); } protected void EnsureCapacity(int? expectedCapacity = null) diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index 9252b6787ea..a610a63005f 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -515,7 +515,7 @@ private AcceptTxResult AddCore(Transaction tx, ref TxFilteringState state, bool if (!inserted) { // it means it failed on adding to the pool - it is possible when new tx has the same sender - // and nonce as already eqxistent tx and is not good enough to replace it + // and nonce as already existent tx and is not good enough to replace it Metrics.PendingTransactionsPassedFiltersButCannotReplace++; return AcceptTxResult.ReplacementNotAllowed; } From 054e55dec3df559865c72e895fd8c58612978fee Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 16:47:57 +0100 Subject: [PATCH 12/15] one unit test and review comments --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 38 +++++++++++++++++-- .../Nethermind.TxPool.Test/TxPoolTests.cs | 10 ++--- .../Nethermind.TxPool/AcceptTxResult.cs | 4 +- .../OnlyOneTxPerDelegatedAccountFilter.cs | 2 +- src/Nethermind/Nethermind.TxPool/TxPool.cs | 6 +-- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index 79051222c44..fc0516e7887 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -1,7 +1,9 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Extensions; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Crypto; @@ -93,7 +95,7 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithSameNonce_Return } [Test] - public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_ReturnsOnlyOneTxPerDelegatedAccount() + public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_ReturnsOnlyExactNonceForDelegatedAccount() { IChainHeadSpecProvider headInfoProvider = Substitute.For(); headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance); @@ -115,12 +117,12 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_R AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None); - Assert.That(result, Is.EqualTo(AcceptTxResult.OnlyExactNonceForDelegatedAccount)); + Assert.That(result, Is.EqualTo(AcceptTxResult.FutureNonceForDelegatedAccount)); } private static object[] EipActiveCases = { - new object[]{ true, AcceptTxResult.OnlyExactNonceForDelegatedAccount }, + new object[]{ true, AcceptTxResult.FutureNonceForDelegatedAccount }, new object[]{ false, AcceptTxResult.Accepted}, }; [TestCaseSource(nameof(EipActiveCases))] @@ -206,4 +208,34 @@ public void Accept_AuthorityHasPendingTransaction_ReturnsDelegatorHasPendingTx(b Assert.That(setCodeTxResult, Is.EqualTo(AcceptTxResult.DelegatorHasPendingTx)); } + + [Test] + public void Accept_SetCodeTxHasAuthorityWithPendingTx_ReturnsDelegatorHasPendingTx() + { + IChainHeadSpecProvider headInfoProvider = Substitute.For(); + headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance); + TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For>(), NullLogManager.Instance); + TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); + DelegationCache pendingDelegations = new(); + pendingDelegations.IncrementDelegationCount(TestItem.AddressA); + OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), pendingDelegations); + Transaction transaction = Build.A.Transaction + .WithNonce(1) + .SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; + standardPool.TryInsert(transaction.Hash,transaction); + Transaction setCodeTransaction = Build.A.Transaction + .WithNonce(0) + .WithType(TxType.SetCode) + .WithMaxFeePerGas(9.GWei()) + .WithMaxPriorityFeePerGas(9.GWei()) + .WithGasLimit(100_000) + .WithAuthorizationCode(new AuthorizationTuple(0, TestItem.AddressC, 0, new Core.Crypto.Signature(new byte[64], 0), TestItem.AddressA)) + .WithTo(TestItem.AddressB) + .SignedAndResolved(TestItem.PrivateKeyB).TestObject; + TxFilteringState state = new(); + + AcceptTxResult result = filter.Accept(setCodeTransaction, ref state, TxHandlingOptions.None); + + Assert.That(result, Is.EqualTo(AcceptTxResult.DelegatorHasPendingTx)); + } } diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index e8120c9100d..39731ede34a 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -1772,10 +1772,10 @@ public void Sender_account_has_delegation_and_normal_code((byte[] code, AcceptTx private static IEnumerable DifferentOrderNonces() { - yield return new object[] { 0, 1, AcceptTxResult.Accepted, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; - yield return new object[] { 2, 5, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.OnlyExactNonceForDelegatedAccount }; - yield return new object[] { 1, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; - yield return new object[] { 5, 0, AcceptTxResult.OnlyExactNonceForDelegatedAccount, AcceptTxResult.Accepted }; + yield return new object[] { 0, 1, AcceptTxResult.Accepted, AcceptTxResult.FutureNonceForDelegatedAccount }; + yield return new object[] { 2, 5, AcceptTxResult.FutureNonceForDelegatedAccount, AcceptTxResult.FutureNonceForDelegatedAccount }; + yield return new object[] { 1, 0, AcceptTxResult.FutureNonceForDelegatedAccount, AcceptTxResult.Accepted }; + yield return new object[] { 5, 0, AcceptTxResult.FutureNonceForDelegatedAccount, AcceptTxResult.Accepted }; } [TestCaseSource(nameof(DifferentOrderNonces))] @@ -1954,7 +1954,7 @@ private static IEnumerable SetCodeReplacedTxCases() byte[] delegation = [..Eip7702Constants.DelegationHeader, ..TestItem.AddressB.Bytes]; state.InsertCode(account, delegation, spec); }, - AcceptTxResult.OnlyExactNonceForDelegatedAccount + AcceptTxResult.FutureNonceForDelegatedAccount }; } diff --git a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs index fe2e4133a39..0e50dfa3916 100644 --- a/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs +++ b/src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs @@ -96,9 +96,9 @@ namespace Nethermind.TxPool public static readonly AcceptTxResult MaxTxSizeExceeded = new(16, nameof(MaxTxSizeExceeded)); /// - /// Only one tx is allowed per delegated account. + /// Only one tx with current state matching nonce is allowed per delegated account. /// - public static readonly AcceptTxResult OnlyExactNonceForDelegatedAccount = new(17, nameof(OnlyExactNonceForDelegatedAccount)); + public static readonly AcceptTxResult FutureNonceForDelegatedAccount = new(17, nameof(FutureNonceForDelegatedAccount)); /// /// There is a pending delegation in the tx pool already diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index a147a941054..fb7303403b7 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -44,7 +44,7 @@ public AcceptTxResult Accept(Transaction tx, ref TxFilteringState state, TxHandl //If the account is delegated we only accept the next transaction nonce if (state.SenderAccount.Nonce != tx.Nonce) { - return AcceptTxResult.OnlyExactNonceForDelegatedAccount; + return AcceptTxResult.FutureNonceForDelegatedAccount; } return AcceptTxResult.Accepted; } diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index a610a63005f..86bc6f3e9d5 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -120,7 +120,7 @@ public TxPool(IEthereumEcdsa ecdsa, TxPoolHeadChanged += _broadcaster.OnNewHead; _transactions = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, comparer, logManager); - _transactions.Removed += OnReplacedTx; + _transactions.Removed += OnRemovedTx; _blobTransactions = txPoolConfig.BlobsSupport.IsPersistentStorage() ? new PersistentBlobTxDistinctSortedPool(blobTxStorage, _txPoolConfig, comparer, logManager) @@ -200,7 +200,7 @@ public bool TryGetBlobAndProof(byte[] blobVersionedHash, [NotNullWhen(true)] out byte[]? proof) => _blobTransactions.TryGetBlobAndProof(blobVersionedHash, out blob, out proof); - private void OnReplacedTx(object? sender, SortedPool.SortedPoolRemovedEventArgs args) + private void OnRemovedTx(object? sender, SortedPool.SortedPoolRemovedEventArgs args) { RemovePendingDelegations(args.Value); } @@ -807,7 +807,7 @@ public void Dispose() _broadcaster.Dispose(); _headInfo.HeadChanged -= OnHeadChange; _headBlocksChannel.Writer.Complete(); - _transactions.Removed -= OnReplacedTx; + _transactions.Removed -= OnRemovedTx; } /// From caeede5156ccada57158546465f9d5d958bd287b Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 17:07:51 +0100 Subject: [PATCH 13/15] renamed filter --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 20 +++++++++---------- .../OnlyOneTxPerDelegatedAccountFilter.cs | 2 +- src/Nethermind/Nethermind.TxPool/TxPool.cs | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index fc0516e7887..7a11d9d335f 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -26,7 +26,7 @@ using System.Threading.Tasks; namespace Nethermind.TxPool.Test; -internal class OnlyOneTxPerDelegatedAccountFilterTest +internal class DelegatedAccountFilterTest { [Test] public void Accept_SenderIsNotDelegated_ReturnsAccepted() @@ -35,7 +35,7 @@ public void Accept_SenderIsNotDelegated_ReturnsAccepted() headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance); TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For>(), NullLogManager.Instance); TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), new DelegationCache()); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), new DelegationCache()); Transaction transaction = Build.A.Transaction.SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(); @@ -59,7 +59,7 @@ public void Accept_SenderIsDelegatedWithNoTransactionsInPool_ReturnsAccepted() headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance); TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For>(), NullLogManager.Instance); TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); Transaction transaction = Build.A.Transaction.SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(transaction, stateProvider); @@ -85,7 +85,7 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithSameNonce_Return CodeInfoRepository codeInfoRepository = new(); byte[] code = [.. Eip7702Constants.DelegationHeader, .. TestItem.PrivateKeyA.Address.Bytes]; codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); Transaction transaction = Build.A.Transaction.SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(transaction, stateProvider); @@ -95,7 +95,7 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithSameNonce_Return } [Test] - public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_ReturnsOnlyExactNonceForDelegatedAccount() + public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_ReturnsFutureNonceForDelegatedAccount() { IChainHeadSpecProvider headInfoProvider = Substitute.For(); headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance); @@ -111,7 +111,7 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_R CodeInfoRepository codeInfoRepository = new(); byte[] code = [.. Eip7702Constants.DelegationHeader, .. TestItem.PrivateKeyA.Address.Bytes]; codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); Transaction transaction = Build.A.Transaction.WithNonce(1).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(transaction, stateProvider); @@ -142,7 +142,7 @@ public void Accept_Eip7702IsNotActivated_ReturnsExpected(bool isActive, AcceptTx CodeInfoRepository codeInfoRepository = new(); byte[] code = [.. Eip7702Constants.DelegationHeader, .. TestItem.PrivateKeyA.Address.Bytes]; codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, stateProvider, codeInfoRepository, new DelegationCache()); Transaction transaction = Build.A.Transaction.WithNonce(1).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(transaction, stateProvider); @@ -160,7 +160,7 @@ public void Accept_SenderHasPendingDelegation_ReturnsPendingDelegation() TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); DelegationCache pendingDelegations = new(); pendingDelegations.IncrementDelegationCount(TestItem.AddressA); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), pendingDelegations); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), pendingDelegations); Transaction transaction = Build.A.Transaction.WithNonce(0).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; TxFilteringState state = new(); @@ -177,7 +177,7 @@ public void Accept_AuthorityHasPendingTransaction_ReturnsDelegatorHasPendingTx(b headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance); TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For>(), NullLogManager.Instance); TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), new()); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), new()); Transaction transaction; if (useBlobPool) { @@ -218,7 +218,7 @@ public void Accept_SetCodeTxHasAuthorityWithPendingTx_ReturnsDelegatorHasPending TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For>(), NullLogManager.Instance); DelegationCache pendingDelegations = new(); pendingDelegations.IncrementDelegationCount(TestItem.AddressA); - OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), pendingDelegations); + DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For(), new CodeInfoRepository(), pendingDelegations); Transaction transaction = Build.A.Transaction .WithNonce(1) .SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs index fb7303403b7..d5d78f2f9e1 100644 --- a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs +++ b/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs @@ -9,7 +9,7 @@ namespace Nethermind.TxPool.Filters { - internal sealed class OnlyOneTxPerDelegatedAccountFilter( + internal sealed class DelegatedAccountFilter( IChainHeadSpecProvider specProvider, TxDistinctSortedPool standardPool, TxDistinctSortedPool blobPool, diff --git a/src/Nethermind/Nethermind.TxPool/TxPool.cs b/src/Nethermind/Nethermind.TxPool/TxPool.cs index 86bc6f3e9d5..471d5a7a15c 100644 --- a/src/Nethermind/Nethermind.TxPool/TxPool.cs +++ b/src/Nethermind/Nethermind.TxPool/TxPool.cs @@ -153,7 +153,7 @@ public TxPool(IEthereumEcdsa ecdsa, new FutureNonceFilter(txPoolConfig), new GapNonceFilter(_transactions, _blobTransactions, _logger), new RecoverAuthorityFilter(ecdsa), - new OnlyOneTxPerDelegatedAccountFilter(_specProvider, _transactions, _blobTransactions, chainHeadInfoProvider.ReadOnlyStateProvider, chainHeadInfoProvider.CodeInfoRepository, _pendingDelegations), + new DelegatedAccountFilter(_specProvider, _transactions, _blobTransactions, chainHeadInfoProvider.ReadOnlyStateProvider, chainHeadInfoProvider.CodeInfoRepository, _pendingDelegations), ]; if (incomingTxFilter is not null) From 57c7256f985d6ee84fd2dc6d85738c9d52402a84 Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 17:09:28 +0100 Subject: [PATCH 14/15] format --- .../OnlyOneTxPerDelegatedAccountFilterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs index 7a11d9d335f..edbe648a889 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs @@ -222,7 +222,7 @@ public void Accept_SetCodeTxHasAuthorityWithPendingTx_ReturnsDelegatorHasPending Transaction transaction = Build.A.Transaction .WithNonce(1) .SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject; - standardPool.TryInsert(transaction.Hash,transaction); + standardPool.TryInsert(transaction.Hash, transaction); Transaction setCodeTransaction = Build.A.Transaction .WithNonce(0) .WithType(TxType.SetCode) From 5594c0a77dab5cb320ba7f80031e49f34c863bcf Mon Sep 17 00:00:00 2001 From: ak88 Date: Mon, 10 Feb 2025 17:32:02 +0100 Subject: [PATCH 15/15] renamed files --- ...elegatedAccountFilterTest.cs => DelegatedAccountFilterTest.cs} | 0 ...neTxPerDelegatedAccountFilter.cs => DelegatedAccountFilter.cs} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Nethermind/Nethermind.TxPool.Test/{OnlyOneTxPerDelegatedAccountFilterTest.cs => DelegatedAccountFilterTest.cs} (100%) rename src/Nethermind/Nethermind.TxPool/Filters/{OnlyOneTxPerDelegatedAccountFilter.cs => DelegatedAccountFilter.cs} (100%) diff --git a/src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs b/src/Nethermind/Nethermind.TxPool.Test/DelegatedAccountFilterTest.cs similarity index 100% rename from src/Nethermind/Nethermind.TxPool.Test/OnlyOneTxPerDelegatedAccountFilterTest.cs rename to src/Nethermind/Nethermind.TxPool.Test/DelegatedAccountFilterTest.cs diff --git a/src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs b/src/Nethermind/Nethermind.TxPool/Filters/DelegatedAccountFilter.cs similarity index 100% rename from src/Nethermind/Nethermind.TxPool/Filters/OnlyOneTxPerDelegatedAccountFilter.cs rename to src/Nethermind/Nethermind.TxPool/Filters/DelegatedAccountFilter.cs