aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2022-08-09 16:26:17 -0400
committerAndrew Chow <achow101-github@achow101.com>2022-08-09 16:36:00 -0400
commitac59112a6a093e641ce2803260dd9de97b1cd961 (patch)
tree0d5e7e69bd3ac628195cfad542bb95c607160494 /src/script
parentc012875b9ded0a5183602f002738ca823d559518 (diff)
parent544b4332f0e122167bdb94dc963405422faa30cb (diff)
downloadbitcoin-ac59112a6a093e641ce2803260dd9de97b1cd961.tar.xz
Merge bitcoin/bitcoin#23480: Add rawtr() descriptor for P2TR with specified (tweaked) output key
544b4332f0e122167bdb94dc963405422faa30cb Add wallet tests for spending rawtr() (Pieter Wuille) e1e3081200a71b6c9b0dcf236bc2a37ed1aa7552 If P2TR tweaked key is available, sign with it (Pieter Wuille) 8d9670ccb756592bddb2a269bf5078d62658537b Add rawtr() descriptor for P2TR with unknown tweak (Pieter Wuille) Pull request description: It may be useful to be able to represent P2TR outputs in descriptors whose script tree and/or internal key aren't known. This PR does that, by adding a `rawtr(KEY)` descriptor, where the KEY represents the output key directly. If the private key corresponding to that output key is known, it also permits signing with it. I'm not convinced this is desirable, but presumably "tr(KEY)" sounds more intended for direct use than "rawtr(KEY)". ACKs for top commit: achow101: ACK 544b4332f0e122167bdb94dc963405422faa30cb sanket1729: code review ACK 544b4332f0e122167bdb94dc963405422faa30cb w0xlt: reACK https://github.com/bitcoin/bitcoin/pull/23480/commits/544b4332f0e122167bdb94dc963405422faa30cb Tree-SHA512: 0de08de517468bc22ab0c00db471ce33144f5dc211ebc2974c6ea95709f44e830532ec5cdb0128c572513d352120bd651c4559516d4500b5b0a3d257c4b45aca
Diffstat (limited to 'src/script')
-rw-r--r--src/script/descriptor.cpp35
-rw-r--r--src/script/sign.cpp5
2 files changed, 40 insertions, 0 deletions
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 34a4da74f8..db386c9ab8 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -1015,6 +1015,24 @@ public:
bool IsSingleType() const final { return true; }
};
+/** A parsed rawtr(...) descriptor. */
+class RawTRDescriptor final : public DescriptorImpl
+{
+protected:
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript> scripts, FlatSigningProvider& out) const override
+ {
+ assert(keys.size() == 1);
+ XOnlyPubKey xpk(keys[0]);
+ if (!xpk.IsFullyValid()) return {};
+ WitnessV1Taproot output{xpk};
+ return Vector(GetScriptForDestination(output));
+ }
+public:
+ RawTRDescriptor(std::unique_ptr<PubkeyProvider> output_key) : DescriptorImpl(Vector(std::move(output_key)), "rawtr") {}
+ std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
+ bool IsSingleType() const final { return true; }
+};
+
////////////////////////////////////////////////////////////////////////////
// Parser //
////////////////////////////////////////////////////////////////////////////
@@ -1453,6 +1471,16 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
error = "Can only have tr at top level";
return nullptr;
}
+ if (ctx == ParseScriptContext::TOP && Func("rawtr", expr)) {
+ auto arg = Expr(expr);
+ auto output_key = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error);
+ if (!output_key) return nullptr;
+ ++key_exp_index;
+ return std::make_unique<RawTRDescriptor>(std::move(output_key));
+ } else if (Func("rawtr", expr)) {
+ error = "Can only have rawtr at top level";
+ return nullptr;
+ }
if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
std::string str(expr.begin(), expr.end());
if (!IsHex(str)) {
@@ -1626,6 +1654,13 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
}
}
}
+ // If the above doesn't work, construct a rawtr() descriptor with just the encoded x-only pubkey.
+ if (pubkey.IsFullyValid()) {
+ auto key = InferXOnlyPubkey(pubkey, ParseScriptContext::P2TR, provider);
+ if (key) {
+ return std::make_unique<RawTRDescriptor>(std::move(key));
+ }
+ }
}
if (ctx == ParseScriptContext::P2WSH) {
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 3b8071d9d1..79cf918c9b 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -243,6 +243,11 @@ static bool SignTaproot(const SigningProvider& provider, const BaseSignatureCrea
sigdata.taproot_key_path_sig = sig;
}
}
+ if (sigdata.taproot_key_path_sig.size() == 0) {
+ if (creator.CreateSchnorrSig(provider, sig, output, nullptr, nullptr, SigVersion::TAPROOT)) {
+ sigdata.taproot_key_path_sig = sig;
+ }
+ }
if (sigdata.taproot_key_path_sig.size()) {
result = Vector(sigdata.taproot_key_path_sig);
return true;