|
|
|
@ -244,7 +244,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
|
|
|
|
|
bool m_xonly;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey, bool xonly = false) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
|
|
|
|
|
ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey, bool xonly) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
|
|
|
|
|
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) override
|
|
|
|
|
{
|
|
|
|
|
key = m_pubkey;
|
|
|
|
@ -931,7 +931,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
|
|
|
|
|
CPubKey pubkey(data);
|
|
|
|
|
if (pubkey.IsFullyValid()) {
|
|
|
|
|
if (permit_uncompressed || pubkey.IsCompressed()) {
|
|
|
|
|
return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey);
|
|
|
|
|
return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false);
|
|
|
|
|
} else {
|
|
|
|
|
error = "Uncompressed keys are not allowed";
|
|
|
|
|
return nullptr;
|
|
|
|
@ -952,7 +952,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
|
|
|
|
|
if (permit_uncompressed || key.IsCompressed()) {
|
|
|
|
|
CPubKey pubkey = key.GetPubKey();
|
|
|
|
|
out.keys.emplace(pubkey.GetID(), key);
|
|
|
|
|
return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey);
|
|
|
|
|
return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR);
|
|
|
|
|
} else {
|
|
|
|
|
error = "Uncompressed keys are not allowed";
|
|
|
|
|
return nullptr;
|
|
|
|
@ -1221,7 +1221,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
|
|
|
|
|
{
|
|
|
|
|
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey);
|
|
|
|
|
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, false);
|
|
|
|
|
KeyOriginInfo info;
|
|
|
|
|
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
|
|
|
|
|
return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
|
|
|
|
@ -1229,18 +1229,42 @@ std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptCo
|
|
|
|
|
return key_provider;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<PubkeyProvider> InferXOnlyPubkey(const XOnlyPubKey& xkey, ParseScriptContext ctx, const SigningProvider& provider)
|
|
|
|
|
{
|
|
|
|
|
unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02};
|
|
|
|
|
std::copy(xkey.begin(), xkey.end(), full_key + 1);
|
|
|
|
|
CPubKey pubkey(full_key);
|
|
|
|
|
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, true);
|
|
|
|
|
KeyOriginInfo info;
|
|
|
|
|
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
|
|
|
|
|
return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
|
|
|
|
|
} else {
|
|
|
|
|
full_key[0] = 0x03;
|
|
|
|
|
pubkey = CPubKey(full_key);
|
|
|
|
|
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
|
|
|
|
|
return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return key_provider;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
|
|
|
|
|
{
|
|
|
|
|
if (ctx == ParseScriptContext::P2TR && script.size() == 34 && script[0] == 32 && script[33] == OP_CHECKSIG) {
|
|
|
|
|
XOnlyPubKey key{Span<const unsigned char>{script.data() + 1, script.data() + 33}};
|
|
|
|
|
return std::make_unique<PKDescriptor>(InferXOnlyPubkey(key, ctx, provider));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::vector<unsigned char>> data;
|
|
|
|
|
TxoutType txntype = Solver(script, data);
|
|
|
|
|
|
|
|
|
|
if (txntype == TxoutType::PUBKEY) {
|
|
|
|
|
if (txntype == TxoutType::PUBKEY && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) {
|
|
|
|
|
CPubKey pubkey(data[0]);
|
|
|
|
|
if (pubkey.IsValid()) {
|
|
|
|
|
return std::make_unique<PKDescriptor>(InferPubkey(pubkey, ctx, provider));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (txntype == TxoutType::PUBKEYHASH) {
|
|
|
|
|
if (txntype == TxoutType::PUBKEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) {
|
|
|
|
|
uint160 hash(data[0]);
|
|
|
|
|
CKeyID keyid(hash);
|
|
|
|
|
CPubKey pubkey;
|
|
|
|
@ -1248,7 +1272,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|
|
|
|
return std::make_unique<PKHDescriptor>(InferPubkey(pubkey, ctx, provider));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (txntype == TxoutType::WITNESS_V0_KEYHASH && ctx != ParseScriptContext::P2WSH) {
|
|
|
|
|
if (txntype == TxoutType::WITNESS_V0_KEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH)) {
|
|
|
|
|
uint160 hash(data[0]);
|
|
|
|
|
CKeyID keyid(hash);
|
|
|
|
|
CPubKey pubkey;
|
|
|
|
@ -1256,7 +1280,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|
|
|
|
return std::make_unique<WPKHDescriptor>(InferPubkey(pubkey, ctx, provider));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (txntype == TxoutType::MULTISIG) {
|
|
|
|
|
if (txntype == TxoutType::MULTISIG && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) {
|
|
|
|
|
std::vector<std::unique_ptr<PubkeyProvider>> providers;
|
|
|
|
|
for (size_t i = 1; i + 1 < data.size(); ++i) {
|
|
|
|
|
CPubKey pubkey(data[i]);
|
|
|
|
@ -1273,7 +1297,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|
|
|
|
if (sub) return std::make_unique<SHDescriptor>(std::move(sub));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && ctx != ParseScriptContext::P2WSH) {
|
|
|
|
|
if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH)) {
|
|
|
|
|
CScriptID scriptid;
|
|
|
|
|
CRIPEMD160().Write(data[0].data(), data[0].size()).Finalize(scriptid.begin());
|
|
|
|
|
CScript subscript;
|
|
|
|
@ -1282,6 +1306,40 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|
|
|
|
if (sub) return std::make_unique<WSHDescriptor>(std::move(sub));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (txntype == TxoutType::WITNESS_V1_TAPROOT && ctx == ParseScriptContext::TOP) {
|
|
|
|
|
// Extract x-only pubkey from output.
|
|
|
|
|
XOnlyPubKey pubkey;
|
|
|
|
|
std::copy(data[0].begin(), data[0].end(), pubkey.begin());
|
|
|
|
|
// Request spending data.
|
|
|
|
|
TaprootSpendData tap;
|
|
|
|
|
if (provider.GetTaprootSpendData(pubkey, tap)) {
|
|
|
|
|
// If found, convert it back to tree form.
|
|
|
|
|
auto tree = InferTaprootTree(tap, pubkey);
|
|
|
|
|
if (tree) {
|
|
|
|
|
// If that works, try to infer subdescriptors for all leaves.
|
|
|
|
|
bool ok = true;
|
|
|
|
|
std::vector<std::unique_ptr<DescriptorImpl>> subscripts; //!< list of script subexpressions
|
|
|
|
|
std::vector<int> depths; //!< depth in the tree of each subexpression (same length subscripts)
|
|
|
|
|
for (const auto& [depth, script, leaf_ver] : *tree) {
|
|
|
|
|
std::unique_ptr<DescriptorImpl> subdesc;
|
|
|
|
|
if (leaf_ver == TAPROOT_LEAF_TAPSCRIPT) {
|
|
|
|
|
subdesc = InferScript(script, ParseScriptContext::P2TR, provider);
|
|
|
|
|
}
|
|
|
|
|
if (!subdesc) {
|
|
|
|
|
ok = false;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
subscripts.push_back(std::move(subdesc));
|
|
|
|
|
depths.push_back(depth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ok) {
|
|
|
|
|
auto key = InferXOnlyPubkey(tap.internal_key, ParseScriptContext::P2TR, provider);
|
|
|
|
|
return std::make_unique<TRDescriptor>(std::move(key), std::move(subscripts), std::move(depths));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CTxDestination dest;
|
|
|
|
|
if (ExtractDestination(script, dest)) {
|
|
|
|
|