Skip to content

Commit

Permalink
Feature/filter setcode tx (#8167)
Browse files Browse the repository at this point in the history
Co-authored-by: Lukasz Rozmej <[email protected]>
  • Loading branch information
ak88 and LukaszRozmej authored Feb 12, 2025
1 parent 5a74ffc commit 6c755fb
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -24,7 +26,7 @@
using System.Threading.Tasks;

namespace Nethermind.TxPool.Test;
internal class OnlyOneTxPerDelegatedAccountFilterTest
internal class DelegatedAccountFilterTest
{
[Test]
public void Accept_SenderIsNotDelegated_ReturnsAccepted()
Expand All @@ -33,7 +35,7 @@ public void Accept_SenderIsNotDelegated_ReturnsAccepted()
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());
DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For<IReadOnlyStateProvider>(), new CodeInfoRepository(), new DelegationCache());
Transaction transaction = Build.A.Transaction.SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject;
TxFilteringState state = new();

Expand All @@ -57,9 +59,9 @@ public void Accept_SenderIsDelegatedWithNoTransactionsInPool_ReturnsAccepted()
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, 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();
TxFilteringState state = new(transaction, stateProvider);

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

Expand All @@ -83,17 +85,17 @@ 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();
TxFilteringState state = new(transaction, stateProvider);

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

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

[Test]
public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_ReturnsOnlyOneTxPerDelegatedAccount()
public void Accept_SenderIsDelegatedWithOneTransactionInPoolWithDifferentNonce_ReturnsFutureNonceForDelegatedAccount()
{
IChainHeadSpecProvider headInfoProvider = Substitute.For<IChainHeadSpecProvider>();
headInfoProvider.GetCurrentHeadSpec().Returns(Prague.Instance);
Expand All @@ -109,18 +111,18 @@ 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();
TxFilteringState state = new(transaction, stateProvider);

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

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

private static object[] EipActiveCases =
{
new object[]{ true, AcceptTxResult.MoreThanOneTxPerDelegatedAccount },
new object[]{ true, AcceptTxResult.FutureNonceForDelegatedAccount },
new object[]{ false, AcceptTxResult.Accepted},
};
[TestCaseSource(nameof(EipActiveCases))]
Expand All @@ -140,9 +142,9 @@ 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();
TxFilteringState state = new(transaction, stateProvider);

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

Expand All @@ -157,13 +159,83 @@ public void Accept_SenderHasPendingDelegation_ReturnsPendingDelegation()
TxDistinctSortedPool standardPool = new TxDistinctSortedPool(MemoryAllowance.MemPoolSize, Substitute.For<IComparer<Transaction>>(), NullLogManager.Instance);
TxDistinctSortedPool blobPool = new BlobTxDistinctSortedPool(10, Substitute.For<IComparer<Transaction>>(), NullLogManager.Instance);
DelegationCache pendingDelegations = new();
pendingDelegations.IncrementDelegationCount(TestItem.AddressA, 0);
OnlyOneTxPerDelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For<IReadOnlyStateProvider>(), new CodeInfoRepository(), pendingDelegations);
pendingDelegations.IncrementDelegationCount(TestItem.AddressA);
DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For<IReadOnlyStateProvider>(), new CodeInfoRepository(), pendingDelegations);
Transaction transaction = Build.A.Transaction.WithNonce(0).SignedAndResolved(new EthereumEcdsa(0), TestItem.PrivateKeyA).TestObject;
TxFilteringState state = new();

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

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

[TestCase(true)]
[TestCase(false)]
public void Accept_AuthorityHasPendingTransaction_ReturnsDelegatorHasPendingTx(bool useBlobPool)
{
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);
DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For<IReadOnlyStateProvider>(), 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));
}

[Test]
public void Accept_SetCodeTxHasAuthorityWithPendingTx_ReturnsDelegatorHasPendingTx()
{
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);
DelegationCache pendingDelegations = new();
pendingDelegations.IncrementDelegationCount(TestItem.AddressA);
DelegatedAccountFilter filter = new(headInfoProvider, standardPool, blobPool, Substitute.For<IReadOnlyStateProvider>(), 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));
}
}
Loading

0 comments on commit 6c755fb

Please sign in to comment.