rpc: include_unsafe option for fundrawtransaction #21359

pull t-bast wants to merge 1 commits into bitcoin:master from t-bast:fund-raw-transaction-allow-unsafe changing 8 files +97 −10
  1. t-bast commented at 10:05 am on March 4, 2021: member

    Allow RPC users to opt-in to unsafe inputs when funding a raw transaction.

    Applications that need to manage a complex RBF flow (such as lightning nodes using anchor outputs) are very limited if they can only use safe inputs.

    I also added this option to send and walletcreatefundedpsbt who internally delegate to fundrawtransaction.

    Fixes #21299

  2. fanquake added the label RPC/REST/ZMQ on Mar 4, 2021
  3. DrahtBot commented at 3:49 pm on March 4, 2021: 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:

    • #21207 (MOVEONLY: CWallet transaction code out of wallet.cpp/.h by ryanofsky)
    • #21206 (refactor: Make CWalletTx sync state type-safe by ryanofsky)

    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.

  4. DrahtBot added the label Needs rebase on Mar 8, 2021
  5. t-bast force-pushed on Mar 9, 2021
  6. DrahtBot removed the label Needs rebase on Mar 9, 2021
  7. in src/wallet/wallet.cpp:2617 in 92e5b3addc outdated
    2613@@ -2613,7 +2614,7 @@ SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkh
    2614     return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
    2615 }
    2616 
    2617-bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
    2618+bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool includeUnsafe, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
    


    luke-jr commented at 6:44 pm on March 9, 2021:
    I suggest adding includeUnsafe into CCoinControl instead.

    t-bast commented at 6:56 pm on March 9, 2021:
    I completely agree, I mentioned that in the PR description. If there’s a concept ACK, CCoinControl would be a good place to store that bool. Do you prefer includeUnsafe (more consistent with the RPC) or fSafeOnly (more consistent with the inner codebase)?

  8. DrahtBot added the label Needs rebase on Mar 10, 2021
  9. t-bast force-pushed on Mar 10, 2021
  10. in src/wallet/wallet.cpp:2846 in 0dc8808230 outdated
    2797@@ -2797,7 +2798,7 @@ bool CWallet::CreateTransactionInternal(
    2798         txNew.nLockTime = GetLocktimeForNewTransaction(chain(), GetLastBlockHash(), GetLastBlockHeight());
    2799         {
    2800             std::vector<COutput> vAvailableCoins;
    2801-            AvailableCoins(vAvailableCoins, true, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0);
    2802+            AvailableCoins(vAvailableCoins, !coin_control.m_include_unsafe_inputs, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0);
    


    t-bast commented at 2:41 pm on March 10, 2021:

    We could remove the fOnlySafe argument to AvailableCoins now that this is provided by coin_control.

    The only gotcha is that AvailableCoins can be called without a coin_control, but I checked the codebase and in all the places where that happens fOnlySafe is set to true, so we could set it inside AvailableCoins to const bool only_safe = {coinControl ? !coinControl->m_include_unsafe_inputs : true};.

    Do you want me to apply that change in this PR?

  11. DrahtBot removed the label Needs rebase on Mar 10, 2021
  12. DrahtBot added the label Needs rebase on Mar 16, 2021
  13. t-bast force-pushed on Mar 17, 2021
  14. t-bast commented at 6:14 pm on March 17, 2021: member

    @achow101 @luke-jr would you have some time to give a quick pass to this hopefully very simple PR and let me know if there’s a concept ACK and it’s worth pursuing? :pray:

    I know, Taproot is happening (is it?), I understand if you don’t have much time available :smile:

  15. DrahtBot removed the label Needs rebase on Mar 17, 2021
  16. achow101 commented at 10:24 pm on March 17, 2021: member
    ACK 16076bb2a8517c6a8b101ad04e220ad3b3f71bcf
  17. t-bast commented at 11:03 am on March 25, 2021: member

    Is there something I can do to help this PR move forward?

    We really need it to unblock anchor outputs in lightning (we can run a modified bitcoind with this patch applied for our own node, but we can’t ask our users to run a non-release bitcoind version).

  18. renepickhardt commented at 8:36 am on March 29, 2021: none

    Looks good to me.

    Could there go anything other wrong than a transaction becoming invalid because an input disappeared? (this of course would not be really wrong)

  19. t-bast commented at 8:59 am on March 29, 2021: member

    Could there go anything other wrong than a transaction becoming invalid because an input disappeared?

    It’s a very good question, it’s part of my “unknown unknowns” and why I’m curious to get feedback from more people here. It seems to me that there isn’t anything else, but there are many things I don’t know so I wouldn’t rely on my instincts only ¯_(ツ)_/¯

  20. in test/functional/rpc_fundrawtransaction.py:932 in 16076bb2a8 outdated
    928@@ -928,6 +929,29 @@ def test_transaction_too_large(self):
    929         self.nodes[0].generate(10)
    930         assert_raises_rpc_error(-4, "Transaction too large", recipient.fundrawtransaction, rawtx)
    931 
    932+    def test_include_unsafe(self):
    


    jonatack commented at 9:16 am on March 29, 2021:
    As FundTransaction() has other callers like the walletcreatefundedpsbt and send RPCs, might be a good idea to have test_include_unsafe tests that guard against present/future regressions in rpc_test_psbt.py and wallet_send.py.

    t-bast commented at 9:51 am on March 29, 2021:
    Good idea, will do.

    t-bast commented at 9:57 am on March 30, 2021:
    Done in https://github.com/bitcoin/bitcoin/pull/21359/commits/c3eb1994c24167bedb114e34b53dc7cbeb9ff403 I also added explicit support for these APIs, it makes more sense that way.
  21. in src/wallet/rpcwallet.cpp:3212 in 16076bb2a8 outdated
    3207@@ -3203,6 +3208,9 @@ static RPCHelpMan fundrawtransaction()
    3208                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
    3209                         {
    3210                             {"add_inputs", RPCArg::Type::BOOL, /* default */ "true", "For a transaction with existing inputs, automatically include more if they are not enough."},
    3211+                            {"include_unsafe", RPCArg::Type::BOOL, /* default */ "false", "Include inputs that are not safe to spend.\n"
    3212+                                                          "Beware that the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
    


    jonatack commented at 9:20 am on March 29, 2021:
    s/Beware/Be aware/ or s/Beware that/Warning:/

  22. jonatack commented at 10:15 am on March 29, 2021: member
    This would need a release note.
  23. laanwj added this to the "Blockers" column in a project

  24. t-bast commented at 9:58 am on March 30, 2021: member

    This would need a release note.

    Added in https://github.com/bitcoin/bitcoin/pull/21359/commits/c3eb1994c24167bedb114e34b53dc7cbeb9ff403, let me know if that’s how it should be done.

  25. in test/functional/wallet_send.py:145 in c3eb1994c2 outdated
    138@@ -133,6 +139,11 @@ def test_send(self, from_wallet, to_wallet=None, amount=None, data=None,
    139             assert not "txid" in res
    140             assert "psbt" in res
    141 
    142+        if include_unsafe:
    143+            from_balance = from_wallet.getbalances()["mine"]["untrusted_pending"]
    144+        else:
    145+            from_balance = from_wallet.getbalance()
    


    jonatack commented at 1:42 pm on March 30, 2021:

    will review soon, the release note LGTM

    0            from_balance = from_wallet.getbalances()["mine"]["trusted"]
    

    as IIRC we are moving away from getbalance in favor of getbalances… so it’s good that you have abstracted it out to this one place (edit: it’s not just one place, but could make it one in a function)

    should from_balance when include_unsafe is true not also include “trusted”?


    t-bast commented at 11:52 am on April 12, 2021:
    I’m not sure that change should be done in this PR. It may be worth sweeping all uses of getbalance() to replace them with getbalances()["mine"]["trusted"] in a separate PR, don’t you think? I volunteer to make that follow-up PR right after this one if that sounds good to you.

    instagibbs commented at 6:07 am on April 19, 2021:
    it’s new code, if you don’t mind conforming to the newer standard for new code makes any future PR to “sweep” it up smaller?

    t-bast commented at 8:35 am on April 19, 2021:
  26. DrahtBot added the label Needs rebase on Apr 1, 2021
  27. t-bast force-pushed on Apr 1, 2021
  28. DrahtBot removed the label Needs rebase on Apr 1, 2021
  29. in src/wallet/rpcwallet.cpp:3211 in 378ced96ec outdated
    3207@@ -3203,6 +3208,9 @@ static RPCHelpMan fundrawtransaction()
    3208                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
    3209                         {
    3210                             {"add_inputs", RPCArg::Type::BOOL, /* default */ "true", "For a transaction with existing inputs, automatically include more if they are not enough."},
    3211+                            {"include_unsafe", RPCArg::Type::BOOL, /* default */ "false", "Include inputs that are not safe to spend.\n"
    


    instagibbs commented at 6:08 am on April 19, 2021:
    Might want to explain what is unsafe about them speifically, otherwise it seems to lead to the “why are you allowing it” question.

    t-bast commented at 8:36 am on April 19, 2021:
    Makes sense, anything that can improve documentation is worth adding. I copied the explanation from the safe flag in https://github.com/bitcoin/bitcoin/pull/21359/commits/1bb252669dc5e8feb41e4975d609108eb28c8667, let me know if you think the wording should be updated to be clearer.
  30. DrahtBot added the label Needs rebase on Apr 19, 2021
  31. t-bast force-pushed on Apr 19, 2021
  32. DrahtBot removed the label Needs rebase on Apr 19, 2021
  33. DrahtBot added the label Needs rebase on Apr 26, 2021
  34. t-bast force-pushed on Apr 26, 2021
  35. in test/functional/rpc_psbt.py:403 in 4e4d7c01b4 outdated
    398+        self.nodes[2].createwallet(wallet_name="unsafe")
    399+        wunsafe = self.nodes[2].get_wallet_rpc("unsafe")
    400+        self.nodes[0].sendtoaddress(wunsafe.getnewaddress(), 2)
    401+        self.sync_mempools()
    402+        assert_raises_rpc_error(-4, "Insufficient funds", wunsafe.walletcreatefundedpsbt, [], [{self.nodes[0].getnewaddress():1}])
    403+        wunsafe.walletcreatefundedpsbt([], [{self.nodes[0].getnewaddress():1}], 0, {"include_unsafe": True})
    


    jonatack commented at 11:35 am on April 26, 2021:

    style nit if you need to retouch (same on previous line)

    0        wunsafe.walletcreatefundedpsbt([], [{self.nodes[0].getnewaddress(): 1}], 0, {"include_unsafe": True})
    

    t-bast commented at 12:55 pm on April 26, 2021:
    The rest of that file doesn’t put a whitespace in that case, this is why I used this format to stay coherent across the file, but if you think it makes sense to fix I should change it everywhere in the file, right?

    jonatack commented at 1:26 pm on April 26, 2021:
    I wouldn’t worry about it apart from the new code and even then it’s a pico nit.

  36. in test/functional/wallet_send.py:44 in 4e4d7c01b4 outdated
    41 
    42-        from_balance_before = from_wallet.getbalance()
    43+        if include_unsafe:
    44+            from_balance_before = from_wallet.getbalances()["mine"]["untrusted_pending"]
    45+        else:
    46+            from_balance_before = from_wallet.getbalances()["mine"]["trusted"]
    


    jonatack commented at 11:42 am on April 26, 2021:

    While this works for the purposes of the test, should from_balance_before always include “trusted”:

    0        from_balance_before = from_wallet.getbalances()["mine"]["trusted"]
    1        if include_unsafe:
    2            from_balance_before += from_wallet.getbalances()["mine"]["untrusted_pending"]
    

    t-bast commented at 12:54 pm on April 26, 2021:
  37. in test/functional/wallet_send.py:145 in 4e4d7c01b4 outdated
    138@@ -133,6 +139,11 @@ def test_send(self, from_wallet, to_wallet=None, amount=None, data=None,
    139             assert not "txid" in res
    140             assert "psbt" in res
    141 
    142+        if include_unsafe:
    143+            from_balance = from_wallet.getbalances()["mine"]["untrusted_pending"]
    144+        else:
    145+            from_balance = from_wallet.getbalances()["mine"]["trusted"]
    


    jonatack commented at 11:43 am on April 26, 2021:

    same here

    0        from_balance = from_wallet.getbalances()["mine"]["trusted"]
    1        if include_unsafe:
    2            from_balance += from_wallet.getbalances()["mine"]["untrusted_pending"]
    

  38. jonatack commented at 11:50 am on April 26, 2021: member

    ACK 4e4d7c01b4134ea3b920345ee2a62e2b06cd458e

    Some comments below.

  39. DrahtBot removed the label Needs rebase on Apr 26, 2021
  40. jonatack commented at 1:29 pm on April 26, 2021: member
    ACK 0709545365d045b24563b4683881f65a2b34afdd
  41. DrahtBot added the label Needs rebase on Apr 29, 2021
  42. t-bast force-pushed on Apr 30, 2021
  43. in src/wallet/wallet.cpp:2541 in a5c3d9cc4c outdated
    2533@@ -2535,6 +2534,13 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
    2534                                    vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
    2535                 return true;
    2536             }
    2537+            // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
    2538+            // received from other wallets.
    2539+            if (coin_control.m_include_unsafe_inputs && SelectCoinsMinConf(value_to_select,
    2540+                                                        CoinEligibilityFilter(0, 0, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
    2541+                                                        vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
    


    jonatack commented at 7:40 am on April 30, 2021:

    nit, I think it’s best to not indent arguments the same as the function they are a part of. Maybe something like

    0-            if (coin_control.m_include_unsafe_inputs && SelectCoinsMinConf(value_to_select,
    1-                                                        CoinEligibilityFilter(0, 0, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
    2-                                                        vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
    3+            if (coin_control.m_include_unsafe_inputs
    4+                && SelectCoinsMinConf(
    5+                    value_to_select,
    6+                    CoinEligibilityFilter(0, 0, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
    7+                    vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
    8                 return true;
    

  44. jonatack commented at 7:41 am on April 30, 2021: member

    ACK a5c3d9cc4cafef3434c97656ab0d4b4fe4727d51

    Happy to re-ack for #21359 (review) and #21359 (review).

  45. t-bast force-pushed on Apr 30, 2021
  46. DrahtBot removed the label Needs rebase on Apr 30, 2021
  47. in src/wallet/wallet.cpp:2539 in 2bf0b1e7ee outdated
    2533@@ -2535,6 +2534,14 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
    2534                                    vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
    2535                 return true;
    2536             }
    2537+            // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
    2538+            // received from other wallets.
    2539+            if (coin_control.m_include_unsafe_inputs 
    


    jonatack commented at 8:48 am on April 30, 2021:

    linter appeasement time (sorry about that if it’s from my suggestion)

    0            if (coin_control.m_include_unsafe_inputs
    

  48. t-bast force-pushed on Apr 30, 2021
  49. jonatack commented at 9:42 am on April 30, 2021: member
    re-ACK 1b1dad3efbbdf86f5426bf9c43902f40cb9a06c0
  50. MarcoFalke requested review from instagibbs on Apr 30, 2021
  51. in test/functional/rpc_fundrawtransaction.py:964 in 1b1dad3efb outdated
    948+        # But we can opt-in to use them for funding.
    949+        fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": True})
    950+        tx_dec = wallet.decoderawtransaction(fundedtx['hex'])
    951+        assert any([txin['txid'] == txid and txin['vout'] == vout for txin in tx_dec['vin']])
    952+        signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex'])
    953+        wallet.sendrawtransaction(signedtx['hex'])
    


    ariard commented at 2:16 pm on April 30, 2021:
    Can you extend the test with a case where the unsafe input has been confirmed to observe that “include_safe=True” also consider confirmed inputs ?

  52. in src/wallet/rpcwallet.cpp:3213 in 1b1dad3efb outdated
    3209@@ -3205,6 +3210,9 @@ static RPCHelpMan fundrawtransaction()
    3210                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
    3211                         {
    3212                             {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
    3213+                            {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
    


    ariard commented at 2:21 pm on April 30, 2021:
    I think “opt-in RBF” is better than “replacement” to qualify transactions which may be evicted of the mempool due to bip 125 rules.

    t-bast commented at 4:30 pm on April 30, 2021:
    It took the definition of fSafe here: https://github.com/bitcoin/bitcoin/blob/2b45cf0bcdb3d2c1de46899e30885c953b57b475/src/wallet/wallet.h#L595 Is there consensus on updating this in every place where it’s used?
  53. in src/wallet/wallet.cpp:2541 in 1b1dad3efb outdated
    2533@@ -2535,6 +2534,14 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
    2534                                    vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
    2535                 return true;
    2536             }
    2537+            // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
    2538+            // received from other wallets.
    2539+            if (coin_control.m_include_unsafe_inputs
    2540+                && SelectCoinsMinConf(
    2541+                    value_to_select, CoinEligibilityFilter(0, 0, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
    


    ariard commented at 2:58 pm on April 30, 2021:

    Have a look on CoinEligibilityFilter, it says “We never spend of unconfirmed foreign outputs as we cannot rely on it on these funds yet”. I don’t think it’s true anymore ?

    Further, maybe add in-line comments about CoinEligibilityFilter parameters “/* conf_mine / 0, / conf_theirs */ 1”, good for readabilty


  54. in src/wallet/rpcwallet.cpp:4041 in 1b1dad3efb outdated
    4037@@ -4030,6 +4038,9 @@ static RPCHelpMan send()
    4038             {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
    4039                 {
    4040                     {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
    4041+                    {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
    


    ariard commented at 3:07 pm on April 30, 2021:
    Did we already consider for spending replacement transactions from our wallets before this PR ? isRBFOptIndoesn’t seem used in FundTransaction path. Unsafe inputs definition doesn’t seem to be tied to replaceability only key externality ?

    t-bast commented at 4:58 pm on April 30, 2021:
    I’m not 100% I understand your comment. Are you saying that FundTransaction doesn’t check isRBFOptIn, which means that the wallet may currently use unconfirmed outputs from replaceable txs if they’re our own txs (which could be an issue because we could replace that tx and invalidate its children)?
  55. rpc: include_unsafe option for fundrawtransaction
    Allow RPC users to opt-in to unsafe inputs when funding a raw transaction.
    
    Applications that need to manage a complex RBF flow (such as lightning
    nodes using anchor outputs) are very limited if they can only use safe inputs.
    
    Fixes #21299
    11d6459b6e
  56. t-bast force-pushed on Apr 30, 2021
  57. DrahtBot commented at 9:33 am on May 3, 2021: member

    🕵️ @harding has been requested to review this pull request as specified in the REVIEWERS file.

  58. laanwj commented at 2:01 pm on May 10, 2021: member
    Code review ACK 11d6459b6e101f05f36e13799c400bef82d2fc21
  59. laanwj merged this on May 10, 2021
  60. laanwj closed this on May 10, 2021

  61. laanwj removed this from the "Blockers" column in a project

  62. sidhujag referenced this in commit 5f93fe80ef on May 10, 2021
  63. t-bast referenced this in commit c30dd02cd8 on May 11, 2021
  64. meshcollider referenced this in commit 386ba92e83 on May 13, 2021
  65. t-bast deleted the branch on May 13, 2021
  66. luke-jr referenced this in commit 0fc166c629 on Jun 27, 2021
  67. gwillen referenced this in commit d56bdbd28f on Jun 1, 2022
  68. DrahtBot locked this on Aug 16, 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-07-05 19:13 UTC

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