Skip to content

Conversation

@achow101
Copy link
Member

Adds a GetOutputType() method to get the OutputType of a descriptor. Some descriptors don't have a determinate OutputType, so we actually use an Optional<OutputType>. For descriptors with indeterminate OutputType, we return nullopt.

addr() and raw() use OutputTypes as determined by the CTxDestination they have. For simplicity, ScriptHash destinations are LEGACY even though they could be P2SH_SEGWIT.
combo(), pk(), and multi() are nullopt as they either don't have an OutputType or they have multiple. DescriptorImpl defaults to nullopt.
pkh() is LEGACY as expected
wpkh() and wsh() are BECH32 as expected.
sh() checks whether the sub-descriptor is BECH32. If so, it is P2SH_SEGWIT. Otherwise it is LEGACY.

The descriptor tests are updated to check the OutputType too.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jan 31, 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.

@promag
Copy link
Contributor

promag commented Feb 3, 2020

Do you have a use case for these?

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.

Concept ACK. After some discussion in #15590 I think adding GetOutputType() to Descriptor is preferable over the approach there of adding GetAddressType() and IsSegWit().

I don't like the use of ExtractDestination though. Let's just determine the output type from the descriptor itself similar to #15590. That also avoids the next problem:

For simplicity, ScriptHash destinations are LEGACY even though they could be P2SH_SEGWIT

This assumption breaks BIP49 descriptor import with HWI. See e.g. https://github.com/bitcoin/bitcoin/pull/16546/files#diff-b2bb174788c7409b671c46ccc86034bdR4359-R4378. This current uses GetAddressType() and IsSegWit(), and if I switched it to use GetOutputType() it would import the wrapped segwit descriptor as legacy.

@achow101
Copy link
Member Author

I don't like the use of ExtractDestination though. Let's just determine the output type from the descriptor itself similar to #15590. That also avoids the next problem:

For simplicity, ScriptHash destinations are LEGACY even though they could be P2SH_SEGWIT

These only apply to addr() and raw() descriptors. The rest where all solving information is available do the correct thing.

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.

Code review ACK b4fcf7ad56d0981797a4424f38f0524275d26e59 modulo (an explanation for) the assert.

Copy link
Member

Choose a reason for hiding this comment

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

I don't mind, but why are you making m_name public?

Copy link
Member Author

@achow101 achow101 Feb 10, 2020

Choose a reason for hiding this comment

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

It doesn't. The default visibility is private.

You should really see this change as moving m_subdescriptor_arg into the protected area rather than moving m_mame.

Copy link
Member

Choose a reason for hiding this comment

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

Oops, I misread that move. That makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

However there's a warning:

script/descriptor.cpp:368:176: warning: field 'm_subdescriptor_arg' will be initialized after field 'm_name' [-Wreorder]
    DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_subdescriptor_arg(std::move(script)), m_name(name) {}

Copy link
Member Author

Choose a reason for hiding this comment

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

That should be fixed now.

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.

Code review ACK 7e80f64

@fjahr
Copy link
Contributor

fjahr commented Feb 19, 2020

ACK 7e80f64

Reviewed code, built and ran tests locally.

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.

ACK 7e80f64 code review/build/tests

Copy link
Member

@instagibbs instagibbs left a comment

Choose a reason for hiding this comment

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

For simplicity, ScriptHash destinations are LEGACY even though they could be P2SH_SEGWIT.

This is not readily apparent to me as a reviewer or reader of the code why it's that way?

