-
Notifications
You must be signed in to change notification settings - Fork 37.7k
test: Extend p2p_ibd_tx_relay.py to verify no-transaction are requested during IBD #20277
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
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
src/net_processing.cpp
Outdated
// | ||
// Orphan transaction is discarded. Note, we don't both to add id to recentRejects | ||
// as it's expected to be quickly clean up during IBD. | ||
if (ChainstateActive().IsInitialBlockDownload()) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the scope resolution operator need to be used here like everywhere else? if (::ChainstateActive().IsInitialBlockDownload()) return;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! I'll update once PR got Concept ACK/NACK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK. Thanks for adding the no-tx-request-in-IBD test. Verified the no-parent-orphan-in-IBD test fails without commit "p2p: Don't resolve orphans during IBD".
src/net_processing.cpp
Outdated
// | ||
// Orphan transaction is discarded. Note, we don't both to add id to recentRejects | ||
// as it's expected to be quickly clean up during IBD. | ||
if (ChainstateActive().IsInitialBlockDownload()) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
d65dca4 partial WIP suggestions, though I think it could still be more clearly written
- // To save bandwidth during IBD, stop orphan processing early. With the state of
- // our UTXO set far from tip, we might not have yet the unspent output spend by this
- // transaction or this transaction is already double-spend but not yet seen block.
- // Further, we can't assert accuracy of its feerate.
+ // If we are in IBD, exit from orphan processing early to save bandwidth. With the
+ // state of our UTXO set far from the tip, we might not yet have the unspent output
+ // of this transaction, or the transaction is already double-spent but not yet
+ // included in a block. We also cannot assert the accuracy of its feerate.
//
- // Orphan transaction is discarded. Note, we don't both to add id to recentRejects
- // as it's expected to be quickly clean up during IBD.
- if (ChainstateActive().IsInitialBlockDownload()) return;
+ // Orphan transaction is discarded. We don't bother to add it to recentRejects, as
+ // it's expected to be quickly cleaned up during IBD.
+ if (::ChainstateActive().IsInitialBlockDownload()) return;
"it's expected" is somewhat ambiguous, could you use an explicit subject?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this is the recentRejects filter. I did modify the comment to underscore that during IBD blocks are received fast and thus the filter quickly cleanup in consequence.
How much difference is this going to make in practice? For a node without incoming connections it seems unlikely to have peers that don't support the |
Concept ACK |
- feature_uacomment.py - feature_asmap.py
Right, I should have explicit the assumption on sender, that they are non-Bitcoin Core clients. Thus we can't be certain they enforce the regular tx-relay flow inv,getdata,tx but might send directly txn, don't bothering with any I agree that the waste is likely to be minor in any-case, but note that this PR is aiming to align behavior with current inv-reception code (L2690) as described in PR description. This point has the added benefit to make easier to reason on holistic tx-relay behavior when we review more important p2p stuff, IMHO. |
EDIT: this was for a different version of this PR. This seems like an extremely verbose PR to modify an unlikely and unimportant edge case. We don't expect to process unconfirmed transactions during IBD for a couple of reasons:
So a peer would need to send us an unsolicited tx ignoring our feefilter for us to even reach this logic. It seems inconsistent to process that transaction as normal, but not do the normal orphan processing logic too. We could modify the transaction processing logic to ignore all tx messages during IBD, which seems reasonable and at least consistent. I don't think we need a 10 line comment and 100 line test case to justify that - just say that we don't process unconfirmed transactions during IBD. |
I tend to agree with @jnewbery that just ignoring all unrequested transactions during IBD would make more sense, but I'd go further and suggest we generally ignore all unrequested transactions (perhaps excepting peers with PF_RELAY permission), to mitigate potential CPU DoS. |
8afa4fa
to
f6b125a
Compare
Thanks to answering my wonder about jumping directly to stop processing unrequested transaction instead of only scoping to orphan. Updated branch with this behavior.
I hear you on that, some reviewers might like comments on rational not only on code behaviors, even for edge cases, hard to all agree on. Note that "100 line test case" includes a new test ( |
f6b125a
to
51ea531
Compare
Note to reviewers, you might verify
And
|
51ea531
to
d6ebe6a
Compare
Thanks @MarcoFalke, updated at 75b45eb. |
d6ebe6a
to
75b45eb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK. Much prefer this more general approach to the original branch.
EDIT: this was for a different version of this PR.
75b45eb
to
0cd6088
Compare
If you want the ci to run on this, you might have to rebase on current master. Edit: Or maybe not |
@MarcoFalke Ah should I rebase on master to clean out the time out about libfuzzer+valgrind or it's cirrus-ci's VM runtime ? |
@ariard can you try rebasing? |
See mailing list thread, moving this PR as draft until I gather feedback on this proposal, or at least no one speaks up. |
As a minor procedural point, I think it would have been better to open a new PR for the current branch. This PR has now been through three significantly different iterations, and it's impossible to tell which versions the review comments/ACKs are referring to. |
test/functional/p2p_tx_download.py
Outdated
def test_unrequested_tx(self): | ||
self.log.info("Check that nodes don't process unrequested txn") | ||
self.restart_node(0) | ||
|
||
unrequested_tx = CTransaction() | ||
unrequested_tx.vin.append(CTxIn()) | ||
|
||
unrequested_tx.vout.append(CTxOut()) | ||
unrequested_tx.calc_sha256() | ||
|
||
peer = self.nodes[0].add_p2p_connection(P2PInterface()) | ||
peer.send_message(msg_tx(unrequested_tx)) | ||
with self.nodes[0].assert_debug_log(expected_msgs=['unrequested transaction from peer=0']): | ||
peer.sync_with_ping() | ||
assert_equal(len(self.nodes[0].getrawmempool()), 0) | ||
peer.peer_disconnect() | ||
peer.wait_for_disconnect() | ||
|
||
self.log.info("Check that nodes process unrequested txn with relay permission ") | ||
self.restart_node(0, extra_args=['-whitelist=relay@127.0.0.1']) | ||
|
||
peer = self.nodes[0].add_p2p_connection(P2PInterface()) | ||
peer.send_message(msg_tx(unrequested_tx)) | ||
with self.nodes[0].assert_debug_log(expected_msgs=['from peer=0 was not accepted: scriptpubkey']): | ||
peer.sync_with_ping() | ||
assert_equal(len(self.nodes[0].getrawmempool()), 0) | ||
peer.peer_disconnect() | ||
peer.wait_for_disconnect() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems that assert_equal(len(self.nodes[0].getrawmempool()), 0)
isn't really doing anything since the tx being used is always invalid so we don't ever expect it to be accepted to the mempool.
Suggest using a valid tx instead and then testing the changes to the mempool directly (count=0 if tx msg is received before being requested and count=1 if tx msg is received after tx is requested) instead of doing an implicit check via the logs using assert_debug_log
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good suggestion. Initially I was using valid transactions to feed the node and changed it after this comment. I guess the getrawmempool
is a leftover. Will remove it on #21224.
I think it's still fine to use invalid transactions as the behavior under check is "Does this transaction reach mempool acceptance ?", which is probed through the assert_debug_log
. "Is this transaction mempool-valid ?" is already a distinct checked behavior, of which we're not interested here ?
@jnewbery Agree, I've a new branch handling the parent-orphan fetching case and fixing all the tests. Going to open it soon and leave test coverage tx-requester extension here. |
35b4168
to
8d7d5dc
Compare
This PR has been restrained to the lightweight test coverage extension. The halting of unrequested transaction processing has been moved in its own one. See #21224 |
test/functional/p2p_ibd_txrelay.py
Outdated
peer = self.nodes[0].add_p2p_connection(P2PInterface()) | ||
peer.send_message(msg_inv([CInv(t=MSG_WTX, h=0xffaa)])) | ||
# As tx-announcing connection is inbound, wait for the inbound delay applied by requester. | ||
sleep(NONPREF_PEER_TX_DELAY) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could speed this up? I think txrequest works with mocktime, too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I can confirm txrequests works with mocktime. Updated with your suggestion.
8d7d5dc
to
ec04fa5
Compare
ACK ec04fa5 The test makes sense. I'd say it's gonna be easier to get this merged if you open a separate clean PR. As someone who looked at it for the first time, I found it distracting going through all irrelevant legacy comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK ec04fa5 with some questions and suggestions
@@ -324,6 +327,9 @@ def __init__(self, support_addrv2=False, wtxidrelay=True): | |||
# If the peer supports wtxid-relay | |||
self.wtxidrelay = wtxidrelay | |||
|
|||
# Getdata counter for tx-relay related tests | |||
self.tx_getdata_count = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5b2ab87 With this change can remove these lines?
--- a/test/functional/p2p_tx_download.py
+++ b/test/functional/p2p_tx_download.py
@@ -117,9 +117,6 @@ class TxDownloadTest(BitcoinTestFramework):
p = self.nodes[0].p2ps[0]
- with p2p_lock:
- p.tx_getdata_count = 0
-
mock_time = int(time.time() + 1)
@@ -37,6 +69,9 @@ def run_test(self): | |||
assert not node.getblockchaininfo()['initialblockdownload'] | |||
self.wait_until(lambda: all(peer['minfeefilter'] == NORMAL_FEE_FILTER for peer in node.getpeerinfo())) | |||
|
|||
def run_test(self): | |||
self.test_inv_ibd() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Would it make sense for this new test to be in
p2p_tx_download.py
where we have similar testing? - Perhaps also test that
tx_getdata_count
is/can be greater than zero once out of IBD?
A few PEP8 suggestions and (maybe, IIUC) a clarifying constant:
--- a/test/functional/p2p_ibd_txrelay.py
+++ b/test/functional/p2p_ibd_txrelay.py
@@ -8,6 +8,7 @@
"""
from decimal import Decimal
+import time
@@ -25,10 +26,10 @@ from test_framework.util import (
-import time
MAX_FEE_FILTER = Decimal(9170997) / COIN
NORMAL_FEE_FILTER = Decimal(100) / COIN
+WTXID = 0xffaa
@@ -43,7 +44,7 @@ class P2PIBDTxRelayTest(BitcoinTestFramework):
peer = self.nodes[0].add_p2p_connection(P2PInterface())
- peer.send_message(msg_inv([CInv(t=MSG_WTX, h=0xffaa)]))
+ peer.send_message(msg_inv([CInv(t=MSG_WTX, h=WTXID)]))
@@ -73,5 +74,6 @@ class P2PIBDTxRelayTest(BitcoinTestFramework):
self.test_feefilter_ibd()
+
if __name__ == '__main__':
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -122,7 +122,7 @@ MAGIC_BYTES = {
# Constants from net_processing
NONPREF_PEER_TX_DELAY = 2 # seconds
-TXID_RELAY_DELAY = 2 # seconds
+TXID_RELAY_DELAY = 2 # seconds
🐙 This pull request conflicts with the target branch and needs rebase. Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft". |
There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
@jnewbery @mzumsande @naumenkogs you might be interested in re-opening / following up with this change? |
This PR extends our functional test coverage of
net_processing.cpp
, following the overhaul of transaction request.It extends
p2p_ibd_txrelay.py
to verify that we don't request transaction during IBD, even lawfully ones from tx-relay peers. It also move network constants/methods inp2p.py
to serve generically across the test framework.