diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index a9a678349a3..e5dbe82595d 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -8,10 +8,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -44,11 +46,21 @@ static RPCHelpMan sendrawtransaction() { return RPCHelpMan{ "sendrawtransaction", - "Submit a raw transaction (serialized, hex-encoded) to local node and network.\n" - "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n" - "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n" - "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n" + "Submit a raw transaction (serialized, hex-encoded) to the network.\n" + + "\nIf -privatebroadcast is disabled, then the transaction will be put into the\n" + "local mempool of the node and will be sent unconditionally to all currently\n" + "connected peers, so using sendrawtransaction for manual rebroadcast will degrade\n" + "privacy by leaking the transaction's origin, as nodes will normally not\n" + "rebroadcast non-wallet transactions already in their mempool.\n" + + "\nIf -privatebroadcast is enabled, then the transaction will be sent only via\n" + "dedicated, short-lived connections to Tor or I2P peers or IPv4/IPv6 peers\n" + "via the Tor network. This conceals the transaction's origin. The transaction\n" + "will only enter the local mempool when it is received back from the network.\n" + "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_UTXO_SET, may throw if the transaction cannot be added to the mempool.\n" + "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, @@ -98,11 +110,23 @@ static RPCHelpMan sendrawtransaction() std::string err_string; AssertLockNotHeld(cs_main); NodeContext& node = EnsureAnyNodeContext(request.context); + const bool private_broadcast_enabled{gArgs.GetBoolArg("-privatebroadcast", DEFAULT_PRIVATE_BROADCAST)}; + if (private_broadcast_enabled && + !g_reachable_nets.Contains(NET_ONION) && + !g_reachable_nets.Contains(NET_I2P)) { + throw JSONRPCError(RPC_MISC_ERROR, + "-privatebroadcast is enabled, but none of the Tor or I2P networks is " + "reachable. Maybe the location of the Tor proxy couldn't be retrieved " + "from the Tor daemon at startup. Check whether the Tor daemon is running " + "and that -torcontrol, -torpassword and -i2psam are configured properly."); + } + const auto method = private_broadcast_enabled ? node::TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST + : node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL; const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, - node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL, + method, /*wait_callback=*/true); if (TransactionError::OK != err) { throw JSONRPCTransactionError(err, err_string);