Skip to content

Commit 9dd7bd4

Browse files
committed
Merge #18034: Get the OutputType for a descriptor
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/bitcoin@7e80f64 Sjors: Code review ACK 7e80f64 jonatack: ACK 7e80f64 code review/build/tests Tree-SHA512: c5a813447b62e982435e1c948066f8d6c148c9ebffb0a5eb5a9028b173b01d5ead2f076a5ca3f7f37698538baa346f82a977ee48f583d89cb4e5ebd9111b2341
2 parents e9fc8f6 + 7e80f64 commit 9dd7bd4

File tree

3 files changed

+89
-39
lines changed

3 files changed

+89
-39
lines changed

src/script/descriptor.cpp

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,14 +339,15 @@ class DescriptorImpl : public Descriptor
339339
{
340340
//! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for Multisig).
341341
const std::vector<std::unique_ptr<PubkeyProvider>> m_pubkey_args;
342+
//! The string name of the descriptor function.
343+
const std::string m_name;
344+
345+
protected:
342346
//! The sub-descriptor argument (nullptr for everything but SH and WSH).
343347
//! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
344348
//! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
345349
const std::unique_ptr<DescriptorImpl> m_subdescriptor_arg;
346-
//! The string name of the descriptor function.
347-
const std::string m_name;
348350

349-
protected:
350351
//! Return a serialization of anything except pubkey and script arguments, to be prepended to those.
351352
virtual std::string ToStringExtra() const { return ""; }
352353

@@ -364,7 +365,7 @@ class DescriptorImpl : public Descriptor
364365
virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0;
365366

366367
public:
367-
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) {}
368+
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)) {}
368369

369370
bool IsSolvable() const override
370371
{
@@ -500,6 +501,8 @@ class DescriptorImpl : public Descriptor
500501
out = Merge(out, subprovider);
501502
}
502503
}
504+
505+
Optional<OutputType> GetOutputType() const override { return nullopt; }
503506
};
504507

505508
/** A parsed addr(A) descriptor. */
@@ -512,6 +515,19 @@ class AddressDescriptor final : public DescriptorImpl
512515
public:
513516
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
514517
bool IsSolvable() const final { return false; }
518+
519+
Optional<OutputType> GetOutputType() const override
520+
{
521+
switch (m_destination.which()) {
522+
case 1 /* PKHash */:
523+
case 2 /* ScriptHash */: return OutputType::LEGACY;
524+
case 3 /* WitnessV0ScriptHash */:
525+
case 4 /* WitnessV0KeyHash */:
526+
case 5 /* WitnessUnknown */: return OutputType::BECH32;
527+
case 0 /* CNoDestination */:
528+
default: return nullopt;
529+
}
530+
}
515531
};
516532

517533
/** A parsed raw(H) descriptor. */
@@ -524,6 +540,21 @@ class RawDescriptor final : public DescriptorImpl
524540
public:
525541
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
526542
bool IsSolvable() const final { return false; }
543+
544+
Optional<OutputType> GetOutputType() const override
545+
{
546+
CTxDestination dest;
547+
ExtractDestination(m_script, dest);
548+
switch (dest.which()) {
549+
case 1 /* PKHash */:
550+
case 2 /* ScriptHash */: return OutputType::LEGACY;
551+
case 3 /* WitnessV0ScriptHash */:
552+
case 4 /* WitnessV0KeyHash */:
553+
case 5 /* WitnessUnknown */: return OutputType::BECH32;
554+
case 0 /* CNoDestination */:
555+
default: return nullopt;
556+
}
557+
}
527558
};
528559

529560
/** A parsed pk(P) descriptor. */
@@ -547,6 +578,7 @@ class PKHDescriptor final : public DescriptorImpl
547578
}
548579
public:
549580
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
581+
Optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
550582
};
551583

552584
/** A parsed wpkh(P) descriptor. */
@@ -561,6 +593,7 @@ class WPKHDescriptor final : public DescriptorImpl
561593
}
562594
public:
563595
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {}
596+
Optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
564597
};
565598

566599
/** A parsed combo(P) descriptor. */
@@ -612,6 +645,13 @@ class SHDescriptor final : public DescriptorImpl
612645
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(ScriptHash(*script))); }
613646
public:
614647
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
648+
649+
Optional<OutputType> GetOutputType() const override
650+
{
651+
assert(m_subdescriptor_arg);
652+
if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
653+
return OutputType::LEGACY;
654+
}
615655
};
616656

617657
/** A parsed wsh(...) descriptor. */
@@ -621,6 +661,7 @@ class WSHDescriptor final : public DescriptorImpl
621661
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(WitnessV0ScriptHash(*script))); }
622662
public:
623663
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
664+
Optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
624665
};
625666

626667
////////////////////////////////////////////////////////////////////////////

src/script/descriptor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef BITCOIN_SCRIPT_DESCRIPTOR_H
66
#define BITCOIN_SCRIPT_DESCRIPTOR_H
77

8+
#include <optional.h>
9+
#include <outputtype.h>
810
#include <script/script.h>
911
#include <script/sign.h>
1012
#include <script/signingprovider.h>
@@ -71,6 +73,9 @@ struct Descriptor {
7173
* @param[out] out Any private keys available for the specified `pos`.
7274
*/
7375
virtual void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const = 0;
76+
77+
/** @return The OutputType of the scriptPubKey(s) produced by this descriptor. Or nullopt if indeterminate (multiple or none) */
78+
virtual Optional<OutputType> GetOutputType() const = 0;
7479
};
7580

7681
/** Parse a `descriptor` string. Included private keys are put in `out`.

0 commit comments

Comments
 (0)