Skip to content

test: add test for rebroadcast of transaction received via p2p#34359

Merged
sedited merged 1 commit intobitcoin:masterfrom
mzumsande:202601_test_rebroadcast
Mar 11, 2026
Merged

test: add test for rebroadcast of transaction received via p2p#34359
sedited merged 1 commit intobitcoin:masterfrom
mzumsande:202601_test_rebroadcast

Conversation

@mzumsande
Copy link
Contributor

@mzumsande mzumsande commented Jan 21, 2026

The wallet doesn't only rebroadcast transactions it created, but also relevant transactions received via p2p.
Since this is not self-evident, add test coverage for it.

@DrahtBot DrahtBot added the Tests label Jan 21, 2026
@DrahtBot
Copy link
Contributor

DrahtBot commented Jan 21, 2026

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/34359.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK maflcko, vasild, furszy, danielabrozzoni

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #34533 (wallet: resubmit transactions with private broadcast if enabled by vasild)

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.

@vasild
Copy link
Contributor

vasild commented Jan 22, 2026

2026-01-21T03:34:27.4304152Z �[0;36m test 2026-01-21T03:34:27.140268Z TestFramework (INFO): node0 sends a tx to node1 and disconnects �[0m
...
2026-01-21T03:34:27.4319719Z �[0;34m node0 2026-01-21T03:34:27.149584Z (mocktime: 2026-02-07T03:50:31Z) [httpworker.1] [wallet/wallet.h:938] [WalletLogPrintf] [default_wallet] Submitting wtx c255f5b61919a60877d4e91eb81f656f85e743513119f5ddcc9cffc4ffb62b45 to mempool and for broadcast to peers �[0m
...
2026-01-21T03:34:27.4320508Z �[0;34m node0 2026-01-21T03:34:27.149947Z (mocktime: 2026-02-07T03:50:31Z) [httpworker.1] [wallet/wallet.h:938] [WalletLogPrintf] [default_wallet] CommitTransaction(): Transaction cannot be broadcast immediately, bad-txns-inputs-missingorspent �[0m

So, node0 did not like the transaction it generated and failed to broadcast it to node1: bad-txns-inputs-missingorspent. Happens only sometimes.

@mzumsande
Copy link
Contributor Author

mzumsande commented Jan 22, 2026

yes - because of the wallet bug, the wallet creates an invalid transaction, trying to double-spend an utxo that was already used in a block. The node then rejects that tx obviously, and the rpc querying for the tx fails.
I'll rebase on #34358 with the next push. [Edit:done now]

@mzumsande
Copy link
Contributor Author

rebased/undrafted after merge of #34358

@mzumsande mzumsande marked this pull request as ready for review January 29, 2026 03:05
@vasild vasild mentioned this pull request Feb 2, 2026
13 tasks
Copy link
Contributor

@vasild vasild left a comment

Choose a reason for hiding this comment

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

ACK 5c9dedf

@mzumsande
Copy link
Contributor Author

5c9dedf to b2c9eac: addressed feedback

Copy link
Contributor

@vasild vasild left a comment

Choose a reason for hiding this comment

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

ACK b2c9eac

@mzumsande
Copy link
Contributor Author

b2c9eac to 990e2cd: rebased

Copy link
Contributor

@vasild vasild left a comment

Choose a reason for hiding this comment

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

ACK 990e2cd

def set_test_params(self):
self.num_nodes = 1
self.num_nodes = 2
self.extra_args = [["-whitelist=relay,noban@127.0.0.1"], ["-whitelist=relay,noban@127.0.0.1"]]
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason why this is needed? Without this, sending the tx fails, but I don't see why.

Copy link
Contributor

Choose a reason for hiding this comment

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

node0 must have node1 with the noban permission in order to send the transaction to it without delay in this part of the test:

        self.log.info("node0 sends a tx to node1 and disconnects")
        recv_addr = node1.getnewaddress()
        recv_txid = node.sendtoaddress(recv_addr, 1)

bitcoin/src/net_processing.cpp

Lines 5981 to 5989 in b6b8f8a

bool fSendTrickle = node.HasPermission(NetPermissionFlags::NoBan);
if (tx_relay->m_next_inv_send_time < current_time) {
fSendTrickle = true;
if (node.IsInboundConn()) {
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL, node.m_network_key);
} else {
tx_relay->m_next_inv_send_time = current_time + m_rng.rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
}
}

Note that in this part of the test the time is frozen and does not flow because setmocktime() has been called on node0 so it never sets fSendTrickle to true and thus never sends the transaction to node1.

Btw this suffices:

Suggested change
self.extra_args = [["-whitelist=relay,noban@127.0.0.1"], ["-whitelist=relay,noban@127.0.0.1"]]
self.extra_args = [["-whitelist=noban@127.0.0.1"], []]

Copy link
Member

Choose a reason for hiding this comment

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

Ok, that is pretty obvious, thx. Could also add a comment, like # Needed due to mocktime. A third alternative could be self.noban_tx_relay = True # Needed due to mocktime.

Copy link
Contributor

Choose a reason for hiding this comment

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

... or to advance the mocktime across NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL, node.m_network_key) but that would always leave, at least in theory, some chance that we did not advance enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

used self.noban_tx_relay, which is more common

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

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

lgtm. Feel free to ignore the nits.

I guess this doesn't add any coverage in terms of new paths/lines, because the wallet does not differentiate between tx sources, but if this ever were to change in the future, this test would already be there.

review ACK 990e2cd 🦉

Show signature

Signature:

untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: review ACK 990e2cd0babf7a2ee90d7b40e91a0c7477511957 🦉
Qvh92TAwBuuBKdQwPindEYsKDLnaNpJ8iBuqe/CM1y4flECUTk5rYxTez0Xkgs5tWg/eb7685VUp8bnGdkSgCQ==

node.setmocktime(now + RESEND_TIMER_LIMIT)
# Tell scheduler to call MaybeResendWalletTxs now.
node.mockscheduler(60)
# Give some time for trickle to occur
Copy link
Member

Choose a reason for hiding this comment

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

nit: I guess this is no longer needed and can be removed now? Also -- unrelated, the peer_second.wait_for_broadcast([txid]) can be moved into the assert_debug_log scope, so that the timeout=2-polling on it can be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

The wallet doesn't only rebroadcast transactions it created, but
also relevant transactions received via p2p. Since this is not
self-evident, add test coverage for it.
@mzumsande mzumsande force-pushed the 202601_test_rebroadcast branch from 990e2cd to 73e3853 Compare February 27, 2026 11:33
@mzumsande
Copy link
Contributor Author

mzumsande commented Feb 27, 2026

990e2cd to 73e3853: addressed feedback

I guess this doesn't add any coverage in terms of new paths/lines, because the wallet does not differentiate between tx sources, but if this ever were to change in the future, this test would already be there.

Yes, my main motivation is to have a test for this behavior before discussing changes to it.

I knew that rebroadcast has privacy downsides, but I always thought that just making sure your txns confirm in a couple of hours would be sufficient to mitigate it, which seemed annoying but manageable to me.

But I never realized that just passively (not submitting any txns) running a Bitcoin core node for a day with a loaded wallet used a long time ago (maybe even with private broadcast then) would put you at risk of being deanonymized via dusting / rebroadcast tracking - even though I'm sure more regular wallet contributors knew this, after all there is the ancient issue #3828.

@maflcko
Copy link
Member

maflcko commented Feb 27, 2026

Just addressed some nits:

re-ACK 73e3853 🦌

Show signature

Signature:

untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
trusted comment: re-ACK 73e385311055eb6c0e3ddb2221f927a3872af1fb 🦌
zjBj3GEv01zf0Guo3qrZXQrLOPpIZFK4Wx5VdzynhAezS9nYDqHGcmp3CUltj2Hh6GlStWdIsBrwFwXA3CVbBQ==

@DrahtBot DrahtBot requested a review from vasild February 27, 2026 12:20
Copy link
Contributor

@vasild vasild left a comment

Choose a reason for hiding this comment

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

ACK 73e3853

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

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

ACK 73e3853

@DrahtBot DrahtBot mentioned this pull request Mar 4, 2026
Copy link
Member

@danielabrozzoni danielabrozzoni left a comment

Choose a reason for hiding this comment

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

tACK 73e3853

It wasn't obvious to me that the wallet rebroadcasts transactions it's the recipient of, so it's nice to have a test that makes this a bit more explicit.

I left a micro-nit in case you need to retouch, otherwise it's good as-is.

node.getmempoolentry(txid)
node.getmempoolentry(child_txid)

self.log.info("Test rebroadcast of transactions received by others")
Copy link
Member

Choose a reason for hiding this comment

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

nit: I find "received by others" to be slightly confusing, because instead of reading it as "p2p tx message that someone sent us", I read it as "transaction whose recipient is someone else", which is the opposite of what's happening here (node1 does the rebroadcast and is the recipient).

Maybe "Test rebroadcast of incoming wallet transactions" is clearer.

@sedited sedited merged commit 3201abe into bitcoin:master Mar 11, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants