rpc: make importaddress compatible with descriptors wallet #27034

pull furszy wants to merge 1 commits into bitcoin:master from furszy:2022_rpc_importaddress_descriptors_compatible changing 7 files +90 −47
  1. furszy commented at 3:21 pm on February 3, 2023: member

    Made it as part of reviewing other PRs; so it’s simpler to watch certain address/hex in descriptor wallets (without having to go through importdescriptors nuances).

    basically importing the standalone address as a addr(ADDR) descriptor and the raw hex as a raw(HEX) descriptor.

    Note: As we don’t allow mixing watch-only descriptors with spendable ones, the previous behavior is retained if the user try to import an address into a wallet with private keys enabled.

  2. DrahtBot commented at 3:21 pm on February 3, 2023: contributor

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

    Code Coverage

    For detailed information about the code coverage, see the test coverage report.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK aureleoules
    Concept ACK Sjors, kristapsk

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #26840 (refactor: importpubkey, importprivkey, importaddress, importmulti, and importdescriptors rpc by KolbyML)

    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.

  3. DrahtBot added the label RPC/REST/ZMQ on Feb 3, 2023
  4. furszy force-pushed on Feb 3, 2023
  5. furszy force-pushed on Feb 6, 2023
  6. in src/wallet/rpc/backup.cpp:256 in fa78ec839a outdated
    249@@ -247,7 +250,15 @@ RPCHelpMan importaddress()
    250     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
    251     if (!pwallet) return UniValue::VNULL;
    252 
    253-    EnsureLegacyScriptPubKeyMan(*pwallet, true);
    254+    bool has_legacy = pwallet->GetLegacyScriptPubKeyMan();
    255+    if (!has_legacy) {
    256+        // As we don't allow mixing watch-only descriptors with spendable ones,
    257+        // continue creating a legacy spkm if that is the case
    


    Sjors commented at 9:42 am on February 6, 2023:
    Let’s not create a legacy spkm inside a descriptor wallet. Just fail instead, and tell the user to use importdescriptors for that use case.

    furszy commented at 1:36 pm on February 6, 2023:

    This is actually to retain the current behavior, it does not create an hybrid wallet; the legacy spkm creation only happens on blank non-descriptors wallet.

    The internal EnsureLegacyScriptPubKeyMan workflow uses SetupLegacyScriptPubKeyMan which fails if the wallet contains any spkm or the WALLET_FLAG_DESCRIPTORS wallet flag.


    Sjors commented at 2:16 pm on February 6, 2023:
    Ah, that’s worth mentioning in the comment, and maybe also covering with a test.

    furszy commented at 2:52 pm on February 6, 2023:
    yeah 👍🏼

    furszy commented at 3:21 pm on February 6, 2023:
    Pushed test coverage for it.
  7. Sjors commented at 9:48 am on February 6, 2023: member
    Concept ACK on reviving importaddress for descriptor wallets for some use cases. But it should continue to fail for anything that doesn’t work, and not create a hybrid legacy wallet.
  8. kristapsk commented at 9:52 am on February 6, 2023: contributor
    Concept ACK
  9. furszy commented at 1:40 pm on February 6, 2023: member

    Concept ACK on reviving importaddress for descriptor wallets for some use cases. But it should continue to fail for anything that doesn’t work, and not create a hybrid legacy wallet.

    Actually, the comment that I wrote there is wrong, not the code. Will fix it. The same previous behavior is retained; the flow does not create an hybrid wallet; the legacy spkm creation only happens on blank non-descriptors wallets. (https://github.com/bitcoin/bitcoin/pull/27034#discussion_r1097385816).

  10. in src/wallet/rpc/wallet.cpp:62 in fa78ec839a outdated
    58@@ -59,6 +59,7 @@ static RPCHelpMan getwalletinfo()
    59                         }, /*skip_type_check=*/true},
    60                         {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
    61                         {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
    62+                        {RPCResult::Type::BOOL, "has_legacy", "whether this wallet contain a legacy scriptPubKey manager or not"},
    


    Sjors commented at 2:19 pm on February 6, 2023:
    I can see how it’s useful in a test, but otherwise it’s too much of an implementation detail, and potentially confusing.

    furszy commented at 2:51 pm on February 6, 2023:
    I don’t think that differs much from the returned ‘descriptors’ flag. The information might be useful for debugging users’ issues. But.. I’m not so strong for it neither. Flag removed.

    Sjors commented at 4:25 pm on February 6, 2023:
    It sounds like almost a mix between descriptors and !blank, but whether or not a legacy wallet contains a (in memory) LegacySPKM should not matter to the user. I didn’t even know we don’t create an empty one in all cases.
  11. furszy force-pushed on Feb 6, 2023
  12. furszy force-pushed on Feb 6, 2023
  13. furszy force-pushed on Feb 6, 2023
  14. furszy force-pushed on Feb 6, 2023
  15. maflcko commented at 3:15 pm on February 20, 2023: member

    https://cirrus-ci.com/task/5389792813252608?logs=ci#L3465

    0                                       self.test_legacy_importaddress()
    1                                     File "/tmp/cirrus-ci-build/ci/scratch/build/bitcoin-i686-pc-linux-gnu/test/functional/wallet_basic.py", line 72, in test_legacy_importaddress
    2                                       assert_equal(wallet_watch_only.getbalances()["watchonly"]['untrusted_pending'], 10)
    3                                     File "/tmp/cirrus-ci-build/ci/scratch/build/bitcoin-i686-pc-linux-gnu/test/functional/test_framework/util.py", line 56, in assert_equal
    4                                       raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args))
    5                                   AssertionError: not(0E-8 == 10)
    
  16. furszy force-pushed on Feb 20, 2023
  17. furszy commented at 10:39 pm on February 20, 2023: member

    https://cirrus-ci.com/task/5389792813252608?logs=ci#L3465

    0                                       self.test_legacy_importaddress()
    1                                     File "/tmp/cirrus-ci-build/ci/scratch/build/bitcoin-i686-pc-linux-gnu/test/functional/wallet_basic.py", line 72, in test_legacy_importaddress
    2                                       assert_equal(wallet_watch_only.getbalances()["watchonly"]['untrusted_pending'], 10)
    3                                     File "/tmp/cirrus-ci-build/ci/scratch/build/bitcoin-i686-pc-linux-gnu/test/functional/test_framework/util.py", line 56, in assert_equal
    4                                       raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args))
    5                                   AssertionError: not(0E-8 == 10)
    

    Pushed. Thanks @MarcoFalke. The issue was related to the trickle mechanism and the test network topology (lack of sync between mempools). Nothing new really, a sync_mempool call after sending the tx fixed it.

  18. in src/wallet/rpc/backup.cpp:230 in c744d32a0a outdated
    226@@ -225,7 +227,8 @@ RPCHelpMan importaddress()
    227             "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
    228             "as change, and not show up in many RPCs.\n"
    229             "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
    230-            "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" with \"addr(X)\" for descriptor wallets.\n",
    231+            "Note: This command will create a new descriptor/s if the wallet has private keys disabled and has no legacy scriptPubKey manager."
    


    Sjors commented at 10:27 am on February 21, 2023:

    Suggested alternative wording that avoids “scriptPubKey manager”.

    0For descriptor wallets, this command only works if it has private keys disabled.
    1It will create a new descriptor/s. Otherwise, use \"importdescriptors\" instead.
    

    furszy commented at 1:59 pm on February 24, 2023:
    pushed without the last part, mainly because the user cannot import watch-only descriptors on a private keys enabled wallet. So, importdescriptors wouldn’t help anyway.
  19. in src/wallet/rpc/backup.cpp:231 in c744d32a0a outdated
    226@@ -225,7 +227,8 @@ RPCHelpMan importaddress()
    227             "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
    228             "as change, and not show up in many RPCs.\n"
    229             "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
    230-            "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" with \"addr(X)\" for descriptor wallets.\n",
    231+            "Note: This command will create a new descriptor/s if the wallet has private keys disabled and has no legacy scriptPubKey manager."
    232+            "For any other case, the legacy scriptPubKey manager will be used\n",
    


    Sjors commented at 10:27 am on February 21, 2023:
    This sentence can be dropped with my suggestion.
  20. in src/wallet/rpc/backup.cpp:259 in c744d32a0a outdated
    255+    if (!use_legacy) {
    256+        // As we don't allow mixing watch-only descriptors with spendable ones,
    257+        // ensure legacy spkm if wallet is blank and descriptors are not supported.
    258+        // (blank check is done inside 'EnsureLegacyScriptPubKeyMan()')
    259+        if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
    260+            EnsureLegacyScriptPubKeyMan(*pwallet, /*also_create=*/true);
    


    Sjors commented at 10:33 am on February 21, 2023:
    I’m confused: !use_legacy means we have a descriptor wallet. We should never create a LegacyScriptPubKeyMan in that case. I don’t understand what this if block is trying to achieve, but I think it should throw JSONRPCError(RPC_WALLET_ERROR, "Use 'importdescriptors' instead"

    furszy commented at 1:21 pm on February 24, 2023:

    yeah ok. No legacy spkm can be created here because EnsureLegacyScriptPubKeyMan internally calls to SetupLegacyScriptPubKeyMan which returns early if the WALLET_FLAG_DESCRIPTORS is set.

    I thought that we had a release version that upgraded the legacy wallet into a descriptors wallet, letting the user import descriptors while the legacy spkm is available. But.. seems that we never allowed it, at least not officially.

    Good, thanks.


    Sjors commented at 9:24 am on March 1, 2023:

    upgraded the legacy wallet into a descriptors wallet

    I think it’s best to have only one way to go from a legacy wallet to a descriptor wallet (the migration RPC), so in the long run it’s easier to keep testing this stuff.


    furszy commented at 6:56 pm on March 1, 2023:

    upgraded the legacy wallet into a descriptors wallet

    I think it’s best to have only one way to go from a legacy wallet to a descriptor wallet (the migration RPC), so in the long run it’s easier to keep testing this stuff.

    yeah, agree.

  21. Sjors changes_requested
  22. Sjors commented at 10:35 am on February 21, 2023: member

    the legacy spkm creation only happens on blank non-descriptors wallets

    I don’t think this is true, but maybe I’m reading the code wrong.

  23. DrahtBot added the label Needs rebase on Feb 22, 2023
  24. furszy force-pushed on Feb 24, 2023
  25. furszy force-pushed on Feb 24, 2023
  26. furszy commented at 2:04 pm on February 24, 2023: member

    the legacy spkm creation only happens on blank non-descriptors wallets

    I don’t think this is true, but maybe I’m reading the code wrong.

    You mean that there are other situations where a legacy spkm should be created? Or you were referring to #27034 (review)?

    Just pushed an update diff. Thanks for the feedback 👌🏼 .

  27. DrahtBot removed the label Needs rebase on Feb 24, 2023
  28. rpc: make importaddress compatible with descriptors wallet
    so it's simpler to watch for certain address/hex.
    be3ae51ece
  29. DrahtBot added the label Needs rebase on May 1, 2023
  30. furszy force-pushed on May 1, 2023
  31. DrahtBot removed the label Needs rebase on May 1, 2023
  32. luke-jr referenced this in commit c090b420e0 on Aug 16, 2023
  33. achow101 requested review from achow101 on Sep 20, 2023
  34. in src/wallet/rpc/backup.cpp:231 in be3ae51ece
    227@@ -226,7 +228,7 @@ RPCHelpMan importaddress()
    228             "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
    229             "as change, and not show up in many RPCs.\n"
    230             "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
    231-            "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" for descriptor wallets.\n",
    232+            "Note: For descriptor wallets, this command will create new descriptor/s, and only works if the wallet has private keys disabled.\n",
    


    aureleoules commented at 10:56 pm on October 10, 2023:

    nit: Is the /s a typo?

    0            "Note: For descriptor wallets, this command will create new descriptors, and only works if the wallet has private keys disabled.\n",
    
  35. aureleoules commented at 11:03 pm on October 10, 2023: member

    ACK be3ae51ece862fc072d2574c34c808315ebdbff9 I reviewed the code and it looks good to me. I added a test below to cover the missing test coverage if you want to pick it up (see https://corecheck.dev/bitcoin/bitcoin/pulls/27034).

     0diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
     1index f22581ccab..921602da1e 100755
     2--- a/test/functional/wallet_descriptor.py
     3+++ b/test/functional/wallet_descriptor.py
     4@@ -122,16 +122,24 @@ class WalletDescriptorTest(BitcoinTestFramework):
     5         assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.importwallet, 'wallet.dump')
     6         assert_raises_rpc_error(-4, "Only legacy wallets are supported by this command", recv_wrpc.rpc.sethdseed)
     7 
     8-        # Test importaddress
     9-        self.log.info("Test watch-only descriptor wallet")
    10+        self.log.info("Test importaddress on watch-only descriptor wallet")
    11         self.nodes[0].createwallet(wallet_name="watch-only-desc", disable_private_keys=True, descriptors=True, blank=True)
    12         wallet_watch_only = self.nodes[0].get_wallet_rpc("watch-only-desc")
    13         wallet_watch_only.importaddress(addr)
    14         assert_equal(wallet_watch_only.getaddressinfo(addr)['ismine'], True)
    15         assert_equal(wallet_watch_only.getaddressinfo(addr)['solvable'], False)
    16         assert_equal(wallet_watch_only.getbalances()["mine"]['untrusted_pending'], 10)
    17+        raw_script = "a91430ca314f85d5036bc09c8e3bdaf68814008b6ee887"
    18+        assert_raises_rpc_error(-4, "P2SH import feature disabled for descriptors' wallet. Use 'importdescriptors' to specify inner P2SH function", wallet_watch_only.importaddress, raw_script, p2sh=True)
    19+        wallet_watch_only.importaddress(raw_script)
    20         self.nodes[0].unloadwallet("watch-only-desc")
    21 
    22+        self.log.info("Test importaddress on descriptor wallet")
    23+        self.nodes[0].createwallet(wallet_name="non-watch-only-desc", descriptors=True)
    24+        wallet_non_watch_only = self.nodes[0].get_wallet_rpc("non-watch-only-desc")
    25+        assert_raises_rpc_error(-4, "Cannot import address in wallet with private keys enabled. Create wallet with no private keys to watch specific addresses/scripts", wallet_non_watch_only.importaddress, addr)
    26+        self.nodes[0].unloadwallet("non-watch-only-desc")
    27+
    28         self.log.info("Test encryption")
    29         # Get the master fingerprint before encrypt
    30         info1 = send_wrpc.getaddressinfo(send_wrpc.getnewaddress())
    
  36. DrahtBot requested review from Sjors on Oct 10, 2023
  37. furszy commented at 0:20 am on October 11, 2023: member

    Thanks for the review @aureleoules! https://corecheck.dev/bitcoin/bitcoin/pulls/27034 works great ❤️.

    I think that will close the PR so we can remove this RPC command within the legacy wallet removal path. Happy to re-open it if there is more interest on it.

  38. furszy closed this on Oct 11, 2023

  39. bitcoin locked this on Oct 10, 2024

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-11-21 18:12 UTC

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