diff --git a/include/bitcoin/node/interfaces/electrum.hpp b/include/bitcoin/node/interfaces/electrum.hpp index b1463da8..4994e0bf 100644 --- a/include/bitcoin/node/interfaces/electrum.hpp +++ b/include/bitcoin/node/interfaces/electrum.hpp @@ -28,13 +28,14 @@ namespace interface { struct electrum_methods { + /// Electrum protocol version 1.4.2 static constexpr std::tuple methods { /// Blockchain methods. - method<"blockchain.block.header", number_t, optional<0.0>>{ "height", "cp_height" }, - method<"blockchain.block.headers", number_t, number_t, optional<0.0>>{ "start_height", "count", "cp_height" }, - method<"blockchain.estimatefee", number_t>{ "number" }, + 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.relayfee">{}, method<"blockchain.scripthash.get_balance", string_t>{ "scripthash" }, method<"blockchain.scripthash.get_history", string_t>{ "scripthash" }, @@ -43,9 +44,9 @@ struct electrum_methods method<"blockchain.scripthash.subscribe", string_t>{ "scripthash" }, method<"blockchain.scripthash.unsubscribe", string_t>{ "scripthash" }, method<"blockchain.transaction.broadcast", string_t>{ "raw_tx" }, - method<"blockchain.transaction.get", string_t, optional>{ "tx_hash", "verbose" }, + method<"blockchain.transaction.get", string_t, boolean_t>{ "tx_hash", "verbose" }, method<"blockchain.transaction.get_merkle", string_t, number_t>{ "tx_hash", "height" }, - method<"blockchain.transaction.id_from_pos", number_t, number_t, optional>{ "height", "tx_pos", "merkle" }, + method<"blockchain.transaction.id_from_pos", number_t, number_t, boolean_t>{ "height", "tx_pos", "merkle" }, /// Server methods. method<"server.add_peer", object_t>{ "features" }, @@ -54,7 +55,10 @@ struct electrum_methods method<"server.features">{}, method<"server.peers.subscribe">{}, method<"server.ping">{}, - method<"server.version", optional<""_t>, optional<"1.4"_t>>{ "client_name", "protocol_version" } + method<"server.version", string_t, value_t>{ "client_name", "protocol_version" }, + + /// Mempool methods. + method<"mempool.get_fee_histogram">{} }; template @@ -66,8 +70,8 @@ struct electrum_methods // Derive this from above in c++26 using reflection. using blockchain_block_header = at<0>; using blockchain_block_headers = at<1>; - using blockchain_estimatefee = at<2>; - using blockchain_headers_subscribe = at<3>; + using blockchain_headers_subscribe = at<2>; + using blockchain_estimatefee = at<3>; using blockchain_relayfee = at<4>; using blockchain_scripthash_get_balance = at<5>; using blockchain_scripthash_get_history = at<6>; @@ -86,6 +90,7 @@ struct electrum_methods using server_peers_subscribe = at<19>; using server_ping = at<20>; using server_version = at<21>; + using mempool_get_fee_histogram = at<22>; }; } // namespace interface diff --git a/include/bitcoin/node/interfaces/types.hpp b/include/bitcoin/node/interfaces/types.hpp index 855ba89b..c887479e 100644 --- a/include/bitcoin/node/interfaces/types.hpp +++ b/include/bitcoin/node/interfaces/types.hpp @@ -44,9 +44,11 @@ using string_t = network::rpc::string_t; using number_t = network::rpc::number_t; using object_t = network::rpc::object_t; using array_t = network::rpc::array_t; +using value_t = network::rpc::value_t; namespace empty { constexpr auto array = network::rpc::empty::array; }; namespace empty { constexpr auto object = network::rpc::empty::object; }; +namespace empty { constexpr auto value = network::rpc::empty::value; }; } // namespace interface } // namespace node diff --git a/include/bitcoin/node/protocols/protocol_electrum.hpp b/include/bitcoin/node/protocols/protocol_electrum.hpp index f25bcf0b..d4c96e86 100644 --- a/include/bitcoin/node/protocols/protocol_electrum.hpp +++ b/include/bitcoin/node/protocols/protocol_electrum.hpp @@ -47,11 +47,71 @@ class BCN_API protocol_electrum void start() NOEXCEPT override; protected: - /// Handlers. + /// Handlers (blockchain). + bool handle_blockchain_block_header(const code& ec, + rpc_interface::blockchain_block_header, double height, + double cp_height) NOEXCEPT; + bool handle_blockchain_block_headers(const code& ec, + rpc_interface::blockchain_block_headers, double start_height, + double count, double cp_height) NOEXCEPT; bool handle_blockchain_headers_subscribe(const code& ec, rpc_interface::blockchain_headers_subscribe) NOEXCEPT; + bool handle_blockchain_estimatefee(const code& ec, + rpc_interface::blockchain_estimatefee, double) NOEXCEPT; bool handle_blockchain_relayfee(const code& ec, rpc_interface::blockchain_relayfee) NOEXCEPT; + bool handle_blockchain_scripthash_get_balance(const code& ec, + rpc_interface::blockchain_scripthash_get_balance, + const std::string& scripthash) NOEXCEPT; + bool handle_blockchain_scripthash_get_history(const code& ec, + rpc_interface::blockchain_scripthash_get_history, + const std::string& scripthash) NOEXCEPT; + bool handle_blockchain_scripthash_get_mempool(const code& ec, + rpc_interface::blockchain_scripthash_get_mempool, + const std::string& scripthash) NOEXCEPT; + bool handle_blockchain_scripthash_listunspent(const code& ec, + rpc_interface::blockchain_scripthash_listunspent, + const std::string& scripthash) NOEXCEPT; + bool handle_blockchain_scripthash_subscribe(const code& ec, + rpc_interface::blockchain_scripthash_subscribe, + const std::string& scripthash) NOEXCEPT; + bool handle_blockchain_scripthash_unsubscribe(const code& ec, + rpc_interface::blockchain_scripthash_unsubscribe, + const std::string& scripthash) NOEXCEPT; + bool handle_blockchain_transaction_broadcast(const code& ec, + rpc_interface::blockchain_transaction_broadcast, + const std::string& raw_tx) NOEXCEPT; + bool handle_blockchain_transaction_get(const code& ec, + rpc_interface::blockchain_transaction_get, const std::string& tx_hash, + bool verbose) NOEXCEPT; + bool handle_blockchain_transaction_get_merkle(const code& ec, + rpc_interface::blockchain_transaction_get_merkle, + const std::string& tx_hash, double height) NOEXCEPT; + bool handle_blockchain_transaction_id_from_pos(const code& ec, + rpc_interface::blockchain_transaction_id_from_pos, double height, + double tx_pos, bool merkle) NOEXCEPT; + + /// Handlers (server). + bool handle_server_add_peer(const code& ec, + rpc_interface::server_add_peer, + const network::rpc::object_t& features) NOEXCEPT; + bool handle_server_banner(const code& ec, + rpc_interface::server_banner) NOEXCEPT; + bool handle_server_donation_address(const code& ec, + rpc_interface::server_donation_address) NOEXCEPT; + bool handle_server_features(const code& ec, + rpc_interface::server_features) NOEXCEPT; + bool handle_server_peers_subscribe(const code& ec, + rpc_interface::server_peers_subscribe) NOEXCEPT; + bool handle_server_ping(const code& ec, + rpc_interface::server_ping) NOEXCEPT; + bool handle_server_version(const code& ec, + rpc_interface::server_version, const std::string& client_name, + const network::rpc::value_t& protocol_version) NOEXCEPT; + + /// Handlers (mempool). + bool handle_mempool_get_fee_histogram(const code& ec, + rpc_interface::mempool_get_fee_histogram) NOEXCEPT; }; } // namespace node diff --git a/include/bitcoin/node/protocols/protocol_rpc.hpp b/include/bitcoin/node/protocols/protocol_rpc.hpp index f5264c0d..0720deec 100644 --- a/include/bitcoin/node/protocols/protocol_rpc.hpp +++ b/include/bitcoin/node/protocols/protocol_rpc.hpp @@ -26,7 +26,7 @@ namespace libbitcoin { namespace node { - + /// Abstract base for RPC protocols, thread safe. template class BCN_API protocol_rpc @@ -47,6 +47,10 @@ class BCN_API protocol_rpc } }; +#define SUBSCRIBE_RPC(...) SUBSCRIBE_CHANNEL(void, __VA_ARGS__) +#define SEND_RPC(message, size_hint, method, ...) \ + send(message, size_hint, &CLASS::method, __VA_ARGS__) + } // namespace node } // namespace libbitcoin diff --git a/src/protocols/protocol_bitcoind_rpc.cpp b/src/protocols/protocol_bitcoind_rpc.cpp index 92049d78..6ae0a04c 100644 --- a/src/protocols/protocol_bitcoind_rpc.cpp +++ b/src/protocols/protocol_bitcoind_rpc.cpp @@ -344,7 +344,7 @@ bool protocol_bitcoind_rpc::handle_verify_tx_out_set(const code& ec, return true; } -// Senders +// Senders. // ---------------------------------------------------------------------------- void protocol_bitcoind_rpc::send_error(const code& ec) NOEXCEPT diff --git a/src/protocols/protocol_electrum.cpp b/src/protocols/protocol_electrum.cpp index 66aa789e..1cf5d587 100644 --- a/src/protocols/protocol_electrum.cpp +++ b/src/protocols/protocol_electrum.cpp @@ -18,12 +18,14 @@ */ #include +#include + namespace libbitcoin { namespace node { #define CLASS protocol_electrum -#define SUBSCRIBE_RPC(...) SUBSCRIBE_CHANNEL(void, __VA_ARGS__) +using namespace network; using namespace std::placeholders; BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) @@ -40,26 +42,242 @@ void protocol_electrum::start() NOEXCEPT if (started()) return; + // Blockchain methods. + 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_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_subscribe, _1, _2, _3); + SUBSCRIBE_RPC(handle_blockchain_scripthash_unsubscribe, _1, _2, _3); + SUBSCRIBE_RPC(handle_blockchain_transaction_broadcast, _1, _2, _3); + SUBSCRIBE_RPC(handle_blockchain_transaction_get, _1, _2, _3, _4); + SUBSCRIBE_RPC(handle_blockchain_transaction_get_merkle, _1, _2, _3, _4); + SUBSCRIBE_RPC(handle_blockchain_transaction_id_from_pos, _1, _2, _3, _4, _5); + + // Server methods + SUBSCRIBE_RPC(handle_server_add_peer, _1, _2, _3); + SUBSCRIBE_RPC(handle_server_banner, _1, _2); + SUBSCRIBE_RPC(handle_server_donation_address, _1, _2); + SUBSCRIBE_RPC(handle_server_features, _1, _2); + SUBSCRIBE_RPC(handle_server_peers_subscribe, _1, _2); + SUBSCRIBE_RPC(handle_server_ping, _1, _2); + SUBSCRIBE_RPC(handle_server_version, _1, _2, _3, _4); + + // Mempool methods. + SUBSCRIBE_RPC(handle_mempool_get_fee_histogram, _1, _2); node::protocol_rpc::start(); } -// Handlers. +// Handlers (blockchain). // ---------------------------------------------------------------------------- +bool protocol_electrum::handle_blockchain_block_header(const code& ec, + rpc_interface::blockchain_block_header, double , + double ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_block_headers(const code& ec, + rpc_interface::blockchain_block_headers, double , + double , double ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + bool protocol_electrum::handle_blockchain_headers_subscribe(const code& ec, rpc_interface::blockchain_headers_subscribe) NOEXCEPT { - // TODO: - return !ec; + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_estimatefee(const code& ec, + rpc_interface::blockchain_estimatefee, double ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; } bool protocol_electrum::handle_blockchain_relayfee(const code& ec, rpc_interface::blockchain_relayfee) NOEXCEPT { - // TODO: - return !ec; + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_scripthash_get_balance(const code& ec, + rpc_interface::blockchain_scripthash_get_balance, + const std::string& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_scripthash_get_history(const code& ec, + rpc_interface::blockchain_scripthash_get_history, + const std::string& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_scripthash_get_mempool(const code& ec, + rpc_interface::blockchain_scripthash_get_mempool, + const std::string& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_scripthash_listunspent(const code& ec, + rpc_interface::blockchain_scripthash_listunspent, + const std::string& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_scripthash_subscribe(const code& ec, + rpc_interface::blockchain_scripthash_subscribe, + const std::string& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_scripthash_unsubscribe(const code& ec, + rpc_interface::blockchain_scripthash_unsubscribe, + const std::string& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_transaction_broadcast(const code& ec, + rpc_interface::blockchain_transaction_broadcast, + const std::string& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_transaction_get(const code& ec, + rpc_interface::blockchain_transaction_get, const std::string& , + bool ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_transaction_get_merkle(const code& ec, + rpc_interface::blockchain_transaction_get_merkle, const std::string& , + double ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_blockchain_transaction_id_from_pos(const code& ec, + rpc_interface::blockchain_transaction_id_from_pos, double , + double , bool ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +// Handlers (server). +// ---------------------------------------------------------------------------- + +bool protocol_electrum::handle_server_add_peer(const code& ec, + rpc_interface::server_add_peer, const rpc::object_t& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_server_banner(const code& ec, + rpc_interface::server_banner) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_server_donation_address(const code& ec, + rpc_interface::server_donation_address) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_server_features(const code& ec, + rpc_interface::server_features) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_server_peers_subscribe(const code& ec, + rpc_interface::server_peers_subscribe) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +bool protocol_electrum::handle_server_ping(const code& ec, + rpc_interface::server_ping) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +// value_t can be string_t or array_t of two string_t. +bool protocol_electrum::handle_server_version(const code& ec, + rpc_interface::server_version, const std::string& , + const rpc::value_t& ) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; +} + +// Handlers (mempool). +// ---------------------------------------------------------------------------- + +bool protocol_electrum::handle_mempool_get_fee_histogram(const code& ec, + rpc_interface::mempool_get_fee_histogram) NOEXCEPT +{ + if (stopped(ec)) return false; + send_error(error::not_implemented); + return true; } BC_POP_WARNING() diff --git a/src/protocols/protocol_stratum_v1.cpp b/src/protocols/protocol_stratum_v1.cpp index 833f25a4..658e94e5 100644 --- a/src/protocols/protocol_stratum_v1.cpp +++ b/src/protocols/protocol_stratum_v1.cpp @@ -18,11 +18,12 @@ */ #include +#include + namespace libbitcoin { namespace node { #define CLASS protocol_stratum_v1 -#define SUBSCRIBE_RPC(...) SUBSCRIBE_CHANNEL(void, __VA_ARGS__) using namespace std::placeholders;