mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 23:09:44 -04:00
rpc: Have deriveaddresses derive receiving and change
When given a multipath descriptor, derive all of the descriptors. The derived addresses will be returned in an object consisting of multiple arrays. For compatibility, when given a single path descriptor, the addresses are provided in a single array as before.
This commit is contained in:
parent
360456cd22
commit
cddc0ba9a9
1 changed files with 61 additions and 36 deletions
|
@ -220,66 +220,8 @@ static RPCHelpMan getdescriptorinfo()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static RPCHelpMan deriveaddresses()
|
static UniValue DeriveAddresses(const Descriptor* desc, int64_t range_begin, int64_t range_end, FlatSigningProvider& key_provider)
|
||||||
{
|
{
|
||||||
const std::string EXAMPLE_DESCRIPTOR = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu";
|
|
||||||
|
|
||||||
return RPCHelpMan{"deriveaddresses",
|
|
||||||
{"\nDerives one or more addresses corresponding to an output descriptor.\n"
|
|
||||||
"Examples of output descriptors are:\n"
|
|
||||||
" pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
|
|
||||||
" wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey\n"
|
|
||||||
" sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
|
|
||||||
" raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
|
|
||||||
" tr(<pubkey>,multi_a(<n>,<pubkey>,<pubkey>,...)) P2TR-multisig outputs for the given threshold and pubkeys\n"
|
|
||||||
"\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
|
|
||||||
"or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n"
|
|
||||||
"For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"
|
|
||||||
"Note that only descriptors that specify a single derivation path can be derived.\n"},
|
|
||||||
{
|
|
||||||
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
|
|
||||||
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
|
|
||||||
},
|
|
||||||
RPCResult{
|
|
||||||
RPCResult::Type::ARR, "", "",
|
|
||||||
{
|
|
||||||
{RPCResult::Type::STR, "address", "the derived addresses"},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RPCExamples{
|
|
||||||
"First three native segwit receive addresses\n" +
|
|
||||||
HelpExampleCli("deriveaddresses", "\"" + EXAMPLE_DESCRIPTOR + "\" \"[0,2]\"") +
|
|
||||||
HelpExampleRpc("deriveaddresses", "\"" + EXAMPLE_DESCRIPTOR + "\", \"[0,2]\"")
|
|
||||||
},
|
|
||||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
|
||||||
{
|
|
||||||
const std::string desc_str = request.params[0].get_str();
|
|
||||||
|
|
||||||
int64_t range_begin = 0;
|
|
||||||
int64_t range_end = 0;
|
|
||||||
|
|
||||||
if (request.params.size() >= 2 && !request.params[1].isNull()) {
|
|
||||||
std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlatSigningProvider key_provider;
|
|
||||||
std::string error;
|
|
||||||
auto descs = Parse(desc_str, key_provider, error, /* require_checksum = */ true);
|
|
||||||
if (descs.empty()) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
|
||||||
}
|
|
||||||
if (descs.size() > 1) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor with multipath derivation path specifiers are not allowed");
|
|
||||||
}
|
|
||||||
auto& desc = descs.at(0);
|
|
||||||
if (!desc->IsRange() && request.params.size() > 1) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desc->IsRange() && request.params.size() == 1) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified for a ranged descriptor");
|
|
||||||
}
|
|
||||||
|
|
||||||
UniValue addresses(UniValue::VARR);
|
UniValue addresses(UniValue::VARR);
|
||||||
|
|
||||||
for (int64_t i = range_begin; i <= range_end; ++i) {
|
for (int64_t i = range_begin; i <= range_end; ++i) {
|
||||||
|
@ -310,6 +252,89 @@ static RPCHelpMan deriveaddresses()
|
||||||
}
|
}
|
||||||
|
|
||||||
return addresses;
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RPCHelpMan deriveaddresses()
|
||||||
|
{
|
||||||
|
const std::string EXAMPLE_DESCRIPTOR = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu";
|
||||||
|
|
||||||
|
return RPCHelpMan{"deriveaddresses",
|
||||||
|
{"\nDerives one or more addresses corresponding to an output descriptor.\n"
|
||||||
|
"Examples of output descriptors are:\n"
|
||||||
|
" pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
|
||||||
|
" wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey\n"
|
||||||
|
" sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
|
||||||
|
" raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
|
||||||
|
" tr(<pubkey>,multi_a(<n>,<pubkey>,<pubkey>,...)) P2TR-multisig outputs for the given threshold and pubkeys\n"
|
||||||
|
"\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
|
||||||
|
"or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n"
|
||||||
|
"For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"},
|
||||||
|
{
|
||||||
|
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
|
||||||
|
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RPCResult{"for single derivation descriptors",
|
||||||
|
RPCResult::Type::ARR, "", "",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::STR, "address", "the derived addresses"},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RPCResult{"for multipath descriptors",
|
||||||
|
RPCResult::Type::ARR, "", "The derived addresses for each of the multipath expansions of the descriptor, in multipath specifier order",
|
||||||
|
{
|
||||||
|
{
|
||||||
|
RPCResult::Type::ARR, "", "The derived addresses for a multipath descriptor expansion",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::STR, "address", "the derived address"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RPCExamples{
|
||||||
|
"First three native segwit receive addresses\n" +
|
||||||
|
HelpExampleCli("deriveaddresses", "\"" + EXAMPLE_DESCRIPTOR + "\" \"[0,2]\"") +
|
||||||
|
HelpExampleRpc("deriveaddresses", "\"" + EXAMPLE_DESCRIPTOR + "\", \"[0,2]\"")
|
||||||
|
},
|
||||||
|
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||||
|
{
|
||||||
|
const std::string desc_str = request.params[0].get_str();
|
||||||
|
|
||||||
|
int64_t range_begin = 0;
|
||||||
|
int64_t range_end = 0;
|
||||||
|
|
||||||
|
if (request.params.size() >= 2 && !request.params[1].isNull()) {
|
||||||
|
std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatSigningProvider key_provider;
|
||||||
|
std::string error;
|
||||||
|
auto descs = Parse(desc_str, key_provider, error, /* require_checksum = */ true);
|
||||||
|
if (descs.empty()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||||
|
}
|
||||||
|
auto& desc = descs.at(0);
|
||||||
|
if (!desc->IsRange() && request.params.size() > 1) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc->IsRange() && request.params.size() == 1) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified for a ranged descriptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue addresses = DeriveAddresses(desc.get(), range_begin, range_end, key_provider);
|
||||||
|
|
||||||
|
if (descs.size() == 1) {
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue ret(UniValue::VARR);
|
||||||
|
ret.push_back(addresses);
|
||||||
|
for (size_t i = 1; i < descs.size(); ++i) {
|
||||||
|
ret.push_back(DeriveAddresses(descs.at(i).get(), range_begin, range_end, key_provider));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue