Skip to content

Commit 0c9fedf

Browse files
committed
fix incorrect multisig redeem script size limit for segwit
The multisig script generation process currently fails when the user exceeds 15 keys, even when it shouldn't. The maximum number of keys allowed for segwit redeem scripts (p2sh-segwit and bech32) is 20 keys. This is because the redeem script placed in the witness is not restricted by the item size limit. The reason behind this issue is the utilization of the legacy p2sh redeem script restrictions on segwit ones. Redeem scripts longer than 520 bytes are blocked from being inserted into the keystore, which causes the signing process and the descriptor inference process to fail. This occurs because the multisig generation flow uses the same keystore as the legacy spkm (FillableSigningProvider), which contains the 520-byte limit.
1 parent f7a173b commit 0c9fedf

File tree

6 files changed

+18
-11
lines changed

6 files changed

+18
-11
lines changed

src/outputtype.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
8181
}
8282
}
8383

84-
CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType type)
84+
CTxDestination AddAndGetDestinationForScript(FlatSigningProvider& keystore, const CScript& script, OutputType type)
8585
{
8686
// Add script to keystore
87-
keystore.AddCScript(script);
88-
// Note that scripts over MAX_SCRIPT_ELEMENT_SIZE bytes are not yet supported.
87+
keystore.scripts.emplace(CScriptID(script), script);
88+
8989
switch (type) {
9090
case OutputType::LEGACY:
9191
return ScriptHash(script);
@@ -94,7 +94,7 @@ CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore,
9494
CTxDestination witdest = WitnessV0ScriptHash(script);
9595
CScript witprog = GetScriptForDestination(witdest);
9696
// Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
97-
keystore.AddCScript(witprog);
97+
keystore.scripts.emplace(CScriptID(witprog), witprog);
9898
if (type == OutputType::BECH32) {
9999
return witdest;
100100
} else {

src/outputtype.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
4646
* This function will automatically add the script (and any other
4747
* necessary scripts) to the keystore.
4848
*/
49-
CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType);
49+
CTxDestination AddAndGetDestinationForScript(FlatSigningProvider& keystore, const CScript& script, OutputType);
5050

5151
/** Get the OutputType for a CTxDestination */
5252
std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest);

src/rpc/output_script.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,7 @@ static RPCHelpMan createmultisig()
143143
output_type = parsed.value();
144144
}
145145

146-
// Construct using pay-to-script-hash:
147-
FillableSigningProvider keystore;
146+
FlatSigningProvider keystore;
148147
CScript inner;
149148
const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);
150149

src/rpc/util.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string&
224224
}
225225

226226
// Creates a multisig address from a given list of public keys, number of signatures required, and the address type
227-
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out)
227+
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FlatSigningProvider& keystore, CScript& script_out)
228228
{
229229
// Gather public keys
230230
if (required < 1) {

src/rpc/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList&
117117

118118
CPubKey HexToPubKey(const std::string& hex_in);
119119
CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string& addr_in);
120-
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out);
120+
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FlatSigningProvider& keystore, CScript& script_out);
121121

122122
UniValue DescribeAddress(const CTxDestination& dest);
123123

src/wallet/rpc/addresses.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,17 @@ RPCHelpMan addmultisigaddress()
289289
output_type = parsed.value();
290290
}
291291

292-
// Construct using pay-to-script-hash:
292+
// Construct multisig scripts
293+
FlatSigningProvider provider;
293294
CScript inner;
294-
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, spk_man, inner);
295+
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, provider, inner);
296+
297+
// Import scripts into the wallet
298+
for (const auto& [id, script] : provider.scripts) {
299+
spk_man.AddCScript(script);
300+
}
301+
302+
// Store destination in the addressbook
295303
pwallet->SetAddressBook(dest, label, AddressPurpose::SEND);
296304

297305
// Make the descriptor

0 commit comments

Comments
 (0)