mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-07 11:12:50 +01:00
Add support for inferring descriptors from scripts
This commit is contained in:
@@ -625,6 +625,80 @@ std::unique_ptr<Descriptor> ParseScript(Span<const char>& sp, ParseScriptContext
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
|
||||
{
|
||||
std::unique_ptr<PubkeyProvider> key_provider = MakeUnique<ConstPubkeyProvider>(pubkey);
|
||||
KeyOriginInfo info;
|
||||
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
|
||||
return MakeUnique<OriginPubkeyProvider>(std::move(info), std::move(key_provider));
|
||||
}
|
||||
return key_provider;
|
||||
}
|
||||
|
||||
std::unique_ptr<Descriptor> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> data;
|
||||
txnouttype txntype = Solver(script, data);
|
||||
|
||||
if (txntype == TX_PUBKEY) {
|
||||
CPubKey pubkey(data[0].begin(), data[0].end());
|
||||
if (pubkey.IsValid()) {
|
||||
return MakeUnique<SingleKeyDescriptor>(InferPubkey(pubkey, ctx, provider), P2PKGetScript, "pk");
|
||||
}
|
||||
}
|
||||
if (txntype == TX_PUBKEYHASH) {
|
||||
uint160 hash(data[0]);
|
||||
CKeyID keyid(hash);
|
||||
CPubKey pubkey;
|
||||
if (provider.GetPubKey(keyid, pubkey)) {
|
||||
return MakeUnique<SingleKeyDescriptor>(InferPubkey(pubkey, ctx, provider), P2PKHGetScript, "pkh");
|
||||
}
|
||||
}
|
||||
if (txntype == TX_WITNESS_V0_KEYHASH && ctx != ParseScriptContext::P2WSH) {
|
||||
uint160 hash(data[0]);
|
||||
CKeyID keyid(hash);
|
||||
CPubKey pubkey;
|
||||
if (provider.GetPubKey(keyid, pubkey)) {
|
||||
return MakeUnique<SingleKeyDescriptor>(InferPubkey(pubkey, ctx, provider), P2WPKHGetScript, "wpkh");
|
||||
}
|
||||
}
|
||||
if (txntype == TX_MULTISIG) {
|
||||
std::vector<std::unique_ptr<PubkeyProvider>> providers;
|
||||
for (size_t i = 1; i + 1 < data.size(); ++i) {
|
||||
CPubKey pubkey(data[i].begin(), data[i].end());
|
||||
providers.push_back(InferPubkey(pubkey, ctx, provider));
|
||||
}
|
||||
return MakeUnique<MultisigDescriptor>((int)data[0][0], std::move(providers));
|
||||
}
|
||||
if (txntype == TX_SCRIPTHASH && ctx == ParseScriptContext::TOP) {
|
||||
uint160 hash(data[0]);
|
||||
CScriptID scriptid(hash);
|
||||
CScript subscript;
|
||||
if (provider.GetCScript(scriptid, subscript)) {
|
||||
auto sub = InferScript(subscript, ParseScriptContext::P2SH, provider);
|
||||
if (sub) return MakeUnique<ConvertorDescriptor>(std::move(sub), ConvertP2SH, "sh");
|
||||
}
|
||||
}
|
||||
if (txntype == TX_WITNESS_V0_SCRIPTHASH && ctx != ParseScriptContext::P2WSH) {
|
||||
CScriptID scriptid;
|
||||
CRIPEMD160().Write(data[0].data(), data[0].size()).Finalize(scriptid.begin());
|
||||
CScript subscript;
|
||||
if (provider.GetCScript(scriptid, subscript)) {
|
||||
auto sub = InferScript(subscript, ParseScriptContext::P2WSH, provider);
|
||||
if (sub) return MakeUnique<ConvertorDescriptor>(std::move(sub), ConvertP2WSH, "wsh");
|
||||
}
|
||||
}
|
||||
|
||||
CTxDestination dest;
|
||||
if (ExtractDestination(script, dest)) {
|
||||
if (GetScriptForDestination(dest) == script) {
|
||||
return MakeUnique<AddressDescriptor>(std::move(dest));
|
||||
}
|
||||
}
|
||||
|
||||
return MakeUnique<RawDescriptor>(script);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out)
|
||||
@@ -634,3 +708,8 @@ std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProv
|
||||
if (sp.size() == 0 && ret) return ret;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Descriptor> InferDescriptor(const CScript& script, const SigningProvider& provider)
|
||||
{
|
||||
return InferScript(script, ParseScriptContext::TOP, provider);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user