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

Feature/filter setcode tx #8167

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
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
Loading