Skip to content

Commit df55d44

Browse files
committed
Track the index of the key expression in PubkeyProvider
1 parent 474ea3b commit df55d44

File tree

1 file changed

+31
-22
lines changed

1 file changed

+31
-22
lines changed

src/script/descriptor.cpp

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ typedef std::vector<uint32_t> KeyPath;
150150
/** Interface for public key objects in descriptors. */
151151
struct PubkeyProvider
152152
{
153+
protected:
154+
//! Index of this key expression in the descriptor
155+
//! E.g. If this PubkeyProvider is key1 in multi(2, key1, key2, key3), then m_expr_index = 0
156+
uint32_t m_expr_index;
157+
158+
public:
159+
PubkeyProvider(uint32_t exp_index) : m_expr_index(exp_index) {}
160+
153161
virtual ~PubkeyProvider() = default;
154162

155163
/** Derive a public key. If key==nullptr, only info is desired. */
@@ -182,7 +190,7 @@ class OriginPubkeyProvider final : public PubkeyProvider
182190
}
183191

184192
public:
185-
OriginPubkeyProvider(KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : m_origin(std::move(info)), m_provider(std::move(provider)) {}
193+
OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)) {}
186194
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
187195
{
188196
if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
@@ -212,7 +220,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
212220
CPubKey m_pubkey;
213221

214222
public:
215-
ConstPubkeyProvider(const CPubKey& pubkey) : m_pubkey(pubkey) {}
223+
ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey) : PubkeyProvider(exp_index), m_pubkey(pubkey) {}
216224
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
217225
{
218226
if (key) *key = m_pubkey;
@@ -272,7 +280,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
272280
}
273281

274282
public:
275-
BIP32PubkeyProvider(const CExtPubKey& extkey, KeyPath path, DeriveType derive) : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
283+
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) {}
276284
bool IsRange() const override { return m_derive != DeriveType::NO; }
277285
size_t GetSize() const override { return 33; }
278286
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
@@ -698,7 +706,7 @@ NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath&
698706
}
699707

700708
/** Parse a public key that excludes origin information. */
701-
std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
709+
std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
702710
{
703711
using namespace spanparsing;
704712

@@ -714,7 +722,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, boo
714722
CPubKey pubkey(data);
715723
if (pubkey.IsFullyValid()) {
716724
if (permit_uncompressed || pubkey.IsCompressed()) {
717-
return MakeUnique<ConstPubkeyProvider>(pubkey);
725+
return MakeUnique<ConstPubkeyProvider>(key_exp_index, pubkey);
718726
} else {
719727
error = "Uncompressed keys are not allowed";
720728
return nullptr;
@@ -728,7 +736,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, boo
728736
if (permit_uncompressed || key.IsCompressed()) {
729737
CPubKey pubkey = key.GetPubKey();
730738
out.keys.emplace(pubkey.GetID(), key);
731-
return MakeUnique<ConstPubkeyProvider>(pubkey);
739+
return MakeUnique<ConstPubkeyProvider>(key_exp_index, pubkey);
732740
} else {
733741
error = "Uncompressed keys are not allowed";
734742
return nullptr;
@@ -755,11 +763,11 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, boo
755763
extpubkey = extkey.Neuter();
756764
out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key);
757765
}
758-
return MakeUnique<BIP32PubkeyProvider>(extpubkey, std::move(path), type);
766+
return MakeUnique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type);
759767
}
760768

761769
/** Parse a public key including origin information (if enabled). */
762-
std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
770+
std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out, std::string& error)
763771
{
764772
using namespace spanparsing;
765773

@@ -768,7 +776,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool per
768776
error = "Multiple ']' characters found for a single pubkey";
769777
return nullptr;
770778
}
771-
if (origin_split.size() == 1) return ParsePubkeyInner(origin_split[0], permit_uncompressed, out, error);
779+
if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], permit_uncompressed, out, error);
772780
if (origin_split[0].size() < 1 || origin_split[0][0] != '[') {
773781
error = strprintf("Key origin start '[ character expected but not found, got '%c' instead", origin_split[0][0]);
774782
return nullptr;
@@ -789,30 +797,30 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool per
789797
assert(fpr_bytes.size() == 4);
790798
std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
791799
if (!ParseKeyPath(slash_split, info.path, error)) return nullptr;
792-
auto provider = ParsePubkeyInner(origin_split[1], permit_uncompressed, out, error);
800+
auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], permit_uncompressed, out, error);
793801
if (!provider) return nullptr;
794-
return MakeUnique<OriginPubkeyProvider>(std::move(info), std::move(provider));
802+
return MakeUnique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
795803
}
796804

