6
6
7
7
#include < key_io.h>
8
8
#include < pubkey.h>
9
+ #include < script/miniscript.h>
9
10
#include < script/script.h>
10
11
#include < script/standard.h>
11
12
@@ -161,6 +162,20 @@ struct PubkeyProvider
161
162
162
163
virtual ~PubkeyProvider () = default ;
163
164
165
+ /* * Compare two public keys represented by this provider.
166
+ * Used by the Miniscript descriptors to check for duplicate keys in the script.
167
+ */
168
+ bool operator <(PubkeyProvider& other) const {
169
+ CPubKey a, b;
170
+ SigningProvider dummy;
171
+ KeyOriginInfo dummy_info;
172
+
173
+ GetPubKey (0 , dummy, a, dummy_info);
174
+ other.GetPubKey (0 , dummy, b, dummy_info);
175
+
176
+ return a < b;
177
+ }
178
+
164
179
/* * Derive a public key.
165
180
* read_cache is the cache to read keys from (if not nullptr)
166
181
* write_cache is the cache to write keys to (if not nullptr)
@@ -493,12 +508,12 @@ class BIP32PubkeyProvider final : public PubkeyProvider
493
508
/* * Base class for all Descriptor implementations. */
494
509
class DescriptorImpl : public Descriptor
495
510
{
496
- // ! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for Multisig).
511
+ protected:
512
+ // ! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for WSH and Multisig).
497
513
const std::vector<std::unique_ptr<PubkeyProvider>> m_pubkey_args;
498
514
// ! The string name of the descriptor function.
499
515
const std::string m_name;
500
516
501
- protected:
502
517
// ! The sub-descriptor arguments (empty for everything but SH and WSH).
503
518
// ! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
504
519
// ! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
@@ -563,7 +578,7 @@ class DescriptorImpl : public Descriptor
563
578
return true ;
564
579
}
565
580
566
- bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr ) const
581
+ virtual bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr ) const
567
582
{
568
583
std::string extra = ToStringExtra ();
569
584
size_t pos = extra.size () > 0 ? 1 : 0 ;
@@ -917,6 +932,89 @@ class TRDescriptor final : public DescriptorImpl
917
932
bool IsSingleType () const final { return true ; }
918
933
};
919
934
935
+ /* We instantiate Miniscript here with a simple integer as key type.
936
+ * The value of these key integers are an index in the
937
+ * DescriptorImpl::m_pubkey_args vector.
938
+ */
939
+
940
+ /* *
941
+ * The context for converting a Miniscript descriptor into a Script.
942
+ */
943
+ class ScriptMaker {
944
+ // ! Keys contained in the Miniscript (the evaluation of DescriptorImpl::m_pubkey_args).
945
+ const std::vector<CPubKey>& m_keys;
946
+
947
+ public:
948
+ ScriptMaker (const std::vector<CPubKey>& keys LIFETIMEBOUND) : m_keys(keys) {}
949
+
950
+ std::vector<unsigned char > ToPKBytes (uint32_t key) const {
951
+ return {m_keys[key].begin (), m_keys[key].end ()};
952
+ }
953
+
954
+ std::vector<unsigned char > ToPKHBytes (uint32_t key) const {
955
+ auto id = m_keys[key].GetID ();
956
+ return {id.begin (), id.end ()};
957
+ }
958
+ };
959
+
960
+ /* *
961
+ * The context for converting a Miniscript descriptor to its textual form.
962
+ */
963
+ class StringMaker {
964
+ // ! To convert private keys for private descriptors.
965
+ const SigningProvider* m_arg;
966
+ // ! Keys contained in the Miniscript (a reference to DescriptorImpl::m_pubkey_args).
967
+ const std::vector<std::unique_ptr<PubkeyProvider>>& m_pubkeys;
968
+ // ! Whether to serialize keys as private or public.
969
+ bool m_private;
970
+
971
+ public:
972
+ StringMaker (const SigningProvider* arg LIFETIMEBOUND, const std::vector<std::unique_ptr<PubkeyProvider>>& pubkeys LIFETIMEBOUND, bool priv)
973
+ : m_arg(arg), m_pubkeys(pubkeys), m_private(priv) {}
974
+
975
+ std::optional<std::string> ToString (uint32_t key) const
976
+ {
977
+ std::string ret;
978
+ if (m_private) {
979
+ if (!m_pubkeys[key]->ToPrivateString (*m_arg, ret)) return {};
980
+ } else {
981
+ ret = m_pubkeys[key]->ToString ();
982
+ }
983
+ return ret;
984
+ }
985
+ };
986
+
987
+ class MiniscriptDescriptor final : public DescriptorImpl
988
+ {
989
+ private:
990
+ miniscript::NodeRef<uint32_t > m_node;
991
+
992
+ protected:
993
+ std::vector<CScript> MakeScripts (const std::vector<CPubKey>& keys, Span<const CScript> scripts,
994
+ FlatSigningProvider& provider) const override
995
+ {
996
+ for (const auto & key : keys) provider.pubkeys .emplace (key.GetID (), key);
997
+ return Vector (m_node->ToScript (ScriptMaker (keys)));
998
+ }
999
+
1000
+ public:
1001
+ MiniscriptDescriptor (std::vector<std::unique_ptr<PubkeyProvider>> providers, miniscript::NodeRef<uint32_t > node)
1002
+ : DescriptorImpl(std::move(providers), " ?" ), m_node(std::move(node)) {}
1003
+
1004
+ bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type,
1005
+ const DescriptorCache* cache = nullptr ) const override
1006
+ {
1007
+ if (const auto res = m_node->ToString (StringMaker (arg, m_pubkey_args, type == StringType::PRIVATE))) {
1008
+ out = *res;
1009
+ return true ;
1010
+ }
1011
+ return false ;
1012
+ }
1013
+
1014
+ bool IsSolvable () const override { return false ; } // For now, mark these descriptors as non-solvable (as we don't have signing logic for them).
1015
+ bool IsSingleType () const final { return true ; }
1016
+ };
1017
+
920
1018
// //////////////////////////////////////////////////////////////////////////
921
1019
// Parser //
922
1020
// //////////////////////////////////////////////////////////////////////////
@@ -1058,6 +1156,94 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
1058
1156
return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move (info), std::move (provider));
1059
1157
}
1060
1158
1159
+ std::unique_ptr<PubkeyProvider> InferPubkey (const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
1160
+ {
1161
+ std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, false );
1162
+ KeyOriginInfo info;
1163
+ if (provider.GetKeyOrigin (pubkey.GetID (), info)) {
1164
+ return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1165
+ }
1166
+ return key_provider;
1167
+ }
1168
+
1169
+ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey (const XOnlyPubKey& xkey, ParseScriptContext ctx, const SigningProvider& provider)
1170
+ {
1171
+ unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02 };
1172
+ std::copy (xkey.begin (), xkey.end (), full_key + 1 );
1173
+ CPubKey pubkey (full_key);
1174
+ std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, true );
1175
+ KeyOriginInfo info;
1176
+ if (provider.GetKeyOriginByXOnly (xkey, info)) {
1177
+ return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1178
+ }
1179
+ return key_provider;
1180
+ }
1181
+
1182
+ /* *
1183
+ * The context for parsing a Miniscript descriptor (either from Script or from its textual representation).
1184
+ */
1185
+ struct KeyParser {
1186
+ // ! The Key type is an index in DescriptorImpl::m_pubkey_args
1187
+ using Key = uint32_t ;
1188
+ // ! Must not be nullptr if parsing from string.
1189
+ FlatSigningProvider* m_out;
1190
+ // ! Must not be nullptr if parsing from Script.
1191
+ const SigningProvider* m_in;
1192
+ // ! List of keys contained in the Miniscript.
1193
+ mutable std::vector<std::unique_ptr<PubkeyProvider>> m_keys;
1194
+ // ! Used to detect key parsing errors within a Miniscript.
1195
+ mutable std::string m_key_parsing_error;
1196
+
1197
+ KeyParser (FlatSigningProvider* out LIFETIMEBOUND, const SigningProvider* in LIFETIMEBOUND) : m_out(out), m_in(in) {}
1198
+
1199
+ bool KeyCompare (const Key& a, const Key& b) const {
1200
+ return *m_keys.at (a) < *m_keys.at (b);
1201
+ }
1202
+
1203
+ template <typename I> std::optional<Key> FromString (I begin, I end) const
1204
+ {
1205
+ assert (m_out);
1206
+ Key key = m_keys.size ();
1207
+ auto pk = ParsePubkey (key, {&*begin, &*end}, ParseScriptContext::P2WSH, *m_out, m_key_parsing_error);
1208
+ if (!pk) return {};
1209
+ m_keys.push_back (std::move (pk));
1210
+ return key;
1211
+ }
1212
+
1213
+ std::optional<std::string> ToString (const Key& key) const
1214
+ {
1215
+ return m_keys.at (key)->ToString ();
1216
+ }
1217
+
1218
+ template <typename I> std::optional<Key> FromPKBytes (I begin, I end) const
1219
+ {
1220
+ assert (m_in);
1221
+ CPubKey pubkey (begin, end);
1222
+ if (pubkey.IsValid ()) {
1223
+ Key key = m_keys.size ();
1224
+ m_keys.push_back (InferPubkey (pubkey, ParseScriptContext::P2WSH, *m_in));
1225
+ return key;
1226
+ }
1227
+ return {};
1228
+ }
1229
+
1230
+ template <typename I> std::optional<Key> FromPKHBytes (I begin, I end) const
1231
+ {
1232
+ assert (end - begin == 20 );
1233
+ assert (m_in);
1234
+ uint160 hash;
1235
+ std::copy (begin, end, hash.begin ());
1236
+ CKeyID keyid (hash);
1237
+ CPubKey pubkey;
1238
+ if (m_in->GetPubKey (keyid, pubkey)) {
1239
+ Key key = m_keys.size ();
1240
+ m_keys.push_back (InferPubkey (pubkey, ParseScriptContext::P2WSH, *m_in));
1241
+ return key;
1242
+ }
1243
+ return {};
1244
+ }
1245
+ };
1246
+
1061
1247
/* * Parse a script in a particular context. */
1062
1248
std::unique_ptr<DescriptorImpl> ParseScript (uint32_t & key_exp_index, Span<const char >& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
1063
1249
{
@@ -1279,6 +1465,45 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
1279
1465
error = " Can only have raw() at top level" ;
1280
1466
return nullptr ;
1281
1467
}
1468
+ // Process miniscript expressions.
1469
+ {
1470
+ KeyParser parser (&out, nullptr );
1471
+ auto node = miniscript::FromString (std::string (expr.begin (), expr.end ()), parser);
1472
+ if (node) {
1473
+ if (ctx != ParseScriptContext::P2WSH) {
1474
+ error = " Miniscript expressions can only be used in wsh" ;
1475
+ return nullptr ;
1476
+ }
1477
+ if (parser.m_key_parsing_error != " " ) {
1478
+ error = std::move (parser.m_key_parsing_error );
1479
+ return nullptr ;
1480
+ }
1481
+ if (!node->IsSane ()) {
1482
+ // Try to find the first insane sub for better error reporting.
1483
+ auto insane_node = node.get ();
1484
+ if (const auto sub = node->FindInsaneSub ()) insane_node = sub;
1485
+ if (const auto str = insane_node->ToString (parser)) error = *str;
1486
+ if (!insane_node->IsValid ()) {
1487
+ error += " is invalid" ;
1488
+ } else {
1489
+ error += " is not sane" ;
1490
+ if (!insane_node->IsNonMalleable ()) {
1491
+ error += " : malleable witnesses exist" ;
1492
+ } else if (insane_node == node.get () && !insane_node->NeedsSignature ()) {
1493
+ error += " : witnesses without signature exist" ;
1494
+ } else if (!insane_node->CheckTimeLocksMix ()) {
1495
+ error += " : contains mixes of timelocks expressed in blocks and seconds" ;
1496
+ } else if (!insane_node->CheckDuplicateKey ()) {
1497
+ error += " : contains duplicate public keys" ;
1498
+ } else if (!insane_node->ValidSatisfactions ()) {
1499
+ error += " : needs witnesses that may exceed resource limits" ;
1500
+ }
1501
+ }
1502
+ return nullptr ;
1503
+ }
1504
+ return std::make_unique<MiniscriptDescriptor>(std::move (parser.m_keys ), std::move (node));
1505
+ }
1506
+ }
1282
1507
if (ctx == ParseScriptContext::P2SH) {
1283
1508
error = " A function is needed within P2SH" ;
1284
1509
return nullptr ;
@@ -1290,29 +1515,6 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
1290
1515
return nullptr ;
1291
1516
}
1292
1517
1293
- std::unique_ptr<PubkeyProvider> InferPubkey (const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
1294
- {
1295
- std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, false );
1296
- KeyOriginInfo info;
1297
- if (provider.GetKeyOrigin (pubkey.GetID (), info)) {
1298
- return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1299
- }
1300
- return key_provider;
1301
- }
1302
-
1303
- std::unique_ptr<PubkeyProvider> InferXOnlyPubkey (const XOnlyPubKey& xkey, ParseScriptContext ctx, const SigningProvider& provider)
1304
- {
1305
- unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02 };
1306
- std::copy (xkey.begin (), xkey.end (), full_key + 1 );
1307
- CPubKey pubkey (full_key);
1308
- std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0 , pubkey, true );
1309
- KeyOriginInfo info;
1310
- if (provider.GetKeyOriginByXOnly (xkey, info)) {
1311
- return std::make_unique<OriginPubkeyProvider>(0 , std::move (info), std::move (key_provider));
1312
- }
1313
- return key_provider;
1314
- }
1315
-
1316
1518
std::unique_ptr<DescriptorImpl> InferMultiA (const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
1317
1519
{
1318
1520
auto match = MatchMultiA (script);
@@ -1426,6 +1628,14 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
1426
1628
}
1427
1629
}
1428
1630
1631
+ if (ctx == ParseScriptContext::P2WSH) {
1632
+ KeyParser parser (nullptr , &provider);
1633
+ auto node = miniscript::FromScript (script, parser);
1634
+ if (node && node->IsSane ()) {
1635
+ return std::make_unique<MiniscriptDescriptor>(std::move (parser.m_keys ), std::move (node));
1636
+ }
1637
+ }
1638
+
1429
1639
CTxDestination dest;
1430
1640
if (ExtractDestination (script, dest)) {
1431
1641
if (GetScriptForDestination (dest) == script) {
0 commit comments