8000 wallet: add parent_desc to getaddressinfo by achow101 · Pull Request #19136 · bitcoin/bitcoin · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

wallet: add parent_desc to getaddressinfo #19136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 18, 2021

Conversation

achow101
Copy link
Member
@achow101 achow101 commented Jun 1, 2020

Adds parent_desc field to the getaddressinfo RPC to export a public descriptor. Using the given address, getaddressinfo will look up which DescriptorScriptPubKeyMan can be used to produce that address. It will then return the descriptor for that DescriptorScriptPubKeyMan in the parent_desc field. The descriptor will be in a normalized form where the xpub at the last hardened step is derived so that the descriptor can be imported to other wallets. Tests are added to check that the correct descriptor is being returned for the wallet's addresses and that these descriptors can be imported and used in other wallets.

As part of this PR, a ToNormalizedString function is added to the descriptor classes. This really only has an effect on BIP32PubkeyProviders that have hardened derivation steps. Tests are added to check that normalized descriptors are returned.

@DrahtBot
Copy link
Contributor
DrahtBot commented Jun 2, 2020

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

Conflicts

Reviewers, this pull request conflicts with the following ones:

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.

@Sjors
Copy link
Member
Sjors commented Jun 8, 2020

Do we need a whole new RPC for this? Why not expand getaddressinfo?

@meshcollider
Copy link
Contributor

Agree with Sjors, unless you have plans to somehow build upon this later, I think it might as well just be added to getaddressinfo

@achow101
Copy link
Member Author

Changed this to be a new field parent_desc in getaddressinfo. Also rebased.

@achow101 achow101 changed the title wallet: add dumpwalletdescriptor RPC wallet: add parent_desc to getaddressinfo Jul 21, 2020
@Sjors
Copy link
Member
Sjors commented Aug 31, 2020

Concept ACK. This has a silent merge conflict with either #19373 or #19660: script/descriptor.cpp:455:34: error: no matching function for call to 'HexStr'

Copy link
Contributor
@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK.

@achow101 achow101 force-pushed the export-descriptor branch 2 times, most recently from 411518b to ff14b4f Compare August 31, 2020 17:12
@achow101
Copy link
Member Author

Concept ACK. This has a silent merge conflict with either #19373 or #19660: script/descriptor.cpp:455:34: error: no matching function for call to 'HexStr'

Rebased and fixed.

Copy link
Contributor
@S3RK S3RK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it's cumbersome to work with normalised descriptor represented as a string. It has been proved to be prone to errors and also less expressive. Luckily we already have a struct for this!

What if we use object representation for such a descriptor and convert it to string only at the last step.
I have something like this in my mind:

  1. Add PubkeyProvider::GetLastUnhardenedKey(...). The function will be shorter and easier to understand than ToNormalizedString which does two things right now: a) derives the key and b) converts it to string.
  2. Use it in Descriptor::GetNormalizedDescriptor(...). By using GetLastUnhardenedKey it's obvious now what do we mean by "normalized" without going to deep into the code.
  3. In DescriptorScriptPubKeyMan::GetDescriptorString we call GetNormalizedDescriptor() first and than use usual ToPrivateSring() or ToString() functions on the returned descriptor.

Another benefit of this approach is that we don't need more arguments and conditions in ToStringHelepr.

Let me know what you think, I can do a PoC if you'd endorse this idea.

@achow101
Copy link
Member Author

@S3RK I originally attempted an approach like that but was not able to make it work well. The problem is largely in the same place that the problem with this PR is: nested origin pubkey providers. In both this PR and your proposal, you will still have some weirdness to handle when the bip32 pubkey provider returns an origin pubkey provider, but this itself is already within an origin pubkey provider.

@S3RK
Copy link
Contributor
S3RK commented Sep 15, 2020

@achow101 I understand that it's an intrinsic part of the logic here. However my point is that we need to strive to make that weird part as easy to understand as possible. And this is why I believe working with objects/structs is better. When you work with KeyOriginInfo you don't need to rely on a magic number to strip the info from a string. Even bigger issue is not even the constant itself, but tight coupling of unrelated parts of the codebase — BIP32PubkeyProvider and OriginPubkeyProvider are now invisibly tied together by the convention of formatting origin info as a string.

