mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
merge bitcoin#20867: Support up to 20 keys for multisig under Segwit context
This commit is contained in:
parent
7c59923845
commit
7cddf70c58
@ -277,8 +277,8 @@ CTxDestination AddAndGetMultisigDestination(const int required, const std::vecto
|
|||||||
if ((int)pubkeys.size() < required) {
|
if ((int)pubkeys.size() < required) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required));
|
||||||
}
|
}
|
||||||
if (pubkeys.size() > 16) {
|
if (pubkeys.size() > MAX_PUBKEYS_PER_MULTISIG) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Number of keys involved in the multisignature address creation > %d\nReduce the number", MAX_PUBKEYS_PER_MULTISIG));
|
||||||
}
|
}
|
||||||
|
|
||||||
script_out = GetScriptForMultisig(required, pubkeys);
|
script_out = GetScriptForMultisig(required, pubkeys);
|
||||||
|
@ -978,8 +978,8 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
|
|||||||
providers.emplace_back(std::move(pk));
|
providers.emplace_back(std::move(pk));
|
||||||
key_exp_index++;
|
key_exp_index++;
|
||||||
}
|
}
|
||||||
if (providers.empty() || providers.size() > 16) {
|
if (providers.empty() || providers.size() > MAX_PUBKEYS_PER_MULTISIG) {
|
||||||
error = strprintf("Cannot have %u keys in multisig; must have between 1 and 16 keys, inclusive", providers.size());
|
error = strprintf("Cannot have %u keys in multisig; must have between 1 and %d keys, inclusive", providers.size(), MAX_PUBKEYS_PER_MULTISIG);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (thres < 1) {
|
} else if (thres < 1) {
|
||||||
error = strprintf("Multisig threshold cannot be %d, must be at least 1", thres);
|
error = strprintf("Multisig threshold cannot be %d, must be at least 1", thres);
|
||||||
@ -995,6 +995,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ctx == ParseScriptContext::P2SH) {
|
if (ctx == ParseScriptContext::P2SH) {
|
||||||
|
// This limits the maximum number of compressed pubkeys to 15.
|
||||||
if (script_size + 3 > MAX_SCRIPT_ELEMENT_SIZE) {
|
if (script_size + 3 > MAX_SCRIPT_ELEMENT_SIZE) {
|
||||||
error = strprintf("P2SH script is too large, %d bytes is larger than %d bytes", script_size + 3, MAX_SCRIPT_ELEMENT_SIZE);
|
error = strprintf("P2SH script is too large, %d bytes is larger than %d bytes", script_size + 3, MAX_SCRIPT_ELEMENT_SIZE);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -221,7 +221,7 @@ bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, co
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
bool CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
||||||
// Excludes OP_1NEGATE, OP_1-16 since they are by definition minimal
|
// Excludes OP_1NEGATE, OP_1-16 since they are by definition minimal
|
||||||
assert(0 <= opcode && opcode <= OP_PUSHDATA4);
|
assert(0 <= opcode && opcode <= OP_PUSHDATA4);
|
||||||
if (data.size() == 0) {
|
if (data.size() == 0) {
|
||||||
|
@ -179,6 +179,8 @@ using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CM
|
|||||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
|
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
|
||||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);
|
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);
|
||||||
|
|
||||||
|
bool CheckMinimalPush(const std::vector<unsigned char>& data, opcodetype opcode);
|
||||||
|
|
||||||
int FindAndDelete(CScript& script, const CScript& b);
|
int FindAndDelete(CScript& script, const CScript& b);
|
||||||
|
|
||||||
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
||||||
|
@ -70,21 +70,53 @@ static constexpr bool IsSmallInteger(opcodetype opcode)
|
|||||||
return opcode >= OP_1 && opcode <= OP_16;
|
return opcode >= OP_1 && opcode <= OP_16;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool MatchMultisig(const CScript& script, unsigned int& required, std::vector<valtype>& pubkeys)
|
static constexpr bool IsPushdataOp(opcodetype opcode)
|
||||||
|
{
|
||||||
|
return opcode > OP_FALSE && opcode <= OP_PUSHDATA4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr bool IsValidMultisigKeyCount(int n_keys)
|
||||||
|
{
|
||||||
|
return n_keys > 0 && n_keys <= MAX_PUBKEYS_PER_MULTISIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool GetMultisigKeyCount(opcodetype opcode, valtype data, int& count)
|
||||||
|
{
|
||||||
|
if (IsSmallInteger(opcode)) {
|
||||||
|
count = CScript::DecodeOP_N(opcode);
|
||||||
|
return IsValidMultisigKeyCount(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPushdataOp(opcode)) {
|
||||||
|
if (!CheckMinimalPush(data, opcode)) return false;
|
||||||
|
try {
|
||||||
|
count = CScriptNum(data, /* fRequireMinimal = */ true).getint();
|
||||||
|
return IsValidMultisigKeyCount(count);
|
||||||
|
} catch (const scriptnum_error&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool MatchMultisig(const CScript& script, int& required_sigs, std::vector<valtype>& pubkeys)
|
||||||
{
|
{
|
||||||
opcodetype opcode;
|
opcodetype opcode;
|
||||||
valtype data;
|
valtype data;
|
||||||
|
int num_keys;
|
||||||
|
|
||||||
CScript::const_iterator it = script.begin();
|
CScript::const_iterator it = script.begin();
|
||||||
if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
|
if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
|
||||||
|
|
||||||
if (!script.GetOp(it, opcode, data) || !IsSmallInteger(opcode)) return false;
|
if (!script.GetOp(it, opcode, data) || !GetMultisigKeyCount(opcode, data, required_sigs)) return false;
|
||||||
required = CScript::DecodeOP_N(opcode);
|
|
||||||
while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
|
while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
|
||||||
pubkeys.emplace_back(std::move(data));
|
pubkeys.emplace_back(std::move(data));
|
||||||
}
|
}
|
||||||
if (!IsSmallInteger(opcode)) return false;
|
if (!GetMultisigKeyCount(opcode, data, num_keys)) return false;
|
||||||
unsigned int keys = CScript::DecodeOP_N(opcode);
|
|
||||||
if (pubkeys.size() != keys || keys < required) return false;
|
if (pubkeys.size() != static_cast<unsigned long>(num_keys) || num_keys < required_sigs) return false;
|
||||||
|
|
||||||
return (it + 1 == script.end());
|
return (it + 1 == script.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,12 +153,12 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned c
|
|||||||
return TxoutType::PUBKEYHASH;
|
return TxoutType::PUBKEYHASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int required;
|
int required;
|
||||||
std::vector<std::vector<unsigned char>> keys;
|
std::vector<std::vector<unsigned char>> keys;
|
||||||
if (MatchMultisig(scriptPubKey, required, keys)) {
|
if (MatchMultisig(scriptPubKey, required, keys)) {
|
||||||
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
|
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..20
|
||||||
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
|
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
|
||||||
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
|
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..20
|
||||||
return TxoutType::MULTISIG;
|
return TxoutType::MULTISIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,10 +272,11 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
|||||||
{
|
{
|
||||||
CScript script;
|
CScript script;
|
||||||
|
|
||||||
script << CScript::EncodeOP_N(nRequired);
|
script << nRequired;
|
||||||
for (const CPubKey& key : keys)
|
for (const CPubKey& key : keys)
|
||||||
script << ToByteVector(key);
|
script << ToByteVector(key);
|
||||||
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
script << keys.size() << OP_CHECKMULTISIG;
|
||||||
|
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <pubkey.h>
|
||||||
#include <script/descriptor.h>
|
#include <script/descriptor.h>
|
||||||
#include <script/sign.h>
|
#include <script/sign.h>
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
@ -27,6 +28,14 @@ void CheckUnparsable(const std::string& prv, const std::string& pub, const std::
|
|||||||
BOOST_CHECK_EQUAL(error, expected_error);
|
BOOST_CHECK_EQUAL(error, expected_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check that the script is inferred as non-standard */
|
||||||
|
void CheckInferRaw(const CScript& script)
|
||||||
|
{
|
||||||
|
FlatSigningProvider dummy_provider;
|
||||||
|
std::unique_ptr<Descriptor> desc = InferDescriptor(script, dummy_provider);
|
||||||
|
BOOST_CHECK(desc->ToString().rfind("raw(", 0) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr int DEFAULT = 0;
|
constexpr int DEFAULT = 0;
|
||||||
constexpr int RANGE = 1; // Expected to be ranged descriptor
|
constexpr int RANGE = 1; // Expected to be ranged descriptor
|
||||||
constexpr int HARDENED = 2; // Derivation needs access to private keys
|
constexpr int HARDENED = 2; // Derivation needs access to private keys
|
||||||
@ -327,8 +336,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
|
|||||||
CheckUnparsable("multi(0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be 0, must be at least 1"); // Threshold of 0
|
CheckUnparsable("multi(0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be 0, must be at least 1"); // Threshold of 0
|
||||||
CheckUnparsable("multi(3,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(3,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be larger than the number of keys; threshold is 3 but only 2 keys specified"); // Threshold larger than number of keys
|
CheckUnparsable("multi(3,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(3,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be larger than the number of keys; threshold is 3 but only 2 keys specified"); // Threshold larger than number of keys
|
||||||
CheckUnparsable("multi(3,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f)", "multi(3,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8)", "Cannot have 4 pubkeys in bare multisig; only at most 3 pubkeys"); // Threshold larger than number of keys
|
CheckUnparsable("multi(3,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f)", "multi(3,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8)", "Cannot have 4 pubkeys in bare multisig; only at most 3 pubkeys"); // Threshold larger than number of keys
|
||||||
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Cannot have 17 keys in multisig; must have between 1 and 16 keys, inclusive"); // Cannot have more than 16 keys in a multisig
|
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "P2SH script is too large, 581 bytes is larger than 520 bytes"); // Cannot have more than 15 keys in a P2SH multisig, or we exceed maximum push size
|
||||||
|
|
||||||
// Check for invalid nesting of structures
|
// Check for invalid nesting of structures
|
||||||
CheckUnparsable("sh(XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2SH"); // P2SH needs a script, not a key
|
CheckUnparsable("sh(XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2SH"); // P2SH needs a script, not a key
|
||||||
CheckUnparsable("sh(sh(pk(XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2SH
|
CheckUnparsable("sh(sh(pk(XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2)))", "sh(sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have sh() at top level"); // Cannot embed P2SH inside P2SH
|
||||||
@ -346,6 +354,27 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
|
|||||||
CheckUnparsable("", "addr(asdf)", "Address is not valid"); // Invalid address
|
CheckUnparsable("", "addr(asdf)", "Address is not valid"); // Invalid address
|
||||||
CheckUnparsable("", "raw(asdf)", "Raw script is not hex"); // Invalid script
|
CheckUnparsable("", "raw(asdf)", "Raw script is not hex"); // Invalid script
|
||||||
CheckUnparsable("", "raw(Ü)#00000000", "Invalid characters in payload"); // Invalid chars
|
CheckUnparsable("", "raw(Ü)#00000000", "Invalid characters in payload"); // Invalid chars
|
||||||
|
|
||||||
|
// A 2of4 but using a direct push rather than OP_2
|
||||||
|
CScript nonminimalmultisig;
|
||||||
|
CKey keys[4];
|
||||||
|
nonminimalmultisig << std::vector<unsigned char>{2};
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
keys[i].MakeNewKey(true);
|
||||||
|
nonminimalmultisig << ToByteVector(keys[i].GetPubKey());
|
||||||
|
}
|
||||||
|
nonminimalmultisig << 4 << OP_CHECKMULTISIG;
|
||||||
|
CheckInferRaw(nonminimalmultisig);
|
||||||
|
|
||||||
|
// A 2of4 but using a direct push rather than OP_4
|
||||||
|
nonminimalmultisig.clear();
|
||||||
|
nonminimalmultisig << 2;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
keys[i].MakeNewKey(true);
|
||||||
|
nonminimalmultisig << ToByteVector(keys[i].GetPubKey());
|
||||||
|
}
|
||||||
|
nonminimalmultisig << std::vector<unsigned char>{4} << OP_CHECKMULTISIG;
|
||||||
|
CheckInferRaw(nonminimalmultisig);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -433,6 +433,42 @@ class ImportDescriptorsTest(BitcoinTestFramework):
|
|||||||
assert_equal(tx_signed_2['complete'], True)
|
assert_equal(tx_signed_2['complete'], True)
|
||||||
self.nodes[1].sendrawtransaction(tx_signed_2['hex'])
|
self.nodes[1].sendrawtransaction(tx_signed_2['hex'])
|
||||||
|
|
||||||
|
|
||||||
|
self.log.info("Under P2SH, multisig are standard with up to 15 "
|
||||||
|
"compressed keys")
|
||||||
|
self.nodes[1].createwallet(wallet_name='multi_priv_big_legacy',
|
||||||
|
blank=True, descriptors=True)
|
||||||
|
multi_priv_big = self.nodes[1].get_wallet_rpc('multi_priv_big_legacy')
|
||||||
|
xkey = "tprv8ZgxMBicQKsPeZSeYx7VXDDTs3XrTcmZQpRLbAeSQFCQGgKwR4gKpcxHaKdoTNHniv4EPDJNdzA3KxRrrBHcAgth8fU5X4oCndkkxk39iAt/*"
|
||||||
|
xkey_int = "tprv8ZgxMBicQKsPeZSeYx7VXDDTs3XrTcmZQpRLbAeSQFCQGgKwR4gKpcxHaKdoTNHniv4EPDJNdzA3KxRrrBHcAgth8fU5X4oCndkkxk39iAt/1/*"
|
||||||
|
res = multi_priv_big.importdescriptors([
|
||||||
|
{
|
||||||
|
"desc": descsum_create(f"sh(multi(15,{(xkey + ',') * 14}{xkey}))"),
|
||||||
|
"active": True,
|
||||||
|
"range": 1000,
|
||||||
|
"next_index": 0,
|
||||||
|
"timestamp": "now"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc": descsum_create(f"sh(multi(15,{(xkey_int + ',') * 14}{xkey_int}))"),
|
||||||
|
"active": True,
|
||||||
|
"internal": True,
|
||||||
|
"range": 1000,
|
||||||
|
"next_index": 0,
|
||||||
|
"timestamp": "now"
|
||||||
|
}])
|
||||||
|
assert_equal(res[0]['success'], True)
|
||||||
|
assert_equal(res[1]['success'], True)
|
||||||
|
|
||||||
|
addr = multi_priv_big.getnewaddress("")
|
||||||
|
w0.sendtoaddress(addr, 10)
|
||||||
|
self.nodes[0].generate(6)
|
||||||
|
self.sync_all()
|
||||||
|
# It is standard and would relay.
|
||||||
|
txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "",
|
||||||
|
True)
|
||||||
|
|
||||||
|
|
||||||
self.log.info("Combo descriptors cannot be active")
|
self.log.info("Combo descriptors cannot be active")
|
||||||
self.test_importdesc({"desc": descsum_create("combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"),
|
self.test_importdesc({"desc": descsum_create("combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"),
|
||||||
"active": True,
|
"active": True,
|
||||||
|
Loading…
Reference in New Issue
Block a user