Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/descriptors.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Supporting RPCs are:
- `importdescriptors` takes as input descriptors to import into a descriptor wallet
(since v0.21).
- `listdescriptors` outputs descriptors imported into a descriptor wallet (since v22).
- `scanblocks` takes as input descriptors to scan for in blocks and returns the
relevant blockhashes (since v24).

This document describes the language. For the specifics on usage, see the RPC
documentation for the functions mentioned above.
Expand Down
265 changes: 240 additions & 25 deletions src/rpc/blockchain.cpp

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "generatetodescriptor", 0, "num_blocks" },
{ "generatetodescriptor", 2, "maxtries" },
{ "generateblock", 1, "transactions" },
{ "generateblock", 2, "submit" },
#endif // ENABLE_MINER
{ "getnetworkhashps", 0, "nblocks" },
{ "getnetworkhashps", 1, "height" },
Expand Down Expand Up @@ -104,6 +105,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendmany", 10, "fee_rate" },
{ "sendmany", 11, "verbose" },
{ "deriveaddresses", 1, "range" },
{ "scanblocks", 1, "scanobjects" },
{ "scanblocks", 2, "start_height" },
{ "scanblocks", 3, "stop_height" },
{ "scantxoutset", 1, "scanobjects" },
{ "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" },
Expand Down
10 changes: 8 additions & 2 deletions src/rpc/evo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ static RPCArg GetRpcArg(const std::string& strParamName)
{"reward", RPCArg::Type::NUM, RPCArg::Optional::NO, "The payout share in basis points."},
}},
},
"\"payoutAddress\"|[{\"address\",\"reward\"},...]", {"string or array", "string or array"}}
RPCArgOptions{
.oneline_description={"\"payoutAddress\" | [{\"address\",\"reward\"},...] (string or array)"},
.type_str={"string or array", "string or array"},
}}
},
{"payoutAddress_update",
{"payoutAddress", RPCArg::Type::ARR, RPCArg::Optional::NO,
Expand All @@ -175,7 +178,10 @@ static RPCArg GetRpcArg(const std::string& strParamName)
{"reward", RPCArg::Type::NUM, RPCArg::Optional::NO, "The payout share in basis points."},
}},
},
"\"payoutAddress\"|[{\"address\",\"reward\"},...]", {"string or array", "string or array"}}
RPCArgOptions{
.oneline_description={"\"payoutAddress\" | [{\"address\",\"reward\"},...] (string or array)"},
.type_str={"string or array", "string or array"},
}}
},
Comment thread
knst marked this conversation as resolved.
{"proTxHash",
{"proTxHash", RPCArg::Type::STR, RPCArg::Optional::NO,
Expand Down
66 changes: 37 additions & 29 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ static RPCHelpMan getnetworkhashps()
}

#if ENABLE_MINER
static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, uint256& block_hash)
static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
{
block_hash.SetNull();
block_out.reset();
block.hashMerkleRoot = BlockMerkleRoot(block);

while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !ShutdownRequested()) {
Expand All @@ -139,12 +139,14 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
return true;
}

std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
if (!chainman.ProcessNewBlock(shared_pblock, true, nullptr)) {
block_out = std::make_shared<const CBlock>(block);

if (!process_new_block) return true;

if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, nullptr)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
}

block_hash = block.GetHash();
return true;
}

Expand All @@ -158,16 +160,15 @@ static UniValue generateBlocks(ChainstateManager& chainman, const NodeContext& n
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), node, &mempool).CreateNewBlock(coinbase_script));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;

uint256 block_hash;
if (!GenerateBlock(chainman, *pblock, nMaxTries, block_hash)) {
std::shared_ptr<const CBlock> block_out;
if (!GenerateBlock(chainman, pblocktemplate->block, nMaxTries, block_out, /*process_new_block=*/true)) {
break;
}

if (!block_hash.IsNull()) {
if (block_out) {
--nGenerate;
blockHashes.push_back(block_hash.GetHex());
blockHashes.push_back(block_out->GetHash().GetHex());
}
}
return blockHashes;
Expand Down Expand Up @@ -299,11 +300,13 @@ static RPCHelpMan generateblock()
{"rawtx/txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
},
},
{"submit", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to submit the block before the RPC call returns or to return it as hex."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "hash", "hash of generated block"},
{RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "hex of generated block, only present when submit=false"},
}
},
RPCExamples{
Expand Down Expand Up @@ -352,10 +355,12 @@ static RPCHelpMan generateblock()
}
}

