diff options
author | Samuel Dobson <dobsonsa68@gmail.com> | 2020-02-22 07:57:56 +1300 |
---|---|---|
committer | Samuel Dobson <dobsonsa68@gmail.com> | 2020-02-22 08:02:52 +1300 |
commit | 9dd7bd47be2f046ea4b114ab86a099ec483d9f3a (patch) | |
tree | ae7353fce13a513d3de0711dcb10ac5779656e30 /src/script | |
parent | e9fc8f6e7f572224d2bd4577eee6d538331ef663 (diff) | |
parent | 7e80f646b24a2abf3c031a649bcc706a695f80da (diff) | |
download | bitcoin-9dd7bd47be2f046ea4b114ab86a099ec483d9f3a.tar.xz |
Merge #18034: Get the OutputType for a descriptor
7e80f646b24a2abf3c031a649bcc706a695f80da 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 7e80f646b24a2abf3c031a649bcc706a695f80da
meshcollider:
utACK 7e80f646b24a2abf3c031a649bcc706a695f80da
instagibbs:
cursory ACK https://github.com/bitcoin/bitcoin/pull/18034/commits/7e80f646b24a2abf3c031a649bcc706a695f80da
Sjors:
Code review ACK 7e80f646b24a2abf3c031a649bcc706a695f80da
jonatack:
ACK 7e80f64 code review/build/tests
Tree-SHA512: c5a813447b62e982435e1c948066f8d6c148c9ebffb0a5eb5a9028b173b01d5ead2f076a5ca3f7f37698538baa346f82a977ee48f583d89cb4e5ebd9111b2341
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/descriptor.cpp | 49 | ||||
-rw-r--r-- | src/script/descriptor.h | 5 |
2 files changed, 50 insertions, 4 deletions
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 773d6a55c4..b1d9a5bda7 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -339,14 +339,15 @@ class DescriptorImpl : public Descriptor { //! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for Multisig). const std::vector<std::unique_ptr<PubkeyProvider>> m_pubkey_args; + //! The string name of the descriptor function. + const std::string m_name; + +protected: //! The sub-descriptor argument (nullptr for everything but SH and WSH). //! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT) //! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions. const std::unique_ptr<DescriptorImpl> m_subdescriptor_arg; - //! The string name of the descriptor function. - const std::string m_name; -protected: //! Return a serialization of anything except pubkey and script arguments, to be prepended to those. virtual std::string ToStringExtra() const { return ""; } @@ -364,7 +365,7 @@ protected: virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0; public: - 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) {} + DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_arg(std::move(script)) {} bool IsSolvable() const override { @@ -500,6 +501,8 @@ public: out = Merge(out, subprovider); } } + + Optional<OutputType> GetOutputType() const override { return nullopt; } }; /** A parsed addr(A) descriptor. */ @@ -512,6 +515,19 @@ protected: public: AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {} bool IsSolvable() const final { return false; } + + Optional<OutputType> GetOutputType() const override + { + switch (m_destination.which()) { + case 1 /* PKHash */: + case 2 /* ScriptHash */: return OutputType::LEGACY; + case 3 /* WitnessV0ScriptHash */: + case 4 /* WitnessV0KeyHash */: + case 5 /* WitnessUnknown */: return OutputType::BECH32; + case 0 /* CNoDestination */: + default: return nullopt; + } + } }; /** A parsed raw(H) descriptor. */ @@ -524,6 +540,21 @@ protected: public: RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {} bool IsSolvable() const final { return false; } + + Optional<OutputType> GetOutputType() const override + { + CTxDestination dest; + ExtractDestination(m_script, dest); + switch (dest.which()) { + case 1 /* PKHash */: + case 2 /* ScriptHash */: return OutputType::LEGACY; + case 3 /* WitnessV0ScriptHash */: + case 4 /* WitnessV0KeyHash */: + case 5 /* WitnessUnknown */: return OutputType::BECH32; + case 0 /* CNoDestination */: + default: return nullopt; + } + } }; /** A parsed pk(P) descriptor. */ @@ -547,6 +578,7 @@ protected: } public: PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {} + Optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; } }; /** A parsed wpkh(P) descriptor. */ @@ -561,6 +593,7 @@ protected: } public: WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {} + Optional<OutputType> GetOutputType() const override { return OutputType::BECH32; } }; /** A parsed combo(P) descriptor. */ @@ -612,6 +645,13 @@ protected: std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); } public: SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {} + + Optional<OutputType> GetOutputType() const override + { + assert(m_subdescriptor_arg); + if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT; + return OutputType::LEGACY; + } }; /** A parsed wsh(...) descriptor. */ @@ -621,6 +661,7 @@ protected: std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); } public: WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {} + Optional<OutputType> GetOutputType() const override { return OutputType::BECH32; } }; //////////////////////////////////////////////////////////////////////////// diff --git a/src/script/descriptor.h b/src/script/descriptor.h index a5a41d78dd..58b920c681 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_SCRIPT_DESCRIPTOR_H #define BITCOIN_SCRIPT_DESCRIPTOR_H +#include <optional.h> +#include <outputtype.h> #include <script/script.h> #include <script/sign.h> #include <script/signingprovider.h> @@ -71,6 +73,9 @@ struct Descriptor { * @param[out] out Any private keys available for the specified `pos`. */ virtual void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const = 0; + + /** @return The OutputType of the scriptPubKey(s) produced by this descriptor. Or nullopt if indeterminate (multiple or none) */ + virtual Optional<OutputType> GetOutputType() const = 0; }; /** Parse a `descriptor` string. Included private keys are put in `out`. |