@@ -244,7 +244,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
244
244
bool m_xonly;
245
245
246
246
public:
247
- ConstPubkeyProvider (uint32_t exp_index, const CPubKey& pubkey, bool xonly = false ) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
247
+ ConstPubkeyProvider (uint32_t exp_index, const CPubKey& pubkey, bool xonly) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
248
248
bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr , DescriptorCache* write_cache = nullptr ) override
249
249
{
250
250
key = m_pubkey;
@@ -931,7 +931,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
931
931
CPubKey pubkey (data);
932
932
if (pubkey.IsFullyValid ()) {
933
933
if (permit_uncompressed || pubkey.IsCompressed ()) {
934
- return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey);
934
+ return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false );
935
935
} else {
936
936
error = " Uncompressed keys are not allowed" ;
937
937
return nullptr ;
@@ -952,7 +952,7 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
952
952
if (permit_uncompressed || key.IsCompressed ()) {
953
953
CPubKey pubkey = key.GetPubKey ();
954
954
out.keys .emplace (pubkey.GetID (), key);
955
- return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey);
955
+ return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR );
956
956
} else {
957
957
error = " Uncompressed keys are not allowed" ;
958
958
return nullptr ;
@@ -1221,42 +1221,66 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
1221
1221
1222
1222
std::unique_ptr<PubkeyProvider> InferPubkey (const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
1223
1223
{
1224
- std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey);
1224
+ std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, false );
1225
1225
KeyOriginInfo info;
1226
1226
if (provider.GetKeyOrigin (pubkey.GetID (), info)) {
1227
1227
return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1228
1228
}
1229
1229
return key_provider;
1230
1230
}
1231
1231
1232
+ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey (const XOnlyPubKey& xkey, ParseScriptContext ctx, const SigningProvider& provider)
1233
+ {
1234
+ unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02 };
1235
+ std::copy (xkey.begin (), xkey.end (), full_key + 1 );
1236
+ CPubKey pubkey (full_key);
1237
+ std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, true );
1238
+ KeyOriginInfo info;
1239
+ if (provider.GetKeyOrigin (pubkey.GetID (), info)) {
1240
+ return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1241
+ } else {
1242
+ full_key[0 ] = 0x03 ;
1243
+ pubkey = CPubKey (full_key);
1244
+ if (provider.GetKeyOrigin (pubkey.GetID (), info)) {
1245
+ return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1246
+ }
1247
+ }
1248
+ return key_provider;
1249
+ }
1250
+
1232
1251
std::unique_ptr<DescriptorImpl> InferScript (const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
1233
1252
{
1253
+ if (ctx == ParseScriptContext::P2TR && script.size () == 34 && script[0 ] == 32 && script[33 ] == OP_CHECKSIG) {
1254
+ XOnlyPubKey key{Span<const unsigned char >{script.data () + 1 , script.data () + 33 }};
1255
+ return std::make_unique<PKDescriptor>(InferXOnlyPubkey (key, ctx, provider));
1256
+ }
1257
+
1234
1258
std::vector<std::vector<unsigned char >> data;
1235
1259
TxoutType txntype = Solver (script, data);
1236
1260
1237
- if (txntype == TxoutType::PUBKEY) {
1261
+ if (txntype == TxoutType::PUBKEY && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) ) {
1238
1262
CPubKey pubkey (data[0 ]);
1239
1263
if (pubkey.IsValid ()) {
1240
1264
return std::make_unique<PKDescriptor>(InferPubkey (pubkey, ctx, provider));
1241
1265
}
1242
1266
}
1243
- if (txntype == TxoutType::PUBKEYHASH) {
1267
+ if (txntype == TxoutType::PUBKEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) ) {
1244
1268
uint160 hash (data[0 ]);
1245
1269
CKeyID keyid (hash);
1246
1270
CPubKey pubkey;
1247
1271
if (provider.GetPubKey (keyid, pubkey)) {
1248
1272
return std::make_unique<PKHDescriptor>(InferPubkey (pubkey, ctx, provider));
1249
1273
}
1250
1274
}
1251
- if (txntype == TxoutType::WITNESS_V0_KEYHASH && ctx != ParseScriptContext::P2WSH ) {
1275
+ if (txntype == TxoutType::WITNESS_V0_KEYHASH && ( ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) ) {
1252
1276
uint160 hash (data[0 ]);
1253
1277
CKeyID keyid (hash);
1254
1278
CPubKey pubkey;
1255
1279
if (provider.GetPubKey (keyid, pubkey)) {
1256
1280
return std::make_unique<WPKHDescriptor>(InferPubkey (pubkey, ctx, provider));
1257
1281
}
1258
1282
}
1259
- if (txntype == TxoutType::MULTISIG) {
1283
+ if (txntype == TxoutType::MULTISIG && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) ) {
1260
1284
std::vector<std::unique_ptr<PubkeyProvider>> providers;
1261
1285
for (size_t i = 1 ; i + 1 < data.size (); ++i) {
1262
1286
CPubKey pubkey (data[i]);
@@ -1273,7 +1297,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
1273
1297
if (sub) return std::make_unique<SHDescriptor>(std::move (sub));
1274
1298
}
1275
1299
}
1276
- if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && ctx != ParseScriptContext::P2WSH ) {
1300
+ if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && ( ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) ) {
1277
1301
CScriptID scriptid;
1278
1302
CRIPEMD160 ().Write (data[0 ].data (), data[0 ].size ()).Finalize (scriptid.begin ());
1279
1303
CScript subscript;
@@ -1282,6 +1306,40 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
1282
1306
if (sub) return std::make_unique<WSHDescriptor>(std::move (sub));
1283
1307
}
1284
1308
}
1309
+ if (txntype == TxoutType::WITNESS_V1_TAPROOT && ctx == ParseScriptContext::TOP) {
1310
+ // Extract x-only pubkey from output.
1311
+ XOnlyPubKey pubkey;
1312
+ std::copy (data[0 ].begin (), data[0 ].end (), pubkey.begin ());
1313
+ // Request spending data.
1314
+ TaprootSpendData tap;
1315
+ if (provider.GetTaprootSpendData (pubkey, tap)) {
1316
+ // If found, convert it back to tree form.
1317
+ auto tree = InferTaprootTree (tap, pubkey);
1318
+ if (tree) {
1319
+ // If that works, try to infer subdescriptors for all leaves.
1320
+ bool ok = true ;
1321
+ std::vector<std::unique_ptr<DescriptorImpl>> subscripts; // !< list of script subexpressions
1322
+ std::vector<int > depths; // !< depth in the tree of each subexpression (same length subscripts)
1323
+ for (const auto & [depth, script, leaf_ver] : *tree) {
1324
+ std::unique_ptr<DescriptorImpl> subdesc;
1325
+ if (leaf_ver == TAPROOT_LEAF_TAPSCRIPT) {
1326
+ subdesc = InferScript (script, ParseScriptContext::P2TR, provider);
1327
+ }
1328
+ if (!subdesc) {
1329
+ ok = false ;
1330
+ break ;
1331
+ } else {
1332
+ subscripts.push_back (std::move (subdesc));
1333
+ depths.push_back (depth);
1334
+ }
1335
+ }
1336
+ if (ok) {
1337
+ auto key = InferXOnlyPubkey (tap.internal_key , ParseScriptContext::P2TR, provider);
1338
+ return std::make_unique<TRDescriptor>(std::move (key), std::move (subscripts), std::move (depths));
1339
+ }
1340
+ }
1341
+ }
1342
+ }
1285
1343
1286
1344
CTxDestination dest;
1287
1345
if (ExtractDestination (script, dest)) {
0 commit comments