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

Fix/6790 return accepted for rejected tx added to broadcast #6889

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 40 additions & 6 deletions src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,41 @@ public void should_add_underpaid_txs_to_full_TxPool_only_if_local(bool isLocal)
AcceptTxResult result = _txPool.SubmitTx(tx, txHandlingOptions);
_txPool.GetPendingTransactionsCount().Should().Be(30);
_txPool.GetOwnPendingTransactions().Length.Should().Be(isLocal ? 1 : 0);
result.ToString().Should().Contain(isLocal ? nameof(AcceptTxResult.FeeTooLowToCompete) : nameof(AcceptTxResult.FeeTooLow));
result.ToString().Should().Contain(isLocal ? nameof(AcceptTxResult.Accepted) : nameof(AcceptTxResult.FeeTooLow));
}

[TestCase(true)]
[TestCase(false)]
public void should_accept_underpaid_txs_if_persistent(bool isPersistentBroadcast) {
// copy and past of the code above for my test use.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of adding this test, test which you multiplied is testing local transactions and local is just other name for persistentBroadcast so it is already tested in the test above

TxHandlingOptions txHandlingOptions = isPersistentBroadcast ? TxHandlingOptions.PersistentBroadcast : TxHandlingOptions.None;

_txPool = CreatePool(new TxPoolConfig() { Size = 1 });

Transaction[] transactions = GetTransactions(GetPeers(3), true, false);

foreach (Address address in transactions.Select(t => t.SenderAddress).Distinct())
{
EnsureSenderBalance(address, UInt256.MaxValue);
}

foreach (Transaction transaction in transactions)
{
transaction.GasPrice = 10;
_txPool.SubmitTx(transaction, TxHandlingOptions.None);
}

Transaction tx = Build.A.Transaction
.WithGasPrice(UInt256.Zero)
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA)
.TestObject;
EnsureSenderBalance(tx.SenderAddress, UInt256.MaxValue);
_txPool.GetPendingTransactionsCount().Should().Be(1);
_txPool.GetOwnPendingTransactions().Length.Should().Be(0);
AcceptTxResult result = _txPool.SubmitTx(tx, txHandlingOptions);
_txPool.GetPendingTransactionsCount().Should().Be(1);
_txPool.GetOwnPendingTransactions().Length.Should().Be(isPersistentBroadcast ? 1 : 0);
result.ToString().Should().Contain(isPersistentBroadcast ? nameof(AcceptTxResult.Accepted) : nameof(AcceptTxResult.FeeTooLow));
}

[TestCase(0)]
Expand Down Expand Up @@ -1381,7 +1415,7 @@ public void should_increase_nonce_when_transaction_not_included_in_txPool_but_br
.WithMaxFeePerGas(1)
.WithMaxPriorityFeePerGas(1)
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).TestObject;
_txPool.SubmitTx(cheapTx, TxHandlingOptions.PersistentBroadcast).Should().Be(AcceptTxResult.FeeTooLowToCompete);
_txPool.SubmitTx(cheapTx, TxHandlingOptions.PersistentBroadcast).Should().Be(AcceptTxResult.Accepted);
_txPool.GetPendingTransactions().Should().NotContain(cheapTx);
_txPool.GetOwnPendingTransactions().Should().Contain(cheapTx);
peer.Received().SendNewTransaction(cheapTx);
Expand All @@ -1393,7 +1427,7 @@ public void should_increase_nonce_when_transaction_not_included_in_txPool_but_br
.WithMaxFeePerGas(1)
.WithMaxPriorityFeePerGas(1)
.SignedAndResolved(_ethereumEcdsa, TestItem.PrivateKeyA).TestObject;
_txPool.SubmitTx(fourthTx, TxHandlingOptions.PersistentBroadcast).Should().Be(AcceptTxResult.FeeTooLowToCompete);
_txPool.SubmitTx(fourthTx, TxHandlingOptions.PersistentBroadcast).Should().Be(AcceptTxResult.Accepted);
_txPool.GetPendingTransactions().Should().NotContain(fourthTx);
_txPool.GetOwnPendingTransactions().Should().Contain(fourthTx);
peer.Received().SendNewTransaction(fourthTx);
Expand Down Expand Up @@ -1530,7 +1564,7 @@ public void Should_not_replace_better_txs_by_worse_ones()
.SignedAndResolved(_ethereumEcdsa, privateKeyOfAttacker).TestObject;

