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.
This commit is contained in:
furszy 2023-08-21 17:45:34 -03:00
parent f7a173b578
commit 0c9fedfc45
No known key found for this signature in database
GPG Key ID: 5DD23CCC686AA623
6 changed files with 18 additions and 11 deletions

View File

@ -81,11 +81,11 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
}
}
CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType type)
CTxDestination AddAndGetDestinationForScript(FlatSigningProvider& keystore, const CScript& script, OutputType type)
{
// Add script to keystore
keystore.AddCScript(script);
// Note that scripts over MAX_SCRIPT_ELEMENT_SIZE bytes are not yet supported.
keystore.scripts.emplace(CScriptID(script), script);
switch (type) {
case OutputType::LEGACY:
return ScriptHash(script);
@ -94,7 +94,7 @@ CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore,
CTxDestination witdest = WitnessV0ScriptHash(script);
CScript witprog = GetScriptForDestination(witdest);
// Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
keystore.AddCScript(witprog);
keystore.scripts.emplace(CScriptID(witprog), witprog);
if (type == OutputType::BECH32) {
return witdest;
} else {

View File

@ -46,7 +46,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
* This function will automatically add the script (and any other
* necessary scripts) to the keystore.
*/
CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType);
CTxDestination AddAndGetDestinationForScript(FlatSigningProvider& keystore, const CScript& script, OutputType);
/** Get the OutputType for a CTxDestination */
std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest);

View File

@ -143,8 +143,7 @@ static RPCHelpMan createmultisig()
output_type = parsed.value();
}
// Construct using pay-to-script-hash:
FillableSigningProvider keystore;
FlatSigningProvider keystore;
CScript inner;
const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);

View File

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

View File

@ -117,7 +117,7 @@ std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList&
CPubKey HexToPubKey(const std::string& hex_in);
CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string& addr_in);
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out);
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FlatSigningProvider& keystore, CScript& script_out);
UniValue DescribeAddress(const CTxDestination& dest);

View File

@ -289,9 +289,17 @@ RPCHelpMan addmultisigaddress()
output_type = parsed.value();
}
// Construct using pay-to-script-hash:
// Construct multisig scripts
FlatSigningProvider provider;
CScript inner;
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, spk_man, inner);
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, provider, inner);
// Import scripts into the wallet
for (const auto& [id, script] : provider.scripts) {
spk_man.AddCScript(script);
}
// Store destination in the addressbook
pwallet->SetAddressBook(dest, label, AddressPurpose::SEND);
// Make the descriptor