From 73e9ebb0550848b7248be2ee936617e54c891fe5 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 18 Mar 2022 21:31:31 +0300 Subject: [PATCH] #325 - implement importmulti function --- .../sidechain_net_handler_bitcoin.hpp | 20 +++++++ .../sidechain_net_handler_bitcoin.cpp | 58 ++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) 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 13eaf9a6..9f4df6f3 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 @@ -22,6 +22,25 @@ public: }; class bitcoin_rpc_client { +public: + enum class multi_type + { + script, + address + }; + struct multi_params + { + multi_params(multi_type _type, const std::string& _address_or_script, const std::string& _label = "") + : type{_type} + , address_or_script{_address_or_script} + , label{_label} + {} + + multi_type type; + std::string address_or_script; + std::string label; + }; + public: bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password, bool _debug_rpc_calls); @@ -42,6 +61,7 @@ public: std::string gettransaction(const std::string &txid, const bool include_watch_only = false); std::string getblockchaininfo(); void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); + void importmulti(const std::vector& address_or_script_array, const bool rescan = true); 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); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 04a0e604..365d373d 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -572,6 +572,55 @@ void bitcoin_rpc_client::importaddress(const std::string &address_or_script, con } } +void bitcoin_rpc_client::importmulti(const std::vector& address_or_script_array, const bool rescan) { + std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"importmulti\", " + "\"method\": \"importmulti\", \"params\": ["); + + std::string argument_1 = "["; + for(const auto& param : address_or_script_array) { + argument_1 += "{\"scriptPubKey\": "; + if (param.type == multi_type::address) + argument_1 += "{\"address\": \"" + param.address_or_script + "\"}"; + else if (param.type == multi_type::script) + argument_1 += "\"" + param.address_or_script + "\""; + else + FC_THROW("Invalid multi_type."); + argument_1 += ", \"label\": \"" + param.label + "\", \"timestamp\": 0}"; + + //! Note + /* Creation time of the key expressed in UNIX epoch time, + or the string "now" to substitute the current synced blockchain time. The timestamp of the oldest + key will determine how far back blockchain rescans need to begin for missing wallet transactions. + "now" can be specified to bypass scanning, for keys which are known to never have been used, and + 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key + creation time of all keys being imported by the importmulti call will be scanned.*/ + + if (¶m != &address_or_script_array.back()) + argument_1 += ", "; + } + argument_1 += "]"; + + std::string argument_2 = std::string{"{\"rescan\": "} + (rescan ? "true" : "false") + "}"; + body += argument_1 + ", " + argument_2 + "]}"; + + const auto reply = send_post_request(body, debug_rpc_calls); + + if (reply.body.empty()) { + wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); + return; + } + + std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + + if (reply.status == 200) { + return; + } else if (json.count("error") && !json.get_child("error").empty()) { + wlog("Bitcoin RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body)("msg", ss.str())); + } +} + std::vector bitcoin_rpc_client::listunspent(const uint32_t minconf, const uint32_t maxconf) { const auto body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"pp_plugin\", \"method\": " "\"listunspent\", \"params\": [" + @@ -1908,6 +1957,8 @@ void sidechain_net_handler_bitcoin::on_changed_objects(const vector &ids, const flat_set &accounts) { + std::vector address_or_script_array; + for (auto id : ids) { if (id.is()) { const auto &swi = database.get_index_type().indices().get(); @@ -1919,16 +1970,19 @@ void sidechain_net_handler_bitcoin::on_changed_objects_cb(const vector("address"); - bitcoin_client->importaddress(pw_address); + address_or_script_array.emplace_back(bitcoin_rpc_client::multi_params{bitcoin_rpc_client::multi_type::address, pw_address}); } if (pw_pt.count("redeemScript")) { std::string pw_redeem_script = pw_pt.get("redeemScript"); - bitcoin_client->importaddress(pw_redeem_script, "", true, true); + address_or_script_array.emplace_back(bitcoin_rpc_client::multi_params{bitcoin_rpc_client::multi_type::script, pw_redeem_script}); } } } } + + if(!address_or_script_array.empty()) + bitcoin_client->importmulti(address_or_script_array); } // =============================================================================