diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2018-10-12 18:22:22 -0700 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2018-10-26 10:21:05 -0700 |
commit | 4d78bd93b5bdf886e743022e80f4edb8a982cf0d (patch) | |
tree | ea0b49240ffaca4a5ca1dd1cbbbdd1f157301c13 /src | |
parent | f4e4ea1ceecfb978584bd4f43cb6826e44ba86a3 (diff) |
Add support for inferring descriptors from scripts
Diffstat (limited to 'src')
-rw-r--r-- | src/script/descriptor.cpp | 79 | ||||
-rw-r--r-- | src/script/descriptor.h | 17 |
2 files changed, 95 insertions, 1 deletions
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 478797e958..c498024092 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -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); +} diff --git a/src/script/descriptor.h b/src/script/descriptor.h index 87e07369c7..e44a6ef3c3 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -51,5 +51,20 @@ struct Descriptor { /** Parse a descriptor string. Included private keys are put in out. Returns nullptr if parsing fails. */ std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out); -#endif // BITCOIN_SCRIPT_DESCRIPTOR_H +/** Find a descriptor for the specified script, using information from provider where possible. + * + * A non-ranged descriptor which only generates the specified script will be returned in all + * circumstances. + * + * For public keys with key origin information, this information will be preserved in the returned + * descriptor. + * + * - If all information for solving `script` is present in `provider`, a descriptor will be returned + * which is `IsSolvable()` and encapsulates said information. + * - Failing that, if `script` corresponds to a known address type, an "addr()" descriptor will be + * returned (which is not `IsSolvable()`). + * - Failing that, a "raw()" descriptor is returned. + */ +std::unique_ptr<Descriptor> InferDescriptor(const CScript& script, const SigningProvider& provider); +#endif // BITCOIN_SCRIPT_DESCRIPTOR_H |