AcceptTxResult result = _txPool.SubmitTx(tx, TxHandlingOptions.PersistentBroadcast);
result.Should().Be(AcceptTxResult.FeeTooLowToCompete);
result.Should().Be(AcceptTxResult.Accepted);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It definitely shouldn't be accepted here, it is a great example of why we need to refactor Broadcast to be TryBroadcast - then it will return false and we will not return AcceptTxResult.Accepted, but AcceptTxResult.FeeTooLowToCompete.
Not accepting txs in this place is a clue of this test, please not modify it - instead modify nethermind code to pass this test


// newly coming txs should evict themselves
_txPool.GetPendingTransactionsBySender().Keys.Count.Should().Be(txPoolConfig.Size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here we have an evidence that txs from above were not actually accepted. So we can't return AcceptTxResult.Accepted in such scenario

Expand Down Expand Up @@ -1582,7 +1616,7 @@ public void Should_not_replace_ready_txs_by_nonce_gap_ones()
.WithGasPrice(1000)
.SignedAndResolved(_ethereumEcdsa, privateKeyOfAttacker).TestObject;

_txPool.SubmitTx(tx, TxHandlingOptions.PersistentBroadcast).Should().Be(AcceptTxResult.FeeTooLowToCompete);
_txPool.SubmitTx(tx, TxHandlingOptions.PersistentBroadcast).Should().Be(AcceptTxResult.Accepted);

// newly coming txs should evict themselves
_txPool.GetPendingTransactionsBySender().Keys.Count.Should().Be(txPoolConfig.Size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same story as in test Should_not_replace_better_txs_by_worse_ones()

Expand All @@ -1591,7 +1625,7 @@ public void Should_not_replace_ready_txs_by_nonce_gap_ones()
_txPool.GetPendingTransactionsCount().Should().Be(txPoolConfig.Size);
}

[TestCase(9, false)]
[TestCase(9, true)]
[TestCase(11, true)]
public void Should_not_add_underpaid_tx_even_if_lower_nonces_are_expensive(int gasPrice, bool expectedResult)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clue of this test, please don't modify it. It should pass when you refactor Broadcast to be TryBroadcast and return Accepted only if successfully added to broadcaster collection

{
Expand Down
11 changes: 5 additions & 6 deletions src/Nethermind/Nethermind.TxPool/TxPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -450,14 +450,13 @@ private AcceptTxResult AddCore(Transaction tx, TxFilteringState state, bool isPe
if (tx.Hash == removed?.Hash)
{
// it means it was added and immediately evicted - pool was full of better txs
if (isPersistentBroadcast)
if (!isPersistentBroadcast || tx.SupportsBlobs)
{
// we are adding only to persistent broadcast - not good enough for standard pool,
// but can be good enough for TxBroadcaster pool - for local txs only
_broadcaster.Broadcast(tx, isPersistentBroadcast);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happened to _broadcaster.Broadcast call?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the if branch now has the opposite condition, if the tx is persistent (and not a blob tx), it would run to the end of the function (line 462~483).

_broadcaster.Broadcast will be run at line 477.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if running through all the normal flow here is best choice as this is a special case, when something we are not adding to main pool will have broadcasting, will wait for @marcindsobczak opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a good option, we definitely don't want to run through all the normal flow here

Metrics.PendingTransactionsPassedFiltersButCannotCompeteOnFees++;
return AcceptTxResult.FeeTooLowToCompete;
}
Metrics.PendingTransactionsPassedFiltersButCannotCompeteOnFees++;
return AcceptTxResult.FeeTooLowToCompete;
// we are adding only to persistent broadcast - not good enough for standard pool,
// but can be good enough for TxBroadcaster pool - for local txs only
}

relevantPool.UpdateGroup(tx.SenderAddress!, state.SenderAccount, UpdateBucketWithAddedTransaction);
Expand Down