rpc, doc: clarify the response of listtransactions RPC #32737

pull rkrux wants to merge 1 commits into bitcoin:master from rkrux:listtx changing 1 files +5 −1
  1. rkrux commented at 2:53 PM on June 12, 2025: contributor

    I noticed this behaviour while perf testing PR #27286 and it was not something that I expected, updating the doc to make it present in the RPCHelp command.

  2. DrahtBot commented at 2:53 PM on June 12, 2025: 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/32737.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK furszy, musaHaruna, achow101
    Stale ACK w0xlt

    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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  3. rkrux force-pushed on Jun 14, 2025
  4. in src/wallet/rpc/transactions.cpp:448 in 8140008759 outdated
     443 | @@ -444,7 +444,10 @@ RPCHelpMan listtransactions()
     444 |      return RPCHelpMan{
     445 |          "listtransactions",
     446 |          "If a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
     447 | -                "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
     448 | +                "Returns up to 'count' most recent transactions ordered from oldest to newest while skipping the first 'from' transactions.\n"
     449 | +                "Every item in the response array is per output level, i.e., a transaction can have multiple items in the array.\n"
    


    luke-jr commented at 7:31 PM on June 25, 2025:

    "output" is kind of a low-level detail, while this is a high-level RPC. It's better to think of entries as logical/financial transactions, as opposed to blockchain transactions.


    rkrux commented at 11:31 AM on June 27, 2025:

    Good point, I have reworded to remove the word "output".

    Seeing the term "transactions" in the RPC name immediately led me to believe it's referring to the blockchain transactions. Hence, I do want to let an example be present because this behaviour was not apparent to me when I first started using this RPC


    rkrux commented at 11:33 AM on June 27, 2025:

    I have not used the term "logical/financial" to describe these transactions yet but I can add it if people believe that would be a valuable addition.

  5. rkrux force-pushed on Jun 27, 2025
  6. rkrux force-pushed on Jun 27, 2025
  7. DrahtBot added the label CI failed on Jun 27, 2025
  8. DrahtBot removed the label CI failed on Jul 1, 2025
  9. achow101 requested review from achow101 on Oct 22, 2025
  10. achow101 requested review from murchandamus on Oct 22, 2025
  11. achow101 commented at 9:58 PM on November 17, 2025: member

    ACK c27629702285029add897b89247ab9493aede22d

  12. DrahtBot requested review from w0xlt on Nov 17, 2025
  13. musaHaruna commented at 1:03 PM on December 15, 2025: contributor

    ACK c27629 I used the example in the docs to verify the behaviour. The doc now clearly explains the RPC! Left a nit suggestion below. I used the test script below to verify behaviour.

    #!/usr/bin/env python3
    """Minimal functional test for `listtransactions` behavior.
    
    This test verifies two documented behaviours:
     1) A single blockchain transaction that sends wallet funds to 1 wallet address
        and 2 non-wallet addresses produces multiple wallet entries: 1 "receive"
        entry and 3 "send" entries (total 4 entries).
     2) Calling `listtransactions` with a label returns only incoming transactions
        paying to addresses with that label.
    """
    
    from test_framework.test_framework import BitcoinTestFramework
    from test_framework.blocktools import COINBASE_MATURITY
    from test_framework.util import assert_equal
    
    class ListTransactionsTest(BitcoinTestFramework):
        def set_test_params(self):
            self.num_nodes = 2
            self.setup_clean_chain = True
            self.extra_args = [[], []]
    
        def skip_test_if_missing_module(self):
            self.skip_if_no_wallet()
    
        def setup_network(self):
            self.setup_nodes()
            self.connect_nodes(0, 1)
            self.sync_all()
    
        def run_test(self):
            # Mine mature coinbase outputs for node0 so it can spend
            self.generate(self.nodes[0], COINBASE_MATURITY + 1, sync_fun=lambda: self.sync_all(self.nodes))
            self.sync_all()
    
            # Prepare addresses: one address in node0's wallet (will be labelled), and
            # two addresses that are not in node0's wallet (use node1 addresses).
            addr_wallet = self.nodes[0].getnewaddress()
            self.nodes[0].setlabel(addr_wallet, "receive_address")
            external_address1 = self.nodes[1].getnewaddress()
            external_address2 = self.nodes[1].getnewaddress()
    
            # Send a single transaction from node0 to three outputs: one to its own
            # address (labelled) and two to external addresses (node1). This should
            # create one blockchain transaction with 3 outputs.
            txid = self.nodes[0].sendmany('', {addr_wallet: 1, external_address1: 1, external_address2: 1})
            # Confirm the transaction
            self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_all(self.nodes))
            self.sync_all()
    
            # Collect listtransactions entries for this txid from node0's wallet
            tx_entries = [txs for txs in self.nodes[0].listtransactions('*', 100) if txs.get('txid') == txid]
    
            # According to documentation: one 'receive' entry and three 'send' entries
            assert_equal(len(tx_entries), 4)
            receive_count = sum(1 for txs in tx_entries if txs['category'] == 'receive')
            send_count = sum(1 for txs in tx_entries if txs['category'] == 'send')
            assert_equal(receive_count, 1)
            assert_equal(send_count, 3)
    
            # Now verify label filtering: listing with the label should return only
            # incoming transactions paying to addresses with that label (i.e. the
            # single 'receive' entry for this tx).
            label_entries = self.nodes[0].listtransactions(label="receive_address", count=100)
            # Filter to entries related to our tx
            label_tx_entries = [txs for txs in label_entries if txs.get('txid') == txid]
            assert_equal(len(label_tx_entries), 1)
            assert_equal(label_tx_entries[0]['category'], 'receive')
            assert_equal(label_tx_entries[0]['address'], addr_wallet)
    
    if __name__ == '__main__':
        ListTransactionsTest(__file__).main()
    
  14. in src/wallet/rpc/transactions.cpp:448 in c276297022
     443 | @@ -444,7 +444,10 @@ RPCHelpMan listtransactions()
     444 |      return RPCHelpMan{
     445 |          "listtransactions",
     446 |          "If a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
     447 | -                "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
     448 | +                "Returns up to 'count' most recent transactions ordered from oldest to newest while skipping the first 'from' transactions.\n"
     449 | +                "A blockchain transaction can have multiple entries in the response. Eg: A blockchain transaction sending wallet funds to\n"
    


    musaHaruna commented at 1:05 PM on December 15, 2025:

    nit: If you retouch

                    "A blockchain transaction can have multiple entries in the response. For example a blockchain transaction sending wallet funds to\n"
    

    I think looks better than the initial abbrevation

  15. in src/wallet/rpc/transactions.cpp:447 in c276297022
     443 | @@ -444,7 +444,10 @@ RPCHelpMan listtransactions()
     444 |      return RPCHelpMan{
     445 |          "listtransactions",
     446 |          "If a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
     447 | -                "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
     448 | +                "Returns up to 'count' most recent transactions ordered from oldest to newest while skipping the first 'from' transactions.\n"
    


    furszy commented at 1:53 AM on December 16, 2025:

    q: how the user would understand what 'from' is on this message? As far as I can see, the message is referring to the "skip" arg instead.


    rkrux commented at 2:57 PM on December 16, 2025:

    the message is referring to the "skip" arg instead.

    I guess yeah, maybe there was a "from" argument earlier here? I somehow automatically ignored this as I was focussed on adding the example below, but I will push a commit rewording this sentence.


    furszy commented at 3:27 PM on December 16, 2025:

    the message is referring to the "skip" arg instead.

    I guess yeah, maybe there was a "from" argument earlier here? I somehow automatically ignored this as I was focussed on adding the example below, but I will push a commit rewording this sentence.

    Sounds good 👍🏼. There was probably something there before. But now it is very odd and not really something users will understand as is.


    rkrux commented at 12:49 PM on December 17, 2025:

    Updated, good catch!

  16. rkrux force-pushed on Dec 17, 2025
  17. in src/wallet/rpc/transactions.cpp:451 in e6cb65b3ba
     443 | @@ -444,7 +444,11 @@ RPCHelpMan listtransactions()
     444 |      return RPCHelpMan{
     445 |          "listtransactions",
     446 |          "If a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
     447 | -                "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
     448 | +                "Returns up to 'count' most recent transactions ordered from oldest to newest while skipping the first number of \n"
     449 | +                "transactions specified in the 'skip' argument. A blockchain transaction can have multiple entries in this RPC response. \n"
     450 | +                "Eg: A blockchain transaction sending wallet funds to 1 wallet address & 2 non-wallet addresses will have 4 entries \n"
     451 | +                "in the response - 1 in the 'receive' category and 3 in the 'send' category (because there are three outgoing entries \n"
     452 | +                "even though one of them is sent to a wallet address).",
    


    furszy commented at 3:14 PM on December 17, 2025:

    Could use "transaction" instead of "blockchain transaction".

    Also, I think the example could be improved, something like:

    "For instance, a wallet transaction that sends funds to three addresses - one belonging to the wallet itself and two external— will produce four entries (one per output, including the change output). As a result, the response of 'listransactions' will contain one entry in the 'receive' category and three entries in the 'send' category. etc.."

    (feel free to add stuff to it - but I think something like this reads slightly better).


    2knwhzwkm6-max commented at 1:21 AM on December 18, 2025:

    Could use "transaction" instead of "blockchain transaction".

    I agree with you

    Also, I think the example could be improved,

    I guess this sentence are great, but I’d avoid “one per output / including the change output” here, since it can be misleading. listtransactions returns wallet entries, not necessarily one item per on-chain output.

    In this example, the key point is that a payment to a wallet-owned address can show up as both a send entry (the wallet created that payment) and a receive entry (the wallet owns the destination).

    Maybe something like: “For instance, a wallet transaction that pays three addresses—one wallet-owned and two external—will produce four entries. The payment to the wallet-owned address can appear both as a send entry and as a receive entry . As a result, the response of listtransactions will contain one entry in the receive category and three entries in the send category. ”


    rkrux commented at 1:11 PM on December 18, 2025:

    Thanks for the suggestions, updated PR to accommodate both of them.

  18. rpc, doc: clarify the response of listtransactions RPC
    I noticed this behaviour while perf testing PR 27286 and it was not something
    that I expected, updating the doc to make it present in the RPCHelp command.
    1ed8e76165
  19. rkrux force-pushed on Dec 18, 2025
  20. furszy commented at 2:37 PM on December 18, 2025: member

    ACK 1ed8e7616527c69dbaa9904cda59e3b73c29fa5d

  21. musaHaruna commented at 8:37 AM on December 22, 2025: contributor

    ACK 1ed8e76 since my last review. New changes looks good, it's much easier to understand as well, looking at it from a user's perspective.

  22. achow101 commented at 11:08 PM on December 22, 2025: member

    ACK 1ed8e7616527c69dbaa9904cda59e3b73c29fa5d

  23. achow101 merged this on Dec 22, 2025
  24. achow101 closed this on Dec 22, 2025


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-04-17 03:12 UTC

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