From 3cc9669f4be74beb4db1da91a80fbd0b4ccfdb58 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 12 Jan 2026 19:23:16 -0500 Subject: [PATCH 1/3] Update tx_details explore query, style, comments. --- src/protocols/protocol_explore.cpp | 123 ++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 39 deletions(-) diff --git a/src/protocols/protocol_explore.cpp b/src/protocols/protocol_explore.cpp index 2345f55e..209d4024 100644 --- a/src/protocols/protocol_explore.cpp +++ b/src/protocols/protocol_explore.cpp @@ -25,6 +25,8 @@ #include #include +// TODO: rationalize confirmed state against database (to_block vs. to_strong). + namespace libbitcoin { namespace server { @@ -248,13 +250,16 @@ bool protocol_explore::handle_get_configuration(const code& ec, return true; } - boost::json::object object{}; - object["address"] = archive().address_enabled(); - object["filter"] = archive().filter_enabled(); - object["turbo"] = database_settings().turbo; - object["witness"] = network_settings().witness_node(); - object["retarget"] = system_settings().forks.retarget; - object["difficult"] = system_settings().forks.difficult; + boost::json::object object + { + { "address", archive().address_enabled() }, + { "filter", archive().filter_enabled() }, + { "turbo", database_settings().turbo }, + { "witness", network_settings().witness_node() }, + { "retarget", system_settings().forks.retarget }, + { "difficult", system_settings().forks.difficult }, + }; + send_json(std::move(object), 32); return true; } @@ -367,10 +372,12 @@ bool protocol_explore::handle_get_block_header_context(const code& ec, return true; } - boost::json::object object{}; - object["hash"] = encode_hash(query.get_header_key(link)); - object["height"] = context.height; - object["mtp"] = context.mtp; + boost::json::object object + { + { "hash", encode_hash(query.get_header_key(link)) }, + { "height", context.height }, + { "mtp", context.mtp }, + }; // The "state" element implies transactions are associated. if (query.is_associated(link)) @@ -447,7 +454,7 @@ bool protocol_explore::handle_get_block_details(const code& ec, // Internal population (optimization). block->populate(); - // False if missing prevouts (not ready). + // Missing prevouts (not ready). if (!query.populate_without_metadata(*block)) { send_not_found(); @@ -462,19 +469,21 @@ bool protocol_explore::handle_get_block_details(const code& ec, const auto subsidy = chain::block::subsidy(context.height, settings.subsidy_interval_blocks, settings.initial_subsidy(), bip42); - boost::json::object object{}; - object["hash"] = encode_hash(block->hash()); - object["height"] = context.height; - object["count"] = block->transactions(); - object["sigops"] = block->signature_operations(bip16, bip141); - object["segregated"] = block->is_segregated(); - object["nominal"] = block->serialized_size(false); - object["maximal"] = block->serialized_size(true); - object["weight"] = block->weight(); - object["fees"] = fees; - object["subsidy"] = subsidy; - object["reward"] = ceilinged_add(fees, subsidy); - object["claim"] = block->claim(); + boost::json::object object + { + { "hash", encode_hash(block->hash()) }, + { "height", context.height }, + { "count", block->transactions() }, + { "sigops", block->signature_operations(bip16, bip141) }, + { "segregated", block->is_segregated() }, + { "nominal", block->serialized_size(false) }, + { "maximal", block->serialized_size(true) }, + { "weight", block->weight() }, + { "fees", fees }, + { "subsidy", subsidy }, + { "reward", ceilinged_add(fees, subsidy) }, + { "claim", block->claim() }, + }; send_json(std::move(object), 512); return true; @@ -736,26 +745,62 @@ bool protocol_explore::handle_get_tx_details(const code& ec, if (stopped(ec)) return false; - // TODO: expand details to include tx.size and tx.weight. + if (media != json) + { + send_not_acceptable(); + return true; + } + const auto& query = archive(); - if (const auto fee = query.get_tx_fee(query.to_tx(*hash)); - fee != max_uint64) + const auto link = query.to_tx(*hash); + const auto tx = query.get_transaction(link, true); + + // Missing tx. + if (!tx) { - switch (media) + send_not_found(); + return true; + } + + // Coinbase missing prevouts (not ready). + const auto coinbase = query.is_coinbase(link); + if (!coinbase && !query.populate_without_metadata(*tx)) + { + send_not_found(); + return true; + } + + boost::json::object object + { + { "coinbase", coinbase }, + { "segregated", tx->is_segregated() }, + { "nominal", tx->serialized_size(false) }, + { "maximal", tx->serialized_size(true) }, + { "weight", tx->weight() }, + { "fee", tx->fee() } + }; + + size_t position{}; + if (query.get_tx_position(position, link)) + { + database::context context{}; + if (!query.get_context(context, query.to_strong(link))) { - case data: - send_chunk(to_little_endian_size(fee)); - return true; - case text: - send_text(encode_base16(to_little_endian_size(fee))); - return true; - case json: - send_json(fee, two * sizeof(fee)); - return true; + send_internal_server_error(database::error::integrity); + return true; } + + const auto bip16 = context.is_enabled(chain::flags::bip16_rule); + const auto bip141 = context.is_enabled(chain::flags::bip141_rule); + object["confirmed"] = boost::json::object + { + { "height", context.height }, + { "position", position }, + { "sigops", tx->signature_operations(bip16, bip141) } + }; } - send_not_found(); + send_json(std::move(object), 128); return true; } From e7140d1befb11d557b407d3e30bd705f6dd71179 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 12 Jan 2026 19:43:30 -0500 Subject: [PATCH 2/3] Add fields to explore tx_details query. --- src/protocols/protocol_explore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/protocols/protocol_explore.cpp b/src/protocols/protocol_explore.cpp index 209d4024..80b2657e 100644 --- a/src/protocols/protocol_explore.cpp +++ b/src/protocols/protocol_explore.cpp @@ -772,11 +772,14 @@ bool protocol_explore::handle_get_tx_details(const code& ec, boost::json::object object { - { "coinbase", coinbase }, + { "wtxid", encode_hash(tx->get_hash(true)) }, { "segregated", tx->is_segregated() }, + { "coinbase", coinbase }, { "nominal", tx->serialized_size(false) }, { "maximal", tx->serialized_size(true) }, { "weight", tx->weight() }, + { "value", tx->value() }, + { "spend", tx->spend() }, { "fee", tx->fee() } }; From 264055b2ed04a5002b2d204521869741609efff1 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Mon, 12 Jan 2026 20:06:33 -0500 Subject: [PATCH 3/3] Fix comment. --- src/protocols/protocol_explore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/protocol_explore.cpp b/src/protocols/protocol_explore.cpp index 80b2657e..ac3b7224 100644 --- a/src/protocols/protocol_explore.cpp +++ b/src/protocols/protocol_explore.cpp @@ -762,7 +762,7 @@ bool protocol_explore::handle_get_tx_details(const code& ec, return true; } - // Coinbase missing prevouts (not ready). + // Non-coinbase missing prevouts (not ready). const auto coinbase = query.is_coinbase(link); if (!coinbase && !query.populate_without_metadata(*tx)) {