From 4d161ceeb29df9380ad68d3687f113f59480929e Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 18 Dec 2023 09:02:20 +0000 Subject: [PATCH] Fix memory leak in libbitcoin --- .../bitcoin/libbitcoin_client.cpp | 56 +++--- .../bitcoin/libbitcoin_client.hpp | 19 +- .../sidechain_net_handler_bitcoin.hpp | 113 +++++------ .../sidechain_net_handler_bitcoin.cpp | 185 ++++++++++-------- 4 files changed, 195 insertions(+), 178 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp index fdcaa98e..ef30fab1 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/libbitcoin_client.cpp @@ -13,10 +13,10 @@ namespace graphene { namespace peerplays_sidechain { -libbitcoin_client::libbitcoin_client(std::string url) : +libbitcoin_client::libbitcoin_client(const std::string &url) : obelisk_client(LIBBITCOIN_SERVER_TIMEOUT, LIBBITCOIN_SERVER_RETRIES) { - std::string reg_expr = "^((?Phttps|http|tcp):\\/\\/)?(?P[a-zA-Z0-9\\-\\.]+)(:(?P\\d{1,5}))?(?P\\/.+)?"; + const std::string reg_expr = "^((?Phttps|http|tcp):\\/\\/)?(?P[a-zA-Z0-9\\-\\.]+)(:(?P\\d{1,5}))?(?P\\/.+)?"; boost::xpressive::sregex sr = boost::xpressive::sregex::compile(reg_expr); boost::xpressive::smatch sm; @@ -38,10 +38,10 @@ libbitcoin_client::libbitcoin_client(std::string url) : } } - uint16_t port_num = std::stoi(port); - std::string final_url = protocol + "://" + host; + const auto port_num = static_cast(std::stoi(port)); + const std::string final_url = protocol + "://" + host; - libbitcoin::config::endpoint address(final_url, port_num); + const libbitcoin::config::endpoint address(final_url, port_num); libbitcoin::client::connection_type connection; connection.retries = LIBBITCOIN_SERVER_RETRIES; @@ -54,22 +54,20 @@ libbitcoin_client::libbitcoin_client(std::string url) : is_connected = true; } -std::string libbitcoin_client::send_transaction(std::string tx) { +std::string libbitcoin_client::send_transaction(const std::string &tx) { std::string res; - auto error_handler = [&](const std::error_code &ec) { + auto error_handler = [](const std::error_code &ec) { elog("error on sending bitcoin transaction ${error_code}", ("error_code", ec.message())); }; - auto result_handler = [&](libbitcoin::code result_code) { + auto result_handler = [&res](libbitcoin::code result_code) { ilog("result code on sending transaction ${result_code}", ("result_code", result_code.message())); res = std::to_string(result_code.value()); }; - libbitcoin::explorer::config::transaction transaction(tx); - - libbitcoin::chain::transaction trx; + const libbitcoin::explorer::config::transaction transaction(tx); // This validates the tx, submits it to local tx pool, and notifies peers. obelisk_client.transaction_pool_broadcast(error_handler, result_handler, transaction); @@ -78,22 +76,22 @@ std::string libbitcoin_client::send_transaction(std::string tx) { return res; } -libbitcoin::chain::output::list libbitcoin_client::get_transaction(std::string tx_id, std::string &tx_hash, uint32_t &confirmitions) { +libbitcoin::chain::output::list libbitcoin_client::get_transaction(const std::string &tx_id, std::string &tx_hash, uint32_t &confirmitions) { libbitcoin::chain::output::list outs; - auto error_handler = [&](const std::error_code &ec) { + auto error_handler = [&tx_id](const std::error_code &ec) { elog("error on fetch_trx_by_hash: ${hash} ${error_code}", ("hash", tx_id)("error_code", ec.message())); }; - auto transaction_handler = [&](const libbitcoin::chain::transaction &tx_handler) { + auto transaction_handler = [&tx_hash, &confirmitions, &outs](const libbitcoin::chain::transaction &tx_handler) { tx_hash = libbitcoin::config::hash256(tx_handler.hash(false)).to_string(); // TODO try to find this value (confirmitions) confirmitions = 1; outs = tx_handler.outputs(); }; - libbitcoin::hash_digest hash = libbitcoin::config::hash256(tx_id); + const libbitcoin::hash_digest hash = libbitcoin::config::hash256(tx_id); // obelisk_client.blockchain_fetch_transaction (error_handler, transaction_handler,hash); obelisk_client.blockchain_fetch_transaction2(error_handler, transaction_handler, hash); @@ -103,14 +101,14 @@ libbitcoin::chain::output::list libbitcoin_client::get_transaction(std::string t return outs; } -std::vector libbitcoin_client::listunspent(std::string address, double amount) { +std::vector libbitcoin_client::listunspent(const std::string &address, double amount) { std::vector result; - auto error_handler = [&](const std::error_code &ec) { + auto error_handler = [](const std::error_code &ec) { elog("error on list_unspent ${error_code}", ("error_code", ec.message())); }; - auto replay_handler = [&](const libbitcoin::chain::points_value &points) { + auto replay_handler = [&result](const libbitcoin::chain::points_value &points) { for (auto &point : points.points) { list_unspent_replay output; output.hash = libbitcoin::config::hash256(point.hash()).to_string(); @@ -120,8 +118,8 @@ std::vector libbitcoin_client::listunspent(std::string addr } }; - libbitcoin::wallet::payment_address payment_address(address); - uint64_t satoshi = 100000000 * amount; + const libbitcoin::wallet::payment_address payment_address(address); + const auto satoshi = static_cast(100000000 * amount); obelisk_client.blockchain_fetch_unspent_outputs(error_handler, replay_handler, payment_address, satoshi, libbitcoin::wallet::select_outputs::algorithm::individual); @@ -135,12 +133,12 @@ bool libbitcoin_client::get_is_test_net() { bool result = false; - auto error_handler = [&](const std::error_code &ec) { + auto error_handler = [](const std::error_code &ec) { elog("error on fetching genesis block ${error_code}", ("error_code", ec.message())); }; - auto block_header_handler = [&](const libbitcoin::chain::header &block_header) { - std::string hash_str = libbitcoin::config::hash256(block_header.hash()).to_string(); + auto block_header_handler = [&result](const libbitcoin::chain::header &block_header) { + const std::string hash_str = libbitcoin::config::hash256(block_header.hash()).to_string(); if (hash_str == GENESIS_TESTNET_HASH || hash_str == GENESIS_REGTEST_HASH) { result = true; } @@ -152,7 +150,7 @@ bool libbitcoin_client::get_is_test_net() { return result; } -uint64_t libbitcoin_client::get_fee_from_trx(libbitcoin::chain::transaction trx) { +uint64_t libbitcoin_client::get_fee_from_trx(const libbitcoin::chain::transaction &trx) { bool general_fee_est_error = false; if (trx.is_coinbase()) { @@ -169,15 +167,15 @@ uint64_t libbitcoin_client::get_fee_from_trx(libbitcoin::chain::transaction trx) // fetch the trx to get total input value uint64_t total_input_value = 0; - auto transaction_handler = [&](const libbitcoin::chain::transaction &tx_handler) { + auto transaction_handler = [&prev_out_trxs, &total_input_value](const libbitcoin::chain::transaction &tx_handler) { std::vector indexes = prev_out_trxs[tx_handler.hash()]; - for (auto &index : indexes) { + for (const auto &index : indexes) { total_input_value += tx_handler.outputs()[index].value(); } }; - auto error_handler = [&](const std::error_code &ec) { + auto error_handler = [&general_fee_est_error](const std::error_code &ec) { elog("error on fetching trx ${error_code}", ("error_code", ec.message())); general_fee_est_error = true; }; @@ -201,12 +199,12 @@ uint64_t libbitcoin_client::get_fee_from_trx(libbitcoin::chain::transaction trx) } } -uint64_t libbitcoin_client::get_average_fee_from_trxs(std::vector trx_list) { +uint64_t libbitcoin_client::get_average_fee_from_trxs(const std::vector &trx_list) { std::vector fee_per_trxs; for (auto &trx : trx_list) { - uint64_t fee = get_fee_from_trx(trx); + const uint64_t fee = get_fee_from_trx(trx); if (fee > 0) { fee_per_trxs.emplace_back(fee); } diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp index 4426983a..9fde979b 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/libbitcoin_client.hpp @@ -5,13 +5,13 @@ #include #include -#include #define LIBBITCOIN_SERVER_TIMEOUT (10) #define LIBBITCOIN_SERVER_RETRIES (100) #define DEAFULT_LIBBITCOIN_TRX_FEE (20000) -#define MAX_TRXS_IN_MEMORY_POOL (30000) +#define MAX_TRXS_IN_MEMORY_POOL (10000) #define MIN_TRXS_IN_BUCKET (100) +#define MAX_THREADS (5) #define GENESIS_MAINNET_HASH "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" #define GENESIS_TESTNET_HASH "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" @@ -19,9 +19,6 @@ namespace graphene { namespace peerplays_sidechain { -typedef std::function - block_update_handler; - struct list_unspent_replay { std::string hash; uint64_t value; @@ -30,12 +27,12 @@ struct list_unspent_replay { class libbitcoin_client { public: - libbitcoin_client(std::string url); - std::string send_transaction(const std::string tx); - libbitcoin::chain::output::list get_transaction(std::string tx_id, std::string &tx_hash, uint32_t &confirmitions); - std::vector listunspent(std::string address, double amount); - uint64_t get_average_fee_from_trxs(std::vector trx_list); - uint64_t get_fee_from_trx(libbitcoin::chain::transaction trx); + explicit libbitcoin_client(const std::string &url); + std::string send_transaction(const std::string &tx); + libbitcoin::chain::output::list get_transaction(const std::string &tx_id, std::string &tx_hash, uint32_t &confirmitions); + std::vector listunspent(const std::string &address, double amount); + uint64_t get_average_fee_from_trxs(const std::vector &trx_list); + uint64_t get_fee_from_trx(const libbitcoin::chain::transaction &trx); bool get_is_test_net(); private: diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index 96e8ec9c..36141ed4 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -63,6 +63,7 @@ public: std::string label; }; + virtual ~bitcoin_client_base() = default; virtual uint64_t estimatesmartfee(uint16_t conf_target = 1) = 0; virtual std::vector getblock(const block_data &block, int32_t verbosity = 2) = 0; virtual btc_tx getrawtransaction(const std::string &txid, const bool verbose = false) = 0; @@ -70,8 +71,8 @@ public: virtual std::string getblockchaininfo() = 0; virtual std::vector listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999) = 0; virtual std::string sendrawtransaction(const std::string &tx_hex) = 0; - virtual void importmulti(const std::vector &address_or_script_array, const bool rescan = true) { - ; + virtual void importmulti(const std::vector &address_or_script_array, const bool rescan = true){ + //! Default implementation does nothing }; virtual std::string loadwallet(const std::string &filename) { return ""; @@ -96,44 +97,37 @@ protected: }; class bitcoin_rpc_client : public bitcoin_client_base, public rpc_client { -public: public: bitcoin_rpc_client(const std::vector &_credentials, bool _debug_rpc_calls, bool _simulate_connection_reselection); - - uint64_t estimatesmartfee(uint16_t conf_target = 1); - std::vector getblock(const block_data &block, int32_t verbosity = 2); - btc_tx getrawtransaction(const std::string &txid, const bool verbose = false); - void getnetworkinfo(); - std::string getblockchaininfo(); - void importmulti(const std::vector &address_or_script_array, const bool rescan = true); + uint64_t estimatesmartfee(uint16_t conf_target = 1) final; + std::vector getblock(const block_data &block, int32_t verbosity = 2) final; + btc_tx getrawtransaction(const std::string &txid, const bool verbose = false) final; + void getnetworkinfo() final; + std::string getblockchaininfo() final; + void importmulti(const std::vector &address_or_script_array, const bool rescan = true) final; std::vector listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999); - std::vector listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999); - std::string loadwallet(const std::string &filename); - std::string sendrawtransaction(const std::string &tx_hex); - std::string walletlock(); - bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); + std::vector listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999) final; + std::string loadwallet(const std::string &filename) final; + std::string sendrawtransaction(const std::string &tx_hex) final; + std::string walletlock() final; + bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60) final; - virtual uint64_t ping(rpc_connection &conn) const override; + uint64_t ping(rpc_connection &conn) const final; private: - std::string ip; - std::string user; - std::string password; - std::string wallet_name; - std::string wallet_password; uint32_t bitcoin_major_version; }; class bitcoin_libbitcoin_client : public bitcoin_client_base, public libbitcoin_client { public: - bitcoin_libbitcoin_client(std::string url); - uint64_t estimatesmartfee(uint16_t conf_target = 1); - std::vector getblock(const block_data &block, int32_t verbosity = 2); - btc_tx getrawtransaction(const std::string &txid, const bool verbose = false); - void getnetworkinfo(); - std::string getblockchaininfo(); - std::vector listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999); - std::string sendrawtransaction(const std::string &tx_hex); + explicit bitcoin_libbitcoin_client(const std::string &url); + uint64_t estimatesmartfee(uint16_t conf_target = 1) final; + std::vector getblock(const block_data &block, int32_t verbosity = 2) final; + btc_tx getrawtransaction(const std::string &txid, const bool verbose = false) final; + void getnetworkinfo() final; + std::string getblockchaininfo() final; + std::vector listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf = 1, const uint32_t maxconf = 9999999) final; + std::string sendrawtransaction(const std::string &tx_hex) final; private: bool is_test_net = false; @@ -145,13 +139,13 @@ private: class zmq_listener_base { public: - virtual ~zmq_listener_base(){}; - zmq_listener_base(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0) { - ip = _ip; - block_zmq_port = _block_zmq_port; - trx_zmq_port = _trx_zmq_port; - stopped = false; - }; + zmq_listener_base(const std::string &_ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0) : + ip(_ip), + block_zmq_port(_block_zmq_port), + trx_zmq_port(_trx_zmq_port), + stopped(false){}; + virtual ~zmq_listener_base() = default; + virtual void start() = 0; boost::signals2::signal block_event_received; boost::signals2::signal trx_event_received; @@ -167,9 +161,9 @@ protected: class zmq_listener : public zmq_listener_base { public: - zmq_listener(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0); - virtual ~zmq_listener(); - void start(); + zmq_listener(const std::string &_ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port = 0); + ~zmq_listener() final; + void start() final; private: void handle_zmq(); @@ -181,9 +175,9 @@ private: class zmq_listener_libbitcoin : public zmq_listener_base { public: - zmq_listener_libbitcoin(std::string _ip, uint32_t _block_zmq_port = 9093, uint32_t _trx_zmq_port = 9094); - virtual ~zmq_listener_libbitcoin(); - void start(); + zmq_listener_libbitcoin(const std::string &_ip, uint32_t _block_zmq_port = 9093, uint32_t _trx_zmq_port = 9094); + ~zmq_listener_libbitcoin() final; + void start() final; private: void handle_block(); @@ -192,6 +186,7 @@ private: libbitcoin::protocol::zmq::context block_context; libbitcoin::protocol::zmq::socket block_socket; libbitcoin::protocol::zmq::poller block_poller; + libbitcoin::protocol::zmq::context trx_context; libbitcoin::protocol::zmq::socket trx_socket; libbitcoin::protocol::zmq::poller trx_poller; @@ -202,17 +197,17 @@ private: class sidechain_net_handler_bitcoin : public sidechain_net_handler { public: sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); - virtual ~sidechain_net_handler_bitcoin(); + ~sidechain_net_handler_bitcoin() final; - bool process_proposal(const proposal_object &po); - void process_primary_wallet(); - void process_sidechain_addresses(); - bool process_deposit(const son_wallet_deposit_object &swdo); - bool process_withdrawal(const son_wallet_withdraw_object &swwo); - std::string process_sidechain_transaction(const sidechain_transaction_object &sto); - std::string send_sidechain_transaction(const sidechain_transaction_object &sto); - bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); - virtual optional estimate_withdrawal_transaction_fee() const override; + bool process_proposal(const proposal_object &po) final; + void process_primary_wallet() final; + void process_sidechain_addresses() final; + bool process_deposit(const son_wallet_deposit_object &swdo) final; + bool process_withdrawal(const son_wallet_withdraw_object &swwo) final; + std::string process_sidechain_transaction(const sidechain_transaction_object &sto) final; + std::string send_sidechain_transaction(const sidechain_transaction_object &sto) final; + bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) final; + optional estimate_withdrawal_transaction_fee() const final; private: std::vector _rpc_credentials; @@ -229,10 +224,16 @@ private: fc::future on_changed_objects_task; bitcoin::bitcoin_address::network network_type; - uint32_t bitcoin_major_version; std::mutex event_handler_mutex; - typedef std::lock_guard scoped_lock; + using scoped_lock = std::lock_guard; + + boost::asio::io_context io_context_block; + boost::asio::executor_work_guard work_guard_block; + boost::thread_group thread_pool_block; + boost::asio::io_context io_context_trx; + boost::asio::executor_work_guard work_guard_trx; + boost::thread_group thread_pool_trx; std::string create_primary_wallet_address(const std::vector &son_pubkeys); @@ -240,7 +241,7 @@ private: std::string create_deposit_transaction(const son_wallet_deposit_object &swdo); std::string create_withdrawal_transaction(const son_wallet_withdraw_object &swwo); - std::string create_transaction(const std::vector &inputs, const fc::flat_map outputs, std::string &redeem_script); + std::string create_transaction(const std::vector &inputs, const fc::flat_map outputs, const std::string &redeem_script); std::string sign_transaction(const sidechain_transaction_object &sto); std::string send_transaction(const sidechain_transaction_object &sto); @@ -249,6 +250,8 @@ private: std::string get_redeemscript_for_userdeposit(const std::string &user_address); void on_changed_objects(const vector &ids, const flat_set &accounts); void on_changed_objects_cb(const vector &ids, const flat_set &accounts); + + void init_thread_pool(boost::asio::io_context &io_context, boost::thread_group &thread_pool, int num_threads); }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 974670ea..99102d2e 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -54,8 +54,8 @@ uint64_t bitcoin_rpc_client::estimatesmartfee(uint16_t conf_target) { } std::vector bitcoin_rpc_client::getblock(const block_data &block, int32_t verbosity) { - std::string params = std::string("[\"") + block.block_hash + std::string("\",") + std::to_string(verbosity) + std::string("]"); - std::string str = send_post_request("getblock", params, debug_rpc_calls); + const std::string params = std::string("[\"") + block.block_hash + std::string("\",") + std::to_string(verbosity) + std::string("]"); + const std::string str = send_post_request("getblock", params, debug_rpc_calls); std::vector result; if (str.empty()) { @@ -66,7 +66,7 @@ std::vector bitcoin_rpc_client::getblock(const block_data &block, boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); - auto json_result = json.get_child_optional("result"); + const auto json_result = json.get_child_optional("result"); for (const auto &tx_child : json_result.get().get_child("tx")) { const auto &tx = tx_child.second; @@ -103,8 +103,8 @@ std::vector bitcoin_rpc_client::getblock(const block_data &block, } void bitcoin_rpc_client::getnetworkinfo() { - std::string params = std::string("[]"); - std::string str = send_post_request("getnetworkinfo", params, debug_rpc_calls); + static const std::string params = std::string("[]"); + const std::string str = send_post_request("getnetworkinfo", params, debug_rpc_calls); std::stringstream network_info_ss(str); boost::property_tree::ptree network_info_json; @@ -115,8 +115,8 @@ void bitcoin_rpc_client::getnetworkinfo() { } btc_tx bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { - std::string params = std::string("[\"") + txid + std::string("\",") + (verbose ? "true" : "false") + std::string("]"); - std::string str = send_post_request("getrawtransaction", params, debug_rpc_calls); + const std::string params = std::string("[\"") + txid + std::string("\",") + (verbose ? "true" : "false") + std::string("]"); + const std::string str = send_post_request("getrawtransaction", params, debug_rpc_calls); btc_tx tx; @@ -126,10 +126,10 @@ btc_tx bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool if (tx_json.count("error") && tx_json.get_child("error").empty()) { - std::string tx_txid = tx_json.get("result.txid"); - uint32_t tx_confirmations = tx_json.get("result.confirmations"); + const std::string tx_txid = tx_json.get("result.txid"); + const uint32_t tx_confirmations = tx_json.get("result.confirmations"); - tx.tx_txid = tx_txid; + tx.tx_txid = std::move(tx_txid); tx.tx_confirmations = tx_confirmations; for (auto &input : tx_json.get_child("result.vout")) { @@ -332,14 +332,14 @@ bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_ else return true; } -bitcoin_libbitcoin_client::bitcoin_libbitcoin_client(std::string url) : +bitcoin_libbitcoin_client::bitcoin_libbitcoin_client(const std::string &url) : libbitcoin_client(url) { estimate_fee_ext = std::unique_ptr(new estimate_fee_external()); } uint64_t bitcoin_libbitcoin_client::estimatesmartfee(uint16_t conf_target) { - std::vector> fees = estimate_fee_ext->get_fee_external(conf_target); + const std::vector> fees = estimate_fee_ext->get_fee_external(conf_target); std::vector accumulated_fees; for (auto &external_fees : fees) { if (external_fees.second != 0) { @@ -357,28 +357,30 @@ uint64_t bitcoin_libbitcoin_client::estimatesmartfee(uint16_t conf_target) { std::vector bitcoin_libbitcoin_client::getblock(const block_data &block, int32_t verbosity) { - std::unique_lock lck(libbitcoin_event_mutex); + { + std::unique_lock lck(libbitcoin_event_mutex); - // estimate fee - const auto &block_trxs = block.block.transactions(); - std::vector bucket_trxs; - for (auto &mem_pool_trx : trx_memory_pool) { - for (auto &trx : block_trxs) { - if (mem_pool_trx.hash() == trx.hash()) { - bucket_trxs.emplace_back(mem_pool_trx); - break; + // estimate fee + const auto &block_trxs = block.block.transactions(); + std::vector bucket_trxs; + for (auto &mem_pool_trx : trx_memory_pool) { + for (auto &trx : block_trxs) { + if (mem_pool_trx.hash() == trx.hash()) { + bucket_trxs.emplace_back(mem_pool_trx); + break; + } } } - } - uint64_t average_fee = get_average_fee_from_trxs(bucket_trxs); - if (average_fee > 0 && bucket_trxs.size() >= MIN_TRXS_IN_BUCKET) { - current_internal_fee = average_fee; - } + const uint64_t average_fee = get_average_fee_from_trxs(bucket_trxs); + if (average_fee > 0 && bucket_trxs.size() >= MIN_TRXS_IN_BUCKET) { + current_internal_fee = average_fee; + } - // We could consider accumulation which could spread to multiple blocks for better metric - // for now we only keep tracking for not confirmed transaction until we get next block - trx_memory_pool.clear(); + // We could consider accumulation which could spread to multiple blocks for better metric + // for now we only keep tracking for not confirmed transaction until we get next block + trx_memory_pool.clear(); + } std::vector result; @@ -481,8 +483,8 @@ std::string bitcoin_libbitcoin_client::getblockchaininfo() { std::vector bitcoin_libbitcoin_client::listunspent_by_address_and_amount(const std::string &address, double transfer_amount, const uint32_t minconf, const uint32_t maxconf) { std::vector result; - std::vector outputs = listunspent(address, transfer_amount); - for (auto &output : outputs) { + const std::vector outputs = listunspent(address, transfer_amount); + for (const auto &output : outputs) { btc_txout txo; txo.txid_ = output.hash; txo.out_num_ = output.index; @@ -494,12 +496,12 @@ std::vector bitcoin_libbitcoin_client::listunspent_by_address_and_amo } std::string bitcoin_libbitcoin_client::sendrawtransaction(const std::string &tx_hex) { - std::string res = send_transaction(tx_hex); + const std::string res = send_transaction(tx_hex); return res; } uint64_t bitcoin_rpc_client::ping(rpc_connection &conn) const { - std::string str = send_post_request(conn, "getblockcount", "[]", debug_rpc_calls); + const std::string str = send_post_request(conn, "getblockcount", "[]", debug_rpc_calls); if (str.length() > 0) return std::stoll(str); return std::numeric_limits::max(); @@ -507,7 +509,7 @@ uint64_t bitcoin_rpc_client::ping(rpc_connection &conn) const { // ============================================================================= -zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq_block_port, uint32_t _zmq_trx_port) : +zmq_listener::zmq_listener(const std::string &_ip, uint32_t _zmq_block_port, uint32_t _zmq_trx_port) : zmq_listener_base(_ip, _zmq_block_port, _zmq_trx_port), ctx(1), socket(ctx, ZMQ_SUB) { @@ -577,7 +579,7 @@ void zmq_listener::handle_zmq() { // ============================================================================= -zmq_listener_libbitcoin::zmq_listener_libbitcoin(std::string _ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port) : +zmq_listener_libbitcoin::zmq_listener_libbitcoin(const std::string &_ip, uint32_t _block_zmq_port, uint32_t _trx_zmq_port) : zmq_listener_base(_ip, _block_zmq_port, _trx_zmq_port), block_socket(block_context, libbitcoin::protocol::zmq::socket::role::subscriber), trx_socket(trx_context, libbitcoin::protocol::zmq::socket::role::subscriber) { @@ -590,7 +592,7 @@ zmq_listener_libbitcoin::~zmq_listener_libbitcoin() { } void zmq_listener_libbitcoin::start() { - std::string endpoint_address = "tcp://" + ip; + const std::string endpoint_address = "tcp://" + ip; libbitcoin::config::endpoint block_address(endpoint_address, block_zmq_port); libbitcoin::config::endpoint trx_address(endpoint_address, trx_zmq_port); @@ -662,18 +664,20 @@ void zmq_listener_libbitcoin::handle_block() { // ============================================================================= sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : - sidechain_net_handler(sidechain_type::bitcoin, _plugin, options) { + sidechain_net_handler(sidechain_type::bitcoin, _plugin, options), + work_guard_block(io_context_block.get_executor()), + work_guard_trx(io_context_trx.get_executor()) { if (options.count("debug-rpc-calls")) { debug_rpc_calls = options.at("debug-rpc-calls").as(); } - bool simulate_connection_reselection = options.at("simulate-rpc-connection-reselection").as(); + const bool simulate_connection_reselection = options.at("simulate-rpc-connection-reselection").as(); - std::vector ips = options.at("bitcoin-node-ip").as>(); + const std::vector ips = options.at("bitcoin-node-ip").as>(); bitcoin_node_zmq_port = options.at("bitcoin-node-zmq-port").as(); - uint32_t rpc_port = options.at("bitcoin-node-rpc-port").as(); - std::string rpc_user = options.at("bitcoin-node-rpc-user").as(); - std::string rpc_password = options.at("bitcoin-node-rpc-password").as(); + const uint32_t rpc_port = options.at("bitcoin-node-rpc-port").as(); + const std::string rpc_user = options.at("bitcoin-node-rpc-user").as(); + const std::string rpc_password = options.at("bitcoin-node-rpc-password").as(); if (options.count("use-bitcoind-client")) { use_bitcoind_client = options.at("use-bitcoind-client").as(); @@ -732,7 +736,7 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain listener = std::unique_ptr(new zmq_listener_libbitcoin(libbitcoin_server_ip, libbitcoin_block_zmq_port, libbitcoin_trx_zmq_port)); } - std::string chain_info = bitcoin_client->getblockchaininfo(); + const std::string chain_info = bitcoin_client->getblockchaininfo(); using namespace bitcoin; network_type = bitcoin_address::network::mainnet; @@ -745,12 +749,15 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain bitcoin_client->getnetworkinfo(); + init_thread_pool(io_context_block, thread_pool_block, MAX_THREADS); + init_thread_pool(io_context_trx, thread_pool_trx, MAX_THREADS); + listener->block_event_received.connect([this](const block_data &block_event_data) { - std::thread(&sidechain_net_handler_bitcoin::block_handle_event, this, block_event_data).detach(); + io_context_block.post(boost::bind(&sidechain_net_handler_bitcoin::block_handle_event, this, block_event_data)); }); listener->trx_event_received.connect([this](const libbitcoin::chain::transaction &trx_event_data) { - std::thread(&sidechain_net_handler_bitcoin::trx_handle_event, this, trx_event_data).detach(); + io_context_trx.post(boost::bind(&sidechain_net_handler_bitcoin::trx_handle_event, this, trx_event_data)); }); listener->start(); @@ -761,6 +768,11 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain } sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() { + work_guard_block.reset(); + work_guard_trx.reset(); + thread_pool_block.join_all(); + thread_pool_trx.join_all(); + try { if (on_changed_objects_task.valid()) { on_changed_objects_task.cancel_and_wait(__FUNCTION__); @@ -1212,7 +1224,7 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj return false; } - std::string tx_str = create_deposit_transaction(swdo); + const std::string tx_str = create_deposit_transaction(swdo); if (!tx_str.empty()) { const chain::global_property_object &gpo = database.get_global_properties(); @@ -1263,7 +1275,7 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw return false; } - std::string tx_str = create_withdrawal_transaction(swwo); + const std::string tx_str = create_withdrawal_transaction(swwo); if (!tx_str.empty()) { const chain::global_property_object &gpo = database.get_global_properties(); @@ -1327,7 +1339,7 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain return false; } - btc_tx tx = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true); + const btc_tx tx = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true); if (tx.tx_in_list.empty()) { // This case will result with segmentation fault. @@ -1349,11 +1361,11 @@ bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain payment_type_address = payment_type::P2WSH; } - btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address); + const btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address); - std::string tx_txid = tx.tx_txid; - uint32_t tx_confirmations = tx.tx_confirmations; - std::string tx_address = addr.get_address(); + const std::string tx_txid = tx.tx_txid; + const uint32_t tx_confirmations = tx.tx_confirmations; + const std::string tx_address = addr.get_address(); int64_t tx_amount = -1; if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) { @@ -1397,14 +1409,14 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s if (use_bitcoind_client) { payment_type_address = payment_type::P2WSH; } - btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address); + const btc_weighted_multisig_address addr(pubkey_weights, network_type, payment_type_address); std::stringstream ss; ss << "{\"result\": {\"address\": \"" << addr.get_address() << "\", \"redeemScript\": \"" << fc::to_hex(addr.get_redeem_script()) << "\"" << "}, \"error\":null}"; - std::string res = ss.str(); + const std::string res = ss.str(); return res; } @@ -1423,8 +1435,8 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(con std::stringstream prev_sw_ss(s); boost::property_tree::ptree prev_sw_pt; boost::property_tree::read_json(prev_sw_ss, prev_sw_pt); - std::string prev_pw_address = prev_sw_pt.get("address"); - std::string prev_redeem_script = prev_sw_pt.get("redeemScript"); + const std::string prev_pw_address = prev_sw_pt.get("address"); + const std::string prev_redeem_script = prev_sw_pt.get("redeemScript"); if (prev_pw_address == new_sw_address) { wlog("BTC previous and new primary wallet addresses are same. No funds moving needed [from ${prev_sw} to ${new_sw_address}]", ("prev_swo", prev_swo.id)("active_sw", new_sw_address)); @@ -1465,18 +1477,18 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_ return ""; } // Get redeem script for deposit address - std::string redeem_script = get_redeemscript_for_userdeposit(swdo.sidechain_from); - std::string pw_address_json = obj->addresses.find(sidechain)->second; + const std::string redeem_script = get_redeemscript_for_userdeposit(swdo.sidechain_from); + const std::string pw_address_json = obj->addresses.find(sidechain)->second; std::stringstream ss(pw_address_json); boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); - std::string pw_address = json.get("address"); + const std::string pw_address = json.get("address"); - std::string txid = swdo.sidechain_transaction_id; - std::string suid = swdo.sidechain_uid; - std::string nvout = suid.substr(suid.find_last_of("-") + 1); + const std::string txid = swdo.sidechain_transaction_id; + const std::string suid = swdo.sidechain_uid; + const std::string nvout = suid.substr(suid.find_last_of("-") + 1); uint64_t deposit_amount = swdo.sidechain_amount.value; uint64_t fee_rate = bitcoin_client->estimatesmartfee(); const uint64_t min_fee_rate = 1000; @@ -1488,7 +1500,7 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_ } deposit_amount -= fee_rate; // Deduct minimum relay fee - double transfer_amount = (double)deposit_amount / 100000000.0; + const double transfer_amount = (double)deposit_amount / 100000000.0; std::vector inputs; fc::flat_map outputs; @@ -1512,14 +1524,14 @@ std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const s return ""; } - std::string pw_address_json = obj->addresses.find(sidechain)->second; + const std::string pw_address_json = obj->addresses.find(sidechain)->second; std::stringstream ss(pw_address_json); boost::property_tree::ptree json; boost::property_tree::read_json(ss, json); - std::string pw_address = json.get("address"); - std::string redeem_script = json.get("redeemScript"); + const std::string pw_address = json.get("address"); + const std::string redeem_script = json.get("redeemScript"); int64_t fee_rate = bitcoin_client->estimatesmartfee(); const int64_t min_fee_rate = 1000; @@ -1551,7 +1563,7 @@ std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const s return create_transaction(inputs, outputs, redeem_script); } -std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector &inputs, const fc::flat_map outputs, std::string &redeem_script) { +std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector &inputs, const fc::flat_map outputs, const std::string &redeem_script) { using namespace bitcoin; bitcoin_transaction_builder tb; @@ -1570,15 +1582,15 @@ std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector< } const auto tx = tb.get_transaction(); - std::string hex_tx = fc::to_hex(pack(tx)); - std::string tx_raw = write_transaction_data(hex_tx, in_amounts, redeem_script); + const std::string hex_tx = fc::to_hex(pack(tx)); + const std::string tx_raw = write_transaction_data(hex_tx, in_amounts, redeem_script); return tx_raw; } std::string sidechain_net_handler_bitcoin::sign_transaction(const sidechain_transaction_object &sto) { using namespace bitcoin; - std::string pubkey = plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain); - std::string prvkey = get_private_key(pubkey); + const std::string pubkey = plugin.get_current_son_object(sidechain).sidechain_public_keys.at(sidechain); + const std::string prvkey = get_private_key(pubkey); std::vector in_amounts; std::string tx_hex; std::string redeem_script; @@ -1589,14 +1601,14 @@ std::string sidechain_net_handler_bitcoin::sign_transaction(const sidechain_tran return ""; } const auto secret = btc_private_key->get_secret(); - bitcoin::bytes privkey_signing(secret.data(), secret.data() + secret.data_size()); + const bitcoin::bytes privkey_signing(secret.data(), secret.data() + secret.data_size()); read_transaction_data(sto.transaction, tx_hex, in_amounts, redeem_script); - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - std::vector redeem_scripts(tx.vin.size(), parse_hex(redeem_script)); + const bitcoin_transaction tx = unpack(parse_hex(tx_hex)); + const std::vector redeem_scripts(tx.vin.size(), parse_hex(redeem_script)); auto sigs = sign_witness_transaction_part(tx, redeem_scripts, in_amounts, privkey_signing, btc_context(), 1); - std::string tx_signature = write_transaction_signatures(sigs); + const std::string tx_signature = write_transaction_signatures(sigs); return tx_signature; } @@ -1613,7 +1625,7 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran std::vector redeem_scripts(tx.vin.size(), parse_hex(redeem_script)); - uint32_t inputs_number = in_amounts.size(); + const uint32_t inputs_number = in_amounts.size(); vector dummy; dummy.resize(inputs_number); // Organise weighted address signatures @@ -1645,8 +1657,8 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran } } - std::string final_tx_hex = fc::to_hex(pack(tx)); - std::string res = bitcoin_client->sendrawtransaction(final_tx_hex); + const std::string final_tx_hex = fc::to_hex(pack(tx)); + const std::string res = bitcoin_client->sendrawtransaction(final_tx_hex); if (res.empty()) { return res; @@ -1657,7 +1669,7 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran void sidechain_net_handler_bitcoin::block_handle_event(const block_data &event_data) { - auto vins = bitcoin_client->getblock(event_data); + const auto vins = bitcoin_client->getblock(event_data); add_to_son_listener_log("BLOCK : " + event_data.block_hash); @@ -1698,6 +1710,7 @@ void sidechain_net_handler_bitcoin::block_handle_event(const block_data &event_d } void sidechain_net_handler_bitcoin::trx_handle_event(const libbitcoin::chain::transaction &trx_data) { + bitcoin_client->import_trx_to_memory_pool(trx_data); } @@ -1720,20 +1733,20 @@ std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(cons auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(son.public_key))); pubkey_weights.push_back(std::make_pair(pub_key, son.weight)); } - auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key))); + const auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key))); payment_type payment_type_address = payment_type::P2SH_WSH; if (use_bitcoind_client) { payment_type_address = payment_type::P2WSH; } - btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type, payment_type_address); + const btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights, network_type, payment_type_address); return fc::to_hex(deposit_addr.get_redeem_script()); } void sidechain_net_handler_bitcoin::on_changed_objects(const vector &ids, const flat_set &accounts) { - fc::time_point now = fc::time_point::now(); - int64_t time_to_next_changed_objects_processing = 5000; + const fc::time_point now = fc::time_point::now(); + const int64_t time_to_next_changed_objects_processing = 5000; fc::time_point next_wakeup(now + fc::microseconds(time_to_next_changed_objects_processing)); @@ -1784,6 +1797,12 @@ void sidechain_net_handler_bitcoin::on_changed_objects_cb(const vector