diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/descriptor.cpp | 52 | ||||
-rw-r--r-- | src/script/miniscript.h | 3 |
2 files changed, 45 insertions, 10 deletions
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 22177504fc..104990abb7 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1114,16 +1114,33 @@ public: class ScriptMaker { //! Keys contained in the Miniscript (the evaluation of DescriptorImpl::m_pubkey_args). const std::vector<CPubKey>& m_keys; + //! The script context we're operating within (Tapscript or P2WSH). + const miniscript::MiniscriptContext m_script_ctx; + + //! Get the ripemd160(sha256()) hash of this key. + //! Any key that is valid in a descriptor serializes as 32 bytes within a Tapscript context. So we + //! must not hash the sign-bit byte in this case. + uint160 GetHash160(uint32_t key) const { + if (miniscript::IsTapscript(m_script_ctx)) { + return Hash160(XOnlyPubKey{m_keys[key]}); + } + return m_keys[key].GetID(); + } public: - ScriptMaker(const std::vector<CPubKey>& keys LIFETIMEBOUND) : m_keys(keys) {} + ScriptMaker(const std::vector<CPubKey>& keys LIFETIMEBOUND, const miniscript::MiniscriptContext script_ctx) : m_keys(keys), m_script_ctx{script_ctx} {} std::vector<unsigned char> ToPKBytes(uint32_t key) const { - return {m_keys[key].begin(), m_keys[key].end()}; + // In Tapscript keys always serialize as x-only, whether an x-only key was used in the descriptor or not. + if (!miniscript::IsTapscript(m_script_ctx)) { + return {m_keys[key].begin(), m_keys[key].end()}; + } + const XOnlyPubKey xonly_pubkey{m_keys[key]}; + return {xonly_pubkey.begin(), xonly_pubkey.end()}; } std::vector<unsigned char> ToPKHBytes(uint32_t key) const { - auto id = m_keys[key].GetID(); + auto id = GetHash160(key); return {id.begin(), id.end()}; } }; @@ -1165,7 +1182,7 @@ protected: FlatSigningProvider& provider) const override { for (const auto& key : keys) provider.pubkeys.emplace(key.GetID(), key); - return Vector(m_node->ToScript(ScriptMaker(keys))); + return Vector(m_node->ToScript(ScriptMaker(keys, m_node->GetMsCtx()))); } public: @@ -1434,11 +1451,19 @@ struct KeyParser { return *m_keys.at(a) < *m_keys.at(b); } + ParseScriptContext ParseContext() const { + switch (m_script_ctx) { + case miniscript::MiniscriptContext::P2WSH: return ParseScriptContext::P2WSH; + case miniscript::MiniscriptContext::TAPSCRIPT: return ParseScriptContext::P2TR; + } + assert(false); + } + template<typename I> std::optional<Key> FromString(I begin, I end) const { assert(m_out); Key key = m_keys.size(); - auto pk = ParsePubkey(key, {&*begin, &*end}, ParseScriptContext::P2WSH, *m_out, m_key_parsing_error); + auto pk = ParsePubkey(key, {&*begin, &*end}, ParseContext(), *m_out, m_key_parsing_error); if (!pk) return {}; m_keys.push_back(std::move(pk)); return key; @@ -1452,11 +1477,18 @@ struct KeyParser { template<typename I> std::optional<Key> FromPKBytes(I begin, I end) const { assert(m_in); - CPubKey pubkey(begin, end); - if (pubkey.IsValidNonHybrid()) { - Key key = m_keys.size(); - m_keys.push_back(InferPubkey(pubkey, ParseScriptContext::P2WSH, *m_in)); + Key key = m_keys.size(); + if (miniscript::IsTapscript(m_script_ctx) && end - begin == 32) { + XOnlyPubKey pubkey; + std::copy(begin, end, pubkey.begin()); + m_keys.push_back(InferPubkey(pubkey.GetEvenCorrespondingCPubKey(), ParseContext(), *m_in)); return key; + } else if (!miniscript::IsTapscript(m_script_ctx)) { + CPubKey pubkey{begin, end}; + if (pubkey.IsValidNonHybrid()) { + m_keys.push_back(InferPubkey(pubkey, ParseContext(), *m_in)); + return key; + } } return {}; } @@ -1471,7 +1503,7 @@ struct KeyParser { CPubKey pubkey; if (m_in->GetPubKey(keyid, pubkey)) { Key key = m_keys.size(); - m_keys.push_back(InferPubkey(pubkey, ParseScriptContext::P2WSH, *m_in)); + m_keys.push_back(InferPubkey(pubkey, ParseContext(), *m_in)); return key; } return {}; diff --git a/src/script/miniscript.h b/src/script/miniscript.h index 1923329cbe..7585168ec2 100644 --- a/src/script/miniscript.h +++ b/src/script/miniscript.h @@ -1516,6 +1516,9 @@ public: //! Return the expression type. Type GetType() const { return typ; } + //! Return the script context for this node. + MiniscriptContext GetMsCtx() const { return m_script_ctx; } + //! Find an insane subnode which has no insane children. Nullptr if there is none. const Node* FindInsaneSub() const { return TreeEval<const Node*>([](const Node& node, Span<const Node*> subs) -> const Node* { |