The other benefits hold up as well: single responsibility and less cyclomatic complexity for functions, self-documented code.

@achow101
Copy link
Member Author

@S3RK If you think you have a better solution, feel free to open a PR with it. I can close this one in favor of that if it does look better.

Copy link
Contributor
@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add release note?

@S3RK
Copy link
Contributor
S3RK commented Oct 1, 2020

@S3RK If you think you have a better solution, feel free to open a PR with it. I can close this one in favor of that if it does look better.

For history. I tried to implement alternative version, and indeed it also has its own problems. Both with nested origin/bip32 providers and also with private key management for intermediate xpub. And the diff is bigger 😞

Copy link
Member
@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e92546a looks mostly good, if only because the tests pass...

GetDescriptorString returns a normalized descriptor for a
DescriptorScriptPubKeyMan.
Adds parent_desc field to getaddressinfo output which contains the
descriptor that was used to derive the address if it is available.
@Sjors
Copy link
Member
Sjors commented Oct 9, 2020

utACK de6b389

Copy link
Member
@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested ACK de6b389 modulo a few minor comments

return true;
}
// Step backwards to find the last hardened step in the path
int i = (int)m_path.size() - 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9be1437 named cast per https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#Res-casts-named

Suggested change
int i = (int)m_path.size() - 1;
int i = static_cast<int>(m_path.size()) - 1;

end_path.push_back(m_path.at(k));
}
// Build the string
std::string origin_str = HexStr(origin.fingerprint) + FormatHDKeypath(origin.path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9be1437

Suggested change
std::string origin_str = HexStr(origin.fingerprint) + FormatHDKeypath(origin.path);
const std::string origin_str = HexStr(origin.fingerprint) + FormatHDKeypath(origin.path);

@@ -243,6 +261,12 @@ class ConstPubkeyProvider final : public PubkeyProvider
ret = EncodeSecret(key);
return true;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& ret, bool priv) const override
Copy link
Member
@jonatack jonatack Dec 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9be1437 here and L218, maybe name the arg out rather than ret like the header file declaration and the other definitions

Suggested change
bool ToNormalizedString(const SigningProvider& arg, std::string& ret, bool priv) const override
bool ToNormalizedString(const SigningProvider& arg, std::string& out, bool priv) const override

@@ -3663,6 +3663,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
{RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."},
{RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."},
{RPCResult::Type::STR, "desc", /* optional */ true, "A descriptor for spending coins sent to this address (only when solvable)."},
{RPCResult::Type::STR, "parent_desc", /* optional */ true, "The descriptor used to derive this address if this is a descriptor wallet"},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e4ac869

  • missing period like the neighboring sentences and maybe add a comma
Suggested change
{RPCResult::Type::STR, "parent_desc", /* optional */ true, "The descriptor used to derive this address if this is a descriptor wallet"},
{RPCResult::Type::STR, "parent_desc", /* optional */ true, "The descriptor used to derive this address, if this is a descriptor wallet."},
  • not sure, but maybe change from:

    "The descriptor used to derive this address, if this is a descriptor wallet."

    to

    "The descriptor used to derive this address, if generated by a descriptor wallet."

'internal': internal
}])

for i in range(0, 10):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

de6b389 nit, if iterator is not used in the for-loop block

Suggested change
for i in range(0, 10):
for _ in range(0, 10):