{
switch (m_destination.which()) {
case 1 /* PKHash */:
case 2 /* ScriptHash */: return OutputType::LEGACY;
Copy link
Member

Choose a reason for hiding this comment

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

motivation for having ScriptHash be "LEGACY" which I think means p2pkh in most contexts?

Copy link
Member Author

Choose a reason for hiding this comment

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

What else would it be?

I would consider just a P2SH scriptPubKey to be legacy if I had no information about the redeemScript.

Copy link
Member

Choose a reason for hiding this comment

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

ahhhh this is addr(), ignore this.

@Sjors
Copy link
Member

Sjors commented Feb 20, 2020

@instagibbs I suppose the alternative is to treat addr() and raw() descriptors as null. It's probably a bad idea to import these things.

@meshcollider
Copy link
Contributor

utACK 7e80f64

I guess the same kind of complaint could apply here too, that the descriptor implementation shouldn't really be the thing worrying about how the destinations are encoded. But that's okay. I assume there is a use-case, even though promag's question was never responded to? I still don't really see the point of this, could you just quickly explain where this will be used? I had a quick look at #16528 and it isn't immediately clear to me that this PR made things easier there vs doing things a different way

@Sjors
Copy link
Member

Sjors commented Feb 21, 2020

@achow101
Copy link
Member Author

@meshcollider The use case is that in #16528, we need to be able to determine the OutputType for a descriptor so that we can assign it the correct slot in m_external_spk_managers/m_internal_spk_managers. The point is that we can tell what kind of address it will produce and automatically make it so that doing getnewaddress will give the correct address type from the correct descriptor.

And I guess @Sjors is using it for something.

@instagibbs
Copy link
Member

cursory ACK 7e80f64

@meshcollider meshcollider merged commit 9dd7bd4 into bitcoin:master Feb 21, 2020
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Feb 22, 2020
7e80f64 Get the OutputType for a descriptor (Andrew Chow)

Pull request description:

  Adds a `GetOutputType()` method to get the OutputType of a descriptor. Some descriptors don't have a determinate OutputType, so we actually use an `Optional<OutputType>`. For descriptors with indeterminate OutputType, we return `nullopt`.

  `addr()` and `raw()` use OutputTypes as determined by the CTxDestination they have. For simplicity, `ScriptHash` destinations are `LEGACY` even though they could be `P2SH_SEGWIT`.
  `combo()`, `pk()`, and `multi()` are `nullopt` as they either don't have an OutputType or they have multiple. `DescriptorImpl` defaults to `nullopt`.
  `pkh()` is `LEGACY` as expected
  `wpkh()` and `wsh()` are `BECH32` as expected.
  `sh()` checks whether the sub-descriptor is `BECH32`. If so, it is `P2SH_SEGWIT`. Otherwise it is `LEGACY`.

  The descriptor tests are updated to check the OutputType too.

ACKs for top commit:
  fjahr:
    ACK 7e80f64
  meshcollider:
    utACK 7e80f64
  instagibbs:
    cursory ACK bitcoin@7e80f64
  Sjors:
    Code review ACK 7e80f64
  jonatack:
    ACK 7e80f64 code review/build/tests

Tree-SHA512: c5a813447b62e982435e1c948066f8d6c148c9ebffb0a5eb5a9028b173b01d5ead2f076a5ca3f7f37698538baa346f82a977ee48f583d89cb4e5ebd9111b2341
sidhujag pushed a commit to syscoin-core/syscoin that referenced this pull request Nov 10, 2020
7e80f64 Get the OutputType for a descriptor (Andrew Chow)

Pull request description:

  Adds a `GetOutputType()` method to get the OutputType of a descriptor. Some descriptors don't have a determinate OutputType, so we actually use an `Optional<OutputType>`. For descriptors with indeterminate OutputType, we return `nullopt`.

  `addr()` and `raw()` use OutputTypes as determined by the CTxDestination they have. For simplicity, `ScriptHash` destinations are `LEGACY` even though they could be `P2SH_SEGWIT`.
  `combo()`, `pk()`, and `multi()` are `nullopt` as they either don't have an OutputType or they have multiple. `DescriptorImpl` defaults to `nullopt`.
  `pkh()` is `LEGACY` as expected
  `wpkh()` and `wsh()` are `BECH32` as expected.
  `sh()` checks whether the sub-descriptor is `BECH32`. If so, it is `P2SH_SEGWIT`. Otherwise it is `LEGACY`.

  The descriptor tests are updated to check the OutputType too.

ACKs for top commit:
  fjahr:
    ACK 7e80f64
  meshcollider:
    utACK 7e80f64
  instagibbs:
    cursory ACK bitcoin@7e80f64
  Sjors:
    Code review ACK 7e80f64
  jonatack:
    ACK 7e80f64 code review/build/tests

Tree-SHA512: c5a813447b62e982435e1c948066f8d6c148c9ebffb0a5eb5a9028b173b01d5ead2f076a5ca3f7f37698538baa346f82a977ee48f583d89cb4e5ebd9111b2341
jasonbcox pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Nov 13, 2020
Summary: Backport of Core [[bitcoin/bitcoin#18034 | PR18034]]

Test Plan:
  ninja all check

Reviewers: #bitcoin_abc, Fabien, majcosta

Reviewed By: #bitcoin_abc, Fabien, majcosta

Differential Revision: https://reviews.bitcoinabc.org/D8395
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
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