797805
/** Parse a script in a particular context. */
798-
std::unique_ptr<DescriptorImpl> ParseScript(Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
806+
std::unique_ptr<DescriptorImpl> ParseScript(uint32_t key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
799807
{
800808
using namespace spanparsing;
801809

802810
auto expr = Expr(sp);
803811
bool sorted_multi = false;
804812
if (Func("pk", expr)) {
805-
auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out, error);
813+
auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
806814
if (!pubkey) return nullptr;
807815
return MakeUnique<PKDescriptor>(std::move(pubkey));
808816
}
809817
if (Func("pkh", expr)) {
810-
auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out, error);
818+
auto pubkey = ParsePubkey(key_exp_index, expr, ctx != ParseScriptContext::P2WSH, out, error);
811819
if (!pubkey) return nullptr;
812820
return MakeUnique<PKHDescriptor>(std::move(pubkey));
813821
}
814822
if (ctx == ParseScriptContext::TOP && Func("combo", expr)) {
815-
auto pubkey = ParsePubkey(expr, true, out, error);
823+
auto pubkey = ParsePubkey(key_exp_index, expr, true, out, error);
816824
if (!pubkey) return nullptr;
817825
return MakeUnique<ComboDescriptor>(std::move(pubkey));
818826
} else if (ctx != ParseScriptContext::TOP && Func("combo", expr)) {
@@ -834,10 +842,11 @@ std::unique_ptr<DescriptorImpl> ParseScript(Span<const char>& sp, ParseScriptCon
834842
return nullptr;
835843
}
836844
auto arg = Expr(expr);
837-
auto pk = ParsePubkey(arg, ctx != ParseScriptContext::P2WSH, out, error);
845+
auto pk = ParsePubkey(key_exp_index, arg, ctx != ParseScriptContext::P2WSH, out, error);
838846
if (!pk) return nullptr;
839847
script_size += pk->GetSize() + 1;
840848
providers.emplace_back(std::move(pk));
849+
key_exp_index++;
841850
}
842851
if (providers.size() < 1 || providers.size() > 16) {
843852
error = strprintf("Cannot have %u keys in multisig; must have between 1 and 16 keys, inclusive", providers.size());
@@ -864,23 +873,23 @@ std::unique_ptr<DescriptorImpl> ParseScript(Span<const char>& sp, ParseScriptCon
864873
return MakeUnique<MultisigDescriptor>(thres, std::move(providers), sorted_multi);
865874
}
866875
if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) {
867-
auto pubkey = ParsePubkey(expr, false, out, error);
876+
auto pubkey = ParsePubkey(key_exp_index, expr, false, out, error);
868877
if (!pubkey) return nullptr;
869878
return MakeUnique<WPKHDescriptor>(std::move(pubkey));
870879
} else if (ctx == ParseScriptContext::P2WSH && Func("wpkh", expr)) {
871880
error = "Cannot have wpkh within wsh";
872881
return nullptr;
873882
}
874883
if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {
875-
auto desc = ParseScript(expr, ParseScriptContext::P2SH, out, error);
884+
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error);
876885
if (!desc || expr.size()) return nullptr;
877886
return MakeUnique<SHDescriptor>(std::move(desc));
878887
} else if (ctx != ParseScriptContext::TOP && Func("sh", expr)) {
879888
error = "Cannot have sh in non-top level";
880889
return nullptr;
881890
}
882891
if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) {
883-
auto desc = ParseScript(expr, ParseScriptContext::P2WSH, out, error);
892+
auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error);
884893
if (!desc || expr.size()) return nullptr;
885894
return MakeUnique<WSHDescriptor>(std::move(desc));
886895
} else if (ctx == ParseScriptContext::P2WSH && Func("wsh", expr)) {
@@ -917,10 +926,10 @@ std::unique_ptr<DescriptorImpl> ParseScript(Span<const char>& sp, ParseScriptCon
917926

918927
std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
919928
{
920-
std::unique_ptr<PubkeyProvider> key_provider = MakeUnique<ConstPubkeyProvider>(pubkey);
929+
std::unique_ptr<PubkeyProvider> key_provider = MakeUnique<ConstPubkeyProvider>(0, pubkey);
921930
KeyOriginInfo info;
922931
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
923-
return MakeUnique<OriginPubkeyProvider>(std::move(info), std::move(key_provider));
932+
return MakeUnique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
924933
}
925934
return key_provider;
926935
}
@@ -1032,7 +1041,7 @@ std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProv
10321041
{
10331042
Span<const char> sp(descriptor.data(), descriptor.size());
10341043
if (!CheckChecksum(sp, require_checksum, error)) return nullptr;
1035-
auto ret = ParseScript(sp, ParseScriptContext::TOP, out, error);
1044+
auto ret = ParseScript(0, sp, ParseScriptContext::TOP, out, error);
10361045
if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret));
10371046
return nullptr;
10381047
}

0 commit comments

Comments
 (0)