else:
addr = exp_rpc.getnewaddress(address_type=addr_type)
test_desc = exp_rpc.getaddressinfo(addr)['parent_desc']
assert_equal(desc, test_desc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

de6b389 nit, the if internal...else...assert_equal logic is repeated 4 times, maybe extract to a helper

meshcollider added a commit that referenced this pull request Jan 28, 2021
647b81b wallet, rpc: add listdescriptors command (Ivan Metlushko)

Pull request description:

  Looking for concept ACKs

  **Rationale**: allow users to inspect the contents of their newly created descriptor wallets.

  Currently the command only returns xpubs which is not very useful in itself, but there are multiples ways to extend it:
   * add an option to export xprv
   * with #19136 it'll be possible to return normalised descriptors suitable for a watch-only purposes

  The output is compatible with `importdescriptors` command so it could be easily used for backup/recover purposes.

  **Output example:**
  ```json
  [
    {
      "desc": "wpkh(tpubD6NzVbkrYhZ4WW6E2ZETFyNfq2hfF23SKxqSGFvUpPAY58jmmuBybwqwFihAyQPk9KnwTt5516NDZRJ7k5QPeKjy7wuVd5WvXNxwwAs5tUD/*)#nhavpr5h",
      "timestamp": 1296688602,
      "active": false,
      "range": [
        0,
        999
      ],
      "next": 0
    }
  ]
  ```

ACKs for top commit:
  jonatack:
    re-ACK 647b81b rebased to master, debug builds cleanly, reviewed diff since last review, tested with a descriptor wallet (and with a legacy wallet)
  achow101:
    re-ACK 647b81b

Tree-SHA512: 51a3620bb17c836c52cecb066d4fa9d5ff418af56809046eaee0528c4dc240a4e90fff5711ba96e399c6664e00b9ee8194e33852b1b9e75af18061296e19a8a7
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Jan 28, 2021
647b81b wallet, rpc: add listdescriptors command (Ivan Metlushko)

Pull request description:

  Looking for concept ACKs

  **Rationale**: allow users to inspect the contents of their newly created descriptor wallets.

  Currently the command only returns xpubs which is not very useful in itself, but there are multiples ways to extend it:
   * add an option to export xprv
   * with bitcoin#19136 it'll be possible to return normalised descriptors suitable for a watch-only purposes

  The output is compatible with `importdescriptors` command so it could be easily used for backup/recover purposes.

  **Output example:**
  ```json
  [
    {
      "desc": "wpkh(tpubD6NzVbkrYhZ4WW6E2ZETFyNfq2hfF23SKxqSGFvUpPAY58jmmuBybwqwFihAyQPk9KnwTt5516NDZRJ7k5QPeKjy7wuVd5WvXNxwwAs5tUD/*)#nhavpr5h",
      "timestamp": 1296688602,
      "active": false,
      "range": [
        0,
        999
      ],
      "next": 0
    }
  ]
  ```

ACKs for top commit:
  jonatack:
    re-ACK 647b81b rebased to master, debug builds cleanly, reviewed diff since last review, tested with a descriptor wallet (and with a legacy wallet)
  achow101:
    re-ACK 647b81b

Tree-SHA512: 51a3620bb17c836c52cecb066d4fa9d5ff418af56809046eaee0528c4dc240a4e90fff5711ba96e399c6664e00b9ee8194e33852b1b9e75af18061296e19a8a7
Copy link
Contributor
@fjahr fjahr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK de6b389

Also did some light manual testing.

@@ -3732,6 +3733,14 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
ret.pushKV("desc", InferDescriptor(scriptPubKey, *provider)->ToString());
}

DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(pwallet->GetScriptPubKeyMan(scriptPubKey));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in e4ac869:

Below, on line 3742, there is another call to GetScriptPubKeyMan(). Maybe move that one up here to save one.

@S3RK
Copy link
Contributor
S3RK commented Feb 9, 2021

Tested ACK de6b389

@fanquake fanquake requested a review from meshcollider February 9, 2021 08:38
Copy link
Contributor
@meshcollider meshcollider left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested ACK de6b389

@meshcollider meshcollider merged commit db656db into bitcoin:master Feb 18, 2021
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Feb 18, 2021
de6b389 tests: Test getaddressinfo parent_desc (Andrew Chow)
e4ac869 rpc: Add parent descriptor to getaddressinfo output (Andrew Chow)
bbe4a36 wallet: Add GetDescriptorString to DescriptorScriptPubKeyMan (Andrew Chow)
9be1437 descriptors: Add ToNormalizedString and tests (Andrew Chow)

Pull request description:

  Adds `parent_desc` field to the `getaddressinfo` RPC to export a public descriptor. Using the given address, `getaddressinfo` will look up which `DescriptorScriptPubKeyMan` can be used to produce that address. It will then return the descriptor for that `DescriptorScriptPubKeyMan` in the `parent_desc` field. The descriptor will be in a normalized form where the xpub at the last hardened step is derived so that the descriptor can be imported to other wallets. Tests are added to check that the correct descriptor is being returned for the wallet's addresses and that these descriptors can be imported and used in other wallets.

  As part of this PR, a `ToNormalizedString` function is added to the descriptor classes. This really only has an effect on `BIP32PubkeyProvider`s that have hardened derivation steps. Tests are added to check that normalized descriptors are returned.

