Broadcast own transactions only via short-lived Tor or I2P connections#29415
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/29415. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please copy-paste 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. |
This comment was marked as abuse.
This comment was marked as abuse.
bd82629 to
74ba7c7
Compare
|
@1440000bytes, thanks for asking! There is some discussion at #27509 (the previous attempt on this).
Yes, it is. See below.
Sending the transaction over clearnet reveals the IP address/geolocation of the sender. A spy with many connections to the network could try to guess who was the originator. So, why not send it to our Tor peers only? Because it is relatively easy for a spy to fingerprint and link clearnet and Tor connections to the same peer. That is, a long running connection over Tor could be linked to a long running clearnet connection. This is why the proposed changes open a short-lived connection that does not reveal any of the identity of the sender. Would this benefit nodes that don't have clearnet connections, e.g. Tor/I2P-only nodes? Yes! In the case where the sender sends two otherwise unrelated transactions over the same long-running Tor connection, the recipient will know that they have the same origin, even though they are not related on-chain. Using single shot connections fixes that too.
Linked in the OP, thanks! |
|
v2 Transport will be enabled by default in the next release (#29347). If there were eventually a change to force clearnet transactions over v2 transport (so the details of the communications were encrypted), would that solve the same problem that this PR is aiming to solve? |
|
@epiccurious, p2p encryption "solves" the spying from intermediate routers on clearnet (aka man-in-the-middle). Tor, I2P and CJDNS solve that too. While this PR uses only Tor and I2P it would solve that problem. But there is more - it will as well solve issues with spying bitcoin nodes. |
Suggested by: David Gumberg (bitcoin#29415 (comment))
|
Sorry for the late post-merge comment. I really like this enhancement, but I have a possible idea for a future tweak that should make it less obvious that a client is using the privatebroadcast mode. Instead of only establishing the 11th connection on-demand when a transaction is scheduled, would it not be significantly stealthier to establish the 11th connection (with dummy version and possibly limited functionality) beforehand if privatebroadcast is set, use it to broadcast our transaction whenever requested, then close it and reopen a new connection some random time after so as to be ready for a retry or a new transaction? It should then be much harder to discern that the connection was opened just to broadcast a single transaction. Doing it in that order could also help with the FEEFILTER issue that was previously mentioned, since our node should then generally have the necessary information about whether or not transactions at a particular fee level will be accepted by the remote node. |
When peer A connects to peer B and sends them a private broadcasted transaction, in practice A cannot hide from B that they are doing a private broadcast. The pattern is just too revealing, even if we prolong the connection duration and allow some more messages to be exchanged. Too much communication and we risk leaking identifying information from A to B. In the approach here we accept that B could deduce that they are a private broadcast recipient but cannot do any harm with that knowledge. |
Parts of this PR are isolated in independent smaller PRs to ease review:
To improve privacy, broadcast locally submitted transactions (from the
sendrawtransactionRPC) to the P2P network only via Tor or I2P short-lived connections, or to IPv4/IPv6 peers but through the Tor network.Introduce a new connection type for private broadcast of transactions with the following properties:
PINGis sent and after receivingPONGthe connection is closedPONG)Broadcast transactions submitted via
sendrawtransactionusing this new mechanism, to a few peers. Keep doing this until we receive back this transaction from one of our ordinary peers (this takes about 1 second on mainnet).The transaction is stored in peerman and does not enter the mempool.
Once we get an
INVfrom one of our ordinary peers, then the normal flow executes: we request the transaction withGETDATA, receive it with aTXmessage, put it in our mempool and broadcast it to all our existent connections (as if we see it for the first time).After we receive the full transaction as a
TXmessage, in reply to ourGETDATArequest, only then consider the transaction has propagated through the network and remove it from the storage in peerman, ending the private broadcast attempts.The messages exchange should look like this:
Whenever a new transaction is received from
sendrawtransactionRPC, the node will send it to a few (NUM_PRIVATE_BROADCAST_PER_TX) recipients right away. If after some time we still have not heard anything about the transaction from the network, then it will be sent to 1 more peer (seePeerManagerImpl::ReattemptPrivateBroadcast()).A few considerations:
How to test this?
Thank you, @stratospher and @andrewtoth!
Start
bitcoindwith-privatebroadcast=1 -debug=privatebroadcast.Create a wallet and get a new address, go to the Signet faucet and request some coins to that address:
Get a new address for the test transaction recipient:
Create the transaction:
Finally, send the transaction:
High-level explanation of the commits
New logging category and config option to enable private broadcast
log: introduce a new category for private broadcastinit: introduce a new option to enable/disable private broadcastImplement the private broadcast connection handling on the
CConnmanside:net: introduce a new connection type for private broadcastnet: implement opening PRIVATE_BROADCAST connectionsPrepare
BroadcastTransaction()for private broadcast requests:net_processing: rename RelayTransaction to better describe what it doesnode: extend node::TxBroadcast with a 3rd optionnet_processing: store transactions for private broadcast in PeerManagerImplement the private broadcast connection handling on the
PeerManagerside:net_processing: reorder the code that handles the VERSION messagenet_processing: move the debug log about receiving VERSION earliernet_processing: modernize PushNodeVersion()net_processing: move a debug check in VERACK processing earliernet_processing: handle ConnectionType::PRIVATE_BROADCAST connectionsnet_processing: stop private broadcast of a transaction after round-tripnet_processing: retry private broadcastEngage the new functionality from
sendrawtransaction:rpc: use private broadcast from sendrawtransaction RPC if -privatebroadcast is ONNew tests:
test: add functional test for private broadcasttest: add unit test for the private broadcast storageThis PR would resolve the following issues:
#3828 Clients leak IPs if they are recipients of a transaction
#14692 Can't configure bitocoind to only send tx via Tor but receive clearnet transactions
#19042 Tor-only transaction broadcast onlynet=onion alternative
#24557 Option for receive events with all networks, but send transactions and/or blocks only with anonymous network[s]?
#25450 Ability to broadcast wallet transactions only via dedicated oneshot Tor connections
#32235 Tor: TX circuit isolation
Issues that are related, but (maybe?) not to be resolved by this PR:
#21876 Broadcast a transaction to specific nodes
#28636 new RPC: sendrawtransactiontopeer
Further extensions:
submitpackageRPC do the private broadcast as well, draft diff in the comment below, thanks ismaelsadeeq!A previous incarnation of this can be found at #27509. It puts the transaction in the mempool and (tries to) hide it from the outside observers. This turned out to be too error prone or maybe even impossible.