Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New filter restricting delegations in txpool #8022

Merged
merged 22 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,19 @@ public void Accept_SenderIsNotDelegated_ReturnsAccepted()
[Test]
public void Accept_SenderIsDelegatedWithNoTransactionsInPool_ReturnsAccepted()
{
IDb stateDb = new MemDb();
IDb codeDb = new MemDb();
TrieStore trieStore = new(stateDb, LimboLogs.Instance);
IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance);
stateProvider.CreateAccount(TestItem.AddressA, 0);
CodeInfoRepository codeInfoRepository = new();
byte[] code = [.. Eip7702Constants.DelegationHeader, .. TestItem.PrivateKeyA.Address.Bytes];
codeInfoRepository.InsertCode(stateProvider, code, TestItem.AddressA, Prague.Instance);
IChainHeadSpecProvider headInfoProvider = Substitute.For<IChainHeadSpecProvider>();
headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance);
TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For<IComparer<Transaction>>(), NullLogManager.Instance);
TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For<IComparer<Transaction>>(), NullLogManager.Instance);
OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For<IReadOnlyStateProvider>(), new CodeInfoRepository(), new DelegationCache());
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();

Expand Down Expand Up @@ -107,12 +115,12 @@ public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_R

AcceptTxResult result = filter.Accept(transaction, ref state, TxHandlingOptions.None);

Assert.That(result, Is.EqualTo(AcceptTxResult.OnlyOneTxPerDelegatedAccount));
Assert.That(result, Is.EqualTo(AcceptTxResult.MoreThanOneTxPerDelegatedAccount));
}

private static object[] EipActiveCases =
{
new object[]{ true, AcceptTxResult.OnlyOneTxPerDelegatedAccount },
new object[]{ true, AcceptTxResult.MoreThanOneTxPerDelegatedAccount },
new object[]{ false, AcceptTxResult.Accepted},
};
[TestCaseSource(nameof(EipActiveCases))]
Expand Down
24 changes: 15 additions & 9 deletions src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1805,11 +1805,12 @@ public void Delegated_account_can_only_have_one_tx()

result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast);

result.Should().Be(AcceptTxResult.OnlyOneTxPerDelegatedAccount);
result.Should().Be(AcceptTxResult.MoreThanOneTxPerDelegatedAccount);
}

[Test]
public void Tx_with_pending_delegation_is_rejected_then_is_accepted_after_delegation_removal()
[TestCase(true)]
[TestCase(true)]
ak88 marked this conversation as resolved.
Show resolved Hide resolved
public void Tx_with_pending_delegation_is_rejected_then_is_accepted_after_delegation_removal(bool withRemoval)
{
ISpecProvider specProvider = GetPragueSpecProvider();
TxPoolConfig txPoolConfig = new TxPoolConfig { Size = 30, PersistentBlobStorageSize = 0 };
Expand Down Expand Up @@ -1842,15 +1843,20 @@ public void Tx_with_pending_delegation_is_rejected_then_is_accepted_after_delega
.WithTo(TestItem.AddressB)
.SignedAndResolved(_ethereumEcdsa, signer).TestObject;

result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast);

result.Should().Be(AcceptTxResult.PendingDelegation);
if (withRemoval)
{
_txPool.RemoveTransaction(firstTx.Hash);

_txPool.RemoveTransaction(firstTx.Hash);
result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast);

result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast);
result.Should().Be(AcceptTxResult.Accepted);
}
else
{
result = _txPool.SubmitTx(secondTx, TxHandlingOptions.PersistentBroadcast);

result.Should().Be(AcceptTxResult.AlreadyKnown);
result.Should().Be(AcceptTxResult.AlreadyKnown);
ak88 marked this conversation as resolved.
Show resolved Hide resolved
}
}

private IDictionary<ITxPoolPeer, PrivateKey> GetPeers(int limit = 100)
Expand Down
15 changes: 8 additions & 7 deletions src/Nethermind/Nethermind.TxPool/AcceptTxResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,21 @@ namespace Nethermind.TxPool
/// Ignores transactions if tx type is not supported
/// </summary>
public static readonly AcceptTxResult NotSupportedTxType = new(15, nameof(NotSupportedTxType));

/// <summary>
/// Only one tx is allowed per delegated account.
/// Transaction size exceeds configured max size.
/// </summary>
public static readonly AcceptTxResult OnlyOneTxPerDelegatedAccount = new(16, nameof(OnlyOneTxPerDelegatedAccount));
public static readonly AcceptTxResult MaxTxSizeExceeded = new(16, nameof(MaxTxSizeExceeded));

/// <summary>
/// There is a pending delegation in the tx pool already
/// Only one tx is allowed per delegated account.
/// </summary>
public static readonly AcceptTxResult PendingDelegation = new(17, nameof(PendingDelegation));

public static readonly AcceptTxResult MoreThanOneTxPerDelegatedAccount = new(17, nameof(MoreThanOneTxPerDelegatedAccount));

/// <summary>
/// Transaction size exceeds configured max size.
/// There is a pending delegation in the tx pool already
/// </summary>
public static readonly AcceptTxResult MaxTxSizeExceeded = new(16, nameof(MaxTxSizeExceeded));
public static readonly AcceptTxResult PendingDelegation = new(18, nameof(PendingDelegation));

/// <summary>
/// The node is syncing and cannot accept transactions at this time.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ 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 some other type
if (!standardPool.BucketEmptyExcept(tx.SenderAddress!, (t) => t.Nonce == tx.Nonce) || !blobPool.BucketEmptyExcept(tx.SenderAddress!, (t) => t.Nonce == tx.Nonce))
//Transactios 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))
{
return AcceptTxResult.OnlyOneTxPerDelegatedAccount;
return AcceptTxResult.MoreThanOneTxPerDelegatedAccount;
}
return AcceptTxResult.Accepted;
}
Expand Down