rpc: make getprivatebroadcastinfo fail if privatebroadcast is not enabled #35267

pull polespinasa wants to merge 3 commits into bitcoin:master from polespinasa:2026-05-11-getprivatetransactioninfoonlyifenabled changing 5 files +16 −0
  1. polespinasa commented at 10:10 PM on May 11, 2026: member

    Makes getprivatebroadcast throw if -privatebroadcast=0.

    This is motivated by: https://github.com/sparrowwallet/sparrow/issues/1989

    Knowing if privatebroadcast is set can be useful for some external software like Sparrow to avoid call getprivatebroadcastinfo each time to see if broadcast was done through that.

  2. DrahtBot added the label RPC/REST/ZMQ on May 11, 2026
  3. DrahtBot commented at 10:10 PM on May 11, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

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

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK andrewtoth, w0xlt
    Approach ACK stickies-v

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

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #34628 (p2p: Replace per-peer transaction rate-limiting with global rate limits by ajtowns)

    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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. polespinasa force-pushed on May 11, 2026
  5. DrahtBot added the label CI failed on May 11, 2026
  6. DrahtBot commented at 10:25 PM on May 11, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/actions/runs/25700308615/job/75458691350</sub> <sub>LLM reason (✨ experimental): CI failed due to a lint error: missing required trailing newline in doc/release-notes-35267.md (lint check trailing_newline).</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  7. in test/functional/p2p_private_broadcast.py:349 in d68687e981


    andrewtoth commented at 10:27 PM on May 11, 2026:

    We already call getprivatebroadcastinfo() here for the tx_originator, so we can assert it's True here instead of duplicating the call for it below.


    polespinasa commented at 10:37 PM on May 11, 2026:

    done


    polespinasa commented at 2:24 PM on May 12, 2026:

    I've reverted this change and moved back where it was inspired by your other comment. That's a function called multiple times, there is no need to perform that check each time it is called.


    stickies-v commented at 7:23 AM on May 14, 2026:

    It doesn't seem straightforward to verify that this change to NetTest doesn't potentially cause issues to other tests that use this class. I think it'd be better to keep this self contained?


    polespinasa commented at 9:05 AM on May 14, 2026:

    The only approach that I can imagine while containing the test inside test_getnetworkinfo() is this, but I don't really like it:

    $ git diff
    diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
    index 1a4d1b44ff..9acfe8ef83 100755
    --- a/test/functional/rpc_net.py
    +++ b/test/functional/rpc_net.py
    @@ -24,6 +24,7 @@ from test_framework.util import (
         assert_greater_than,
         assert_raises_rpc_error,
         p2p_port,
    +    write_config,
     )
     from test_framework.wallet import MiniWallet
     
    @@ -64,16 +65,12 @@ class NetTest(BitcoinTestFramework):
             self.num_nodes = 2
             self.extra_args = [
                 ["-minrelaytxfee=0.00001000"],
    -            [
    -                "-minrelaytxfee=0.00000500",
    -                "-privatebroadcast",
    -            ],
    +            ["-minrelaytxfee=0.00000500"],
             ]
             # Specify a non-working proxy to make sure no actual connections to public IPs are attempted
             for args in self.extra_args:
                 args.append("-proxy=127.0.0.1:1")
             self.supports_cli = False
    -        self.disable_autoconnect = False
     
         def run_test(self):
             # We need miniwallet to make a transaction
    @@ -218,7 +215,17 @@ class NetTest(BitcoinTestFramework):
             assert_equal(info['connections_in'], 1)
             assert_equal(info['connections_out'], 1)
             assert_equal(info['privatebroadcast'], "disabled")
    +
    +        # Temporarily rewrite node 1's config without connect=0 so that
    +        # -privatebroadcast (which is incompatible with -connect) can be tested.
    +        write_config(self.nodes[1].datadir_path / "bitcoin.conf", n=1, chain=self.chain, disable_autoconnect=False)
    +        self.restart_node(1, extra_args=["-minrelaytxfee=0.00000500", "-proxy=127.0.0.1:1", "-privatebroadcast"])
             assert_equal(self.nodes[1].getnetworkinfo()['privatebroadcast'], "enabled")
    +        write_config(self.nodes[1].datadir_path / "bitcoin.conf", n=1, chain=self.chain, extra_config="bind=127.0.0.1\n")
    +        self.restart_node(1, extra_args=self.extra_args[1])
    +        self.connect_nodes(0, 1)
    +        self.sync_all()
     
             with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: false\n']):
                 self.nodes[0].setnetworkactive(state=False)
    
    
  8. in src/rpc/mempool.cpp:151 in d68687e981
     147 | @@ -148,6 +148,7 @@ static RPCMethod getprivatebroadcastinfo()
     148 |          RPCResult{
     149 |              RPCResult::Type::OBJ, "", "",
     150 |              {
     151 | +                {RPCResult::Type::BOOL, "private_broadcast_enabled", "If -privatebroadcast is set"},
    


    andrewtoth commented at 10:28 PM on May 11, 2026:

    Why not just enabled? The RPC is already getprivatebroadcast?

                    {RPCResult::Type::BOOL, "enabled", "If -privatebroadcast is set"},
    

    polespinasa commented at 10:37 PM on May 11, 2026:

    done

  9. andrewtoth approved
  10. andrewtoth commented at 10:29 PM on May 11, 2026: contributor

    Concept ACK

  11. polespinasa force-pushed on May 11, 2026
  12. polespinasa force-pushed on May 11, 2026
  13. in doc/release-notes-35267.md:4 in a714a5d484 outdated
       0 | @@ -0,0 +1,4 @@
       1 | +RPC
       2 | +---
       3 | +
       4 | +The `getprivatebroadcastinfo` RPC now exposes if `-privatebroadcast` startup option was set with a new response key `enabled`.
    


    andrewtoth commented at 12:32 AM on May 12, 2026:

    Needs a trailing newline to get CI to pass.

    The `getprivatebroadcastinfo` RPC now exposes whether the `-privatebroadcast` startup option is enabled with a new response key `enabled`.
    

    polespinasa commented at 11:07 AM on May 12, 2026:

    woops, fixed thanks

  14. in src/rpc/mempool.cpp:151 in a714a5d484 outdated
     147 | @@ -148,6 +148,7 @@ static RPCMethod getprivatebroadcastinfo()
     148 |          RPCResult{
     149 |              RPCResult::Type::OBJ, "", "",
     150 |              {
     151 | +                {RPCResult::Type::BOOL, "enabled", "If -privatebroadcast is set"},
    


    andrewtoth commented at 12:33 AM on May 12, 2026:
                    {RPCResult::Type::BOOL, "enabled", "If -privatebroadcast is enabled"},
    

    polespinasa commented at 11:09 AM on May 12, 2026:

    done

  15. in src/rpc/mempool.cpp:181 in a714a5d484 outdated
     177 | @@ -177,6 +178,10 @@ static RPCMethod getprivatebroadcastinfo()
     178 |              const NodeContext& node{EnsureAnyNodeContext(request.context)};
     179 |              const PeerManager& peerman{EnsurePeerman(node)};
     180 |              const auto txs{peerman.GetPrivateBroadcastInfo()};
     181 | +            UniValue ret(UniValue::VOBJ);
    


    andrewtoth commented at 12:35 AM on May 12, 2026:

    nit: we don't need to move this line. We could just push the enabled value below where we push transactions.


    polespinasa commented at 11:10 AM on May 12, 2026:

    done

  16. in test/functional/p2p_private_broadcast.py:350 in a714a5d484 outdated
     346 | @@ -347,6 +347,9 @@ def get_destinations_len():
     347 |  
     348 |          # Verify the tx we just observed is tracked in getprivatebroadcastinfo.
     349 |          pbinfo = self.nodes[0].getprivatebroadcastinfo()
     350 | +        # originator should report that privatebroadcast was set while the should not
    


    andrewtoth commented at 12:35 AM on May 12, 2026:
            # originator should report that privatebroadcast was set while the receiver should not
    

    polespinasa commented at 11:11 AM on May 12, 2026:

    done

  17. in test/functional/p2p_private_broadcast.py:352 in a714a5d484 outdated
     346 | @@ -347,6 +347,9 @@ def get_destinations_len():
     347 |  
     348 |          # Verify the tx we just observed is tracked in getprivatebroadcastinfo.
     349 |          pbinfo = self.nodes[0].getprivatebroadcastinfo()
     350 | +        # originator should report that privatebroadcast was set while the should not
     351 | +        assert_equal(pbinfo["enabled"], True)
     352 | +        assert_equal(self.nodes[1].getprivatebroadcastinfo()["enabled"], False)
    


    andrewtoth commented at 12:36 AM on May 12, 2026:

    I think this line can still be moved to the beginning of the test. We don't need to check it for each broadcast.


    polespinasa commented at 11:12 AM on May 12, 2026:

    done

  18. andrewtoth commented at 12:38 AM on May 12, 2026: contributor

    PR description is stale, showing the old private_broadcast_enabled field name.

  19. polespinasa force-pushed on May 12, 2026
  20. polespinasa force-pushed on May 12, 2026
  21. polespinasa force-pushed on May 12, 2026
  22. DrahtBot removed the label CI failed on May 12, 2026
  23. in src/rpc/mempool.cpp:151 in 9c2479687b
     147 | @@ -148,6 +148,7 @@ static RPCMethod getprivatebroadcastinfo()
     148 |          RPCResult{
     149 |              RPCResult::Type::OBJ, "", "",
     150 |              {
     151 | +                {RPCResult::Type::BOOL, "enabled", "If -privatebroadcast is enabled"},
    


    stickies-v commented at 12:56 PM on May 12, 2026:

    Perhaps a "status" of Type::STR would be more expressive and extensible?


    polespinasa commented at 2:25 PM on May 12, 2026:

    What other expressions could we need?


    stickies-v commented at 3:40 PM on May 12, 2026:

    It's hard to predict how APIs get extended in the future. Booleans make backwards-compatible upgrades harder. See https://ariya.io/2011/08/hall-of-api-shame-boolean-trap/ . For boolean traps, I don't think the onus should be on the reviewer to think of what other situations might arise, but one that came to mind is: "status": "err-no-tor". I believe we currently don't allow starting up when no private network is found, but that may change in the future.


    polespinasa commented at 7:46 PM on May 12, 2026:

    Fair enough, makes sense.

  24. in src/rpc/mempool.cpp:204 in 9c2479687b
     200 | @@ -200,6 +201,8 @@ static RPCMethod getprivatebroadcastinfo()
     201 |              }
     202 |  
     203 |              UniValue ret(UniValue::VOBJ);
     204 | +            const bool private_broadcast_enabled{gArgs.GetBoolArg("-privatebroadcast", DEFAULT_PRIVATE_BROADCAST)};
    


    stickies-v commented at 1:06 PM on May 12, 2026:

    Using startup args seems brittle. Perhaps a better approach is to expose this in PeerManager::GetInfo(), and then surface it in getnetworkinfo() alongside the other peerman details?


    polespinasa commented at 2:30 PM on May 12, 2026:

    Using startup args seems brittle

    Did it this way to keep the format from sendrawtransaction

    surface it in getnetworkinfo()

    Concept~0 here, I am fine with both approaches. @andrewtoth what do you think?


    rkrux commented at 2:35 PM on May 12, 2026:

    In 30ba2d3eabfe31559604c641ff4c89b424583298

    There's already a similar boolean present in PeerManager, would prefer for it to be used.

    https://github.com/bitcoin/bitcoin/blob/10ca73c02cbff59f2134c0c7da3b8d0a7e727475/src/net_processing.h#L95-L96


    rkrux commented at 2:47 PM on May 12, 2026:

    then surface it in getnetworkinfo()

    I'm leaning towards this based on the descriptions of both these RPCs.

    getnetworkinfo - Returns an object containing various state info regarding P2P networking getprivatebroadcastinfo - Returns information about transactions that are currently being privately broadcast

    getnetworkinfo's description is already sufficient if this new key is added there, but if added in getprivatebroadcastinfo then its description would need to be updated as well.

  25. stickies-v commented at 1:06 PM on May 12, 2026: contributor

    Concept ACK, seems useful to expose.

  26. rkrux commented at 2:48 PM on May 12, 2026: contributor

    Code review at 9c2479687b541ff4c3567d5d297bdcccc5b05636

  27. w0xlt commented at 4:50 PM on May 12, 2026: contributor

    Concept ACK

  28. polespinasa force-pushed on May 13, 2026
  29. in src/rpc/net.cpp:655 in a6116dd3c5
     651 | @@ -652,6 +652,7 @@ static RPCMethod getnetworkinfo()
     652 |                              {RPCResult::Type::STR, "SERVICE_NAME", "the service name"},
     653 |                          }},
     654 |                          {RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"},
     655 | +                        {RPCResult::Type::STR, "privatebroadcast", "if private broadcast is enabled"},
    


    polespinasa commented at 7:49 PM on May 13, 2026:

    Question for reviewers, do you prefer status of private broadcast ? Following #35267 (review) idea of extension?


    stickies-v commented at 10:19 PM on May 13, 2026:

    "private broadcast status (one of \"enabled\", \"disabled\")" has my preference

  30. polespinasa renamed this:
    rpc: inform if privatebroadcast is enabled in getprivatebroadcastinfo
    rpc: inform if privatebroadcast is enabled in getnetworkinfo
    on May 13, 2026
  31. polespinasa commented at 7:52 PM on May 13, 2026: member

    Force pushed to address comments, moved it to getnetworkinfo and changed it from bool to string to make it more flexible to being updated in the future.

    Diff: https://github.com/bitcoin/bitcoin/compare/9c2479687b541ff4c3567d5d297bdcccc5b05636..a6116dd3c5da3fedbb1b44218600e2b7f7219a76

  32. stickies-v commented at 8:36 AM on May 14, 2026: contributor

    Approach ACK. I think it makes more sense to squash the top 3 commits, they all really belong together and are trivial enough?

  33. polespinasa force-pushed on May 14, 2026
  34. polespinasa commented at 9:06 AM on May 14, 2026: member

    I think it makes more sense to squash the top 3 commits

    Squashed the fist two. I like keeping tests in a separate commit.

  35. in src/rpc/net.cpp:713 in 740dafcd3a
     709 | @@ -709,6 +710,7 @@ static RPCMethod getnetworkinfo()
     710 |      if (node.peerman) {
     711 |          auto peerman_info{node.peerman->GetInfo()};
     712 |          obj.pushKV("localrelay", !peerman_info.ignores_incoming_txs);
     713 | +        obj.pushKV("privatebroadcast", peerman_info.private_broadcast ? "enabled" : "disabled");
    


    vasild commented at 1:32 PM on May 18, 2026:

    I think it would be better to use JSON's native true / false (and maybe change the key to "privatebroadcast_enabled").


    polespinasa commented at 2:56 PM on May 18, 2026:

    It was like this in the first approach, but was changed to a more "upgradability" option. See #35267 (review) and #35267 (review) for context

  36. in src/rpc/net.cpp:655 in 740dafcd3a
     651 | @@ -652,6 +652,7 @@ static RPCMethod getnetworkinfo()
     652 |                              {RPCResult::Type::STR, "SERVICE_NAME", "the service name"},
     653 |                          }},
     654 |                          {RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"},
     655 | +                        {RPCResult::Type::STR, "privatebroadcast", "private broadcast status (one of \"enabled\", \"disabled\")"},
    


    vasild commented at 1:48 PM on May 18, 2026:

    Such an output in getnetworkinfo would make it more difficult to change the config option -privatebroadcast= in the future. For example - to change it to tri-state, or to string, or to add a new -privateboadcastwallet=. I am not saying we want to do these, but its good to keep the option to be able to and with this new addition in getnetworkinfo it will be harder.

    To me it makes more sense to throw from the getprivatebroadcastinfo RPC if the config option -privatebroadcast= is set to 0. Like "do something with Foo" -> throws "Foo is not available".

    That would resolve the original problem more elegantly - from Sparrow, query getprivatebroadcastinfo and if it throws then assume no private broadcast. Must be because either there is no such RPC (old Bitcoin Core) or because -privatebroadcast=0.


    polespinasa commented at 3:01 PM on May 18, 2026:

    The first approach of this PR was to return True or False in getprivatebroadcastinfo, but the approach was changed after comments in #35267 (review).

    Throwing in getprivatebroadcastinfo is a breaking change. I don't think it is critical as it has only been there for 1 release and probably there are no many applications depending on it, but I wanted to avoid it just in case.


    vasild commented at 9:44 AM on May 25, 2026:

    Why is it a breaking change? getprivatebroadcastinfo RPC would throw an exception in e.g. Bitcoin Core 30.0 (because no such RPC exists). Do you think that some application (e.g. Sparrow or another) conditionally uses getprivatebroadcastinfo based on the version of Bitcoin Core?


    polespinasa commented at 9:52 AM on May 25, 2026:

    It is a breaking change because in v31.0 it does not throw if it is not enabled. Idk if there's anyone currently using it (I don't think so):

    I don't think it is critical as it has only been there for 1 release and probably there are no many applications depending on it

    But, if possible, I always try to avoid breaking changes.


    vasild commented at 12:38 PM on May 25, 2026:

    Ok, my take is that a new field in getnetworkinfo seems a bit like a clutter and it might make future changes more difficult because once exposed as "privatebroadcast": "enabled/disabled" we would have to keep it that way. It is kind of "frozen".

    Throwing from getprivatebroadcastinfo to me seems like a better solution because any robust client program has to expect an exception anyway. And that combines well with checking whether this is an old Bitcoin Core which does not support the feature.


    polespinasa commented at 1:49 PM on May 25, 2026:

    Concept~0 on it, tagging other reviewers to get more opinions, if we get consensus on just throwing I will change the approach to it happily. cc. @andrewtoth @stickies-v


    stickies-v commented at 10:55 AM on May 26, 2026:

    To me it makes more sense to throw from the getprivatebroadcastinfo RPC if the config option -privatebroadcast= is set to 0

    I agree, that's a nice solution. Keeps things self-contained. Not sure if I'd prefer using the existing RPC_METHOD_NOT_FOUND or adding a new RPC_METHOD_DISABLED. I think the former suffices, but could be open to the latter too.


    polespinasa commented at 10:57 AM on May 26, 2026:

    If we go with this approach a new RPC_METHOD_DISABLED makes more sense imho. So we can clearly inform the user how to use it in the error message, and wallets can rely on error codes to know how to act.


    stickies-v commented at 11:06 AM on May 26, 2026:

    "Private broadcast is not enabled. Ensure you're running Bitcoin Core v31 or higher, and start it with -privatebroadcast=1. "

    Simple is better when it works well enough.


    naiyoma commented at 4:17 PM on May 30, 2026:

    Throwing from getprivatebroadcastinfo to me seems like a better solution because any robust client

    +1 on this being a better approach

    I’ve seen RPC_MISC_ERROR used a couple of times when a feature isn’t enabled

     git grep -niE 'RPC_MISC_ERROR.*(not enabled|not configured|restart bitcoind|is unavailable)' -- 'src/**/*.cpp'
    
    src/rpc/blockchain.cpp:2627:            throw JSONRPCError(RPC_MISC_ERROR, tfm::format("Index is not enabled for filtertype %s", filtertype_name));
    src/rpc/blockchain.cpp:3001:        throw JSONRPCError(RPC_MISC_ERROR, tfm::format("Index is not enabled for filtertype %s", filtertype_name));
    src/rpc/external_signer.cpp:46:            if (command == "") throw JSONRPCError(RPC_MISC_ERROR, "Error: restart bitcoind with -signer=<cmd>");
    src/rpc/mempool.cpp:1025:                throw JSONRPCError(RPC_MISC_ERROR, "Mempool lacks a relevant spend, and txospenderindex is unavailable.");
    

    To me, this might also be appropriate here.

    That said, I think RPC_METHOD_DISABLED is also okay and could also be used for other options in the future.


    polespinasa commented at 12:40 PM on May 31, 2026:

    Given that there are other RPCs using RPC_MISC_ERROR I decided to follow that.

    I prefer RPC_METHOD_DISABLED, but using it implies or being inconsistent with other RPCs or changing all of them (braking change). So for the scope of this PR I kept RPC_MISC_ERROR. If a new error code is desired this can easily be updated together with all the other RPCs.


    stickies-v commented at 2:29 PM on June 1, 2026:

    Given that there are other RPCs using RPC_MISC_ERROR I decided to follow that.

    I don't think there's meaningful benefit for consumers to be consistent here. RPC_MISC_ERROR is the wrong error code, and I don't think we should push ourselves further into a wrong direction just to be consistent when we're already making a breaking change.


    polespinasa commented at 2:48 PM on June 2, 2026:

    I don't think we should push ourselves further into a wrong direction just to be consistent when we're already making a breaking change

    ~Fair enough, I've added a previous commit adding the new error code. And updated the followings according.~

    Fair enough, I've changed the error code.


    sedited commented at 9:22 AM on June 5, 2026:

    I also think RPC_MISC_ERROR is the correct think to throw here. RPC_METHOD_NOT_FOUND is reserved for calls with a malformed method string, not calls that show up in the help, but are disabled for some reason.


    stickies-v commented at 10:21 AM on June 5, 2026:

    The JSON-RPC specification states:

    code message meaning -32601 Method not found The method does not exist / is not available.

    "is not available" seems perfectly applicable here. Whether we implement getprivatebroadcast to throw a RPC_METHOD_NOT_FOUND or we implement conditional registration of the getprivatebroadcastinfo method is an implementation detail and should not leak into the interface. From a user's perspective, all that matters is whether the method is available or not.

    not calls that show up in the help

    I agree that the method showing up in help when it is not available is not ideal. I'm not sure if conditional registration is worth the overhead here, but I could supportive of that too. Regardless, the method should document that it is only available when -privatebroadcast is enabled.


    stickies-v commented at 10:36 AM on June 5, 2026:

    Conditional registration seems pretty straightforward here (when relying on gArgs):

    <details> <summary>git diff on e10f3ed76f</summary>

    diff --git a/doc/release-notes-35267.md b/doc/release-notes-35267.md
    index 07a36d4d13..d5d54c762f 100644
    --- a/doc/release-notes-35267.md
    +++ b/doc/release-notes-35267.md
    @@ -1,5 +1,7 @@
     RPC
     ---
     
    -The `getprivatebroadcastinfo` RPC now throws with error code `-32601` if the node is not running with the `-privatebroadcast` startup option enabled.
    +The `getprivatebroadcastinfo` and `abortprivatebroadcast` RPCs are now only available
    +when the node is running with the `-privatebroadcast` startup option enabled. When it is
    +disabled, calling them returns the `-32601` ("Method not found") error.
     
    diff --git a/src/net_processing.cpp b/src/net_processing.cpp
    index 0ca56e7041..50ea62ff05 100644
    --- a/src/net_processing.cpp
    +++ b/src/net_processing.cpp
    @@ -1852,7 +1852,6 @@ PeerManagerInfo PeerManagerImpl::GetInfo() const
         return PeerManagerInfo{
             .median_outbound_time_offset = m_outbound_time_offsets.Median(),
             .ignores_incoming_txs = m_opts.ignore_incoming_txs,
    -        .private_broadcast = m_opts.private_broadcast,
         };
     }
     
    diff --git a/src/net_processing.h b/src/net_processing.h
    index 630656e2af..4ae48f84e4 100644
    --- a/src/net_processing.h
    +++ b/src/net_processing.h
    @@ -71,7 +71,6 @@ struct CNodeStateStats {
     struct PeerManagerInfo {
         std::chrono::seconds median_outbound_time_offset{0s};
         bool ignores_incoming_txs{false};
    -    bool private_broadcast{DEFAULT_PRIVATE_BROADCAST};
     };
     
     class PeerManager : public CValidationInterface, public NetEventsInterface
    diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
    index 6747458a12..acd5fa6e2f 100644
    --- a/src/rpc/mempool.cpp
    +++ b/src/rpc/mempool.cpp
    @@ -178,9 +178,6 @@ static RPCMethod getprivatebroadcastinfo()
                 const PeerManager& peerman{EnsurePeerman(node)};
                 const auto txs{peerman.GetPrivateBroadcastInfo()};
     
    -            if (!peerman.GetInfo().private_broadcast) {
    -                throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Private broadcast is not enabled. Ensure you're running Bitcoin Core with -privatebroadcast=1.");
    -            }
                 UniValue transactions(UniValue::VARR);
                 for (const auto& tx_info : txs) {
                     UniValue o(UniValue::VOBJ);
    @@ -1534,8 +1531,6 @@ void RegisterMempoolRPCCommands(CRPCTable& t)
     {
         static const CRPCCommand commands[]{
             {"rawtransactions", &sendrawtransaction},
    -        {"rawtransactions", &getprivatebroadcastinfo},
    -        {"rawtransactions", &abortprivatebroadcast},
             {"rawtransactions", &testmempoolaccept},
             {"blockchain", &getmempoolancestors},
             {"blockchain", &getmempooldescendants},
    @@ -1553,4 +1548,14 @@ void RegisterMempoolRPCCommands(CRPCTable& t)
         for (const auto& c : commands) {
             t.appendCommand(c.name, &c);
         }
    +
    +    if (gArgs.GetBoolArg("-privatebroadcast", DEFAULT_PRIVATE_BROADCAST)) {
    +        static const CRPCCommand private_broadcast_commands[]{
    +            {"rawtransactions", &getprivatebroadcastinfo},
    +            {"rawtransactions", &abortprivatebroadcast},
    +        };
    +        for (const auto& c : private_broadcast_commands) {
    +            t.appendCommand(c.name, &c);
    +        }
    +    }
     }
    diff --git a/test/functional/p2p_private_broadcast.py b/test/functional/p2p_private_broadcast.py
    index 7afedea476..dfea0ce979 100755
    --- a/test/functional/p2p_private_broadcast.py
    +++ b/test/functional/p2p_private_broadcast.py
    @@ -223,11 +223,13 @@ class P2PPrivateBroadcast(BitcoinTestFramework):
             tx_receiver = self.nodes[1]
             far_observer = tx_receiver.add_p2p_connection(P2PInterface())
     
    -        self.log.info("Test getprivatebroadcastinfo fails if the node is running without -privatebroadcast set")
    -        assert_raises_rpc_error(-32601, "Private broadcast is not enabled. Ensure you're running Bitcoin Core with -privatebroadcast=1.",
    -            tx_receiver.getprivatebroadcastinfo)
    -
    -        wallet = MiniWallet(tx_originator)
    +        self.log.info("Test the private broadcast RPCs are only registered when -privatebroadcast is set")
    +        assert "getprivatebroadcastinfo" not in tx_receiver.help()
    +        assert "abortprivatebroadcast" not in tx_receiver.help()
    +        assert_raises_rpc_error(-32601, "Method not found", tx_receiver.getprivatebroadcastinfo)
    +        assert_raises_rpc_error(-32601, "Method not found", tx_receiver.abortprivatebroadcast, "00" * 32)
    +        assert "getprivatebroadcastinfo" in tx_originator.help()
    +        assert "abortprivatebroadcast" in tx_originator.help()
     
             self.fill_node_addrman(node_index=0, address_types_to_add=[CAddress.NET_IPV4, CAddress.NET_IPV6, CAddress.NET_TORV3, CAddress.NET_I2P, CAddress.NET_CJDNS])
     
    
    

    </details>

  37. fanquake added the label Private Broadcast on May 29, 2026
  38. polespinasa force-pushed on May 31, 2026
  39. polespinasa force-pushed on May 31, 2026
  40. DrahtBot added the label CI failed on May 31, 2026
  41. polespinasa commented at 12:38 PM on May 31, 2026: member

    Force pushed to change the approach to throw getprivatebroadcastinfo when -privatebroadcast=0.

  42. DrahtBot removed the label CI failed on May 31, 2026
  43. polespinasa renamed this:
    rpc: inform if privatebroadcast is enabled in getnetworkinfo
    rpc: make getprivatebroadcastinfo fail if privatebroadcast is not enabled
    on May 31, 2026
  44. in test/functional/p2p_private_broadcast.py:364 in 4711171fd6
     360 | @@ -361,6 +361,11 @@ def run_test(self):
     361 |          tx_receiver = self.nodes[1]
     362 |          far_observer = tx_receiver.add_p2p_connection(P2PInterface())
     363 |  
     364 | +        # receiver is not runing with -privateboradcast set.
    


    stickies-v commented at 2:26 PM on June 1, 2026:
            # receiver is not running with -privatebroadcast set.
    

    also, this is self-documented in the next log-line


    polespinasa commented at 2:47 PM on June 2, 2026:

    dropped the comment

  45. stickies-v commented at 2:29 PM on June 1, 2026: contributor

    Approach ACK

  46. polespinasa force-pushed on Jun 2, 2026
  47. in src/rpc/protocol.h:52 in 77205413e0
      48 | @@ -49,7 +49,7 @@ enum RPCErrorCode
      49 |      RPC_VERIFY_ALREADY_IN_UTXO_SET  = -27, //!< Transaction already in utxo set
      50 |      RPC_IN_WARMUP                   = -28, //!< Client still warming up
      51 |      RPC_METHOD_DEPRECATED           = -32, //!< RPC method is deprecated
      52 | -
      53 | +    RPC_METHOD_DISABLED             = -37, //!< RPC method is disabled
    


    polespinasa commented at 3:24 PM on June 2, 2026:

    ~Idk what is the number assignment process, just used 37 as is the next non-used number.~

    Just curious, 21 was never assigned as a joke "21 is not an error" or something like that? :)


    stickies-v commented at 4:53 PM on June 2, 2026:

    Can you explain the rationale for adding this new error, because I don't see how it's better than using the existing RPC_METHOD_NOT_FOUND. All the client needs to know is that they can't call this method on this server, and RPC_METHOD_NOT_FOUND handles that perfectly.

    This really feels like an unnecessary addition to me, and adds a small extra burden on users because they now have to handle both the RPC_METHOD_NOT_FOUND (for <v31) and the RPC_METHOD_DISABLED errors (for v31 with this patch).


    polespinasa commented at 4:58 PM on June 2, 2026:

    I have totally misread the error codes suggested in the previous thread. At some point I was thinking "why are they suggesting opposite stuff in each comment?" lol.

    My bad, sorry. Fixed in the next push

  48. polespinasa force-pushed on Jun 2, 2026
  49. DrahtBot added the label Needs rebase on Jun 4, 2026
  50. rpc: getprivatebroadcastinfo throws if -privatebroadcast is disabled 05e0590b5f
  51. test: check getprivatebroadcast throws if the node is running without -privatebroadcast set 6a5d5e3937
  52. add release notes e10f3ed76f
  53. polespinasa force-pushed on Jun 4, 2026
  54. polespinasa commented at 2:55 PM on June 4, 2026: member

    Rebased on top of master to fix conflicts

  55. DrahtBot removed the label Needs rebase on Jun 4, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-06-07 13:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me