const bool process_new_block{request.params[2].isNull() ? true : request.params[2].get_bool()};
CBlock block;

ChainstateManager& chainman = EnsureChainman(node);
Chainstate& active_chainstate = chainman.ActiveChainstate();

CBlock block;
{
LOCK(cs_main);

Expand All @@ -382,15 +387,20 @@ static RPCHelpMan generateblock()
}
}

uint256 block_hash;
std::shared_ptr<const CBlock> block_out;
uint64_t max_tries{DEFAULT_MAX_TRIES};

if (!GenerateBlock(chainman, block, max_tries, block_hash) || block_hash.IsNull()) {
if (!GenerateBlock(chainman, block, max_tries, block_out, process_new_block) || !block_out) {
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
}

UniValue obj(UniValue::VOBJ);
obj.pushKV("hash", block_hash.GetHex());
obj.pushKV("hash", block_out->GetHash().GetHex());
if (!process_new_block) {
CDataStream block_ser{SER_NETWORK, PROTOCOL_VERSION};
block_ser << *block_out;
obj.pushKV("hex", HexStr(block_ser));
}
return obj;
},
};
Expand Down Expand Up @@ -544,22 +554,20 @@ static RPCHelpMan getblocktemplate()
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n",
{
{"template_request", RPCArg::Type::OBJ, RPCArg::Default{UniValue::VOBJ}, "Format of the template",
{
{"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
{"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
{
{"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
{"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
{
{"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
},
},
{"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings",
{
{"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported softfork deployment"},
},
},
{"longpollid", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "delay processing request until the result would vary significantly from the \"longpollid\" of a prior template"},
{"data", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "proposed block data to check, encoded in hexadecimal; valid only for mode=\"proposal\""},
},
"\"template_request\""},
{"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
}},
{"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings",
{
{"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported softfork deployment"},
}},
{"longpollid", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "delay processing request until the result would vary significantly from the \"longpollid\" of a prior template"},
{"data", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "proposed block data to check, encoded in hexadecimal; valid only for mode=\"proposal\""},
},
RPCArgOptions{.oneline_description="\"template_request\""}},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
{
RPCResult{"If the proposal was accepted with mode=='proposal'", RPCResult::Type::NONE, "", ""},
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ static RPCHelpMan stop()
// to the client (intended for testing)
"\nRequest a graceful shutdown of " PACKAGE_NAME ".",
{
{"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", "", {}, /*hidden=*/true},
{"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", RPCArgOptions{.hidden=true}},
},
RPCResult{RPCResult::Type::STR, "", "A string with the content '" + RESULT + "'"},
RPCExamples{""},
Expand Down
14 changes: 7 additions & 7 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ struct Sections {
case RPCArg::Type::BOOL: {
if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion
auto left = indent;
if (arg.m_type_str.size() != 0 && push_name) {
left += "\"" + arg.GetName() + "\": " + arg.m_type_str.at(0);
if (arg.m_opts.type_str.size() != 0 && push_name) {
left += "\"" + arg.GetName() + "\": " + arg.m_opts.type_str.at(0);
} else {
left += push_name ? arg.ToStringObj(/*oneline=*/false) : arg.ToString(/*oneline=*/false);
}
Expand Down Expand Up @@ -608,7 +608,7 @@ std::string RPCHelpMan::ToString() const
ret += m_name;
bool was_optional{false};
for (const auto& arg : m_args) {
if (arg.m_hidden) break; // Any arg that follows is also hidden
if (arg.m_opts.hidden) break; // Any arg that follows is also hidden
const bool optional = arg.IsOptional();
ret += " ";
if (optional) {
Expand All @@ -629,7 +629,7 @@ std::string RPCHelpMan::ToString() const
Sections sections;
for (size_t i{0}; i < m_args.size(); ++i) {
const auto& arg = m_args.at(i);
if (arg.m_hidden) break; // Any arg that follows is also hidden
if (arg.m_opts.hidden) break; // Any arg that follows is also hidden

if (i == 0) ret += "\nArguments:\n";

Expand Down Expand Up @@ -694,8 +694,8 @@ std::string RPCArg::ToDescriptionString(bool is_named_arg) const
{
std::string ret;
ret += "(";
if (m_type_str.size() != 0) {
ret += m_type_str.at(1);
if (m_opts.type_str.size() != 0) {
ret += m_opts.type_str.at(1);
} else {
switch (m_type) {
case Type::STR_HEX:
Expand Down Expand Up @@ -937,7 +937,7 @@ std::string RPCArg::ToStringObj(const bool oneline) const

std::string RPCArg::ToString(const bool oneline) const
{
if (oneline && !m_oneline_description.empty()) return m_oneline_description;
if (oneline && !m_opts.oneline_description.empty()) return m_opts.oneline_description;

switch (m_type) {
case Type::STR_HEX:
Expand Down
27 changes: 12 additions & 15 deletions src/rpc/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ enum class OuterType {
/** Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range of 1000. */
std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider);

struct RPCArgOptions {
std::string oneline_description{}; //!< Should be empty unless it is supposed to override the auto-generated summary line
std::vector<std::string> type_str{}; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_opts.type_str.at(0) will override the type of the value in a key-value pair, m_opts.type_str.at(1) will override the type in the argument description.
bool hidden{false}; //!< For testing only
};

struct RPCArg {
enum class Type {
OBJ,
Expand Down Expand Up @@ -188,28 +194,22 @@ struct RPCArg {

const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments)
const Type m_type;
const bool m_hidden;
const std::vector<RPCArg> m_inner; //!< Only used for arrays or dicts
const Fallback m_fallback;
const std::string m_description;
const std::string m_oneline_description; //!< Should be empty unless it is supposed to override the auto-generated summary line
const std::vector<std::string> m_type_str; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_type_str.at(0) will override the type of the value in a key-value pair, m_type_str.at(1) will override the type in the argument description.
const RPCArgOptions m_opts;

RPCArg(
std::string name,
Type type,
Fallback fallback,
std::string description,
std::string oneline_description = "",
std::vector<std::string> type_str = {},
bool hidden = false)
RPCArgOptions opts = {})
: m_names{std::move(name)},
m_type{std::move(type)},
m_hidden{hidden},
m_fallback{std::move(fallback)},
m_description{std::move(description)},
m_oneline_description{std::move(oneline_description)},
m_type_str{std::move(type_str)}
m_opts{std::move(opts)}
{
CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ && type != Type::OBJ_USER_KEYS);
}
Expand All @@ -220,16 +220,13 @@ struct RPCArg {
Fallback fallback,
std::string description,
std::vector<RPCArg> inner,
std::string oneline_description = "",
std::vector<std::string> type_str = {})
RPCArgOptions opts = {})
: m_names{std::move(name)},
m_type{std::move(type)},
m_hidden{false},
m_inner{std::move(inner)},
m_fallback{std::move(fallback)},
m_description{std::move(description)},
m_oneline_description{std::move(oneline_description)},
m_type_str{std::move(type_str)}
m_opts{std::move(opts)}
{
CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ || type == Type::OBJ_USER_KEYS);
}
Expand All @@ -244,7 +241,7 @@ struct RPCArg {

/**
* Return the type string of the argument.
* Set oneline to allow it to be overridden by a custom oneline type string (m_oneline_description).
* Set oneline to allow it to be overridden by a custom oneline type string (m_opts.oneline_description).
*/
std::string ToString(bool oneline) const;
/**
Expand Down
1 change: 1 addition & 0 deletions src/test/fuzz/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"prioritisetransaction",
"pruneblockchain",
"reconsiderblock",
"scanblocks",
"scantxoutset",
"sendmsgtopeer", // when no peers are connected, no p2p message is sent
"sendrawtransaction",
Expand Down
Loading