diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -179,6 +179,15 @@ /** Interface for public key objects in descriptors. */ struct PubkeyProvider { +protected: + //! Index of this key expression in the descriptor + //! E.g. If this PubkeyProvider is key1 in multi(2, key1, key2, key3), then + //! m_expr_index = 0 + uint32_t m_expr_index; + +public: + PubkeyProvider(uint32_t exp_index) : m_expr_index(exp_index) {} + virtual ~PubkeyProvider() = default; /** Derive a public key. If key==nullptr, only info is desired. */ @@ -217,9 +226,10 @@ } public: - OriginPubkeyProvider(KeyOriginInfo info, + OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr provider) - : m_origin(std::move(info)), m_provider(std::move(provider)) {} + : PubkeyProvider(exp_index), m_origin(std::move(info)), + m_provider(std::move(provider)) {} bool GetPubKey(int pos, const SigningProvider &arg, CPubKey *key, KeyOriginInfo &info) const override { if (!m_provider->GetPubKey(pos, arg, key, info)) { @@ -256,7 +266,8 @@ CPubKey m_pubkey; public: - ConstPubkeyProvider(const CPubKey &pubkey) : m_pubkey(pubkey) {} + ConstPubkeyProvider(uint32_t exp_index, const CPubKey &pubkey) + : PubkeyProvider(exp_index), m_pubkey(pubkey) {} bool GetPubKey(int pos, const SigningProvider &arg, CPubKey *key, KeyOriginInfo &info) const override { if (key) { @@ -328,9 +339,10 @@ } public: - BIP32PubkeyProvider(const CExtPubKey &extkey, KeyPath path, - DeriveType derive) - : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {} + BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey &extkey, + KeyPath path, DeriveType derive) + : PubkeyProvider(exp_index), m_extkey(extkey), m_path(std::move(path)), + m_derive(derive) {} bool IsRange() const override { return m_derive != DeriveType::NO; } size_t GetSize() const override { return 33; } bool GetPubKey(int pos, const SigningProvider &arg, CPubKey *key, @@ -808,7 +820,8 @@ } /** Parse a public key that excludes origin information. */ -std::unique_ptr ParsePubkeyInner(const Span &sp, +std::unique_ptr ParsePubkeyInner(uint32_t key_exp_index, + const Span &sp, FlatSigningProvider &out, std::string &error) { using namespace spanparsing; @@ -824,7 +837,8 @@ std::vector data = ParseHex(str); CPubKey pubkey(data); if (pubkey.IsFullyValid()) { - return std::make_unique(pubkey); + return std::make_unique(key_exp_index, + pubkey); } error = strprintf("Pubkey '%s' is invalid", str); return nullptr; @@ -833,7 +847,7 @@ if (key.IsValid()) { CPubKey pubkey = key.GetPubKey(); out.keys.emplace(pubkey.GetID(), key); - return std::make_unique(pubkey); + return std::make_unique(key_exp_index, pubkey); } } CExtKey extkey = DecodeExtKey(str); @@ -859,12 +873,13 @@ extpubkey = extkey.Neuter(); out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key); } - return std::make_unique(extpubkey, std::move(path), - type); + return std::make_unique(key_exp_index, extpubkey, + std::move(path), type); } /** Parse a public key including origin information (if enabled). */ -std::unique_ptr ParsePubkey(const Span &sp, +std::unique_ptr ParsePubkey(uint32_t key_exp_index, + const Span &sp, FlatSigningProvider &out, std::string &error) { using namespace spanparsing; @@ -875,7 +890,7 @@ return nullptr; } if (origin_split.size() == 1) { - return ParsePubkeyInner(origin_split[0], out, error); + return ParsePubkeyInner(key_exp_index, origin_split[0], out, error); } if (origin_split[0].size() < 1 || origin_split[0][0] != '[') { error = strprintf("Key origin start '[ character expected but not " @@ -904,16 +919,18 @@ if (!ParseKeyPath(slash_split, info.path, error)) { return nullptr; } - auto provider = ParsePubkeyInner(origin_split[1], out, error); + auto provider = + ParsePubkeyInner(key_exp_index, origin_split[1], out, error); if (!provider) { return nullptr; } - return std::make_unique(std::move(info), - std::move(provider)); + return std::make_unique( + key_exp_index, std::move(info), std::move(provider)); } /** Parse a script in a particular context. */ -std::unique_ptr ParseScript(Span &sp, +std::unique_ptr ParseScript(uint32_t key_exp_index, + Span &sp, ParseScriptContext ctx, FlatSigningProvider &out, std::string &error) { @@ -922,21 +939,21 @@ auto expr = Expr(sp); bool sorted_multi = false; if (Func("pk", expr)) { - auto pubkey = ParsePubkey(expr, out, error); + auto pubkey = ParsePubkey(key_exp_index, expr, out, error); if (!pubkey) { return nullptr; } return std::make_unique(std::move(pubkey)); } if (Func("pkh", expr)) { - auto pubkey = ParsePubkey(expr, out, error); + auto pubkey = ParsePubkey(key_exp_index, expr, out, error); if (!pubkey) { return nullptr; } return std::make_unique(std::move(pubkey)); } if (ctx == ParseScriptContext::TOP && Func("combo", expr)) { - auto pubkey = ParsePubkey(expr, out, error); + auto pubkey = ParsePubkey(key_exp_index, expr, out, error); if (!pubkey) { return nullptr; } @@ -963,12 +980,13 @@ return nullptr; } auto arg = Expr(expr); - auto pk = ParsePubkey(arg, out, error); + auto pk = ParsePubkey(key_exp_index, arg, out, error); if (!pk) { return nullptr; } script_size += pk->GetSize() + 1; providers.emplace_back(std::move(pk)); + key_exp_index++; } if (providers.size() < 1 || providers.size() > 16) { error = strprintf("Cannot have %u keys in multisig; must have " @@ -1006,7 +1024,8 @@ sorted_multi); } if (ctx == ParseScriptContext::TOP && Func("sh", expr)) { - auto desc = ParseScript(expr, ParseScriptContext::P2SH, out, error); + auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, + out, error); if (!desc || expr.size()) { return nullptr; } @@ -1043,13 +1062,14 @@ return nullptr; } -static std::unique_ptr -InferPubkey(const CPubKey &pubkey, ParseScriptContext, - const SigningProvider &provider) { - auto key_provider = std::make_unique(pubkey); +std::unique_ptr InferPubkey(const CPubKey &pubkey, + ParseScriptContext, + const SigningProvider &provider) { + std::unique_ptr key_provider = + std::make_unique(0, pubkey); KeyOriginInfo info; if (provider.GetKeyOrigin(pubkey.GetID(), info)) { - return std::make_unique(std::move(info), + return std::make_unique(0, std::move(info), std::move(key_provider)); } return key_provider; @@ -1164,7 +1184,7 @@ if (!CheckChecksum(sp, require_checksum, error)) { return nullptr; } - auto ret = ParseScript(sp, ParseScriptContext::TOP, out, error); + auto ret = ParseScript(0, sp, ParseScriptContext::TOP, out, error); if (sp.size() == 0 && ret) { return std::unique_ptr(std::move(ret)); }