@@ -517,7 +517,7 @@ struct Node {
517
517
}
518
518
519
519
template <typename CTx>
520
- bool ToString (const CTx& ctx, std::string& ret ) const {
520
+ std::optional<std::string> ToString (const CTx& ctx) const {
521
521
// To construct the std::string representation for a Miniscript object, we use
522
522
// the TreeEvalMaybe algorithm. The State is a boolean: whether the parent node is a
523
523
// wrapper. If so, non-wrapper expressions must be prefixed with a ":".
@@ -541,15 +541,15 @@ struct Node {
541
541
case Fragment::WRAP_C:
542
542
if (node.subs [0 ]->fragment == Fragment::PK_K) {
543
543
// pk(K) is syntactic sugar for c:pk_k(K)
544
- std::string key_str;
545
- if (!ctx. ToString (node. subs [ 0 ]-> keys [ 0 ], key_str) ) return {};
546
- return std::move (ret) + " pk(" + std::move (key_str) + " )" ;
544
+ auto key_str = ctx. ToString (node. subs [ 0 ]-> keys [ 0 ]) ;
545
+ if (!key_str) return {};
546
+ return std::move (ret) + " pk(" + std::move (* key_str) + " )" ;
547
547
}
548
548
if (node.subs [0 ]->fragment == Fragment::PK_H) {
549
549
// pkh(K) is syntactic sugar for c:pk_h(K)
550
- std::string key_str;
551
- if (!ctx. ToString (node. subs [ 0 ]-> keys [ 0 ], key_str) ) return {};
552
- return std::move (ret) + " pkh(" + std::move (key_str) + " )" ;
550
+ auto key_str = ctx. ToString (node. subs [ 0 ]-> keys [ 0 ]) ;
551
+ if (!key_str) return {};
552
+ return std::move (ret) + " pkh(" + std::move (* key_str) + " )" ;
553
553
}
554
554
return " c" + std::move (subs[0 ]);
555
555
case Fragment::WRAP_D: return " d" + std::move (subs[0 ]);
@@ -568,14 +568,14 @@ struct Node {
568
568
}
569
569
switch (node.fragment ) {
570
570
case Fragment::PK_K: {
571
- std::string key_str;
572
- if (!ctx. ToString (node. keys [ 0 ], key_str) ) return {};
573
- return std::move (ret) + " pk_k(" + std::move (key_str) + " )" ;
571
+ auto key_str = ctx. ToString (node. keys [ 0 ]) ;
572
+ if (!key_str) return {};
573
+ return std::move (ret) + " pk_k(" + std::move (* key_str) + " )" ;
574
574
}
575
575
case Fragment::PK_H: {
576
- std::string key_str;
577
- if (!ctx. ToString (node. keys [ 0 ], key_str) ) return {};
578
- return std::move (ret) + " pk_h(" + std::move (key_str) + " )" ;
576
+ auto key_str = ctx. ToString (node. keys [ 0 ]) ;
577
+ if (!key_str) return {};
578
+ return std::move (ret) + " pk_h(" + std::move (* key_str) + " )" ;
579
579
}
580
580
case Fragment::AFTER: return std::move (ret) + " after(" + ::ToString (node.k ) + " )" ;
581
581
case Fragment::OLDER: return std::move (ret) + " older(" + ::ToString (node.k ) + " )" ;
@@ -598,9 +598,9 @@ struct Node {
598
598
case Fragment::MULTI: {
599
599
auto str = std::move (ret) + " multi(" + ::ToString (node.k );
600
600
for (const auto & key : node.keys ) {
601
- std::string key_str;
602
- if (!ctx. ToString (key, key_str) ) return {};
603
- str += " ," + std::move (key_str);
601
+ auto key_str = ctx. ToString (key) ;
602
+ if (!key_str) return {};
603
+ str += " ," + std::move (* key_str);
604
604
}
605
605
return std::move (str) + " )" ;
606
606
}
@@ -616,9 +616,7 @@ struct Node {
616
616
return " " ; // Should never be reached.
617
617
};
618
618
619
- auto res = TreeEvalMaybe<std::string>(false , downfn, upfn);
620
- if (res.has_value ()) ret = std::move (*res);
621
- return res.has_value ();
619
+ return TreeEvalMaybe<std::string>(false , downfn, upfn);
622
620
}
623
621
624
622
internal::Ops CalcOps () const {
@@ -858,11 +856,11 @@ int FindNextChar(Span<const char> in, const char m);
858
856
template <typename Key, typename Ctx>
859
857
std::optional<std::pair<Key, int >> ParseKeyEnd (Span<const char > in, const Ctx& ctx)
860
858
{
861
- Key key;
862
859
int key_size = FindNextChar (in, ' )' );
863
860
if (key_size < 1 ) return {};
864
- if (!ctx.FromString (in.begin (), in.begin () + key_size, key)) return {};
865
- return {{std::move (key), key_size}};
861
+ auto key = ctx.FromString (in.begin (), in.begin () + key_size);
862
+ if (!key) return {};
863
+ return {{std::move (*key), key_size}};
866
864
}
867
865
868
866
/* * Parse a hex string ending at the end of the fragment's text representation. */
@@ -1029,12 +1027,12 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx)
1029
1027
// Get keys
1030
1028
std::vector<Key> keys;
1031
1029
while (next_comma != -1 ) {
1032
- Key key;
1033
1030
next_comma = FindNextChar (in, ' ,' );
1034
1031
int key_length = (next_comma == -1 ) ? FindNextChar (in, ' )' ) : next_comma;
1035
1032
if (key_length < 1 ) return {};
1036
- if (!ctx.FromString (in.begin (), in.begin () + key_length, key)) return {};
1037
- keys.push_back (std::move (key));
1033
+ auto key = ctx.FromString (in.begin (), in.begin () + key_length);
1034
+ if (!key) return {};
1035
+ keys.push_back (std::move (*key));
1038
1036
in = in.subspan (key_length + 1 );
1039
1037
}
1040
1038
if (keys.size () < 1 || keys.size () > 20 ) return {};
@@ -1207,10 +1205,10 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx)
1207
1205
* and OP_EQUALVERIFY are decomposed into OP_CHECKSIG, OP_CHECKMULTISIG, OP_EQUAL
1208
1206
* respectively, plus OP_VERIFY.
1209
1207
*/
1210
- bool DecomposeScript ( const CScript& script, std::vector<std::pair<opcodetype, std::vector<unsigned char >>>& out );
1208
+ std::optional<std:: vector<std::pair<opcodetype, std::vector<unsigned char >>>> DecomposeScript ( const CScript& script );
1211
1209
1212
1210
/* * Determine whether the passed pair (created by DecomposeScript) is pushing a number. */
1213
- bool ParseScriptNumber (const std::pair<opcodetype, std::vector<unsigned char >>& in, int64_t & k );
1211
+ std::optional< int64_t > ParseScriptNumber (const std::pair<opcodetype, std::vector<unsigned char >>& in);
1214
1212
1215
1213
enum class DecodeContext {
1216
1214
/* * A single expression of type B, K, or V. Specifically, this can't be an
@@ -1317,34 +1315,35 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx)
1317
1315
}
1318
1316
// Public keys
1319
1317
if (in[0 ].second .size () == 33 ) {
1320
- Key key;
1321
- if (!ctx. FromPKBytes (in[ 0 ]. second . begin (), in[ 0 ]. second . end (), key) ) return {};
1318
+ auto key = ctx. FromPKBytes (in[ 0 ]. second . begin (), in[ 0 ]. second . end ()) ;
1319
+ if (!key) return {};
1322
1320
++in;
1323
- constructed.push_back (MakeNodeRef<Key>(Fragment::PK_K, Vector (std::move (key))));
1321
+ constructed.push_back (MakeNodeRef<Key>(Fragment::PK_K, Vector (std::move (* key))));
1324
1322
break ;
1325
1323
}
1326
1324
if (last - in >= 5 && in[0 ].first == OP_VERIFY && in[1 ].first == OP_EQUAL && in[3 ].first == OP_HASH160 && in[4 ].first == OP_DUP && in[2 ].second .size () == 20 ) {
1327
- Key key;
1328
- if (!ctx. FromPKHBytes (in[ 2 ]. second . begin (), in[ 2 ]. second . end (), key) ) return {};
1325
+ auto key = ctx. FromPKHBytes (in[ 2 ]. second . begin (), in[ 2 ]. second . end ()) ;
1326
+ if (!key) return {};
1329
1327
in += 5 ;
1330
- constructed.push_back (MakeNodeRef<Key>(Fragment::PK_H, Vector (std::move (key))));
1328
+ constructed.push_back (MakeNodeRef<Key>(Fragment::PK_H, Vector (std::move (* key))));
1331
1329
break ;
1332
1330
}
1333
1331
// Time locks
1334
- if (last - in >= 2 && in[0 ].first == OP_CHECKSEQUENCEVERIFY && ParseScriptNumber (in[1 ], k)) {
1332
+ std::optional<int64_t > num;
1333
+ if (last - in >= 2 && in[0 ].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber (in[1 ]))) {
1335
1334
in += 2 ;
1336
- if (k < 1 || k > 0x7FFFFFFFL ) return {};
1337
- constructed.push_back (MakeNodeRef<Key>(Fragment::OLDER, k ));
1335
+ if (*num < 1 || *num > 0x7FFFFFFFL ) return {};
1336
+ constructed.push_back (MakeNodeRef<Key>(Fragment::OLDER, *num ));
1338
1337
break ;
1339
1338
}
1340
- if (last - in >= 2 && in[0 ].first == OP_CHECKLOCKTIMEVERIFY && ParseScriptNumber (in[1 ], k )) {
1339
+ if (last - in >= 2 && in[0 ].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber (in[1 ]) )) {
1341
1340
in += 2 ;
1342
- if (k < 1 || k > 0x7FFFFFFFL ) return {};
1343
- constructed.push_back (MakeNodeRef<Key>(Fragment::AFTER, k ));
1341
+ if (num < 1 || num > 0x7FFFFFFFL ) return {};
1342
+ constructed.push_back (MakeNodeRef<Key>(Fragment::AFTER, *num ));
1344
1343
break ;
1345
1344
}
1346
1345
// Hashes
1347
- if (last - in >= 7 && in[0 ].first == OP_EQUAL && in[3 ].first == OP_VERIFY && in[4 ].first == OP_EQUAL && ParseScriptNumber (in[5 ], k) && k == 32 && in[6 ].first == OP_SIZE) {
1346
+ if (last - in >= 7 && in[0 ].first == OP_EQUAL && in[3 ].first == OP_VERIFY && in[4 ].first == OP_EQUAL && (num = ParseScriptNumber (in[5 ])) && num == 32 && in[6 ].first == OP_SIZE) {
1348
1347
if (in[2 ].first == OP_SHA256 && in[1 ].second .size () == 32 ) {
1349
1348
constructed.push_back (MakeNodeRef<Key>(Fragment::SHA256, in[1 ].second ));
1350
1349
in += 7 ;
@@ -1366,20 +1365,20 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx)
1366
1365
// Multi
1367
1366
if (last - in >= 3 && in[0 ].first == OP_CHECKMULTISIG) {
1368
1367
std::vector<Key> keys;
1369
- if (!ParseScriptNumber (in[1 ], n)) return {};
1370
- if (last - in < 3 + n) return {};
1371
- if (n < 1 || n > 20 ) return {};
1372
- for (int i = 0 ; i < n; ++i) {
1373
- Key key;
1368
+ const auto n = ParseScriptNumber (in[1 ]);
1369
+ if (!n || last - in < 3 + *n) return {};
1370
+ if (*n < 1 || *n > 20 ) return {};
1371
+ for (int i = 0 ; i < *n; ++i) {
1374
1372
if (in[2 + i].second .size () != 33 ) return {};
1375
- if (!ctx.FromPKBytes (in[2 + i].second .begin (), in[2 + i].second .end (), key)) return {};
1376
- keys.push_back (std::move (key));
1373
+ auto key = ctx.FromPKBytes (in[2 + i].second .begin (), in[2 + i].second .end ());
1374
+ if (!key) return {};
1375
+ keys.push_back (std::move (*key));
1377
1376
}
1378
- if (! ParseScriptNumber (in[2 + n], k)) return {} ;
1379
- if (k < 1 || k > n) return {};
1380
- in += 3 + n;
1377
+ const auto k = ParseScriptNumber (in[2 + *n]) ;
1378
+ if (!k || *k < 1 || * k > * n) return {};
1379
+ in += 3 + * n;
1381
1380
std::reverse (keys.begin (), keys.end ());
1382
- constructed.push_back (MakeNodeRef<Key>(Fragment::MULTI, std::move (keys), k));
1381
+ constructed.push_back (MakeNodeRef<Key>(Fragment::MULTI, std::move (keys), * k));
1383
1382
break ;
1384
1383
}
1385
1384
/* * In the following wrappers, we only need to push SINGLE_BKV_EXPR rather
@@ -1407,10 +1406,10 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx)
1407
1406
break ;
1408
1407
}
1409
1408
// Thresh
1410
- if (last - in >= 3 && in[0 ].first == OP_EQUAL && ParseScriptNumber (in[1 ], k )) {
1411
- if (k < 1 ) return {};
1409
+ if (last - in >= 3 && in[0 ].first == OP_EQUAL && (num = ParseScriptNumber (in[1 ]) )) {
1410
+ if (*num < 1 ) return {};
1412
1411
in += 2 ;
1413
- to_parse.emplace_back (DecodeContext::THRESH_W, 0 , k );
1412
+ to_parse.emplace_back (DecodeContext::THRESH_W, 0 , *num );
1414
1413
break ;
1415
1414
}
1416
1415
// OP_ENDIF can be WRAP_J, WRAP_D, ANDOR, OR_C, OR_D, or OR_I
@@ -1645,12 +1644,12 @@ inline NodeRef<typename Ctx::Key> FromString(const std::string& str, const Ctx&
1645
1644
template <typename Ctx>
1646
1645
inline NodeRef<typename Ctx::Key> FromScript (const CScript& script, const Ctx& ctx) {
1647
1646
using namespace internal ;
1648
- std::vector<std::pair<opcodetype, std::vector< unsigned char >>> decomposed ;
1649
- if (!DecomposeScript (script, decomposed) ) return {};
1650
- auto it = decomposed. begin ();
1651
- auto ret = DecodeScript<typename Ctx::Key>(it, decomposed. end (), ctx);
1647
+ auto decomposed = DecomposeScript (script) ;
1648
+ if (!decomposed) return {};
1649
+ auto it = decomposed-> begin ();
1650
+ auto ret = DecodeScript<typename Ctx::Key>(it, decomposed-> end (), ctx);
1652
1651
if (!ret) return {};
1653
- if (it != decomposed. end ()) return {};
1652
+ if (it != decomposed-> end ()) return {};
1654
1653
return ret;
1655
1654
}
1656
1655
0 commit comments