refactor: consolidate sendmany and sendtoaddress code #18202

pull Sjors wants to merge 1 commits into bitcoin:master from Sjors:2020/02/refactor_sendmany_sendtoaddress changing 4 files +68 −81
  1. Sjors commented at 7:13 PM on February 24, 2020: member

    I consolidated code between these two RPC calls, since sendtoaddress is essentially sendmany with 1 destination.

    Unless I overlooked something, the only behaviour change is that some sendtoaddress error codes changed from -4 to -6. The release note mentions this.

    Salvaged from #18201.

  2. Sjors force-pushed on Feb 24, 2020
  3. DrahtBot added the label Build system on Feb 24, 2020
  4. DrahtBot added the label Docs on Feb 24, 2020
  5. DrahtBot added the label GUI on Feb 24, 2020
  6. DrahtBot added the label Refactoring on Feb 24, 2020
  7. DrahtBot added the label RPC/REST/ZMQ on Feb 24, 2020
  8. DrahtBot added the label Tests on Feb 24, 2020
  9. DrahtBot added the label Utils/log/libs on Feb 24, 2020
  10. DrahtBot added the label Wallet on Feb 24, 2020
  11. DrahtBot commented at 8:52 PM on February 24, 2020: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #18354 (Use shared pointers only in validation interface by bvbfan)

    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.

  12. DrahtBot cross-referenced this on Feb 24, 2020 from issue wallet: Pass in transactions and messages for signing instead of exporting the private keys by achow101
  13. DrahtBot cross-referenced this on Feb 24, 2020 from issue "PSBT Operations" dialog by gwillen
  14. DrahtBot cross-referenced this on Feb 24, 2020 from issue refactor: Abstract boost::variant out by elichai
  15. DrahtBot cross-referenced this on Feb 24, 2020 from issue Disallow automatic conversion between disparate hash types by Empact
  16. DrahtBot cross-referenced this on Feb 24, 2020 from issue rpc: Auto-format RPCResult by MarcoFalke
  17. DrahtBot cross-referenced this on Feb 24, 2020 from issue refactor: deduplicate the message sign/verify code by vasild
  18. DrahtBot cross-referenced this on Feb 24, 2020 from issue rpc: set default bip32derivs to true for psbt methods by Sjors
  19. DrahtBot cross-referenced this on Feb 24, 2020 from issue Allow fundrawtransaction and walletcreatefundedpsbt to take external inputs by achow101
  20. DrahtBot cross-referenced this on Feb 24, 2020 from issue wallet: reduce loading time by using unordered maps by achow101
  21. DrahtBot cross-referenced this on Feb 24, 2020 from issue UI external signer support (e.g. hardware wallet) by Sjors
  22. DrahtBot cross-referenced this on Feb 24, 2020 from issue External signer support - Wallet Box edition by Sjors
  23. DrahtBot cross-referenced this on Feb 24, 2020 from issue Native Descriptor Wallets using DescriptorScriptPubKeyMan by achow101
  24. DrahtBot cross-referenced this on Feb 24, 2020 from issue BIP-322: Generic signed message format by kallewoof
  25. DrahtBot cross-referenced this on Feb 24, 2020 from issue rpc: Raise error in getbalance if minconf is not zero by promag
  26. DrahtBot cross-referenced this on Feb 25, 2020 from issue wallet: Show fee in results for signrawtransaction* for segwit inputs by kallewoof
  27. fanquake removed the label Build system on Feb 25, 2020
  28. fanquake removed the label Docs on Feb 25, 2020
  29. fanquake removed the label GUI on Feb 25, 2020
  30. fanquake removed the label Tests on Feb 25, 2020
  31. fanquake removed the label Utils/log/libs on Feb 25, 2020
  32. Sjors force-pushed on Feb 25, 2020
  33. Sjors commented at 9:53 AM on February 25, 2020: member

    Dropped the dependency on #18115 since it was only necessary in the original PR.

  34. Sjors requested review from instagibbs on Feb 25, 2020
  35. Sjors force-pushed on Feb 25, 2020
  36. Sjors force-pushed on Feb 25, 2020
  37. in src/wallet/rpcwallet.cpp:347 in ae2655d431 outdated
     350 | -    if (nValue > curBalance)
     351 | -        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
     352 | +        CScript scriptPubKey = GetScriptForDestination(dest);
     353 | +        CAmount nAmount = AmountFromValue(address_amounts[address]);
     354 | +        if (nAmount <= 0)
     355 | +            throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
    


    instagibbs commented at 3:28 PM on February 25, 2020:

    this string is changing yet I don't see associated test strings changing. Increase coverage?


    instagibbs commented at 3:30 PM on February 25, 2020:

    also good time to add braces to this conditional :)


    Sjors commented at 7:08 PM on February 25, 2020:

    AmountFromValue already checks the range, so dropping it here and adding a test with a negative value.


    instagibbs commented at 7:09 PM on February 25, 2020:

    even better :) CreateTransaction checks as well, heh

  38. instagibbs approved
  39. instagibbs commented at 3:34 PM on February 25, 2020: member

    utACK. Since we're touching a bunch of lines modernizing the variable namings to snake_case is probably apt if you don't mind

  40. Sjors force-pushed on Feb 25, 2020
  41. Sjors commented at 7:15 PM on February 25, 2020: member

    Rebased and snake-cased.

  42. in test/functional/wallet_basic.py:313 in 6da80c72d7 outdated
     308 | @@ -309,6 +309,9 @@ def run_test(self):
     309 |          assert_equal(tx_obj['amount'], Decimal('-0.0001'))
     310 |  
     311 |          # General checks for errors from incorrect inputs
     312 | +        # This will raise an exception because the amount is negative
     313 | +        assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "-1")
    


    instagibbs commented at 7:18 PM on February 25, 2020:

    now that I mention it, I'm a little shocked we don't have coverage on this?


    Sjors commented at 7:23 PM on February 25, 2020:

    We do for the utility function via createrawtransaction tests.


    instagibbs commented at 7:24 PM on February 25, 2020:

    you mean AmountFromValue? I meant specifically for sendtoaddress. Anyways, a test is a win.

  43. instagibbs approved
  44. in src/wallet/rpcwallet.cpp:346 in 6da80c72d7 outdated
     343 | +            throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + address);
     344 | +        }
     345 | +        destinations.insert(dest);
     346 | +
     347 | +        CScript script_pub_key = GetScriptForDestination(dest);
     348 | +        CAmount amount = AmountFromValue(address_amounts[address]);
    


    laanwj commented at 3:55 PM on March 5, 2020:

    This (order N, so in aggregate, quadratic) lookup would be unnecessary if the loop would iterate over key,value pairs in address_amounts. But I don't think univalue offers this functionality?


    Sjors commented at 7:06 PM on March 9, 2020:

    There's getKeys() and getValues() but not both. A future refactor could convert from UniValue to std::map<CTxDestination, CAmount>, but you have to loop over the UniValue at least once. So if it's really a performance bottleneck for big transactions, someone would need to patch UniValue to add e.g. bool getStringDictionary(std::map<std::string,std::string>& dict)


    ryanofsky commented at 9:07 PM on March 9, 2020:

    Can also do

    int i = 0;
    for (const std::string& address: address_amounts.getKeys()) {
        CAmount amount = AmountFromValue(address_amounts[i++]);
        ...
    

    Sjors commented at 1:26 PM on March 10, 2020:

    Ah, I didn't notice this operator: const UniValue& operator[](size_t index) const;

  45. in src/wallet/rpcwallet.cpp:350 in 6da80c72d7 outdated
     351 | -    if (nValue <= 0)
     352 | -        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
     353 | +        bool subtract_fee = false;
     354 | +        for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); idx++) {
     355 | +            const UniValue& addr = subtract_fee_outputs[idx];
     356 | +            if (addr.get_str() == address)
    


    laanwj commented at 4:00 PM on March 5, 2020:

    Please add braces here as required by the style guidelines, or put the subtrace_fee... on the same line. I was to suggest using ranged for here but that doesn't work for univalue as there's no begin() and end().


    Sjors commented at 7:06 PM on March 9, 2020:

    Done

  46. laanwj commented at 4:01 PM on March 5, 2020: member

    Nice cleanup, overall!

  47. DrahtBot cross-referenced this on Mar 9, 2020 from issue rpc/wallet: initialize nFeeRequired to avoid using garbage value on failure by kallewoof
  48. meshcollider commented at 7:27 AM on March 9, 2020: contributor

    Concept ACK, looks good

  49. instagibbs commented at 2:43 PM on March 9, 2020: member

    need rebase

  50. DrahtBot added the label Needs rebase on Mar 9, 2020
  51. Sjors commented at 7:09 PM on March 9, 2020: member

    Rebased, added safety {} and a std::move(mapValue).

  52. Sjors force-pushed on Mar 9, 2020
  53. DrahtBot removed the label Needs rebase on Mar 9, 2020
  54. Sjors force-pushed on Mar 10, 2020
  55. in doc/release-notes-18202.md:4 in 6b528d85ca outdated
       0 | @@ -0,0 +1,8 @@
       1 | +Low-level RPC Changes
       2 | +---------------------
       3 | +
       4 | +- To make RPC `sendtoaddress` more consisent with `sendmany` the following error
    


    flack commented at 6:51 PM on March 10, 2020:
    - To make RPC `sendtoaddress` more consistent with `sendmany` the following error
    
  56. Sjors force-pushed on Mar 11, 2020
  57. DrahtBot cross-referenced this on Mar 25, 2020 from issue Use shared pointers only in validation interface by bvbfan
  58. in src/wallet/rpcwallet.cpp:330 in 771ca9ffd2 outdated
     326 | @@ -327,36 +327,53 @@ static UniValue setlabel(const JSONRPCRequest& request)
     327 |      return NullUniValue;
     328 |  }
     329 |  
     330 | -
     331 | -static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
     332 | +UniValue SendMoney(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, CCoinControl coin_control, UniValue& address_amounts, mapValue_t map_value, UniValue& subtract_fee_outputs)
    


    sipa commented at 3:34 AM on March 27, 2020:

    Do you intend to pass coin_control by value? In the original code it's a const CCoinControl & which avoids a copy.


    Sjors commented at 11:22 AM on March 27, 2020:

    Fixed

  59. sipa commented at 3:37 AM on March 27, 2020: member

    Is it necessary to merge the old SendMoney function into the new one you're creating? It seems preferable to create an intermediary function between SendMoney and its RPC call sites rather than merging all the RPC parsing into SendMoney itself.

  60. Sjors force-pushed on Mar 27, 2020
  61. Sjors commented at 11:23 AM on March 27, 2020: member

    Rebased and added a helper function ParseRecipients() so that SendMoney is now a lot shorter.

  62. Sjors force-pushed on Mar 27, 2020
  63. DrahtBot cross-referenced this on Apr 5, 2020 from issue rpc: remove deprecated CRPCCommand constructor by MarcoFalke
  64. DrahtBot cross-referenced this on Apr 11, 2020 from issue rpc: replace raw pointers with shared_ptrs by brakmic
  65. DrahtBot cross-referenced this on Apr 17, 2020 from issue Reverse cs_main, cs_wallet lock order and reduce cs_main locking by ariard
  66. DrahtBot cross-referenced this on Apr 18, 2020 from issue wallet: Avoid translating RPC errors by MarcoFalke
  67. Sjors requested review from instagibbs on Apr 23, 2020
  68. Sjors requested review from laanwj on Apr 23, 2020
  69. instagibbs commented at 8:10 PM on April 24, 2020: member
  70. Sjors requested review from sipa on Apr 26, 2020
  71. DrahtBot added the label Needs rebase on May 1, 2020
  72. Sjors force-pushed on May 4, 2020
  73. Sjors commented at 10:53 AM on May 4, 2020: member

    Rebased after #16426

  74. DrahtBot removed the label Needs rebase on May 4, 2020
  75. DrahtBot added the label Needs rebase on May 4, 2020
  76. Sjors force-pushed on May 4, 2020
  77. Sjors commented at 6:37 PM on May 4, 2020: member

    Rebased again after #18699

  78. DrahtBot removed the label Needs rebase on May 4, 2020
  79. [rpc] refactor: consolidate sendmany and sendtoaddress code
    The only new behavior is some error codes are changed from -4 to -6.
    08fc6f6cfc
  80. Sjors force-pushed on Jun 19, 2020
  81. in src/wallet/rpcwallet.cpp:345 in 08fc6f6cfc
     348 | -        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
     349 | +        bool subtract_fee = false;
     350 | +        for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); idx++) {
     351 | +            const UniValue& addr = subtract_fee_outputs[idx];
     352 | +            if (addr.get_str() == address) {
     353 | +                subtract_fee = true;
    


    fjahr commented at 7:08 PM on June 22, 2020:
                    subtract_fee = true;
                    break;
    
  82. fjahr approved
  83. fjahr commented at 9:21 PM on June 22, 2020: contributor

    Code review ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa

    Nice refactor.

  84. in doc/release-notes-18202.md:5 in 08fc6f6cfc
       0 | @@ -0,0 +1,8 @@
       1 | +Low-level RPC Changes
       2 | +---------------------
       3 | +
       4 | +- To make RPC `sendtoaddress` more consistent with `sendmany` the following error
       5 | +    `sendtoaddress` codes were changed from `-4` to `-6`:
    


    jonatack commented at 7:16 AM on June 23, 2020:

    08fc6f6c suggestion

    -- To make RPC `sendtoaddress` more consistent with `sendmany` the following error
    -    `sendtoaddress` codes were changed from `-4` to `-6`:
    +- To make RPC `sendtoaddress` more consistent with `sendmany`, the following
    +  `sendtoaddress` error codes are changed from `-4` to `-6`:
    
  85. in src/wallet/rpcwallet.cpp:342 in 08fc6f6cfc
     345 | +        CAmount amount = AmountFromValue(address_amounts[i++]);
     346 |  
     347 | -    if (nValue > curBalance)
     348 | -        throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
     349 | +        bool subtract_fee = false;
     350 | +        for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); idx++) {
    


    jonatack commented at 9:27 AM on June 23, 2020:

    while retouching this code, could update to the current convention

            for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); ++idx) {
    
  86. in src/wallet/rpcwallet.cpp:463 in 08fc6f6cfc
     460 | +    }
     461 | +
     462 | +    std::vector<CRecipient> recipients;
     463 | +    ParseRecipients(address_amounts, subtractFeeFromAmount, recipients);
     464 | +
     465 | +    return SendMoney(pwallet, coin_control, recipients, mapValue);
    


    jonatack commented at 9:31 AM on June 23, 2020:

    can use move for mapValue here as well?

        return SendMoney(pwallet, coin_control, recipients, std::move(mapValue));
    
  87. jonatack commented at 9:39 AM on June 23, 2020: contributor

    ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa

    Some suggestions below. Feel free to ignore the style nits.

  88. Sjors commented at 9:43 AM on June 23, 2020: member

    Thanks, I'll address the above nits if this PR needs touching.

  89. meshcollider commented at 2:42 AM on July 12, 2020: contributor

    Code review & functional test run ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa

    Nits can be left for followup

  90. meshcollider merged this on Jul 12, 2020
  91. meshcollider closed this on Jul 12, 2020

  92. sidhujag referenced this in commit 97ea73b8c3 on Jul 12, 2020
  93. domob1812 referenced this in commit e7206871fe on Jul 13, 2020
  94. Sjors deleted the branch on Jul 14, 2020
  95. Fabcien referenced this in commit 8a091fb6a5 on Aug 31, 2021
  96. bitcoin locked this on Feb 15, 2022

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-05-20 06:54 UTC