Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
rpc: extract ListSinceBlockTxFields() helper
Extract the inline listsinceblock transaction field list into a reusable
helper. The removed entry replaces its Type::ELISION placeholder with an empty
string elision.

ToSections() render an empty std::string elision as "...", and suppress
the array continuation marker when the last inner element renders as a
std::string elision.
  • Loading branch information
satsfy committed Jun 13, 2026
commit 8a615a8800521e10522b8873ca2cb37100024ae7
6 changes: 2 additions & 4 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1023,9 +1023,7 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
}};

if (const auto* text = std::get_if<std::string>(&m_opts.print_elision)) {
if (!text->empty()) {
sections.PushSection({indent + "..." + maybe_separator, *text});
}
sections.PushSection({indent + "..." + maybe_separator, *text});
return;
}
if (std::holds_alternative<HelpElisionSkip>(m_opts.print_elision)) {
Expand Down Expand Up @@ -1077,7 +1075,7 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
}
CHECK_NONFATAL(!m_inner.empty());
CHECK_NONFATAL(elision_has_description(m_inner));
if (m_type == Type::ARR && m_inner.back().m_type != Type::ELISION) {
if (m_type == Type::ARR && m_inner.back().m_type != Type::ELISION && !std::holds_alternative<std::string>(m_inner.back().m_opts.print_elision)) {
sections.PushSection({indent_next + "...", ""});
} else {
// Remove final comma, which would be invalid JSON
Expand Down
54 changes: 32 additions & 22 deletions src/wallet/rpc/transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,33 @@ RPCMethod listtransactions()
};
}

static std::vector<RPCResult> ListSinceBlockTxFields()
{
return Cat<std::vector<RPCResult>>(
{
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
{RPCResult::Type::STR, "category", "The transaction category.\n"
"\"send\" Transactions sent.\n"
"\"receive\" Non-coinbase transactions received.\n"
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
"\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
"\"orphan\" Orphaned coinbase transactions received."},
{RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
"for all other categories"},
{RPCResult::Type::NUM, "vout", "the vout value"},
{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
"'send' category of transactions."},
},
Cat(
TransactionDescriptionString(),
std::vector<RPCResult>{
{RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
{RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
}
)
);
}

RPCMethod listsinceblock()
{
return RPCMethod{
Expand All @@ -544,30 +571,13 @@ RPCMethod listsinceblock()
{
{RPCResult::Type::ARR, "transactions", "",
{
{RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
{
{RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data)."},
{RPCResult::Type::STR, "category", "The transaction category.\n"
"\"send\" Transactions sent.\n"
"\"receive\" Non-coinbase transactions received.\n"
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
"\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
"\"orphan\" Orphaned coinbase transactions received."},
{RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
"for all other categories"},
{RPCResult::Type::NUM, "vout", "the vout value"},
{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
"'send' category of transactions."},
},
TransactionDescriptionString()),
{
{RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
{RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
})},
{RPCResult::Type::OBJ, "", "", ListSinceBlockTxFields()},
}},
{RPCResult::Type::ARR, "removed", /*optional=*/true, "<structure is the same as \"transactions\" above, only present if include_removed=true>\n"
"Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count."
, {{RPCResult::Type::ELISION, "", ""},}},
"Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count.",
{
{RPCResult::Type::OBJ, "", "", ListSinceBlockTxFields(), {.print_elision = std::string{}}},
}},
{RPCResult::Type::STR_HEX, "lastblock", "The hash of the block (target_confirmations-1) from the best block on the main chain, or the genesis hash if the referenced block does not exist yet. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones"},
}
},
Expand Down