@@ -794,6 +794,30 @@ class MultisigDescriptor final : public DescriptorImpl
794
794
bool IsSingleType () const final { return true ; }
795
795
};
796
796
797
+ /* * A parsed (sorted)multi_a(...) descriptor. Always uses x-only pubkeys. */
798
+ class MultiADescriptor final : public DescriptorImpl
799
+ {
800
+ const int m_threshold;
801
+ const bool m_sorted;
802
+ protected:
803
+ std::string ToStringExtra () const override { return strprintf (" %i" , m_threshold); }
804
+ std::vector<CScript> MakeScripts (const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
805
+ CScript ret;
806
+ std::vector<XOnlyPubKey> xkeys;
807
+ for (const auto & key : keys) xkeys.emplace_back (key);
808
+ if (m_sorted) std::sort (xkeys.begin (), xkeys.end ());
809
+ ret << ToByteVector (xkeys[0 ]) << OP_CHECKSIG;
810
+ for (size_t i = 1 ; i < keys.size (); ++i) {
811
+ ret << ToByteVector (xkeys[i]) << OP_CHECKSIGADD;
812
+ }
813
+ ret << m_threshold << OP_NUMEQUAL;
814
+ return Vector (std::move (ret));
815
+ }
816
+ public:
817
+ MultiADescriptor (int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false ) : DescriptorImpl(std::move(providers), sorted ? " sortedmulti_a" : " multi_a" ), m_threshold(threshold), m_sorted(sorted) {}
818
+ bool IsSingleType () const final { return true ; }
819
+ };
820
+
797
821
/* * A parsed sh(...) descriptor. */
798
822
class SHDescriptor final : public DescriptorImpl
799
823
{
@@ -1032,7 +1056,6 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
1032
1056
using namespace spanparsing ;
1033
1057
1034
1058
auto expr = Expr (sp);
1035
- bool sorted_multi = false ;
1036
1059
if (Func (" pk" , expr)) {
1037
1060
auto pubkey = ParsePubkey (key_exp_index, expr, ctx, out, error);
1038
1061
if (!pubkey) return nullptr ;
@@ -1057,7 +1080,12 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
1057
1080
error = " Can only have combo() at top level" ;
1058
1081
return nullptr ;
1059
1082
}
1060
- if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && ((sorted_multi = Func (" sortedmulti" , expr)) || Func (" multi" , expr))) {
1083
+ const bool multi = Func (" multi" , expr);
1084
+ const bool sortedmulti = !multi && Func (" sortedmulti" , expr);
1085
+ const bool multi_a = !(multi || sortedmulti) && Func (" multi_a" , expr);
1086
+ const bool sortedmulti_a = !(multi || sortedmulti || multi_a) && Func (" sortedmulti_a" , expr);
1087
+ if (((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && (multi || sortedmulti)) ||
1088
+ (ctx == ParseScriptContext::P2TR && (multi_a || sortedmulti_a))) {
1061
1089
auto threshold = Expr (expr);
1062
1090
uint32_t thres;
1063
1091
std::vector<std::unique_ptr<PubkeyProvider>> providers;
@@ -1078,9 +1106,12 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
1078
1106
providers.emplace_back (std::move (pk));
1079
1107
key_exp_index++;
1080
1108
}
1081
- if (providers.empty () || providers.size () > MAX_PUBKEYS_PER_MULTISIG) {
1109
+ if ((multi || sortedmulti) && ( providers.empty () || providers.size () > MAX_PUBKEYS_PER_MULTISIG) ) {
1082
1110
error = strprintf (" Cannot have %u keys in multisig; must have between 1 and %d keys, inclusive" , providers.size (), MAX_PUBKEYS_PER_MULTISIG);
1083
1111
return nullptr ;
1112
+ } else if ((multi_a || sortedmulti_a) && (providers.empty () || providers.size () > MAX_PUBKEYS_PER_MULTI_A)) {
1113
+ error = strprintf (" Cannot have %u keys in multi_a; must have between 1 and %d keys, inclusive" , providers.size (), MAX_PUBKEYS_PER_MULTI_A);
1114
+ return nullptr ;
1084
1115
} else if (thres < 1 ) {
1085
1116
error = strprintf (" Multisig threshold cannot be %d, must be at least 1" , thres);
1086
1117
return nullptr ;
@@ -1101,10 +1132,17 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
1101
1132
return nullptr ;
1102
1133
}
1103
1134
}
1104
- return std::make_unique<MultisigDescriptor>(thres, std::move (providers), sorted_multi);
1105
- } else if (Func (" sortedmulti" , expr) || Func (" multi" , expr)) {
1135
+ if (multi || sortedmulti) {
1136
+ return std::make_unique<MultisigDescriptor>(thres, std::move (providers), sortedmulti);
1137
+ } else {
1138
+ return std::make_unique<MultiADescriptor>(thres, std::move (providers), sortedmulti_a);
1139
+ }
1140
+ } else if (multi || sortedmulti) {
1106
1141
error = " Can only have multi/sortedmulti at top level, in sh(), or in wsh()" ;
1107
1142
return nullptr ;
1143
+ } else if (multi_a || sortedmulti_a) {
1144
+ error = " Can only have multi_a/sortedmulti_a inside tr()" ;
1145
+ return nullptr ;
1108
1146
}
1109
1147
if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func (" wpkh" , expr)) {
1110
1148
auto pubkey = ParsePubkey (key_exp_index, expr, ParseScriptContext::P2WPKH, out, error);
0 commit comments