From fbb0744905ef9dac1a417aed712321c7cb4596ad Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 01:01:56 -0400 Subject: [PATCH 1/8] Use "bitcoind" for client-server protocol reference. --- src/parsers/bitcoind_target.cpp | 6 +++--- src/protocols/bitcoind/protocol_bitcoind_rest.cpp | 2 +- src/protocols/bitcoind/protocol_bitcoind_rpc.cpp | 2 +- test/protocols/bitcoind/bitcoind_setup_fixture.hpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/parsers/bitcoind_target.cpp b/src/parsers/bitcoind_target.cpp index 0c4b13c8..59c54fd5 100644 --- a/src/parsers/bitcoind_target.cpp +++ b/src/parsers/bitcoind_target.cpp @@ -42,7 +42,7 @@ static hash_cptr to_hash(const std::string_view& token) NOEXCEPT to_shared(std::move(out)) : hash_cptr{}; } -// Map a Bitcoin Core REST file extension to a media value. +// Map a bitcoind REST file extension to a media value. static bool to_media(uint8_t& out, const std::string_view& extension) NOEXCEPT { if (extension == "bin") @@ -87,7 +87,7 @@ static bool split_leaf(std::string& name, uint8_t& media, return to_media(media, parts.back()); } -// Parse a Bitcoin Core REST path into a json-rpc request model. +// Parse a bitcoind REST path into a json-rpc request model. // github.com/bitcoin/bitcoin/blob/master/doc/REST-interface.md // Supports: block, block/notxdetails, blockhashbyheight, headers, blockpart, // chaininfo (remaining endpoints return invalid_target until implemented). @@ -116,7 +116,7 @@ code bitcoind_target(request_t& out, const std::string_view& path) NOEXCEPT size_t segment{}; - // Accept an optional "rest" prefix (Core mounts endpoints under /rest/). + // Accept an optional "rest" prefix (bitcoind mounts endpoints under /rest/). if (segments[segment] == "rest") ++segment; diff --git a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp index 879f1061..e81f3a6e 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp @@ -275,7 +275,7 @@ bool protocol_bitcoind_rest::handle_get_block_headers(const code& ec, return true; } - // Core caps the header count at 2000. + // bitcoind caps the header count at 2000. constexpr size_t maximum = 2000; constexpr auto header_size = chain::header::serialized_size(); const auto limit = std::min(possible_wide_cast(count), maximum); diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp index 31db91ba..2cb51fb0 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp @@ -573,7 +573,7 @@ bool protocol_bitcoind_rpc::handle_get_raw_transaction(const code& ec, return true; } - // bitcoind() (not bitcoind_verbose) yields Core's tx fields: txid/hash/ + // bitcoind() (not bitcoind_verbose) yields bitcoind's tx fields: txid/hash/ // size/vsize/weight/vin/vout/hex (bitcoind_verbose on a standalone tx // falls back to libbitcoin's plain inputs/outputs form). auto model = value_from(bitcoind(*tx)); diff --git a/test/protocols/bitcoind/bitcoind_setup_fixture.hpp b/test/protocols/bitcoind/bitcoind_setup_fixture.hpp index a346cf75..1cf03471 100644 --- a/test/protocols/bitcoind/bitcoind_setup_fixture.hpp +++ b/test/protocols/bitcoind/bitcoind_setup_fixture.hpp @@ -37,7 +37,7 @@ struct bitcoind_setup_fixture // object). Returns the parsed json-rpc response object (with result/error). boost::json::value rpc(std::string_view method, std::string_view params="[]"); - // Bitcoin Core REST over HTTP GET (target under "/rest/..."). + // bitcoind REST over HTTP GET (target under "/rest/..."). status rest_status(std::string_view target); boost::json::value rest_json(std::string_view target); std::string rest_text(std::string_view target); From 51c0b59abe28981d12ec2baec433a65f290825c3 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 00:40:13 -0400 Subject: [PATCH 2/8] Remove dead code. --- Makefile.am | 3 -- .../libbitcoin-server-test.vcxproj | 1 - .../libbitcoin-server-test.vcxproj.filters | 3 -- .../libbitcoin-server.vcxproj | 2 - .../libbitcoin-server.vcxproj.filters | 6 --- .../libbitcoin-server-test.vcxproj | 1 - .../libbitcoin-server-test.vcxproj.filters | 3 -- .../libbitcoin-server.vcxproj | 2 - .../libbitcoin-server.vcxproj.filters | 6 --- include/bitcoin/server.hpp | 1 - .../bitcoin/server/parsers/bitcoind_query.hpp | 33 --------------- include/bitcoin/server/parsers/parsers.hpp | 1 - src/parsers/bitcoind_query.cpp | 42 ------------------- test/parsers/bitcoind_query.cpp | 28 ------------- 14 files changed, 132 deletions(-) delete mode 100644 include/bitcoin/server/parsers/bitcoind_query.hpp delete mode 100644 src/parsers/bitcoind_query.cpp delete mode 100644 test/parsers/bitcoind_query.cpp diff --git a/Makefile.am b/Makefile.am index 00490a40..3b15bee8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,7 +40,6 @@ src_libbitcoin_server_la_SOURCES = \ src/parser.cpp \ src/server_node.cpp \ src/settings.cpp \ - src/parsers/bitcoind_query.cpp \ src/parsers/bitcoind_target.cpp \ src/parsers/electrum_version.cpp \ src/parsers/native_query.cpp \ @@ -89,7 +88,6 @@ test_libbitcoin_server_test_SOURCES = \ test/test.hpp \ test/mocks/blocks.cpp \ test/mocks/blocks.hpp \ - test/parsers/bitcoind_query.cpp \ test/parsers/bitcoind_target.cpp \ test/parsers/electrum_version.cpp \ test/parsers/native_query.cpp \ @@ -209,7 +207,6 @@ include_bitcoin_server_interfaces_HEADERS = \ include_bitcoin_server_parsersdir = ${includedir}/bitcoin/server/parsers include_bitcoin_server_parsers_HEADERS = \ - include/bitcoin/server/parsers/bitcoind_query.hpp \ include/bitcoin/server/parsers/bitcoind_target.hpp \ include/bitcoin/server/parsers/electrum_version.hpp \ include/bitcoin/server/parsers/native_query.hpp \ diff --git a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj index 1dda035c..d70fcf34 100644 --- a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj @@ -122,7 +122,6 @@ - $(IntDir)test_parsers_electrum_version.obj diff --git a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters index 1c804ffb..329d44ac 100644 --- a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters @@ -42,9 +42,6 @@ src\mocks - - src\parsers - src\parsers diff --git a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj index 402eb343..8f6729ed 100644 --- a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj @@ -124,7 +124,6 @@ - @@ -179,7 +178,6 @@ - diff --git a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters index 55bc05f6..63736a31 100644 --- a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters @@ -72,9 +72,6 @@ src - - src\parsers - src\parsers @@ -233,9 +230,6 @@ include\bitcoin\server - - include\bitcoin\server\parsers - include\bitcoin\server\parsers diff --git a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj index e8cf72c3..cdd024ce 100644 --- a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj @@ -122,7 +122,6 @@ - $(IntDir)test_parsers_electrum_version.obj diff --git a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters index 1c804ffb..329d44ac 100644 --- a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters +++ b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters @@ -42,9 +42,6 @@ src\mocks - - src\parsers - src\parsers diff --git a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj index 6ad51e16..971b213f 100644 --- a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj @@ -124,7 +124,6 @@ - @@ -179,7 +178,6 @@ - diff --git a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters index 55bc05f6..63736a31 100644 --- a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters +++ b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters @@ -72,9 +72,6 @@ src - - src\parsers - src\parsers @@ -233,9 +230,6 @@ include\bitcoin\server - - include\bitcoin\server\parsers - include\bitcoin\server\parsers diff --git a/include/bitcoin/server.hpp b/include/bitcoin/server.hpp index a5dd0928..1e1f935f 100644 --- a/include/bitcoin/server.hpp +++ b/include/bitcoin/server.hpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/include/bitcoin/server/parsers/bitcoind_query.hpp b/include/bitcoin/server/parsers/bitcoind_query.hpp deleted file mode 100644 index 9444c457..00000000 --- a/include/bitcoin/server/parsers/bitcoind_query.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#ifndef LIBBITCOIN_SERVER_PARSERS_BITCOIND_QUERY_HPP -#define LIBBITCOIN_SERVER_PARSERS_BITCOIND_QUERY_HPP - -#include - -namespace libbitcoin { -namespace server { - -BCS_API bool bitcoind_query(network::rpc::request_t& out, - const network::http::request& request) NOEXCEPT; - -} // namespace server -} // namespace libbitcoin - -#endif diff --git a/include/bitcoin/server/parsers/parsers.hpp b/include/bitcoin/server/parsers/parsers.hpp index a958d087..04c1de08 100644 --- a/include/bitcoin/server/parsers/parsers.hpp +++ b/include/bitcoin/server/parsers/parsers.hpp @@ -19,7 +19,6 @@ #ifndef LIBBITCOIN_SERVER_PARSERS_PARSERS_HPP #define LIBBITCOIN_SERVER_PARSERS_PARSERS_HPP -#include #include #include #include diff --git a/src/parsers/bitcoind_query.cpp b/src/parsers/bitcoind_query.cpp deleted file mode 100644 index 8e32b05a..00000000 --- a/src/parsers/bitcoind_query.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#include - -#include - -namespace libbitcoin { -namespace server { - -using namespace system; -using namespace network; -using namespace network::http; - -BC_PUSH_WARNING(NO_ARRAY_INDEXING) -BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) - -bool bitcoind_query(rpc::request_t& , const request& ) NOEXCEPT -{ - return false; -} - -BC_POP_WARNING() -BC_POP_WARNING() - -} // namespace server -} // namespace libbitcoin diff --git a/test/parsers/bitcoind_query.cpp b/test/parsers/bitcoind_query.cpp deleted file mode 100644 index 0685560d..00000000 --- a/test/parsers/bitcoind_query.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#include "../test.hpp" - -BOOST_AUTO_TEST_SUITE(bitcoind_query_tests) - -BOOST_AUTO_TEST_CASE(bitcoind_query_test) -{ - BOOST_REQUIRE(true); -} - -BOOST_AUTO_TEST_SUITE_END() From 16d1666752049455319625c048bc76283f629858 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 00:48:16 -0400 Subject: [PATCH 3/8] Add missing includes, remove defaulted includes. --- include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp | 1 - src/parsers/bitcoind_target.cpp | 2 -- src/protocols/bitcoind/protocol_bitcoind_rest.cpp | 3 --- src/protocols/bitcoind/protocol_bitcoind_rpc.cpp | 4 ++-- src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp | 2 -- 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp b/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp index 6becf52e..c16feb48 100644 --- a/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp +++ b/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp @@ -24,7 +24,6 @@ #include #include #include -#include namespace libbitcoin { namespace server { diff --git a/src/parsers/bitcoind_target.cpp b/src/parsers/bitcoind_target.cpp index 59c54fd5..d0d393c0 100644 --- a/src/parsers/bitcoind_target.cpp +++ b/src/parsers/bitcoind_target.cpp @@ -20,8 +20,6 @@ #include #include -#include -#include #include #include diff --git a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp index e81f3a6e..af730837 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp @@ -20,12 +20,9 @@ #include #include -#include -#include #include #include #include -#include namespace libbitcoin { namespace server { diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp index 2cb51fb0..d3fe1cf7 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp @@ -18,10 +18,10 @@ */ #include +#include +#include #include #include -#include -#include namespace libbitcoin { namespace server { diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp index b9065dcc..ce987a27 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp @@ -18,9 +18,7 @@ */ #include -#include #include -#include namespace libbitcoin { namespace server { From ba9f9a996e489f5fce23e9151579f3dbd8acc077 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 00:55:39 -0400 Subject: [PATCH 4/8] Namespace consistency. --- .../bitcoind/protocol_bitcoind_rest.cpp | 61 ++++++++++--------- .../bitcoind/protocol_bitcoind_rpc.cpp | 56 ++++++++--------- .../bitcoind/protocol_bitcoind_rpc_json.cpp | 5 +- 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp index af730837..041ebbfc 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp @@ -32,8 +32,8 @@ namespace server { subscribe(&CLASS::method, __VA_ARGS__) using namespace system; +using namespace network; using namespace network::rpc; -using namespace network::http; using namespace std::placeholders; using namespace boost::json; @@ -115,9 +115,9 @@ void protocol_bitcoind_rest::handle_receive_get(const code& ec, // Handlers. // ---------------------------------------------------------------------------- -constexpr auto data = to_value(media_type::application_octet_stream); -constexpr auto json = to_value(media_type::application_json); -constexpr auto text = to_value(media_type::text_plain); +constexpr auto data = to_value(http::media_type::application_octet_stream); +constexpr auto json = to_value(http::media_type::application_json); +constexpr auto text = to_value(http::media_type::text_plain); template data_chunk to_data(const Object& object, size_t size, Args&&... args) NOEXCEPT @@ -140,7 +140,7 @@ std::string to_text(const Object& object, size_t size, Args&&... args) NOEXCEPT } bool protocol_bitcoind_rest::handle_get_block(const code& ec, - rest_interface::block, uint8_t media, const system::hash_cptr& hash) NOEXCEPT + rest_interface::block, uint8_t media, const hash_cptr& hash) NOEXCEPT { if (stopped(ec)) return false; @@ -202,7 +202,7 @@ bool protocol_bitcoind_rest::handle_get_block_hash(const code& ec, send_text(encode_base16(hash)); return true; case json: - send_json(boost::json::object{ { "blockhash", encode_hash(hash) } }, + send_json(object{ { "blockhash", encode_hash(hash) } }, two * hash_size); return true; } @@ -212,7 +212,7 @@ bool protocol_bitcoind_rest::handle_get_block_hash(const code& ec, } bool protocol_bitcoind_rest::handle_get_block_txs(const code& ec, - rest_interface::block_txs, uint8_t media, const system::hash_cptr& hash) NOEXCEPT + rest_interface::block_txs, uint8_t media, const hash_cptr& hash) NOEXCEPT { if (stopped(ec)) return false; @@ -252,7 +252,7 @@ bool protocol_bitcoind_rest::handle_get_block_txs(const code& ec, } bool protocol_bitcoind_rest::handle_get_block_headers(const code& ec, - rest_interface::block_headers, uint8_t media, const system::hash_cptr& hash, + rest_interface::block_headers, uint8_t media, const hash_cptr& hash, uint32_t count) NOEXCEPT { if (stopped(ec)) @@ -321,7 +321,7 @@ bool protocol_bitcoind_rest::handle_get_block_headers(const code& ec, } case json: { - boost::json::array out{}; + array out{}; out.reserve(links.size()); for (const auto& link: links) { @@ -345,7 +345,7 @@ bool protocol_bitcoind_rest::handle_get_block_headers(const code& ec, } bool protocol_bitcoind_rest::handle_get_block_part(const code& ec, - rest_interface::block_part, uint8_t media, const system::hash_cptr& hash, + rest_interface::block_part, uint8_t media, const hash_cptr& hash, uint32_t offset, uint32_t size) NOEXCEPT { if (stopped(ec)) @@ -392,7 +392,7 @@ bool protocol_bitcoind_rest::handle_get_block_part(const code& ec, bool protocol_bitcoind_rest::handle_get_block_spent_tx_outputs(const code& ec, rest_interface::block_spent_tx_outputs, uint8_t media, - const system::hash_cptr& hash) NOEXCEPT + const hash_cptr& hash) NOEXCEPT { if (stopped(ec)) return false; @@ -458,7 +458,7 @@ bool protocol_bitcoind_rest::handle_get_block_spent_tx_outputs(const code& ec, } bool protocol_bitcoind_rest::handle_get_block_filter(const code& ec, - rest_interface::block_filter, uint8_t media, const system::hash_cptr& hash, + rest_interface::block_filter, uint8_t media, const hash_cptr& hash, uint8_t) NOEXCEPT { if (stopped(ec)) @@ -488,7 +488,7 @@ bool protocol_bitcoind_rest::handle_get_block_filter(const code& ec, send_text(encode_base16(filter)); return true; case json: - send_json(boost::json::object + send_json(object { { "filter", encode_base16(filter) } }, two * filter.size()); @@ -500,7 +500,7 @@ bool protocol_bitcoind_rest::handle_get_block_filter(const code& ec, } bool protocol_bitcoind_rest::handle_get_block_filter_headers(const code& ec, - rest_interface::block_filter_headers, uint8_t media, const system::hash_cptr& hash, + rest_interface::block_filter_headers, uint8_t media, const hash_cptr& hash, uint8_t) NOEXCEPT { if (stopped(ec)) @@ -529,7 +529,7 @@ bool protocol_bitcoind_rest::handle_get_block_filter_headers(const code& ec, send_text(encode_base16(filter_head)); return true; case json: - send_json(boost::json::object + send_json(object { { "filter_header", encode_hash(filter_head) } }, two * hash_size); @@ -556,7 +556,7 @@ bool protocol_bitcoind_rest::handle_get_chain_information(const code& ec, return true; } - send_json(boost::json::object + send_json(object { { "chain", chain_name(query) }, { "blocks", blocks }, @@ -577,13 +577,14 @@ bool protocol_bitcoind_rest::handle_get_chain_information(const code& ec, void protocol_bitcoind_rest::send_data(data_chunk&& bytes) NOEXCEPT { BC_ASSERT(stranded()); + using namespace http; + static const auto data = from_media_type( + media_type::application_octet_stream); const auto request = reset_request(); - network::http::response message{ network::http::status::ok, - request->version() }; + http::response message{ status::ok, request->version() }; add_common_headers(message, *request); add_access_control_headers(message, *request); - message.set(network::http::field::content_type, network::http:: - from_media_type(media_type::application_octet_stream)); + message.set(http::field::content_type, data); message.body() = std::move(bytes); message.prepare_payload(); SEND(std::move(message), handle_complete, _1, error::success); @@ -592,30 +593,30 @@ void protocol_bitcoind_rest::send_data(data_chunk&& bytes) NOEXCEPT void protocol_bitcoind_rest::send_text(std::string&& text) NOEXCEPT { BC_ASSERT(stranded()); + using namespace http; + static const auto plain = from_media_type(media_type::text_plain); const auto request = reset_request(); - network::http::response message{ network::http::status::ok, - request->version() }; + http::response message{ status::ok, request->version() }; add_common_headers(message, *request); add_access_control_headers(message, *request); - message.set(network::http::field::content_type, network::http:: - from_media_type(media_type::text_plain)); + message.set(field::content_type, plain); message.body() = std::move(text); message.prepare_payload(); SEND(std::move(message), handle_complete, _1, error::success); } -void protocol_bitcoind_rest::send_json(boost::json::value&& model, +void protocol_bitcoind_rest::send_json(value&& model, size_t size_hint) NOEXCEPT { BC_ASSERT(stranded()); + using namespace http; + static const auto json = from_media_type(media_type::application_json); const auto request = reset_request(); - network::http::response message{ network::http::status::ok, - request->version() }; + http::response message{ status::ok, request->version() }; add_common_headers(message, *request); add_access_control_headers(message, *request); - message.set(network::http::field::content_type, network::http:: - from_media_type(media_type::application_json)); - message.body() = network::http::json_value + message.set(field::content_type, json); + message.body() = json_value { .model = std::move(model), .size_hint = size_hint diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp index d3fe1cf7..bc5ebc9d 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp @@ -32,8 +32,10 @@ namespace server { using namespace system; using namespace network; -using namespace network::json; +using namespace network::rpc; +using namespace network::messages; using namespace std::placeholders; +using namespace boost::json; BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED) @@ -133,7 +135,7 @@ void protocol_bitcoind_rpc::handle_receive_post(const code& ec, } // Endpoint accepts only json-rpc posts. - if (!post->body().contains()) + if (!post->body().contains()) { send_bad_request(*post); return; @@ -142,7 +144,7 @@ void protocol_bitcoind_rpc::handle_receive_post(const code& ec, // Get the parsed json-rpc request object. // v1 or v2 both supported, batch not yet supported. // v1 null id and v2 missing id implies notification and no response. - const auto& message = post->body().get().message; + const auto& message = post->body().get().message; // The post is saved off during asynchonous handling and used in send_json // to formulate response headers, isolating handlers from http semantics. @@ -226,8 +228,7 @@ bool protocol_bitcoind_rpc::handle_get_block(const code& ec, value_from(bitcoind_verbose(*block)); inject_block_context(model.as_object(), query, link, block->header()); - send_result(rpc::value_t(std::move(model)), - two * block->serialized_size(witness)); + send_result(std::move(model), two * block->serialized_size(witness)); return true; } @@ -258,15 +259,16 @@ bool protocol_bitcoind_rpc::handle_get_block_chain_info(const code& ec, std::min(1.0, static_cast(blocks) / static_cast(headers)); - send_result(rpc::object_t + // TODO: blocks/headers is a misnomer (off-by-one), intended? + using namespace chain; + send_result(object_t { { "chain", chain_name(query) }, { "blocks", possible_wide_cast(blocks) }, { "headers", possible_wide_cast(headers) }, { "bestblockhash", encode_hash(query.get_header_key(link)) }, { "bits", encode_base16(to_big_endian(header->bits())) }, - { "target", encode_hash(from_uintx( - chain::compact::expand(header->bits()))) }, + { "target", encode_hash(from_uintx(compact::expand(header->bits()))) }, { "difficulty", header->difficulty() }, { "time", header->timestamp() }, { "mediantime", median_time_past(query, link) }, @@ -320,7 +322,7 @@ bool protocol_bitcoind_rpc::handle_get_block_filter(const code& ec, return true; } - send_result(rpc::object_t + send_result(object_t { { "filter", encode_base16(filter) }, { "header", encode_hash(filter_header) } @@ -384,13 +386,12 @@ bool protocol_bitcoind_rpc::handle_get_block_header(const code& ec, auto out = header_to_bitcoind(*header); out["nTx"] = query.get_tx_count(link); inject_block_context(out, query, link, *header); - send_result(rpc::value_t(boost::json::value(std::move(out))), 512); + send_result(value{ std::move(out) }, 512); return true; } bool protocol_bitcoind_rpc::handle_get_block_stats(const code& ec, - rpc_interface::get_block_stats, const network::rpc::value_t&, - const network::rpc::array_t&) NOEXCEPT + rpc_interface::get_block_stats, const value_t&, const array_t&) NOEXCEPT { if (stopped(ec)) return false; send_error(error::not_implemented); @@ -434,14 +435,14 @@ bool protocol_bitcoind_rpc::handle_get_tx_out(const code& ec, // Core returns json null for a missing or spent output (mempool ignored). if (output_fk.is_terminal() || query.is_spent(output_fk)) { - send_result(rpc::value_t{}, 4); + send_result({}, 42); return true; } const auto output = query.get_output(output_fk); if (!output) { - send_result(rpc::value_t{}, 4); + send_result({}, 42); return true; } @@ -450,7 +451,7 @@ bool protocol_bitcoind_rpc::handle_get_tx_out(const code& ec, const auto have_height = query.get_tx_height(tx_height, tx_fk); const auto top = query.get_top_confirmed(); - send_result(rpc::object_t + send_result(object_t { { "bestblock", encode_hash(query.get_top_confirmed_hash()) }, { "confirmations", have_height ? @@ -489,7 +490,7 @@ bool protocol_bitcoind_rpc::handle_save_mem_pool(const code& ec, bool protocol_bitcoind_rpc::handle_scan_tx_out_set(const code& ec, rpc_interface::scan_tx_out_set, const std::string&, - const network::rpc::array_t&) NOEXCEPT + const array_t&) NOEXCEPT { if (stopped(ec)) return false; send_error(error::not_implemented); @@ -521,7 +522,7 @@ bool protocol_bitcoind_rpc::handle_get_network_info(const code& ec, // libbitcoin-server is a node, not a wallet/peer-introspection service; // peer-dependent fields (connections, addresses) are reported as empty. // TODO: surface live connection count and relay fee from node settings. - send_result(rpc::object_t + send_result(object_t { { "version", 0 }, { "subversion", std::string{ "/libbitcoin:server/" } }, @@ -530,10 +531,10 @@ bool protocol_bitcoind_rpc::handle_get_network_info(const code& ec, { "timeoffset", 0 }, { "connections", 0 }, { "networkactive", true }, - { "networks", rpc::array_t{} }, + { "networks", array_t{} }, { "relayfee", 0.00001 }, { "incrementalfee", 0.00001 }, - { "localaddresses", rpc::array_t{} }, + { "localaddresses", array_t{} }, { "warnings", std::string{} } }, 256); return true; @@ -578,8 +579,7 @@ bool protocol_bitcoind_rpc::handle_get_raw_transaction(const code& ec, // falls back to libbitcoin's plain inputs/outputs form). auto model = value_from(bitcoind(*tx)); inject_tx_context(model.as_object(), query, link); - send_result(rpc::value_t(std::move(model)), - two * tx->serialized_size(witness)); + send_result(std::move(model), two * tx->serialized_size(witness)); return true; } @@ -648,14 +648,14 @@ void protocol_bitcoind_rpc::send_error(const code& ec, } void protocol_bitcoind_rpc::send_error(const code& ec, - rpc::value_option&& error, size_t size_hint) NOEXCEPT + value_option&& error, size_t size_hint) NOEXCEPT { BC_ASSERT(stranded()); send_rpc( { .jsonrpc = version_, .id = id_, - .error = rpc::result_t + .error = result_t { .code = ec.value(), .message = ec.message(), @@ -670,7 +670,7 @@ void protocol_bitcoind_rpc::send_text(std::string&& hexidecimal) NOEXCEPT send_result(hexidecimal, hexidecimal.size()); } -void protocol_bitcoind_rpc::send_result(rpc::value_option&& result, +void protocol_bitcoind_rpc::send_result(value_option&& result, size_t size_hint) NOEXCEPT { BC_ASSERT(stranded()); @@ -683,7 +683,7 @@ void protocol_bitcoind_rpc::send_result(rpc::value_option&& result, } // private -void protocol_bitcoind_rpc::send_rpc(rpc::response_t&& model, +void protocol_bitcoind_rpc::send_rpc(response_t&& model, size_t size_hint) NOEXCEPT { BC_ASSERT(stranded()); @@ -703,8 +703,8 @@ void protocol_bitcoind_rpc::send_rpc(rpc::response_t&& model, } // private -void protocol_bitcoind_rpc::set_rpc_request(rpc::version version, - const rpc::id_option& id, const http::request_cptr& request) NOEXCEPT +void protocol_bitcoind_rpc::set_rpc_request(version version, + const id_option& id, const http::request_cptr& request) NOEXCEPT { BC_ASSERT(stranded()); id_ = id; @@ -717,7 +717,7 @@ http::request_cptr protocol_bitcoind_rpc::reset_rpc_request() NOEXCEPT { BC_ASSERT(stranded()); id_.reset(); - version_ = rpc::version::undefined; + version_ = version::undefined; return reset_request(); } diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp index ce987a27..df9085f1 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc_json.cpp @@ -29,7 +29,7 @@ uint32_t protocol_bitcoind_rpc::median_time_past(const node::query& query, const database::header_link& link) NOEXCEPT { chain::context ctx{}; - return query.get_context(ctx, link) ? ctx.median_time_past : 0; + return query.get_context(ctx, link) ? ctx.median_time_past : 0_u32; } void protocol_bitcoind_rpc::inject_block_context(boost::json::object& out, @@ -95,8 +95,9 @@ boost::json::object protocol_bitcoind_rpc::header_to_bitcoind( std::string protocol_bitcoind_rpc::chain_name(const node::query& query) NOEXCEPT { - const auto genesis = query.get_header_key(query.to_confirmed(0)); + const auto genesis = query.get_header_key(query.to_confirmed(zero)); + // TODO: create signet chain selector. using selection = chain::selection; constexpr auto signet = base16_hash( "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"); From 6e6843b7054bf4aa04d54a42f94769a66f94db2d Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 00:59:40 -0400 Subject: [PATCH 5/8] Parameter/integrity validation, style, comments. --- src/parsers/bitcoind_target.cpp | 2 +- .../bitcoind/protocol_bitcoind_rest.cpp | 12 ++-- .../bitcoind/protocol_bitcoind_rpc.cpp | 72 ++++++++++++------- 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/parsers/bitcoind_target.cpp b/src/parsers/bitcoind_target.cpp index d0d393c0..7b91bb72 100644 --- a/src/parsers/bitcoind_target.cpp +++ b/src/parsers/bitcoind_target.cpp @@ -237,7 +237,7 @@ code bitcoind_target(request_t& out, const std::string_view& path) NOEXCEPT "block_filter_headers"; params["media"] = media; params["hash"] = hash; - params["type"] = uint8_t{ 0 }; + params["type"] = 0_u8; return error::success; } diff --git a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp index 041ebbfc..e56b353d 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rest.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rest.cpp @@ -272,10 +272,9 @@ bool protocol_bitcoind_rest::handle_get_block_headers(const code& ec, return true; } - // bitcoind caps the header count at 2000. - constexpr size_t maximum = 2000; + constexpr size_t maximum_headers = 2000; constexpr auto header_size = chain::header::serialized_size(); - const auto limit = std::min(possible_wide_cast(count), maximum); + const auto limit = lesser(count, maximum_headers); const auto links = query.get_confirmed_headers(height, limit); if (links.empty()) { @@ -373,8 +372,9 @@ bool protocol_bitcoind_rest::handle_get_block_part(const code& ec, return true; } - const auto stop = std::min(ceilinged_add(offset, size), full.size()); - data_chunk part{ std::next(full.begin(), offset), std::next(full.begin(), stop) }; + const auto begin = full.begin(); + const auto stop = lesser(ceilinged_add(offset, size), full.size()); + data_chunk part{ std::next(begin, offset), std::next(begin, stop) }; switch (media) { case data: @@ -415,7 +415,7 @@ bool protocol_bitcoind_rest::handle_get_block_spent_tx_outputs(const code& ec, // Resolve every prevout spent by the block's non-coinbase transactions. chain::output_cptrs spent{}; const auto& txs = *block->transactions_ptr(); - for (size_t tx = 1; tx < txs.size(); ++tx) + for (auto tx = one; tx < txs.size(); ++tx) for (const auto& in: *txs.at(tx)->inputs_ptr()) if (const auto out = query.get_output(query.to_output(in->point()))) spent.push_back(out); diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp index bc5ebc9d..839606d7 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp @@ -196,11 +196,18 @@ bool protocol_bitcoind_rpc::handle_get_block(const code& ec, return true; } + size_t level{}; + if (!to_integer(level, verbosity)) + { + send_error(error::invalid_argument); + return true; + } + constexpr auto witness = true; const auto& query = archive(); const auto link = query.to_header(hash); - if (verbosity == 0.0) + if (level == zero) { const auto block = query.get_block(link, witness); if (!block) @@ -213,7 +220,7 @@ bool protocol_bitcoind_rpc::handle_get_block(const code& ec, return true; } - if (verbosity == 1.0 || verbosity == 2.0) + if (level == one || level == two) { const auto block = query.get_block(link, witness); if (!block) @@ -222,8 +229,9 @@ bool protocol_bitcoind_rpc::handle_get_block(const code& ec, return true; } + // TODO: map "level/verbosity" to enumeration and remove comments. // verbosity 1 lists txids; verbosity 2 embeds full tx objects. - auto model = (verbosity == 1.0) ? + auto model = is_one(level) ? value_from(bitcoind_hashed(*block)) : value_from(bitcoind_verbose(*block)); @@ -253,6 +261,7 @@ bool protocol_bitcoind_rpc::handle_get_block_chain_info(const code& ec, return true; } + // TODO: make utility method and move explanation there. // verificationprogress is approximated as confirmed/candidate height, the // best available estimate of the chain tip during sync (1.0 once current). const auto progress = is_zero(headers) ? 1.0 : @@ -286,8 +295,8 @@ bool protocol_bitcoind_rpc::handle_get_block_count(const code& ec, if (stopped(ec)) return false; - send_result(rpc::value_t(possible_wide_cast( - archive().get_top_confirmed())), 20); + const auto top = archive().get_top_confirmed(); + send_result(possible_wide_cast(top), 20); return true; } @@ -336,14 +345,15 @@ bool protocol_bitcoind_rpc::handle_get_block_hash(const code& ec, if (stopped(ec)) return false; - if (height < 0.0) + size_t block_height{}; + if (!to_integer(block_height, height)) { send_error(error::invalid_argument); return true; } const auto& query = archive(); - const auto link = query.to_confirmed(static_cast(height)); + const auto link = query.to_confirmed(block_height); if (link.is_terminal()) { send_error(error::not_found); @@ -421,45 +431,57 @@ bool protocol_bitcoind_rpc::handle_get_tx_out(const code& ec, if (stopped(ec)) return false; + uint32_t index{}; hash_digest hash{}; - if (!decode_hash(hash, txid) || n < 0.0) + if (!decode_hash(hash, txid) || !to_integer(index, n)) { send_error(error::invalid_argument); return true; } const auto& query = archive(); - const auto index = static_cast(n); - const auto output_fk = query.to_output(hash, index); + const auto output_link = query.to_output(hash, index); - // Core returns json null for a missing or spent output (mempool ignored). - if (output_fk.is_terminal() || query.is_spent(output_fk)) + // TODO: is this meant to be query.is_confirmed_spent(output_link)? + // bitcoind returns json null for missing or spent output (mempool ignored). + if (output_link.is_terminal() || query.is_spent(output_link)) { send_result({}, 42); return true; } - const auto output = query.get_output(output_fk); + const auto output = query.get_output(output_link); if (!output) { send_result({}, 42); return true; } - const auto tx_fk = query.to_tx(hash); - size_t tx_height{}; - const auto have_height = query.get_tx_height(tx_height, tx_fk); + // Output's tx must exist. + const auto tx_link = query.to_tx(hash); + if (tx_link.is_terminal()) + { + send_error(error::server_error); + return true; + } + + // Derive header from top for consistent depth result (also cheaper). const auto top = query.get_top_confirmed(); + const auto header_link = query.to_confirmed(top); + + size_t height{}; + const auto strong = query.get_tx_height(height, tx_link); + const auto depth = strong ? add1(floored_subtract(top, height)) : 0_size; + const auto coins = to_floating(output->value()) / + chain::satoshi_per_bitcoin; send_result(object_t { - { "bestblock", encode_hash(query.get_top_confirmed_hash()) }, - { "confirmations", have_height ? - possible_sign_cast(add1(floored_subtract(top, tx_height))) : - 0_i64 }, - { "value", static_cast(output->value()) / 100000000.0 }, + { "bestblock", encode_hash(query.get_header_key(header_link)) }, + { "confirmations", depth }, + { "value", coins }, { "scriptPubKey", value_from(bitcoind(output->script())) }, - { "coinbase", query.is_coinbase(tx_fk) } + { "coinbase", query.is_coinbase(tx_link) } }, 256); return true; } @@ -519,9 +541,10 @@ bool protocol_bitcoind_rpc::handle_get_network_info(const code& ec, if (stopped(ec)) return false; + // TODO: get most of these values from either config or network/node props. + // libbitcoin-server is a node, not a wallet/peer-introspection service; // peer-dependent fields (connections, addresses) are reported as empty. - // TODO: surface live connection count and relay fee from node settings. send_result(object_t { { "version", 0 }, @@ -568,6 +591,7 @@ bool protocol_bitcoind_rpc::handle_get_raw_transaction(const code& ec, return true; } + // TODO: can verbose be validated, to_integer()? if (verbose == 0.0) { send_text(to_text(*tx, tx->serialized_size(witness), witness)); @@ -597,7 +621,7 @@ bool protocol_bitcoind_rpc::handle_send_raw_transaction(const code& ec, return true; } - const auto tx = std::make_shared(data, true); + const auto tx = to_shared(data, true); if (!tx->is_valid()) { send_error(error::invalid_argument); From 34738973709f1d5870c219eaee067ed85d6ff08c Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 01:01:05 -0400 Subject: [PATCH 6/8] Fox tx submission - validate and broadcast (no store). --- .../protocols/protocol_bitcoind_rpc.hpp | 5 + .../bitcoind/protocol_bitcoind_rpc.cpp | 108 ++++++++++++++---- 2 files changed, 89 insertions(+), 24 deletions(-) diff --git a/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp b/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp index c16feb48..6cbfbb16 100644 --- a/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp +++ b/include/bitcoin/server/protocols/protocol_bitcoind_rpc.hpp @@ -147,6 +147,11 @@ class BCS_API protocol_bitcoind_rpc const network::rpc::id_option& id, const network::http::request_cptr& request) NOEXCEPT; + // Validate a transaction given next block context. + bool get_pool_context(system::chain::context& pool) const NOEXCEPT; + code validate_tx(const system::chain::transaction& tx) const NOEXCEPT; + code broadcast_tx(const system::chain::transaction::cptr& tx) NOEXCEPT; + // Obtain cached request and clear cache (requires strand). network::http::request_cptr reset_rpc_request() NOEXCEPT; diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp index 839606d7..4105eced 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp @@ -628,32 +628,40 @@ bool protocol_bitcoind_rpc::handle_send_raw_transaction(const code& ec, return true; } - auto& query = archive(); - const auto txid = tx->hash(false); - - // Archive (so the out-relay can serve getdata) only if not already known. - // TODO: contextual validation (populate_with_metadata + connect) for policy. - if (query.to_tx(txid).is_terminal()) - { - if (tx->check()) - { - send_error(error::invalid_argument); - return true; - } - - if (query.set_code(*tx)) - { - send_error(database::error::integrity); - return true; - } + // Tx archive not allowed in in v4, must move through node::tx_chaser (v5). + ////auto& query = archive(); + ////const auto hash = tx->hash(false); + //// + ////// Archive (so the out-relay can serve getdata) only if not already known. + ////// TODO: contextual validation (populate_with_metadata + connect) for policy. + ////if (query.to_tx(hash).is_terminal()) + ////{ + //// if (tx->check()) + //// { + //// send_error(error::invalid_argument); + //// return true; + //// } + //// + //// if (query.set_code(*tx)) + //// { + //// send_error(database::error::integrity); + //// return true; + //// } + ////} + + // Full validation (TODO above) handled in broadcast_tx() below. + ////// Announce to peers; protocol_transaction_out_106 serves the tx on getdata. + ////broadcast( + //// std::make_shared( + //// messages::peer::transaction{ tx })); + + if (const auto fault = broadcast_tx(tx); fault) + { + send_error(fault); + return true; } - // Announce to peers; protocol_transaction_out_106 serves the tx on getdata. - broadcast( - std::make_shared( - messages::peer::transaction{ tx })); - - send_result(encode_hash(txid), two * system::hash_size); + send_result(encode_hash(tx->hash(false)), two * system::hash_size); return true; } @@ -745,6 +753,58 @@ http::request_cptr protocol_bitcoind_rpc::reset_rpc_request() NOEXCEPT return reset_request(); } +// utility (redundant with protocol_electrum) +// ---------------------------------------------------------------------------- +// TODO: move this to node utility and pass through. + +bool protocol_bitcoind_rpc::get_pool_context(chain::context& pool) const NOEXCEPT +{ + const auto& query = archive(); + const auto& settings = system_settings(); + const auto top = query.get_top_confirmed(); + const auto link = query.to_confirmed(top); + const auto hash = query.get_header_key(link); + const auto state = query.get_chain_state(settings, hash); + if (!state) return false; + pool = chain::chain_state(*state, settings).context(); + return true; +} + +code protocol_bitcoind_rpc::validate_tx( + const chain::transaction& tx) const NOEXCEPT +{ + chain::context ctx{}; + if (!get_pool_context(ctx)) + return error::server_error; + + code ec{}; + + // Ensure tx does not violate tx consensus rules. + if (!ec) ec = tx.check(); + if (!ec) ec = tx.check(ctx); + if (!ec) archive().populate_with_metadata(tx, true); + if (!ec) ec = tx.accept(ctx); + if (!ec) ec = tx.confirm(ctx); + if (!ec) ec = tx.connect(ctx); + + // Ensure tx does not violate presumed block consensus rules. + // This is a DoS guard when validating a tx outside of a block. + if (!ec) ec = tx.check_guard(); + if (!ec) ec = tx.check_guard(ctx); + if (!ec) ec = tx.accept_guard(ctx); + return ec; +} + +code protocol_bitcoind_rpc::broadcast_tx( + const chain::transaction::cptr& tx) NOEXCEPT +{ + if (const auto ec = validate_tx(*tx)) + return ec; + + BROADCAST(peer::transaction, to_shared(tx)); + return {}; +} + BC_POP_WARNING() BC_POP_WARNING() BC_POP_WARNING() From 39ea38bd172c7bb5876fcee8c51f149423a28734 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 00:43:24 -0400 Subject: [PATCH 7/8] Electrum comment. --- src/protocols/electrum/protocol_electrum_transactions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/electrum/protocol_electrum_transactions.cpp b/src/protocols/electrum/protocol_electrum_transactions.cpp index 303abd1a..2b3ebf31 100644 --- a/src/protocols/electrum/protocol_electrum_transactions.cpp +++ b/src/protocols/electrum/protocol_electrum_transactions.cpp @@ -385,7 +385,7 @@ void protocol_electrum::handle_blockchain_transaction_id_from_position( }, two * hash_size * add1(branch.size())); } -// utility +// utility (redundant with protocol_bitcoind_rpc) // ---------------------------------------------------------------------------- // TODO: move this to node utility and pass through. From 3d96544c5229f72d5637e692a928c80611be2605 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 19 Jun 2026 01:01:21 -0400 Subject: [PATCH 8/8] Adapt to upstream (node) change. --- src/protocols/bitcoind/protocol_bitcoind_rpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp index 4105eced..ec1256af 100644 --- a/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind_rpc.cpp @@ -282,7 +282,7 @@ bool protocol_bitcoind_rpc::handle_get_block_chain_info(const code& ec, { "time", header->timestamp() }, { "mediantime", median_time_past(query, link) }, { "verificationprogress", progress }, - { "initialblockdownload", !is_current(true) }, + { "initialblockdownload", !is_current_chain(true) }, { "pruned", false }, { "warnings", std::string{} } }, 512);