diff --git a/Makefile.am b/Makefile.am index 656ab084..c9cc1efa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,7 @@ src_libbitcoin_node_la_SOURCES = \ src/parse/query.cpp \ src/parse/target.cpp \ src/protocols/protocol.cpp \ + src/protocols/protocol_bitcoind.cpp \ src/protocols/protocol_block_in_106.cpp \ src/protocols/protocol_block_in_31800.cpp \ src/protocols/protocol_block_out_106.cpp \ @@ -206,7 +207,8 @@ include_bitcoin_node_interfaces_HEADERS = \ 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/interfaces/stratum_v2.hpp \ + include/bitcoin/node/interfaces/types.hpp include_bitcoin_node_parsedir = ${includedir}/bitcoin/node/parse include_bitcoin_node_parse_HEADERS = \ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index 56c2ea0d..d9b89989 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -268,6 +268,7 @@ add_library( ${CANONICAL_LIB_NAME} "../../src/parse/query.cpp" "../../src/parse/target.cpp" "../../src/protocols/protocol.cpp" + "../../src/protocols/protocol_bitcoind.cpp" "../../src/protocols/protocol_block_in_106.cpp" "../../src/protocols/protocol_block_in_31800.cpp" "../../src/protocols/protocol_block_out_106.cpp" diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj index f6bcf24b..dc0fc4e5 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj @@ -141,6 +141,7 @@ + @@ -197,6 +198,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters index 20807abe..aa009766 100644 --- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters @@ -123,6 +123,9 @@ src\protocols + + src\protocols + src\protocols @@ -287,6 +290,9 @@ 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 0ce94314..1d0ed22b 100644 --- a/include/bitcoin/node.hpp +++ b/include/bitcoin/node.hpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include diff --git a/include/bitcoin/node/error.hpp b/include/bitcoin/node/error.hpp index 13d584b2..d85a6618 100644 --- a/include/bitcoin/node/error.hpp +++ b/include/bitcoin/node/error.hpp @@ -117,6 +117,8 @@ enum error_t : uint8_t invalid_component, invalid_subcomponent, extra_segment, + + /// server (json-rpc parse codes) unexpected_parse }; diff --git a/include/bitcoin/node/interfaces/bitcoind.hpp b/include/bitcoin/node/interfaces/bitcoind.hpp index 91001136..17f70038 100644 --- a/include/bitcoin/node/interfaces/bitcoind.hpp +++ b/include/bitcoin/node/interfaces/bitcoind.hpp @@ -20,6 +20,7 @@ #define LIBBITCOIN_NODE_INTERFACES_BITCOIND_HPP #include +#include namespace libbitcoin { namespace node { @@ -31,118 +32,118 @@ struct bitcoind_methods { /// Blockchain methods. method<"getbestblockhash">{}, - method<"getblock", string_t, optional<0_u32>>{ "blockhash", "verbosity" }, + method<"getblock", string_t, optional<0>>{ "blockhash", "verbosity" }, method<"getblockchaininfo">{}, method<"getblockcount">{}, method<"getblockfilter", string_t, optional<"basic"_t>>{ "blockhash", "filtertype" }, - method<"getblockhash", number_t>{ "height" }, + ////method<"getblockhash", double>{ "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<"getchaintxstats", optional<-1>, 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<"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" }, + method<"verifychain", optional<4>, optional<288>>{ "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">{}, + /////// 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" }, + /////// 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" }, + /////// 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" }, + /////// 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" }, + /////// 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" } + /////// 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 @@ -152,107 +153,108 @@ struct bitcoind_methods 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>; + using get_best_block_hash = at<0>; + using get_block = at<1>; + using get_block_chain_info = at<2>; + using get_block_count = at<3>; + using get_block_filter = at<4>; + ////using get_block_hash = at<5>; + using get_block_header = at<5>; + using get_block_stats = at<6>; + using get_chain_tx_stats = at<7>; + using get_chain_work = at<8>; + using get_tx_out = at<9>; + using get_tx_out_set_info = at<10>; + ////using prune_block_chain = at<12>; + using save_mem_pool = at<11>; + using scan_tx_out_set = at<12>; + using verify_chain = at<13>; + ////using verify_tx_out_set = at<16>; + + ////using get_memory_info = at<17>; + ////using get_rpc_info = at<18>; + ////using help = at<19>; + ////using logging = at<20>; + ////using stop = at<21>; + ////using uptime = at<22>; + ////using get_block_template = at<23>; + ////using get_mining_info = at<24>; + ////using get_network_hash_ps = at<25>; + ////using prioritise_transaction = at<26>; + ////using submit_block = at<27>; + ////using add_node = at<28>; + ////using clear_banned = at<29>; + ////using disconnect_node = at<30>; + ////using get_added_node_info = at<31>; + ////using get_connection_count = at<32>; + ////using get_network_info = at<33>; + ////using get_peer_info = at<34>; + ////using list_banned = at<35>; + ////using ping = at<36>; + ////using set_ban = at<37>; + ////using set_network_active = at<38>; + ////using combine_raw_transaction = at<39>; + ////using create_raw_transaction = at<40>; + ////using decode_raw_transaction = at<41>; + ////using fund_raw_transaction = at<42>; + ////using get_raw_transaction = at<43>; + ////using send_raw_transaction = at<44>; + ////using sign_raw_transaction_with_key = at<45>; + ////using test_mem_pool_accept = at<46>; + ////using test_raw_transaction = at<47>; + ////using create_multisig = at<48>; + ////using decode_psbt = at<49>; + ////using decode_script = at<50>; + ////using estimate_raw_fee = at<51>; + ////using get_descriptor_info = at<52>; + ////using validate_address = at<53>; + ////using abandon_transaction = at<54>; + ////using add_multisig_address = at<55>; + ////using backup_wallet = at<56>; + ////using bump_fee = at<57>; + ////using create_wallet = at<58>; + ////using dump_priv_key = at<59>; + ////using dump_wallet = at<60>; + ////using encrypt_wallet = at<61>; + ////using get_address_info = at<62>; + ////using get_balances = at<63>; + ////using get_new_address = at<64>; + ////using get_received_by_address = at<65>; + ////using get_received_by_label = at<66>; + ////using get_transaction = at<67>; + ////using get_unconfirmed_balance = at<68>; + ////using get_wallet_info = at<69>; + ////using import_address = at<70>; + ////using import_multi = at<71>; + ////using import_priv_key = at<72>; + ////using import_pruned_funds = at<73>; + ////using import_pub_key = at<74>; + ////using import_wallet = at<75>; + ////using key_pool_refill = at<76>; + ////using list_address_groupings = at<77>; + ////using list_labels = at<78>; + ////using list_lock_unspent = at<79>; + ////using list_received_by_address = at<80>; + ////using list_received_by_label = at<81>; + ////using list_transactions = at<82>; + ////using list_unspent = at<83>; + ////using load_wallet = at<84>; + ////using lock_unspent = at<85>; + ////using remove_pruned_funds = at<86>; + ////using rescan_block_chain = at<87>; + ////using send = at<88>; + ////using send_many = at<89>; + ////using send_to_address = at<90>; + ////using set_label = at<91>; + ////using set_tx_fee = at<92>; + ////using sign_message = at<93>; + ////using sign_message_with_priv_key = at<94>; + ////using sync_with_validation_interface_queue = at<95>; + ////using unload_wallet = at<96>; + ////using wallet_create_funded_psbt = at<97>; + ////using wallet_lock = at<98>; + ////using wallet_passphrase = at<99>; + ////using wallet_process_psbt = at<100>; }; } // namespace interface diff --git a/include/bitcoin/node/interfaces/electrum.hpp b/include/bitcoin/node/interfaces/electrum.hpp index 1ea7159d..4b8b3254 100644 --- a/include/bitcoin/node/interfaces/electrum.hpp +++ b/include/bitcoin/node/interfaces/electrum.hpp @@ -20,6 +20,7 @@ #define LIBBITCOIN_NODE_INTERFACES_ELECTRUM_HPP #include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/interfaces/explore.hpp b/include/bitcoin/node/interfaces/explore.hpp index 93b95e91..4b7a8df2 100644 --- a/include/bitcoin/node/interfaces/explore.hpp +++ b/include/bitcoin/node/interfaces/explore.hpp @@ -20,6 +20,7 @@ #define LIBBITCOIN_NODE_INTERFACES_EXPLORE_HPP #include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/interfaces/interfaces.hpp b/include/bitcoin/node/interfaces/interfaces.hpp index 5ac6d2a1..95a376bf 100644 --- a/include/bitcoin/node/interfaces/interfaces.hpp +++ b/include/bitcoin/node/interfaces/interfaces.hpp @@ -19,42 +19,12 @@ #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 +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/interfaces/stratum_v1.hpp b/include/bitcoin/node/interfaces/stratum_v1.hpp index 89f0a5e7..0c052b35 100644 --- a/include/bitcoin/node/interfaces/stratum_v1.hpp +++ b/include/bitcoin/node/interfaces/stratum_v1.hpp @@ -20,6 +20,7 @@ #define LIBBITCOIN_NODE_INTERFACES_STRATUM_V1_HPP #include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/interfaces/stratum_v2.hpp b/include/bitcoin/node/interfaces/stratum_v2.hpp index 9b0e2498..a266d0e5 100644 --- a/include/bitcoin/node/interfaces/stratum_v2.hpp +++ b/include/bitcoin/node/interfaces/stratum_v2.hpp @@ -20,6 +20,7 @@ #define LIBBITCOIN_NODE_INTERFACES_STRATUM_V2_HPP #include +#include namespace libbitcoin { namespace node { diff --git a/include/bitcoin/node/interfaces/types.hpp b/include/bitcoin/node/interfaces/types.hpp new file mode 100644 index 00000000..855ba89b --- /dev/null +++ b/include/bitcoin/node/interfaces/types.hpp @@ -0,0 +1,55 @@ +/** + * 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_TYPES_HPP +#define LIBBITCOIN_NODE_INTERFACES_TYPES_HPP + +#include + +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 + +#endif diff --git a/include/bitcoin/node/protocols/protocol_bitcoind.hpp b/include/bitcoin/node/protocols/protocol_bitcoind.hpp index 31d803b0..3f723c49 100644 --- a/include/bitcoin/node/protocols/protocol_bitcoind.hpp +++ b/include/bitcoin/node/protocols/protocol_bitcoind.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace libbitcoin { @@ -33,6 +34,8 @@ class BCN_API protocol_bitcoind { public: typedef std::shared_ptr ptr; + using interface = interface::bitcoind; + using dispatcher = network::rpc::dispatcher; inline protocol_bitcoind(const auto& session, const network::channel::ptr& channel, @@ -43,18 +46,64 @@ class BCN_API protocol_bitcoind } /// Public start is required. - inline void start() NOEXCEPT override + void start() NOEXCEPT override; + +protected: + template + inline void subscribe(Method&& method, Args&&... args) NOEXCEPT { - node::protocol_http::start(); + dispatcher_.subscribe(BIND_SHARED(method, args)); } -////protected: -//// void handle_receive_get(const code& ec, -//// const network::http::method::get& request) NOEXCEPT override; + /// Dispatch. + void handle_receive_post(const code& ec, + const network::http::method::post::cptr& post) NOEXCEPT override; + + /// Handlers. + bool handle_get_best_block_hash(const code& ec, + interface::get_best_block_hash) NOEXCEPT; + bool handle_get_block(const code& ec, + interface::get_block, const std::string&, double) NOEXCEPT; + bool handle_get_block_chain_info(const code& ec, + interface::get_block_chain_info) NOEXCEPT; + bool handle_get_block_count(const code& ec, + interface::get_block_count) NOEXCEPT; + bool handle_get_block_filter(const code& ec, + interface::get_block_filter, const std::string&, + const std::string&) NOEXCEPT; + ////bool handle_get_block_hash(const code& ec, + //// interface::get_block_hash, double) NOEXCEPT; + bool handle_get_block_header(const code& ec, + interface::get_block_header, const std::string&, bool) NOEXCEPT; + bool handle_get_block_stats(const code& ec, + interface::get_block_stats, const std::string&, + const network::rpc::array_t&) NOEXCEPT; + bool handle_get_chain_tx_stats(const code& ec, + interface::get_chain_tx_stats, double, const std::string&) NOEXCEPT; + bool handle_get_chain_work(const code& ec, + interface::get_chain_work) NOEXCEPT; + bool handle_get_tx_out(const code& ec, + interface::get_tx_out, const std::string&, double, bool) NOEXCEPT; + bool handle_get_tx_out_set_info(const code& ec, + interface::get_tx_out_set_info) NOEXCEPT; + ////bool handle_prune_block_chain(const code& ec, + //// interface::prune_block_chain, double) NOEXCEPT; + bool handle_save_mem_pool(const code& ec, + interface::save_mem_pool) NOEXCEPT; + bool handle_scan_tx_out_set(const code& ec, + interface::scan_tx_out_set, const std::string&, + const network::rpc::array_t&) NOEXCEPT; + bool handle_verify_chain(const code& ec, + interface::verify_chain, double, double) NOEXCEPT; + //bool handle_verify_tx_out_set(const code& ec, + // interface::verify_tx_out_set, const std::string&) NOEXCEPT; private: // This is thread safe. ////const options_t& options_; + + // This is protected by strand. + dispatcher dispatcher_{}; }; } // namespace node diff --git a/include/bitcoin/node/protocols/protocol_explore.hpp b/include/bitcoin/node/protocols/protocol_explore.hpp index 6b40bec7..8821b69e 100644 --- a/include/bitcoin/node/protocols/protocol_explore.hpp +++ b/include/bitcoin/node/protocols/protocol_explore.hpp @@ -172,8 +172,11 @@ class BCN_API protocol_explore database::header_link to_header(const std::optional& height, const std::optional& hash) NOEXCEPT; - dispatcher dispatcher_{}; + // This is thread safe. std::atomic_bool stopping_{}; + + // This is protected by strand. + dispatcher dispatcher_{}; }; } // namespace node diff --git a/src/protocols/protocol_bitcoind.cpp b/src/protocols/protocol_bitcoind.cpp new file mode 100644 index 00000000..50d1f2f3 --- /dev/null +++ b/src/protocols/protocol_bitcoind.cpp @@ -0,0 +1,238 @@ +/** + * 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 + +#include +#include + +namespace libbitcoin { +namespace node { + +#define CLASS protocol_bitcoind +#define SUBSCRIBE_BITCOIND(method, ...) \ + subscribe(&CLASS::method, __VA_ARGS__) + +using namespace system; +using namespace network::rpc; +using namespace network::http; +using namespace std::placeholders; +using namespace boost::json; + +using json_t = json_body::value_type; + +BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED) +BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR) + +// Start. +// ---------------------------------------------------------------------------- + +void protocol_bitcoind::start() NOEXCEPT +{ + using namespace std::placeholders; + + BC_ASSERT(stranded()); + + if (started()) + return; + + SUBSCRIBE_BITCOIND(handle_get_best_block_hash, _1, _2); + SUBSCRIBE_BITCOIND(handle_get_block, _1, _2, _3, _4); + SUBSCRIBE_BITCOIND(handle_get_block_chain_info, _1, _2); + SUBSCRIBE_BITCOIND(handle_get_block_count, _1, _2); + SUBSCRIBE_BITCOIND(handle_get_block_filter, _1, _2, _3, _4); + ////SUBSCRIBE_BITCOIND(handle_get_block_hash, _1, _2, _3); + SUBSCRIBE_BITCOIND(handle_get_block_header, _1, _2, _3, _4); + SUBSCRIBE_BITCOIND(handle_get_block_stats, _1, _2, _3, _4); + SUBSCRIBE_BITCOIND(handle_get_chain_tx_stats, _1, _2, _3, _4); + SUBSCRIBE_BITCOIND(handle_get_chain_work, _1, _2); + SUBSCRIBE_BITCOIND(handle_get_tx_out, _1, _2, _3, _4, _5); + SUBSCRIBE_BITCOIND(handle_get_tx_out_set_info, _1, _2); + ////SUBSCRIBE_BITCOIND(handle_prune_block_chain, _1, _2, _3); + SUBSCRIBE_BITCOIND(handle_save_mem_pool, _1, _2); + SUBSCRIBE_BITCOIND(handle_scan_tx_out_set, _1, _2, _3, _4); + SUBSCRIBE_BITCOIND(handle_verify_chain, _1, _2, _3, _4); + ////SUBSCRIBE_BITCOIND(handle_verify_tx_out_set, _1, _2, _3); + protocol_bitcoind::start(); +} + +// Dispatch. +// ---------------------------------------------------------------------------- + +void protocol_bitcoind::handle_receive_post(const code& ec, + const network::http::method::post::cptr& post) NOEXCEPT +{ + BC_ASSERT(stranded()); + + if (stopped(ec)) + return; + + const auto& body = post->body(); + if (!body.contains()) + { + send_not_acceptable(*post); + return; + } + + request_t request{}; + try + { + request = value_to(body.get().model); + } + catch (const boost::system::system_error& e) + { + send_bad_target(e.code(), *post); + return; + } + catch (...) + { + send_bad_target(error::unexpected_parse, *post); + return; + } + + // TODO: post-process request. + if (const auto code = dispatcher_.notify(request)) + stop(code); +} + +// Handlers. +// ---------------------------------------------------------------------------- + +bool protocol_bitcoind::handle_get_best_block_hash(const code& ec, + interface::get_best_block_hash) NOEXCEPT +{ + return !ec; +} + +// method<"getblock", string_t, optional<0_u32>>{ "blockhash", "verbosity" }, +bool protocol_bitcoind::handle_get_block(const code& ec, + interface::get_block, const std::string&, double) NOEXCEPT +{ + return !ec; +} + +bool protocol_bitcoind::handle_get_block_chain_info(const code& ec, + interface::get_block_chain_info) NOEXCEPT +{ + return !ec; +} + +bool protocol_bitcoind::handle_get_block_count(const code& ec, + interface::get_block_count) NOEXCEPT +{ + return !ec; +} + +// method<"getblockfilter", string_t, optional<"basic"_t>>{ "blockhash", "filtertype" }, +bool protocol_bitcoind::handle_get_block_filter(const code& ec, + interface::get_block_filter, const std::string&, const std::string&) NOEXCEPT +{ + return !ec; +} + +////// method<"getblockhash", number_t>{ "height" }, +////bool protocol_bitcoind::handle_get_block_hash(const code& ec, +//// interface::get_block_hash, network::rpc::number_t) NOEXCEPT +////{ +//// return !ec; +////} + +// method<"getblockheader", string_t, optional>{ "blockhash", "verbose" }, +bool protocol_bitcoind::handle_get_block_header(const code& ec, + interface::get_block_header, const std::string&, bool) NOEXCEPT +{ + return !ec; +} + +// method<"getblockstats", string_t, optional>{ "hash_or_height", "stats" }, +bool protocol_bitcoind::handle_get_block_stats(const code& ec, + interface::get_block_stats, const std::string&, + const network::rpc::array_t&) NOEXCEPT +{ + return !ec; +} + +// method<"getchaintxstats", optional<-1_i32>, optional<""_t>>{ "nblocks", "blockhash" }, +bool protocol_bitcoind::handle_get_chain_tx_stats(const code& ec, + interface::get_chain_tx_stats, double, const std::string&) NOEXCEPT +{ + return !ec; +} + +bool protocol_bitcoind::handle_get_chain_work(const code& ec, + interface::get_chain_work) NOEXCEPT +{ + return !ec; +} + +// method<"gettxout", string_t, number_t, optional>{ "txid", "n", "include_mempool" }, +bool protocol_bitcoind::handle_get_tx_out(const code& ec, + interface::get_tx_out, const std::string&, double, bool) NOEXCEPT +{ + return !ec; +} + +bool protocol_bitcoind::handle_get_tx_out_set_info(const code& ec, + interface::get_tx_out_set_info) NOEXCEPT +{ + return !ec; +} + +////// method<"pruneblockchain", number_t>{ "height" }, +////bool protocol_bitcoind::handle_prune_block_chain(const code& ec, +//// interface::prune_block_chain, double) NOEXCEPT +////{ +//// return !ec; +////} + +bool protocol_bitcoind::handle_save_mem_pool(const code& ec, + interface::save_mem_pool) NOEXCEPT +{ + return !ec; +} + +// method<"scantxoutset", string_t, optional>{ "action", "scanobjects" }, +bool protocol_bitcoind::handle_scan_tx_out_set(const code& ec, + interface::scan_tx_out_set, const std::string&, + const network::rpc::array_t&) NOEXCEPT +{ + return !ec; +} + +// method<"verifychain", optional<4_u32>, optional<288_u32>>{ "checklevel", "nblocks" }, +bool protocol_bitcoind::handle_verify_chain(const code& ec, + interface::verify_chain, double, double) NOEXCEPT +{ + return !ec; +} + +////// method<"verifytxoutset", string_t>{ "input_verify_flag" }, +////bool protocol_bitcoind::handle_verify_tx_out_set(const code& ec, +//// interface::verify_tx_out_set, const std::string&) NOEXCEPT +////{ +//// return !ec; +////} + +BC_POP_WARNING() +BC_POP_WARNING() + +#undef SUBSCRIBE_BITCOIND +#undef CLASS + +} // namespace node +} // namespace libbitcoin diff --git a/src/protocols/protocol_explore.cpp b/src/protocols/protocol_explore.cpp index e1077e04..66cafbab 100644 --- a/src/protocols/protocol_explore.cpp +++ b/src/protocols/protocol_explore.cpp @@ -29,7 +29,6 @@ namespace libbitcoin { namespace node { #define CLASS protocol_explore - #define SUBSCRIBE_EXPLORE(method, ...) \ subscribe(&CLASS::method, __VA_ARGS__) @@ -1161,6 +1160,7 @@ BC_POP_WARNING() BC_POP_WARNING() #undef SUBSCRIBE_EXPLORE +#undef CLASS } // namespace node } // namespace libbitcoin diff --git a/src/sessions/session.cpp b/src/sessions/session.cpp index 9708658f..16687924 100644 --- a/src/sessions/session.cpp +++ b/src/sessions/session.cpp @@ -26,8 +26,6 @@ namespace libbitcoin { namespace node { -#define CLASS session - using namespace system::chain; using namespace database; using namespace network;