mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-11 21:20:39 +02:00
rpc: introduce HelpElision variant and ElideGroup helper
Switch RPCResultOptions::print_elision to a variant <HelpElisionNone, HelpElisionSkip, std::string> and add a constructor that copies a result with replacement options. Use the new ElideGroup() in TxDoc() to apply elision to field groups instead of setting print_elision per field. Type::ELISION stays as a deprecated alias.
This commit is contained in:
committed by
satsfy (Renato Britto)
parent
47da4f9b71
commit
44fc3a290d
@@ -346,16 +346,14 @@ void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const
|
||||
|
||||
std::vector<RPCResult> TxDoc(const TxDocOptions& opts)
|
||||
{
|
||||
std::optional<std::string> maybe_skip{};
|
||||
if (opts.elision_description) maybe_skip.emplace();
|
||||
return {
|
||||
{RPCResult::Type::STR_HEX, "txid", opts.txid_field_doc, {}, {.print_elision=opts.elision_description}},
|
||||
{RPCResult::Type::STR_HEX, "hash", "The transaction hash (differs from txid for witness transactions)", {}, {.print_elision=maybe_skip}},
|
||||
{RPCResult::Type::NUM, "size", "The serialized transaction size", {}, {.print_elision=maybe_skip}},
|
||||
{RPCResult::Type::NUM, "vsize", "The virtual transaction size (differs from size for witness transactions)", {}, {.print_elision=maybe_skip}},
|
||||
{RPCResult::Type::NUM, "weight", "The transaction's weight (between vsize*4-3 and vsize*4)", {}, {.print_elision=maybe_skip}},
|
||||
{RPCResult::Type::NUM, "version", "The version", {}, {.print_elision=maybe_skip}},
|
||||
{RPCResult::Type::NUM_TIME, "locktime", "The lock time", {}, {.print_elision=maybe_skip}},
|
||||
auto fields = std::vector<RPCResult>{
|
||||
{RPCResult::Type::STR_HEX, "txid", opts.txid_field_doc},
|
||||
{RPCResult::Type::STR_HEX, "hash", "The transaction hash (differs from txid for witness transactions)"},
|
||||
{RPCResult::Type::NUM, "size", "The serialized transaction size"},
|
||||
{RPCResult::Type::NUM, "vsize", "The virtual transaction size (differs from size for witness transactions)"},
|
||||
{RPCResult::Type::NUM, "weight", "The transaction's weight (between vsize*4-3 and vsize*4)"},
|
||||
{RPCResult::Type::NUM, "version", "The version"},
|
||||
{RPCResult::Type::NUM_TIME, "locktime", "The lock time"},
|
||||
{RPCResult::Type::ARR, "vin", "",
|
||||
{
|
||||
{RPCResult::Type::OBJ, "", "",
|
||||
@@ -374,7 +372,7 @@ std::vector<RPCResult> TxDoc(const TxDocOptions& opts)
|
||||
}},
|
||||
{RPCResult::Type::NUM, "sequence", "The script sequence number"},
|
||||
}},
|
||||
}, {.print_elision=maybe_skip}},
|
||||
}},
|
||||
{RPCResult::Type::ARR, "vout", "",
|
||||
{
|
||||
{RPCResult::Type::OBJ, "", "", Cat(
|
||||
@@ -383,11 +381,16 @@ std::vector<RPCResult> TxDoc(const TxDocOptions& opts)
|
||||
{RPCResult::Type::NUM, "n", "index"},
|
||||
{RPCResult::Type::OBJ, "scriptPubKey", "", ScriptPubKeyDoc()},
|
||||
},
|
||||
opts.wallet ?
|
||||
opts.wallet ?
|
||||
std::vector<RPCResult>{{RPCResult::Type::BOOL, "ischange", /*optional=*/true, "Output script is change (only present if true)"}} :
|
||||
std::vector<RPCResult>{}
|
||||
)
|
||||
},
|
||||
}, {.print_elision=maybe_skip}},
|
||||
)},
|
||||
}},
|
||||
};
|
||||
|
||||
if (opts.elision_description) {
|
||||
fields = ElideGroup(std::move(fields), *opts.elision_description);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
@@ -1017,16 +1017,25 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
|
||||
|
||||
// Ensure at least one elision description exists, if there is any elision
|
||||
const auto elision_has_description{[](const std::vector<RPCResult>& inner) {
|
||||
return std::ranges::none_of(inner, [](const auto& res) { return res.m_opts.print_elision.has_value(); }) ||
|
||||
std::ranges::any_of(inner, [](const auto& res) { return res.m_opts.print_elision.has_value() && !res.m_opts.print_elision->empty(); });
|
||||
const auto is_elided = [](const RPCResult& res) {
|
||||
return !std::holds_alternative<HelpElisionNone>(res.m_opts.print_elision);
|
||||
};
|
||||
const auto has_summary_text = [](const RPCResult& res) {
|
||||
const auto* text = std::get_if<std::string>(&res.m_opts.print_elision);
|
||||
return text && !text->empty();
|
||||
};
|
||||
return std::ranges::none_of(inner, is_elided) || std::ranges::any_of(inner, has_summary_text);
|
||||
}};
|
||||
|
||||
if (m_opts.print_elision) {
|
||||
if (!m_opts.print_elision->empty()) {
|
||||
sections.PushSection({indent + "..." + maybe_separator, *m_opts.print_elision});
|
||||
if (const auto* text = std::get_if<std::string>(&m_opts.print_elision)) {
|
||||
if (!text->empty()) {
|
||||
sections.PushSection({indent + "..." + maybe_separator, *text});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (std::holds_alternative<HelpElisionSkip>(m_opts.print_elision)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_type) {
|
||||
case Type::ELISION: {
|
||||
@@ -1418,3 +1427,20 @@ uint256 GetTarget(const CBlockIndex& blockindex, const uint256 pow_limit)
|
||||
arith_uint256 target{*CHECK_NONFATAL(DeriveTarget(blockindex.nBits, pow_limit))};
|
||||
return ArithToUint256(target);
|
||||
}
|
||||
|
||||
std::vector<RPCResult> ElideGroup(std::vector<RPCResult> fields, std::string summary)
|
||||
{
|
||||
if (fields.empty()) return fields;
|
||||
std::vector<RPCResult> result;
|
||||
result.reserve(fields.size());
|
||||
for (size_t i = 0; i < fields.size(); ++i) {
|
||||
RPCResultOptions opts = fields[i].m_opts;
|
||||
if (i == 0) {
|
||||
opts.print_elision = summary;
|
||||
} else {
|
||||
opts.print_elision = HelpElisionSkip{};
|
||||
}
|
||||
result.emplace_back(fields[i], std::move(opts));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -292,18 +292,17 @@ struct RPCArg {
|
||||
std::string ToDescriptionString(bool is_named_arg) const;
|
||||
};
|
||||
|
||||
/// Controls how an RPCResult is rendered in human-readable help text.
|
||||
/// The std::string alternative carries the summary text rendered as "...".
|
||||
struct HelpElisionNone {}; //!< field printed normally
|
||||
struct HelpElisionSkip {}; //!< field hidden from help
|
||||
using HelpElision = std::variant<HelpElisionNone, HelpElisionSkip, std::string>;
|
||||
|
||||
struct RPCResultOptions {
|
||||
bool skip_type_check{false};
|
||||
/// Whether to treat this as elided in the human-readable description, and
|
||||
/// possibly supply a description for the elision. Normally, there will be
|
||||
/// one string on any of the elided results, for example `Same output as
|
||||
/// verbosity = 1`, and all other elided strings will be empty.
|
||||
///
|
||||
/// - If nullopt: normal display.
|
||||
/// - If empty string: suppress from help.
|
||||
/// - If non-empty: show "..." with this description.
|
||||
std::optional<std::string> print_elision{std::nullopt};
|
||||
HelpElision print_elision{HelpElisionNone{}};
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
struct RPCResult {
|
||||
enum class Type {
|
||||
@@ -385,6 +384,16 @@ struct RPCResult {
|
||||
RPCResultOptions opts = {})
|
||||
: RPCResult{type, std::move(m_key_name), /*optional=*/false, std::move(description), std::move(inner), std::move(opts)} {}
|
||||
|
||||
/// Copy with replacement options, for stamping new opts onto an existing result.
|
||||
RPCResult(const RPCResult& other, RPCResultOptions opts)
|
||||
: m_type{other.m_type},
|
||||
m_key_name{other.m_key_name},
|
||||
m_inner{other.m_inner},
|
||||
m_optional{other.m_optional},
|
||||
m_opts{std::move(opts)},
|
||||
m_description{other.m_description},
|
||||
m_cond{other.m_cond} {}
|
||||
|
||||
/** Append the sections of the result. */
|
||||
void ToSections(Sections& sections, OuterType outer_type = OuterType::NONE, int current_indent = 0) const;
|
||||
/** Return the type string of the result when it is in an object (dict). */
|
||||
@@ -400,6 +409,10 @@ private:
|
||||
void CheckInnerDoc() const;
|
||||
};
|
||||
|
||||
/// Stamp elision onto an entire vector of RPCResult fields at once.
|
||||
/// Merges into existing m_opts so that flags like skip_type_check are preserved.
|
||||
std::vector<RPCResult> ElideGroup(std::vector<RPCResult> fields, std::string summary = "");
|
||||
|
||||
struct RPCResults {
|
||||
const std::vector<RPCResult> m_results;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user