diff --git a/Makefile.am b/Makefile.am
index 41a5eb6d..f4a5b222 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -199,6 +199,15 @@ include_bitcoin_node_impl_chasersdir = ${includedir}/bitcoin/node/impl/chasers
include_bitcoin_node_impl_chasers_HEADERS = \
include/bitcoin/node/impl/chasers/chaser_organize.ipp
+include_bitcoin_node_interfacesdir = ${includedir}/bitcoin/node/interfaces
+include_bitcoin_node_interfaces_HEADERS = \
+ include/bitcoin/node/interfaces/bitcoind.hpp \
+ include/bitcoin/node/interfaces/electrum.hpp \
+ include/bitcoin/node/interfaces/explore.hpp \
+ include/bitcoin/node/interfaces/interfaces.hpp \
+ include/bitcoin/node/interfaces/stratum_v1.hpp \
+ include/bitcoin/node/interfaces/stratum_v2.hpp
+
include_bitcoin_node_parsedir = ${includedir}/bitcoin/node/parse
include_bitcoin_node_parse_HEADERS = \
include/bitcoin/node/parse/parse.hpp \
diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
index 12908233..0e1641b1 100644
--- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
@@ -191,6 +191,12 @@
+
+
+
+
+
+
diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
index 225490d1..1624b90c 100644
--- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
@@ -26,19 +26,22 @@
{5FFB5F52-0772-4404-0000-00000000000B}
- {5FFB5F52-0772-4404-0000-00000000000F}
+ {5FFB5F52-0772-4404-0000-000000000001}
-
+
{5FFB5F52-0772-4404-0000-00000000000C}
-
+
{5FFB5F52-0772-4404-0000-00000000000D}
-
+
{5FFB5F52-0772-4404-0000-00000000000E}
+
+ {5FFB5F52-0772-4404-0000-00000000000F}
+
- {5FFB5F52-0772-4404-0000-000000000001}
+ {5FFB5F52-0772-4404-0000-000000000002}
{5FFB5F52-0772-4404-0000-000000000000}
@@ -266,6 +269,24 @@
include\bitcoin\node
+
+ include\bitcoin\node\interfaces
+
+
+ include\bitcoin\node\interfaces
+
+
+ include\bitcoin\node\interfaces
+
+
+ include\bitcoin\node\interfaces
+
+
+ include\bitcoin\node\interfaces
+
+
+ include\bitcoin\node\interfaces
+
include\bitcoin\node\parse
diff --git a/include/bitcoin/node.hpp b/include/bitcoin/node.hpp
index aadba788..0c67094e 100644
--- a/include/bitcoin/node.hpp
+++ b/include/bitcoin/node.hpp
@@ -45,6 +45,12 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
#include
diff --git a/include/bitcoin/node/channels/channel_tcp.hpp b/include/bitcoin/node/channels/channel_tcp.hpp
index 9af3c568..c9d1f1e2 100644
--- a/include/bitcoin/node/channels/channel_tcp.hpp
+++ b/include/bitcoin/node/channels/channel_tcp.hpp
@@ -28,6 +28,7 @@ namespace libbitcoin {
namespace node {
/// Abstract base TCP channel state for the node.
+/// This is a placeholder for electrum, bitcoind, and stratum v1/v2 channels.
class BCN_API channel_tcp
: public node::channel,
public network::channel
diff --git a/include/bitcoin/node/interfaces/bitcoind.hpp b/include/bitcoin/node/interfaces/bitcoind.hpp
new file mode 100644
index 00000000..91001136
--- /dev/null
+++ b/include/bitcoin/node/interfaces/bitcoind.hpp
@@ -0,0 +1,262 @@
+/**
+ * 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 .
+ */
+#ifndef LIBBITCOIN_NODE_INTERFACES_BITCOIND_HPP
+#define LIBBITCOIN_NODE_INTERFACES_BITCOIND_HPP
+
+#include
+
+namespace libbitcoin {
+namespace node {
+namespace interface {
+
+struct bitcoind_methods
+{
+ static constexpr std::tuple methods
+ {
+ /// Blockchain methods.
+ method<"getbestblockhash">{},
+ method<"getblock", string_t, optional<0_u32>>{ "blockhash", "verbosity" },
+ method<"getblockchaininfo">{},
+ method<"getblockcount">{},
+ method<"getblockfilter", string_t, optional<"basic"_t>>{ "blockhash", "filtertype" },
+ method<"getblockhash", number_t>{ "height" },
+ method<"getblockheader", string_t, optional>{ "blockhash", "verbose" },
+ method<"getblockstats", string_t, optional>{ "hash_or_height", "stats" },
+ method<"getchaintxstats", optional<-1_i32>, optional<""_t>>{ "nblocks", "blockhash" },
+ method<"getchainwork">{},
+ method<"gettxout", string_t, number_t, optional>{ "txid", "n", "include_mempool" },
+ method<"gettxoutsetinfo">{},
+ method<"pruneblockchain", number_t>{ "height" },
+ method<"savemempool">{},
+ method<"scantxoutset", string_t, optional>{ "action", "scanobjects" },
+ method<"verifychain", optional<4_u32>, optional<288_u32>>{ "checklevel", "nblocks" },
+ method<"verifytxoutset", string_t>{ "input_verify_flag" },
+
+ /// Control methods.
+ method<"getmemoryinfo", optional<"stats"_t>>{ "mode" },
+ method<"getrpcinfo">{},
+ method<"help", optional<""_t>>{ "command" },
+ method<"logging", optional<"*"_t>>{ "include" },
+ method<"stop">{},
+ method<"uptime">{},
+
+ /// Mining methods.
+ method<"getblocktemplate", optional>{ "template_request" },
+ method<"getmininginfo">{},
+ method<"getnetworkhashps", optional<120_u32>, optional<-1_i32>>{ "nblocks", "height" },
+ method<"prioritisetransaction", string_t, number_t, number_t>{ "txid", "dummy", "priority_delta" },
+ method<"submitblock", string_t, optional<""_t>>{ "block", "parameters" },
+
+ /// Network methods.
+ method<"addnode", string_t, string_t>{ "node", "command" },
+ method<"clearbanned">{},
+ method<"disconnectnode", string_t, optional<-1_i32>>{ "address", "nodeid" },
+ method<"getaddednodeinfo", optional, optional, optional<""_t>>{ "include_chain_info", "dns", "addnode" },
+ method<"getconnectioncount">{},
+ method<"getnetworkinfo">{},
+ method<"getpeerinfo">{},
+ method<"listbanned">{},
+ method<"ping">{},
+ method<"setban", string_t, string_t, optional<86400_u32>, optional, optional<""_t>>{ "addr", "command", "bantime", "absolute", "reason" },
+ method<"setnetworkactive", boolean_t>{ "state" },
+
+ /// Rawtransactions methods.
+ method<"combinerawtransaction", array_t>{ "txs" },
+ method<"createrawtransaction", array_t, object_t, optional<0_u32>, optional>{ "inputs", "outputs", "locktime", "replaceable" },
+ method<"decoderawtransaction", string_t>{ "hexstring" },
+ method<"fundrawtransaction", string_t, optional>{ "rawtx", "options" },
+ method<"getrawtransaction", string_t, optional<0_u32>, optional<""_t>>{ "txid", "verbose", "blockhash" },
+ method<"sendrawtransaction", string_t, optional<0_u32>>{ "hexstring", "maxfeerate" },
+ method<"signrawtransactionwithkey", string_t, optional, optional, optional<"ALL|FORKID"_t>>{ "hexstring", "privkeys", "prevtxs", "sighashtype" },
+ method<"testmempoolaccept", array_t, optional<0_u32>>{ "rawtxs", "maxfeerate" },
+ method<"testrawtransaction", string_t>{ "rawtx" },
+
+ /// Util methods (node-related).
+ method<"createmultisig", number_t, array_t>{ "nrequired", "keys" },
+ method<"decodepsbt", string_t>{ "psbt" },
+ method<"decodescript", string_t>{ "hex" },
+ method<"estimaterawfee", number_t, optional<"unset"_t>>{ "conf_target", "estimate_mode" },
+ method<"getdescriptorinfo", string_t>{ "descriptor" },
+ method<"validateaddress", string_t>{ "address" },
+
+ /// Wallet methods (unsupported).
+ method<"abandontransaction", string_t>{ "txid" },
+ method<"addmultisigaddress", number_t, array_t, optional<""_t>, optional<"legacy"_t>>{ "nrequired", "keys", "label", "address_type" },
+ method<"backupwallet", string_t>{ "destination" },
+ method<"bumpfee", string_t, optional>{ "txid", "options" },
+ method<"createwallet", string_t, optional, optional, optional, optional<""_t>, optional, optional, optional, optional<"set"_t>>{ "wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors", "load_on_startup", "external_signer", "change_type" },
+ method<"dumpprivkey", string_t>{ "address" },
+ method<"dumpwallet", string_t>{ "filename" },
+ method<"encryptwallet", string_t>{ "passphrase" },
+ method<"getaddressinfo", string_t>{ "address" },
+ method<"getbalances">{},
+ method<"getnewaddress", optional<""_t>, optional<"legacy"_t>>{ "label", "address_type" },
+ method<"getreceivedbyaddress", string_t, optional<0>>{ "address", "minconf" },
+ method<"getreceivedbylabel", string_t, optional<0>>{ "label", "minconf" },
+ method<"gettransaction", string_t, optional, optional>{ "txid", "include_watchonly", "verbose" },
+ method<"getunconfirmedbalance">{},
+ method<"getwalletinfo">{},
+ method<"importaddress", string_t, optional<""_t>, optional, optional>{ "address", "label", "rescan", "p2sh" },
+ method<"importmulti", array_t, optional>{ "requests", "options" },
+ method<"importprivkey", string_t, optional<""_t>, optional>{ "privkey", "label", "rescan" },
+ method<"importprunedfunds", string_t, string_t>{ "rawtransaction", "txoutproof" },
+ method<"importpubkey", string_t, optional<""_t>, optional>{ "pubkey", "label", "rescan" },
+ method<"importwallet", string_t>{ "filename" },
+ method<"keypoolrefill", optional<100>>{ "newsize" },
+ method<"listaddressgroupings", optional<1>, optional>{ "minconf", "include_watchonly" },
+ method<"listlabels", optional<"receive"_t>>{ "purpose" },
+ method<"listlockunspent">{},
+ 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<"loadwallet", string_t, optional>{ "filename", "load_on_startup" },
+ method<"lockunspent", boolean_t, optional>{ "unlock", "transactions" },
+ method<"removeprunedfunds", string_t>{ "txid" },
+ method<"rescanblockchain", optional<0>>{ "start_height" },
+ method<"send", object_t, optional>{ "outputs", "options" },
+ method<"sendmany", string_t, object_t, optional<1>, optional<""_t>, optional<""_t>, optional, optional, optional<25>, optional<"unset"_t>, optional, optional<0>>{ "dummy", "outputs", "minconf", "comment", "comment_to", "subtractfeefrom", "replaceable", "conf_target", "estimate_mode", "avoid_reuse", "fee_rate" },
+ method<"sendtoaddress", string_t, number_t, optional<""_t>, optional<""_t>, optional, optional<25>, optional<"unset"_t>, optional, optional<0>, optional>{ "address", "amount", "comment", "comment_to", "subtractfeefromamount", "conf_target", "estimate_mode", "avoid_reuse", "fee_rate", "verbose" },
+ method<"setlabel", string_t, string_t>{ "address", "label" },
+ method<"settxfee", number_t>{ "amount" },
+ method<"signmessage", string_t, string_t>{ "address", "message" },
+ method<"signmessagewithprivkey", string_t, string_t>{ "privkey", "message" },
+ method<"syncwithvalidationinterfacequeue">{},
+ method<"unloadwallet", optional<""_t>, optional>{ "wallet_name", "load_on_startup" },
+ method<"walletcreatefundedpsbt", optional, optional, optional<0>, optional>{ "inputs", "outputs", "locktime", "options" },
+ method<"walletlock">{},
+ method<"walletpassphrase", string_t, number_t>{ "passphrase", "timeout" },
+ method<"walletprocesspsbt", string_t, optional, optional, optional>{ "psbt", "sign", "bip32derivs", "complete" }
+ };
+
+ template
+ using subscriber = network::unsubscriber;
+
+ template
+ using at = method_at;
+
+ // Derive this from above in c++26 using reflection.
+ using getbestblockhash = at<0>;
+ using getblock = at<1>;
+ using getblockchaininfo = at<2>;
+ using getblockcount = at<3>;
+ using getblockfilter = at<4>;
+ using getblockhash = at<5>;
+ using getblockheader = at<6>;
+ using getblockstats = at<7>;
+ using getchaintxstats = at<8>;
+ using getchainwork = at<9>;
+ using gettxout = at<10>;
+ using gettxoutsetinfo = at<11>;
+ using pruneblockchain = at<12>;
+ using savemempool = at<13>;
+ using scantxoutset = at<14>;
+ using verifychain = at<15>;
+ using verifytxoutset = at<16>;
+ using getmemoryinfo = at<17>;
+ using getrpcinfo = at<18>;
+ using help = at<19>;
+ using logging = at<20>;
+ using stop = at<21>;
+ using uptime = at<22>;
+ using getblocktemplate = at<23>;
+ using getmininginfo = at<24>;
+ using getnetworkhashps = at<25>;
+ using prioritisetransaction = at<26>;
+ using submitblock = at<27>;
+ using addnode = at<28>;
+ using clearbanned = at<29>;
+ using disconnectnode = at<30>;
+ using getaddednodeinfo = at<31>;
+ using getconnectioncount = at<32>;
+ using getnetworkinfo = at<33>;
+ using getpeerinfo = at<34>;
+ using listbanned = at<35>;
+ using ping = at<36>;
+ using setban = at<37>;
+ using setnetworkactive = at<38>;
+ using combinerawtransaction = at<39>;
+ using createrawtransaction = at<40>;
+ using decoderawtransaction = at<41>;
+ using fundrawtransaction = at<42>;
+ using getrawtransaction = at<43>;
+ using sendrawtransaction = at<44>;
+ using signrawtransactionwithkey = at<45>;
+ using testmempoolaccept = at<46>;
+ using testrawtransaction = at<47>;
+ using createmultisig = at<48>;
+ using decodepsbt = at<49>;
+ using decodescript = at<50>;
+ using estimaterawfee = at<51>;
+ using getdescriptorinfo = at<52>;
+ using validateaddress = at<53>;
+ using abandontransaction = at<54>;
+ using addmultisigaddress = at<55>;
+ using backupwallet = at<56>;
+ using bumpfee = at<57>;
+ using createwallet = at<58>;
+ using dumpprivkey = at<59>;
+ using dumpwallet = at<60>;
+ using encryptwallet = at<61>;
+ using getaddressinfo = at<62>;
+ using getbalances = at<63>;
+ using getnewaddress = at<64>;
+ using getreceivedbyaddress = at<65>;
+ using getreceivedbylabel = at<66>;
+ using gettransaction = at<67>;
+ using getunconfirmedbalance = at<68>;
+ using getwalletinfo = at<69>;
+ using importaddress = at<70>;
+ using importmulti = at<71>;
+ using importprivkey = at<72>;
+ using importprunedfunds = at<73>;
+ using importpubkey = at<74>;
+ using importwallet = at<75>;
+ using keypoolrefill = at<76>;
+ using listaddressgroupings = at<77>;
+ using listlabels = at<78>;
+ using listlockunspent = at<79>;
+ using listreceivedbyaddress = at<80>;
+ using listreceivedbylabel = at<81>;
+ using listtransactions = at<82>;
+ using listunspent = at<83>;
+ using loadwallet = at<84>;
+ using lockunspent = at<85>;
+ using removeprunedfunds = at<86>;
+ using rescanblockchain = at<87>;
+ using send = at<88>;
+ using sendmany = at<89>;
+ using sendtoaddress = at<90>;
+ using setlabel = at<91>;
+ using settxfee = at<92>;
+ using signmessage = at<93>;
+ using signmessagewithprivkey = at<94>;
+ using syncwithvalidationinterfacequeue = at<95>;
+ using unloadwallet = at<96>;
+ using walletcreatefundedpsbt = at<97>;
+ using walletlock = at<98>;
+ using walletpassphrase = at<99>;
+ using walletprocesspsbt = at<100>;
+};
+
+} // namespace interface
+} // namespace node
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/node/interfaces/electrum.hpp b/include/bitcoin/node/interfaces/electrum.hpp
new file mode 100644
index 00000000..1ea7159d
--- /dev/null
+++ b/include/bitcoin/node/interfaces/electrum.hpp
@@ -0,0 +1,96 @@
+/**
+ * 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 .
+ */
+#ifndef LIBBITCOIN_NODE_INTERFACES_ELECTRUM_HPP
+#define LIBBITCOIN_NODE_INTERFACES_ELECTRUM_HPP
+
+#include
+
+namespace libbitcoin {
+namespace node {
+namespace interface {
+
+struct electrum_methods
+{
+ static constexpr std::tuple methods
+ {
+ /// Blockchain methods.
+ method<"blockchain.block.header", number_t, optional<0>>{ "height", "cp_height" },
+ method<"blockchain.block.headers", number_t, number_t, optional<0>>{ "start_height", "count", "cp_height" },
+ method<"blockchain.estimatefee", number_t>{ "number" },
+ method<"blockchain.headers.subscribe">{},
+ 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.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_merkle", string_t, number_t>{ "tx_hash", "height" },
+ method<"blockchain.transaction.id_from_pos", number_t, number_t, optional>{ "height", "tx_pos", "merkle" },
+
+ /// Server methods.
+ method<"server.add_peer", object_t>{ "features" },
+ method<"server.banner">{},
+ method<"server.donation_address">{},
+ method<"server.features">{},
+ method<"server.peers.subscribe">{},
+ method<"server.ping">{},
+ method<"server.version", optional<""_t>, optional<"1.4"_t>>{ "client_name", "protocol_version" }
+ };
+
+ template
+ using subscriber = network::unsubscriber;
+
+ template
+ using at = method_at;
+
+ // 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_relayfee = 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_subscribe = at<9>;
+ using blockchain_scripthash_unsubscribe = at<10>;
+ using blockchain_transaction_broadcast = at<11>;
+ using blockchain_transaction_get = at<12>;
+ using blockchain_transaction_get_merkle = at<13>;
+ using blockchain_transaction_id_from_pos = at<14>;
+ using server_add_peer = at<15>;
+ using server_banner = at<16>;
+ using server_donation_address = at<17>;
+ using server_features = at<18>;
+ using server_peers_subscribe = at<19>;
+ using server_ping = at<20>;
+ using server_version = at<21>;
+
+ ////using subscribers = unsubscriber>;
+};
+
+} // namespace interface
+} // namespace node
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/node/interfaces/explore.hpp b/include/bitcoin/node/interfaces/explore.hpp
new file mode 100644
index 00000000..1cf9d037
--- /dev/null
+++ b/include/bitcoin/node/interfaces/explore.hpp
@@ -0,0 +1,164 @@
+/**
+ * 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 .
+ */
+#ifndef LIBBITCOIN_NODE_INTERFACES_EXPLORE_HPP
+#define LIBBITCOIN_NODE_INTERFACES_EXPLORE_HPP
+
+#include
+
+namespace libbitcoin {
+namespace node {
+namespace interface {
+
+struct explore_methods
+{
+ static constexpr std::tuple methods
+ {
+ method<"top", uint8_t, uint8_t>{ "version", "media" },
+ method<"block", uint8_t, uint8_t, nullable, nullable, optional>{ "version", "media", "hash", "height", "witness" },
+ method<"block_header", uint8_t, uint8_t, nullable, nullable>{ "version", "media", "hash", "height" },
+ method<"block_txs", uint8_t, uint8_t, nullable, nullable>{ "version", "media", "hash", "height" },
+ method<"block_fees", uint8_t, uint8_t, nullable, nullable>{ "version", "media", "hash", "height" },
+ method<"block_filter", uint8_t, uint8_t, uint8_t, nullable, nullable>{ "version", "media", "type", "hash", "height" },
+ method<"block_filter_hash", uint8_t, uint8_t, uint8_t, nullable, nullable>{ "version", "media", "type", "hash", "height" },
+ method<"block_filter_header", uint8_t, uint8_t, uint8_t, nullable, nullable>{ "version", "media", "type", "hash", "height" },
+ method<"block_tx", uint8_t, uint8_t, uint32_t, nullable, nullable, optional>{ "version", "media", "position", "hash", "height", "witness" },
+
+ method<"tx", uint8_t, uint8_t, system::hash_cptr, optional>{ "version", "media", "hash", "witness" },
+ method<"tx_header", uint8_t, uint8_t, system::hash_cptr>{ "version", "media", "hash" },
+ method<"tx_fee", uint8_t, uint8_t, system::hash_cptr>{ "version", "media", "hash" },
+
+ method<"inputs", uint8_t, uint8_t, system::hash_cptr, optional>{ "version", "media", "hash", "witness" },
+ method<"input", uint8_t, uint8_t, system::hash_cptr, uint32_t, optional>{ "version", "media", "hash", "index", "witness" },
+ method<"input_script", uint8_t, uint8_t, system::hash_cptr, uint32_t>{ "version", "media", "hash", "index" },
+ method<"input_witness", uint8_t, uint8_t, system::hash_cptr, uint32_t>{ "version", "media", "hash", "index" },
+
+ method<"outputs", uint8_t, uint8_t, system::hash_cptr>{ "version", "media", "hash" },
+ method<"output", uint8_t, uint8_t, system::hash_cptr, uint32_t>{ "version", "media", "hash", "index" },
+ method<"output_script", uint8_t, uint8_t, system::hash_cptr, uint32_t>{ "version", "media", "hash", "index" },
+ method<"output_spender", uint8_t, uint8_t, system::hash_cptr, uint32_t>{ "version", "media", "hash", "index" },
+ method<"output_spenders", uint8_t, uint8_t, system::hash_cptr, uint32_t>{ "version", "media", "hash", "index" },
+
+ method<"address", uint8_t, uint8_t, system::hash_cptr, optional>{ "version", "media", "hash", "turbo" },
+ method<"address_confirmed", uint8_t, uint8_t, system::hash_cptr, optional>{ "version", "media", "hash", "turbo" },
+ method<"address_unconfirmed", uint8_t, uint8_t, system::hash_cptr, optional>{ "version", "media", "hash", "turbo" },
+ method<"address_balance", uint8_t, uint8_t, system::hash_cptr, optional>{ "version", "media", "hash", "turbo" }
+ };
+
+ template
+ using subscriber = network::unsubscriber;
+
+ template
+ using at = method_at;
+
+ // Derive this from above in c++26 using reflection.
+
+ using top = at<0>;
+
+ using block = at<1>;
+ using block_header = at<2>;
+ using block_txs = at<3>;
+ using block_fees = at<4>;
+ using block_filter = at<5>;
+ using block_filter_hash = at<6>;
+ using block_filter_header = at<7>;
+ using block_tx = at<8>;
+
+ using tx = at<9>;
+ using tx_header = at<10>;
+ using tx_fee = at<11>;
+
+ using inputs = at<12>;
+ using input = at<13>;
+ using input_script = at<14>;
+ using input_witness = at<15>;
+
+ using outputs = at<16>;
+ using output = at<17>;
+ using output_script = at<18>;
+ using output_spender = at<19>;
+ using output_spenders = at<20>;
+
+ using address = at<21>;
+ using address_confirmed = at<22>;
+ using address_unconfirmed = at<23>;
+ using address_balance = at<24>;
+};
+
+/// ?format=data|text|json (via query string).
+/// -----------------------------------------------------------------------
+
+/// /v1/block/top {1}
+
+/// /v1/block/hash/[bkhash] {1}
+/// /v1/block/height/[height] {1}
+
+/// /v1/block/hash/[bkhash]/header {1}
+/// /v1/block/height/[height]/header {1}
+
+/// /v1/block/hash/[bkhash]/fees {1}
+/// /v1/block/height/[height]/fees {1}
+
+/// /v1/block/hash/[bkhash]/filter/[type] {1}
+/// /v1/block/height/[height]/filter/[type] {1}
+
+/// /v1/block/hash/[bkhash]/filter/[type]/hash {1}
+/// /v1/block/height/[height]/filter/[type]/hash {1}
+
+/// /v1/block/hash/[bkhash]/filter/[type]/header {1}
+/// /v1/block/height/[height]/filter/[type]/header {1}
+
+/// /v1/block/hash/[bkhash]/txs {all txs in the block}
+/// /v1/block/height/[height]/txs {all txs in the block}
+
+/// /v1/block/hash/[bkhash]/tx/[position] {1}
+/// /v1/block/height/[height]/tx/[position] {1}
+
+/// -----------------------------------------------------------------------
+
+/// /v1/tx/[txhash] {1}
+/// /v1/tx/[txhash]/header {1 - if confirmed}
+/// /v1/tx/[txhash]/fee {1}
+
+/// -----------------------------------------------------------------------
+
+/// /v1/input/[txhash] {all inputs in the tx}
+/// /v1/input/[txhash]/[index] {1}
+/// /v1/input/[txhash]/[index]/script {1}
+/// /v1/input/[txhash]/[index]/witness {1}
+
+/// -----------------------------------------------------------------------
+
+/// /v1/output/[txhash] {all outputs in the tx}
+/// /v1/output/[txhash]/[index] {1}
+/// /v1/output/[txhash]/[index]/script {1}
+/// /v1/output/[txhash]/[index]/spender {1 - if confirmed}
+/// /v1/output/[txhash]/[index]/spenders {all}
+
+/// -----------------------------------------------------------------------
+
+/// /v1/address/[output-script-hash] {all}
+/// /v1/address/[output-script-hash]/unconfirmed {all unconfirmed}
+/// /v1/address/[output-script-hash]/confirmed {all unconfirmed}
+/// /v1/address/[output-script-hash]/balance {all confirmed}
+
+} // namespace interface
+} // namespace node
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/node/interfaces/interfaces.hpp b/include/bitcoin/node/interfaces/interfaces.hpp
new file mode 100644
index 00000000..5ac6d2a1
--- /dev/null
+++ b/include/bitcoin/node/interfaces/interfaces.hpp
@@ -0,0 +1,73 @@
+/**
+ * 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 .
+ */
+#ifndef LIBBITCOIN_NODE_INTERFACES_HPP
+#define LIBBITCOIN_NODE_INTERFACES_HPP
+
+namespace libbitcoin {
+namespace node {
+namespace interface {
+
+/// Alias network::rpc names within interface::.
+
+template
+using method = network::rpc::method;
+template
+using method_at = network::rpc::method_at;
+template
+using publish = network::rpc::publish;
+
+template
+using optional = network::rpc::optional;
+template
+using nullable = network::rpc::nullable;
+using boolean_t = network::rpc::boolean_t;
+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;
+
+namespace empty { constexpr auto array = network::rpc::empty::array; };
+namespace empty { constexpr auto object = network::rpc::empty::object; };
+
+} // namespace interface
+} // namespace node
+} // namespace libbitcoin
+
+#include
+#include
+#include
+#include
+#include
+
+namespace libbitcoin {
+namespace node {
+namespace interface {
+
+using bitcoind = publish;
+using electrum = publish;
+using explore = publish;
+using stratum_v1 = publish;
+using stratum_v2 = publish;
+
+} // namespace interface
+} // namespace node
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/node/interfaces/stratum_v1.hpp b/include/bitcoin/node/interfaces/stratum_v1.hpp
new file mode 100644
index 00000000..89f0a5e7
--- /dev/null
+++ b/include/bitcoin/node/interfaces/stratum_v1.hpp
@@ -0,0 +1,72 @@
+/**
+ * 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 .
+ */
+#ifndef LIBBITCOIN_NODE_INTERFACES_STRATUM_V1_HPP
+#define LIBBITCOIN_NODE_INTERFACES_STRATUM_V1_HPP
+
+#include
+
+namespace libbitcoin {
+namespace node {
+namespace interface {
+
+struct stratum_v1_methods
+{
+ static constexpr std::tuple methods
+ {
+ /// Client requests.
+ method<"mining.subscribe", optional<""_t>, optional<0>>{ "user_agent", "extranonce1_size" },
+ method<"mining.authorize", string_t, string_t>{ "username", "password" },
+ method<"mining.submit", string_t, string_t, string_t, number_t, string_t>{ "worker_name", "job_id", "extranonce2", "ntime", "nonce" },
+ method<"mining.extranonce.subscribe">{},
+ method<"mining.extranonce.unsubscribe", number_t>{ "id" },
+
+ /// Server notifications.
+ method<"mining.configure", object_t>{ "extensions" },
+ method<"mining.set_difficulty", optional<1.0>>{ "difficulty" },
+ method<"mining.notify", string_t, string_t, string_t, string_t, array_t, number_t, number_t, number_t, boolean_t, boolean_t, boolean_t>{ "job_id", "prevhash", "coinb1", "coinb2", "merkle_branch", "version", "nbits", "ntime", "clean_jobs", "hash1", "hash2" },
+ method<"client.reconnect", string_t, number_t, number_t>{ "url", "port", "id" },
+ method<"client.hello", object_t>{ "protocol" },
+ method<"client.rejected", string_t, string_t>{ "job_id", "reject_reason" }
+ };
+
+ template
+ using subscriber = network::unsubscriber;
+
+ template
+ using at = method_at;
+
+ // Derive this from above in c++26 using reflection.
+ using mining_subscribe = at<0>;
+ using mining_authorize = at<1>;
+ using mining_submit = at<2>;
+ using mining_extranonce_subscribe = at<3>;
+ using mining_extranonce_unsubscribe = at<4>;
+ using mining_configure = at<5>;
+ using mining_set_difficulty = at<6>;
+ using mining_notify = at<7>;
+ using client_reconnect = at<8>;
+ using client_hello = at<9>;
+ using client_rejected = at<10>;
+};
+
+} // namespace interface
+} // namespace node
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/node/interfaces/stratum_v2.hpp b/include/bitcoin/node/interfaces/stratum_v2.hpp
new file mode 100644
index 00000000..9b0e2498
--- /dev/null
+++ b/include/bitcoin/node/interfaces/stratum_v2.hpp
@@ -0,0 +1,108 @@
+/**
+ * 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 .
+ */
+#ifndef LIBBITCOIN_NODE_INTERFACES_STRATUM_V2_HPP
+#define LIBBITCOIN_NODE_INTERFACES_STRATUM_V2_HPP
+
+#include
+
+namespace libbitcoin {
+namespace node {
+namespace interface {
+
+struct stratum_v2_methods
+{
+ static constexpr std::tuple methods
+ {
+ /// Common setup messages.
+ method<"setup_connection", number_t, number_t, number_t, number_t, string_t, string_t, string_t>{ "min_version", "max_version", "flags", "endpoint_port", "endpoint_host", "vendor", "user_agent" },
+ method<"setup_connection_success", number_t, number_t>{ "used_version", "flags" },
+ method<"setup_connection_error", string_t>{ "code" },
+
+ /// Standard mining channel (header-only, primary for devices/firmware).
+ method<"open_standard_mining_channel", string_t, number_t, string_t, number_t>{ "user_identity", "nominal_hash_rate", "max_target", "min_extranonce_size" },
+ method<"open_standard_mining_channel_success", number_t, string_t, string_t, number_t>{ "channel_id", "target", "extranonce_prefix", "extranonce_size" },
+ method<"open_standard_mining_channel_error", string_t>{ "code" },
+
+ /// Extended mining channel.
+ method<"open_extended_mining_channel", string_t, number_t, string_t, number_t>{ "user_identity", "nominal_hash_rate", "max_target", "min_extranonce_size" },
+ method<"open_extended_mining_channel_success", number_t, string_t, string_t, number_t, number_t, number_t>{ "channel_id", "target", "extranonce_prefix", "extranonce_size", "max_coinbase_size", "coinbase_output_max_additional_size" },
+ method<"open_extended_mining_channel_error", string_t>{ "code" },
+
+ /// Channel management.
+ method<"update_channel", number_t, number_t, optional<""_t>>{ "channel_id", "nominal_hash_rate", "max_target" },
+ method<"update_channel_error", number_t, string_t>{ "channel_id", "code" },
+ method<"close_channel", number_t, optional<""_t>>{ "channel_id", "reason" },
+ method<"set_target", number_t, string_t>{ "channel_id", "maximum_target" },
+
+ /// Header-only job declaration.
+ method<"new_mining_job", number_t, boolean_t, number_t, string_t, string_t, number_t>{ "job_id", "future_job", "version", "prev_hash", "merkle_root", "ntime_offset" },
+ method<"set_new_prev_hash", number_t, number_t, string_t, number_t, number_t>{ "channel_id", "job_id", "prev_hash", "min_ntime", "nbits" },
+
+ /// Extended / custom jobs.
+ method<"new_extended_mining_job", number_t, boolean_t, number_t, string_t, string_t, array_t>{ "job_id", "future_job", "version", "coinbase_prefix", "coinbase_suffix", "merkle_path" },
+ method<"set_custom_mining_job", number_t, boolean_t, number_t, string_t, number_t, number_t, array_t, array_t>{ "channel_id", "future_job", "job_id", "prev_hash", "version", "ntime", "merkle_branch", "transactions" },
+ method<"set_custom_mining_job_success", number_t>{ "job_id" },
+ method<"set_custom_mining_job_error", number_t, string_t>{ "job_id", "code" },
+
+ /// Share submission.
+ method<"submit_shares", number_t, number_t, number_t, number_t, number_t, number_t>{ "channel_id", "sequence_number", "job_id", "nonce", "ntime", "version" },
+ method<"submit_shares_success", number_t, optional<""_t>>{ "sequence_number", "new_target" },
+ method<"submit_shares_error", number_t, string_t>{ "sequence_number", "code" },
+
+ /// Miscellaneous.
+ method<"reconnect", string_t, number_t>{ "new_host", "new_port" }
+ };
+
+ template
+ using subscriber = network::unsubscriber;
+
+ template
+ using at = method_at;
+
+ // Derive this from above in c++26 using reflection.
+ using setup_connection = at<0>;
+ using setup_connection_success = at<1>;
+ using setup_connection_error = at<2>;
+ using open_standard_mining_channel = at<3>;
+ using open_standard_mining_channel_success = at<4>;
+ using open_standard_mining_channel_error = at<5>;
+ using open_extended_mining_channel = at<6>;
+ using open_extended_mining_channel_success = at<7>;
+ using open_extended_mining_channel_error = at<8>;
+ using update_channel = at<9>;
+ using update_channel_error = at<10>;
+ using close_channel = at<11>;
+ using set_target = at<12>;
+ using new_mining_job = at<13>;
+ using set_new_prev_hash = at<14>;
+ using new_extended_mining_job = at<15>;
+ using set_custom_mining_job = at<16>;
+ using set_custom_mining_job_success = at<17>;
+ using set_custom_mining_job_error = at<18>;
+ using submit_shares = at<19>;
+ using submit_shares_success = at<20>;
+ using submit_shares_error = at<21>;
+ using reconnect = at<22>;
+};
+
+} // namespace interface
+} // namespace node
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/node/protocols/protocol_explore.hpp b/include/bitcoin/node/protocols/protocol_explore.hpp
index 1ae45731..c173bebb 100644
--- a/include/bitcoin/node/protocols/protocol_explore.hpp
+++ b/include/bitcoin/node/protocols/protocol_explore.hpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
namespace libbitcoin {
@@ -34,7 +35,7 @@ class BCN_API protocol_explore
{
public:
typedef std::shared_ptr ptr;
- using interface = network::rpc::interface::explore;
+ using interface = interface::explore;
using dispatcher = network::rpc::dispatcher;
protocol_explore(const auto& session,