ACKs for top commit:
  Sjors:
    utACK de6b389
  S3RK:
    Tested ACK de6b389
  jonatack:
    Tested ACK de6b389 modulo a few minor comments
  fjahr:
    Code review ACK de6b389
  meshcollider:
    Tested ACK de6b389

Tree-SHA512: a633e4a39f2abbd95afd7488484cfa66fdd2651dac59fe59f2b80a0940a2a4a13acf889c534a6948903d701484a2ba1218e3081feafe0b9a720dccfa9e43ca2b
laanwj added a commit that referenced this pull request Feb 26, 2021
a69c3b3 wallet: listdescriptors uses normalized descriptor form (Ivan Metlushko)

Pull request description:

  Rationale: show importable descriptors with `listdescriptors` RPC

  It uses #19136 to derive xpub at the last hardened step.

  **Before**:
  ```
  [
      {
        "desc": "wpkh(tpubD6NzVbkrYhZ4YUQRJL49TWw1VR5v3QKUNYaGGMUfJUm19x5ZqQ2hEiPiYbAQvD2nHoPGQGPg3snLPM8sjmYpvx7XQhkmyfk8xhsUwKbXzyh/84'/1'/0'/0/*)#p4cn3erf",
        "timestamp": 1613982591,
        "active": true,
        "internal": false,
        "range": [
          0,
          999
        ],
        "next": 0
      },
      ...
  ]
  ```

  **After**:
  ```
  [
    {
      "desc": "wpkh([d4ade89c/84'/1'/0']tpubDDUEYcVXy6Vh5meHvcXN3sAr4k3fWwLZGpAHbkAHL8EnkDxp4d99CjNhJHfM2fUJicANvAKnCZS6XaVAgwAeKYc1KesGCN5qbQ25qQHrRxM/0/*)#8wq8rcft",
      "timestamp": 1613982591,
      "active": true,
      "internal": false,
      "range": [
        0,
        999
      ],
      "next": 0
    },
    ...
  ]
  ```

ACKs for top commit:
  achow101:
    ACK a69c3b3

Tree-SHA512: 4f92e726cb8245aa0b520729cfd272945f0c66830f0555544e0618883aca516318543fa6ab1862058c64b4e4ed54ad1da953e032f4846eef7454122031c1b005
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Feb 26, 2021
…or form

a69c3b3 wallet: listdescriptors uses normalized descriptor form (Ivan Metlushko)

Pull request description:

  Rationale: show importable descriptors with `listdescriptors` RPC

  It uses bitcoin#19136 to derive xpub at the last hardened step.

  **Before**:
  ```
  [
      {
        "desc": "wpkh(tpubD6NzVbkrYhZ4YUQRJL49TWw1VR5v3QKUNYaGGMUfJUm19x5ZqQ2hEiPiYbAQvD2nHoPGQGPg3snLPM8sjmYpvx7XQhkmyfk8xhsUwKbXzyh/84'/1'/0'/0/*)#p4cn3erf",
        "timestamp": 1613982591,
        "active": true,
        "internal": false,
        "range": [
          0,
          999
        ],
        "next": 0
      },
      ...
  ]
  ```

  **After**:
  ```
  [
    {
      "desc": "wpkh([d4ade89c/84'/1'/0']tpubDDUEYcVXy6Vh5meHvcXN3sAr4k3fWwLZGpAHbkAHL8EnkDxp4d99CjNhJHfM2fUJicANvAKnCZS6XaVAgwAeKYc1KesGCN5qbQ25qQHrRxM/0/*)#8wq8rcft",
      "timestamp": 1613982591,
      "active": true,
      "internal": false,
      "range": [
        0,
        999
      ],
      "next": 0
    },
    ...
  ]
  ```

ACKs for top commit:
  achow101:
    ACK a69c3b3

Tree-SHA512: 4f92e726cb8245aa0b520729cfd272945f0c66830f0555544e0618883aca516318543fa6ab1862058c64b4e4ed54ad1da953e032f4846eef7454122031c1b005
@bitcoin bitcoin deleted a comment Mar 15, 2021
@bitcoin bitcoin locked and limited conversation to collaborators Mar 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants
0