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: member

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

    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. fanquake removed the label Build system on Feb 25, 2020
  13. fanquake removed the label Docs on Feb 25, 2020
  14. fanquake removed the label GUI on Feb 25, 2020
  15. fanquake removed the label Tests on Feb 25, 2020
  16. fanquake removed the label Utils/log/libs on Feb 25, 2020
  17. Sjors force-pushed on Feb 25, 2020
  18. 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.
  19. Sjors requested review from instagibbs on Feb 25, 2020
  20. Sjors force-pushed on Feb 25, 2020
  21. Sjors force-pushed on Feb 25, 2020
  22. 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
  23. instagibbs approved
  24. 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
  25. Sjors force-pushed on Feb 25, 2020
  26. Sjors commented at 7:15 pm on February 25, 2020: member
    Rebased and snake-cased.
  27. 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.
  28. instagibbs approved
  29. 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

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

    Sjors commented at 1:26 pm on March 10, 2020:
    Ah, I didn’t notice this operator: const UniValue& operator[](size_t index) const;
  30. 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
  31. laanwj commented at 4:01 pm on March 5, 2020: member
    Nice cleanup, overall!
  32. meshcollider commented at 7:27 am on March 9, 2020: contributor
    Concept ACK, looks good
  33. instagibbs commented at 2:43 pm on March 9, 2020: member
    need rebase
  34. DrahtBot added the label Needs rebase on Mar 9, 2020
  35. Sjors commented at 7:09 pm on March 9, 2020: member
    Rebased, added safety {} and a std::move(mapValue).
  36. Sjors force-pushed on Mar 9, 2020
  37. DrahtBot removed the label Needs rebase on Mar 9, 2020
  38. Sjors force-pushed on Mar 10, 2020
  39. 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:
    0- To make RPC `sendtoaddress` more consistent with `sendmany` the following error
    
  40. Sjors force-pushed on Mar 11, 2020
  41. 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
  42. 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.
  43. Sjors force-pushed on Mar 27, 2020
  44. 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.
  45. Sjors force-pushed on Mar 27, 2020
  46. Sjors requested review from instagibbs on Apr 23, 2020
  47. Sjors requested review from laanwj on Apr 23, 2020
  48. instagibbs commented at 8:10 pm on April 24, 2020: member
  49. Sjors requested review from sipa on Apr 26, 2020
  50. DrahtBot added the label Needs rebase on May 1, 2020
  51. Sjors force-pushed on May 4, 2020
  52. Sjors commented at 10:53 am on May 4, 2020: member
    Rebased after #16426
  53. DrahtBot removed the label Needs rebase on May 4, 2020
  54. DrahtBot added the label Needs rebase on May 4, 2020
  55. Sjors force-pushed on May 4, 2020
  56. Sjors commented at 6:37 pm on May 4, 2020: member
    Rebased again after #18699
  57. DrahtBot removed the label Needs rebase on May 4, 2020
  58. [rpc] refactor: consolidate sendmany and sendtoaddress code
    The only new behavior is some error codes are changed from -4 to -6.
    08fc6f6cfc
  59. Sjors force-pushed on Jun 19, 2020
  60. 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:
    0                subtract_fee = true;
    1                break;
    
  61. fjahr approved
  62. fjahr commented at 9:21 pm on June 22, 2020: member

    Code review ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa

    Nice refactor.

  63. 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

    0-- To make RPC `sendtoaddress` more consistent with `sendmany` the following error
    1-    `sendtoaddress` codes were changed from `-4` to `-6`:
    2+- To make RPC `sendtoaddress` more consistent with `sendmany`, the following
    3+  `sendtoaddress` error codes are changed from `-4` to `-6`:
    
  64. 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

    0        for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); ++idx) {
    
  65. 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?

    0    return SendMoney(pwallet, coin_control, recipients, std::move(mapValue));
    
  66. jonatack commented at 9:39 am on June 23, 2020: member

    ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa

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

  67. Sjors commented at 9:43 am on June 23, 2020: member
    Thanks, I’ll address the above nits if this PR needs touching.
  68. meshcollider commented at 2:42 am on July 12, 2020: contributor

    Code review & functional test run ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa

    Nits can be left for followup

  69. meshcollider merged this on Jul 12, 2020
  70. meshcollider closed this on Jul 12, 2020

  71. sidhujag referenced this in commit 97ea73b8c3 on Jul 12, 2020
  72. domob1812 referenced this in commit e7206871fe on Jul 13, 2020
  73. Sjors deleted the branch on Jul 14, 2020
  74. Fabcien referenced this in commit 8a091fb6a5 on Aug 31, 2021
  75. DrahtBot 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: 2024-12-18 12:12 UTC

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