diff --git a/Makefile.am b/Makefile.am
index 25dd320b..e412f114 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -87,6 +87,7 @@ console_bs_SOURCES = \
console/executor.cpp \
console/executor.hpp \
console/executor_commands.cpp \
+ console/executor_daemon.cpp \
console/executor_dumps.cpp \
console/executor_events.cpp \
console/executor_logging.cpp \
diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt
index cbd650dd..29f614fa 100644
--- a/builds/cmake/CMakeLists.txt
+++ b/builds/cmake/CMakeLists.txt
@@ -325,6 +325,7 @@ if (with-console)
"../../console/executor.cpp"
"../../console/executor.hpp"
"../../console/executor_commands.cpp"
+ "../../console/executor_daemon.cpp"
"../../console/executor_dumps.cpp"
"../../console/executor_events.cpp"
"../../console/executor_logging.cpp"
diff --git a/builds/msvc/vs2022/bs/bs.vcxproj b/builds/msvc/vs2022/bs/bs.vcxproj
index 90aa552c..ec650ba2 100644
--- a/builds/msvc/vs2022/bs/bs.vcxproj
+++ b/builds/msvc/vs2022/bs/bs.vcxproj
@@ -132,6 +132,7 @@
$(IntDir)console_executor.obj
+
diff --git a/builds/msvc/vs2022/bs/bs.vcxproj.filters b/builds/msvc/vs2022/bs/bs.vcxproj.filters
index 2de592cb..485c2957 100644
--- a/builds/msvc/vs2022/bs/bs.vcxproj.filters
+++ b/builds/msvc/vs2022/bs/bs.vcxproj.filters
@@ -54,6 +54,9 @@
src
+
+ src
+
src
diff --git a/console/executor_daemon.cpp b/console/executor_daemon.cpp
new file mode 100644
index 00000000..fe1ab520
--- /dev/null
+++ b/console/executor_daemon.cpp
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2011-2025 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 "executor.hpp"
+
+namespace libbitcoin {
+namespace server {
+
+} // namespace server
+} // namespace libbitcoin
diff --git a/console/executor_signals.cpp b/console/executor_signals.cpp
index 01d75e1a..d4484fb4 100644
--- a/console/executor_signals.cpp
+++ b/console/executor_signals.cpp
@@ -62,7 +62,7 @@ void executor::set_signal_handlers()
#if defined(HAVE_MSC)
::SetConsoleCtrlHandler(&executor::control_handler, TRUE);
#else
- // struct keywork avoids name conflict with posix function sigaction.
+ // struct keyword avoids name conflict with posix function sigaction.
struct sigaction action{};
// Restart interrupted system calls.
diff --git a/console/main.cpp b/console/main.cpp
index e6a2549d..fda989e3 100644
--- a/console/main.cpp
+++ b/console/main.cpp
@@ -78,10 +78,8 @@ BC_USE_LIBBITCOIN_MAIN
/// All console input and output streams for the application originate here.
int bc::system::main(int argc, char* argv[])
{
- using namespace bc;
using namespace bc::system;
using namespace bc::network;
- using namespace bc::node;
using namespace bc::server;
// en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio
diff --git a/include/bitcoin/server/interfaces/bitcoind_rpc.hpp b/include/bitcoin/server/interfaces/bitcoind_rpc.hpp
index 37fa625e..e9397551 100644
--- a/include/bitcoin/server/interfaces/bitcoind_rpc.hpp
+++ b/include/bitcoin/server/interfaces/bitcoind_rpc.hpp
@@ -126,7 +126,7 @@ struct bitcoind_rpc_methods
////method<"listreceivedbyaddress", optional<1>, optional, optional, optional<""_t>>{ "minconf", "include_empty", "include_watchonly", "address_filter" },
////method<"listreceivedbylabel", optional<1>, optional, optional>{ "minconf", "include_empty", "include_watchonly" },
////method<"listtransactions", optional<""_t>, optional<10>, optional<0>, optional>{ "label", "count", "skip", "include_watchonly" },
- ////method<"listunspent", optional<1>, optional, optional, optional>{ "minconf", "addresses", "include_unsafe", "query_options" },
+ ////method<"list_unspent", optional<1>, optional, optional, optional>{ "minconf", "addresses", "include_unsafe", "query_options" },
////method<"loadwallet", string_t, optional>{ "filename", "load_on_startup" },
////method<"lockunspent", boolean_t, optional>{ "unlock", "transactions" },
////method<"removeprunedfunds", string_t>{ "txid" },
diff --git a/include/bitcoin/server/interfaces/electrum.hpp b/include/bitcoin/server/interfaces/electrum.hpp
index 375d47d2..c262f3b0 100644
--- a/include/bitcoin/server/interfaces/electrum.hpp
+++ b/include/bitcoin/server/interfaces/electrum.hpp
@@ -35,12 +35,12 @@ struct electrum_methods
method<"blockchain.block.header", number_t, number_t>{ "height", "cp_height" },
method<"blockchain.block.headers", number_t, number_t, number_t>{ "start_height", "count", "cp_height" },
method<"blockchain.headers.subscribe">{},
- method<"blockchain.estimatefee", number_t>{ "number" },
+ method<"blockchain.estimatefee", number_t, optional<""_t>>{ "number", "mode" },
method<"blockchain.relayfee">{},
method<"blockchain.scripthash.get_balance", string_t>{ "scripthash" },
method<"blockchain.scripthash.get_history", string_t>{ "scripthash" },
method<"blockchain.scripthash.get_mempool", string_t>{ "scripthash" },
- method<"blockchain.scripthash.listunspent", string_t>{ "scripthash" },
+ method<"blockchain.scripthash.list_unspent", string_t>{ "scripthash" },
method<"blockchain.scripthash.subscribe", string_t>{ "scripthash" },
method<"blockchain.scripthash.unsubscribe", string_t>{ "scripthash" },
method<"blockchain.transaction.broadcast", string_t>{ "raw_tx" },
@@ -71,12 +71,12 @@ struct electrum_methods
using blockchain_block_header = at<0>;
using blockchain_block_headers = at<1>;
using blockchain_headers_subscribe = at<2>;
- using blockchain_estimatefee = at<3>;
- using blockchain_relayfee = at<4>;
+ using blockchain_estimate_fee = at<3>;
+ using blockchain_relay_fee = at<4>;
using blockchain_scripthash_get_balance = at<5>;
using blockchain_scripthash_get_history = at<6>;
using blockchain_scripthash_get_mempool = at<7>;
- using blockchain_scripthash_listunspent = at<8>;
+ using blockchain_scripthash_list_unspent = at<8>;
using blockchain_scripthash_subscribe = at<9>;
using blockchain_scripthash_unsubscribe = at<10>;
using blockchain_transaction_broadcast = at<11>;
diff --git a/include/bitcoin/server/protocols/protocol_electrum.hpp b/include/bitcoin/server/protocols/protocol_electrum.hpp
index 9ba9df98..bae5e85c 100644
--- a/include/bitcoin/server/protocols/protocol_electrum.hpp
+++ b/include/bitcoin/server/protocols/protocol_electrum.hpp
@@ -59,10 +59,11 @@ class BCS_API protocol_electrum
double count, double cp_height) NOEXCEPT;
void handle_blockchain_headers_subscribe(const code& ec,
rpc_interface::blockchain_headers_subscribe) NOEXCEPT;
- void handle_blockchain_estimatefee(const code& ec,
- rpc_interface::blockchain_estimatefee, double) NOEXCEPT;
- void handle_blockchain_relayfee(const code& ec,
- rpc_interface::blockchain_relayfee) NOEXCEPT;
+ void handle_blockchain_estimate_fee(const code& ec,
+ rpc_interface::blockchain_estimate_fee, double number,
+ const std::string& mode) NOEXCEPT;
+ void handle_blockchain_relay_fee(const code& ec,
+ rpc_interface::blockchain_relay_fee) NOEXCEPT;
void handle_blockchain_scripthash_get_balance(const code& ec,
rpc_interface::blockchain_scripthash_get_balance,
const std::string& scripthash) NOEXCEPT;
@@ -72,8 +73,8 @@ class BCS_API protocol_electrum
void handle_blockchain_scripthash_get_mempool(const code& ec,
rpc_interface::blockchain_scripthash_get_mempool,
const std::string& scripthash) NOEXCEPT;
- void handle_blockchain_scripthash_listunspent(const code& ec,
- rpc_interface::blockchain_scripthash_listunspent,
+ void handle_blockchain_scripthash_list_unspent(const code& ec,
+ rpc_interface::blockchain_scripthash_list_unspent,
const std::string& scripthash) NOEXCEPT;
void handle_blockchain_scripthash_subscribe(const code& ec,
rpc_interface::blockchain_scripthash_subscribe,
diff --git a/include/bitcoin/server/protocols/protocol_electrum_version.hpp b/include/bitcoin/server/protocols/protocol_electrum_version.hpp
index 88fe245a..ba38af6c 100644
--- a/include/bitcoin/server/protocols/protocol_electrum_version.hpp
+++ b/include/bitcoin/server/protocols/protocol_electrum_version.hpp
@@ -48,7 +48,7 @@ class BCS_API protocol_electrum_version
}
virtual void shake(network::result_handler&& handler) NOEXCEPT;
- virtual void complete(const code& ec, const code& shake) NOEXCEPT;
+ virtual void finished(const code& ec, const code& shake) NOEXCEPT;
protected:
static constexpr electrum_version minimum = electrum_version::v1_4;
diff --git a/src/parsers/native_query.cpp b/src/parsers/native_query.cpp
index 1cb3dcf6..765e711a 100644
--- a/src/parsers/native_query.cpp
+++ b/src/parsers/native_query.cpp
@@ -128,6 +128,8 @@ media_type get_media(const rpc::request_t& model) NOEXCEPT
case media_type::application_json:
case media_type::application_octet_stream:
return value;
+ default:
+ return media_type::unknown;
}
}
}
diff --git a/src/protocols/protocol_electrum.cpp b/src/protocols/protocol_electrum.cpp
index fd3ebe47..4f6a5907 100644
--- a/src/protocols/protocol_electrum.cpp
+++ b/src/protocols/protocol_electrum.cpp
@@ -29,6 +29,7 @@ namespace server {
#define CLASS protocol_electrum
+using namespace system;
using namespace interface;
using namespace std::placeholders;
@@ -50,12 +51,12 @@ void protocol_electrum::start() NOEXCEPT
SUBSCRIBE_RPC(handle_blockchain_block_header, _1, _2, _3, _4);
SUBSCRIBE_RPC(handle_blockchain_block_headers, _1, _2, _3, _4, _5);
SUBSCRIBE_RPC(handle_blockchain_headers_subscribe, _1, _2);
- SUBSCRIBE_RPC(handle_blockchain_estimatefee, _1, _2, _3);
- SUBSCRIBE_RPC(handle_blockchain_relayfee, _1, _2);
+ SUBSCRIBE_RPC(handle_blockchain_estimate_fee, _1, _2, _3, _4);
+ SUBSCRIBE_RPC(handle_blockchain_relay_fee, _1, _2);
SUBSCRIBE_RPC(handle_blockchain_scripthash_get_balance, _1, _2, _3);
SUBSCRIBE_RPC(handle_blockchain_scripthash_get_history, _1, _2, _3);
SUBSCRIBE_RPC(handle_blockchain_scripthash_get_mempool, _1, _2, _3);
- SUBSCRIBE_RPC(handle_blockchain_scripthash_listunspent, _1, _2, _3);
+ SUBSCRIBE_RPC(handle_blockchain_scripthash_list_unspent, _1, _2, _3);
SUBSCRIBE_RPC(handle_blockchain_scripthash_subscribe, _1, _2, _3);
SUBSCRIBE_RPC(handle_blockchain_scripthash_unsubscribe, _1, _2, _3);
SUBSCRIBE_RPC(handle_blockchain_transaction_broadcast, _1, _2, _3);
@@ -99,22 +100,60 @@ void protocol_electrum::handle_blockchain_block_headers(const code& ec,
void protocol_electrum::handle_blockchain_headers_subscribe(const code& ec,
rpc_interface::blockchain_headers_subscribe) NOEXCEPT
{
- if (stopped(ec)) return;
- send_code(error::not_implemented);
+ if (stopped(ec))
+ return;
+
+ const auto& query = archive();
+ const auto link = query.to_header(query.get_top_confirmed_hash());
+ const auto height = query.get_height(link);
+ const auto header = query.get_header(link);
+ if (height.is_terminal() || !header)
+ {
+ send_code(error::not_found);
+ return;
+ }
+
+ // See protocol_native::to_hex().
+ std::string hex(two * chain::header::serialized_size(), '\0');
+ stream::out::fast sink{ hex };
+ write::base16::fast writer{ sink };
+ header->to_data(writer);
+ BC_ASSERT(writer);
+
+ // TODO: idempotent subscribe to chase::organized via session/chaser/node.
+ // TODO: upon notification send just the header notified by the link.
+ // TODO: it is client responsibility to deal with reorgs and race gaps.
+ send_result(value_t
+ {
+ object_t
+ {
+ { "height", height.value },
+ { "hex", hex }
+ }
+ }, 256, BIND(complete, _1));
}
-void protocol_electrum::handle_blockchain_estimatefee(const code& ec,
- rpc_interface::blockchain_estimatefee, double ) NOEXCEPT
+void protocol_electrum::handle_blockchain_estimate_fee(const code& ec,
+ rpc_interface::blockchain_estimate_fee, double number,
+ const std::string& ) NOEXCEPT
{
- if (stopped(ec)) return;
- send_code(error::not_implemented);
+ if (stopped(ec))
+ return;
+
+ // TODO: estimate fees from blocks based on expected block inclusion.
+ // TODO: this can be computed from recent blocks and cached by the server.
+ // TODO: update the cache before broadcasting header notifications.
+ send_result(number, 70, BIND(complete, _1));
}
-void protocol_electrum::handle_blockchain_relayfee(const code& ec,
- rpc_interface::blockchain_relayfee) NOEXCEPT
+void protocol_electrum::handle_blockchain_relay_fee(const code& ec,
+ rpc_interface::blockchain_relay_fee) NOEXCEPT
{
- if (stopped(ec)) return;
- send_code(error::not_implemented);
+ if (stopped(ec))
+ return;
+
+ // TODO: implement from [node] config, removed in protocol 1.6.
+ send_result(0.00000001, 70, BIND(complete, _1));
}
void protocol_electrum::handle_blockchain_scripthash_get_balance(const code& ec,
@@ -141,8 +180,8 @@ void protocol_electrum::handle_blockchain_scripthash_get_mempool(const code& ec,
send_code(error::not_implemented);
}
-void protocol_electrum::handle_blockchain_scripthash_listunspent(const code& ec,
- rpc_interface::blockchain_scripthash_listunspent,
+void protocol_electrum::handle_blockchain_scripthash_list_unspent(const code& ec,
+ rpc_interface::blockchain_scripthash_list_unspent,
const std::string& ) NOEXCEPT
{
if (stopped(ec)) return;
@@ -210,8 +249,10 @@ void protocol_electrum::handle_server_add_peer(const code& ec,
void protocol_electrum::handle_server_banner(const code& ec,
rpc_interface::server_banner) NOEXCEPT
{
- if (stopped(ec)) return;
- send_code(error::not_implemented);
+ if (stopped(ec))
+ return;
+
+ send_result(network_settings().user_agent, 70, BIND(complete, _1));
}
void protocol_electrum::handle_server_donation_address(const code& ec,
@@ -248,8 +289,19 @@ void protocol_electrum::handle_server_ping(const code& ec,
void protocol_electrum::handle_mempool_get_fee_histogram(const code& ec,
rpc_interface::mempool_get_fee_histogram) NOEXCEPT
{
- if (stopped(ec)) return;
- send_code(error::not_implemented);
+ if (stopped(ec))
+ return;
+
+ // TODO: requires tx pool metadata graph.
+ send_result(value_t
+ {
+ array_t
+ {
+ array_t{ 1, 1024 },
+ array_t{ 2, 2048 },
+ array_t{ 4, 4096 }
+ }
+ }, 256, BIND(complete, _1));
}
BC_POP_WARNING()
diff --git a/src/protocols/protocol_electrum_version.cpp b/src/protocols/protocol_electrum_version.cpp
index e3be7dfa..f7d966fb 100644
--- a/src/protocols/protocol_electrum_version.cpp
+++ b/src/protocols/protocol_electrum_version.cpp
@@ -38,7 +38,7 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
-// Start/complete (handshake).
+// Start/finished (handshake).
// ----------------------------------------------------------------------------
// Session resumes the channel following return from start().
@@ -59,7 +59,7 @@ void protocol_electrum_version::shake(result_handler&& handler) NOEXCEPT
protocol_rpc::start();
}
-void protocol_electrum_version::complete(const code& ec,
+void protocol_electrum_version::finished(const code& ec,
const code& shake) NOEXCEPT
{
BC_ASSERT(stranded());
@@ -92,7 +92,7 @@ void protocol_electrum_version::handle_server_version(const code& ec,
(!set_client(client_name) || !set_version(protocol_version)))
{
const auto reason = error::invalid_argument;
- send_code(reason, BIND(complete, _1, reason));
+ send_code(reason, BIND(finished, _1, reason));
}
else
{
@@ -103,7 +103,7 @@ void protocol_electrum_version::handle_server_version(const code& ec,
{ string_t{ server_name() } },
{ string_t{ negotiated_version() } }
}
- }, 70, BIND(complete, _1, error::success));
+ }, 70, BIND(finished, _1, error::success));
}
// Handshake must leave channel paused, before leaving stranded handler.
@@ -225,6 +225,7 @@ std::string_view protocol_electrum_version::version_to_string(
{
static const std::unordered_map map
{
+ { electrum_version::v0_0, "0.0" },
{ electrum_version::v0_6, "0.6" },
{ electrum_version::v0_8, "0.8" },
{ electrum_version::v0_9, "0.9" },
@@ -236,8 +237,7 @@ std::string_view protocol_electrum_version::version_to_string(
{ electrum_version::v1_4, "1.4" },
{ electrum_version::v1_4_1, "1.4.1" },
{ electrum_version::v1_4_2, "1.4.2" },
- { electrum_version::v1_6, "1.6" },
- { electrum_version::v0_0, "0.0" }
+ { electrum_version::v1_6, "1.6" }
};
const auto it = map.find(version);
@@ -250,6 +250,7 @@ electrum_version protocol_electrum_version::version_from_string(
{
static const std::unordered_map map
{
+ { "0.0", electrum_version::v0_0 },
{ "0.6", electrum_version::v0_6 },
{ "0.8", electrum_version::v0_8 },
{ "0.9", electrum_version::v0_9 },
@@ -261,8 +262,7 @@ electrum_version protocol_electrum_version::version_from_string(
{ "1.4", electrum_version::v1_4 },
{ "1.4.1", electrum_version::v1_4_1 },
{ "1.4.2", electrum_version::v1_4_2 },
- { "1.6", electrum_version::v1_6 },
- { "0.0", electrum_version::v0_0 }
+ { "1.6", electrum_version::v1_6 }
};
const auto it = map.find(version);
diff --git a/src/protocols/protocol_native.cpp b/src/protocols/protocol_native.cpp
index 50804433..6631d333 100644
--- a/src/protocols/protocol_native.cpp
+++ b/src/protocols/protocol_native.cpp
@@ -139,7 +139,7 @@ bool protocol_native::try_dispatch_object(const http::request& request) NOEXCEPT
// Serialization.
// ----------------------------------------------------------------------------
-constexpr auto html = to_value(http::media_type::text_html);
+////constexpr auto html = to_value(http::media_type::text_html);
constexpr auto text = to_value(http::media_type::text_plain);
constexpr auto json = to_value(http::media_type::application_json);
constexpr auto data = to_value(http::media_type::application_octet_stream);