diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/utils.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/utils.cpp index a82a7c40..6d802a2f 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/utils.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/utils.cpp @@ -96,49 +96,4 @@ std::string write_transaction_data(const std::string &tx, const std::vector get_outputs_from_transaction_by_address(const std::string &tx_json, const std::string &to_address) { - std::stringstream ss(tx_json); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - std::vector result; - - if (json.count("error") && !json.get_child("error").empty()) { - return result; - } - - std::string tx_txid = json.get("result.txid"); - - for (auto &vout : json.get_child("result.vout")) { - std::vector to_addresses; - if (vout.second.find("scriptPubKey") == vout.second.not_found() || - vout.second.get_child("scriptPubKey").find("addresses") == vout.second.get_child("scriptPubKey").not_found()) { - continue; - } - - for (auto &address : vout.second.get_child("scriptPubKey.addresses")) { - to_addresses.push_back(address.second.data()); - } - - if ((to_address == "") || - (std::find(to_addresses.begin(), to_addresses.end(), to_address) != to_addresses.end())) { - std::string tx_amount_s = vout.second.get("value"); - tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); - uint64_t tx_amount = std::stoll(tx_amount_s); - - std::string tx_vout_s = vout.second.get("n"); - uint64_t tx_vout = std::stoll(tx_vout_s); - - prev_out pout; - pout.hash_tx = tx_txid; - pout.n_vout = tx_vout; - pout.amount = tx_amount; - result.push_back(pout); - if (to_address == "") { - return result; - } - } - } - return result; -} - }}} // namespace graphene::peerplays_sidechain::bitcoin diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/types.hpp index 680ab7f8..0997194b 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/types.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/types.hpp @@ -42,15 +42,6 @@ struct prev_out { return false; } - bool operator==(const prev_out &obj) const { - if (this->hash_tx == obj.hash_tx && - this->n_vout == obj.n_vout && - this->amount == obj.amount) { - return true; - } - return false; - } - std::string hash_tx; uint32_t n_vout; uint64_t amount; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp index 430889e5..4e1c4b58 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/utils.hpp @@ -23,6 +23,4 @@ void read_transaction_data(const std::string &string_buf, std::string &tx_hex, s std::string write_transaction_data(const std::string &tx, const std::vector &in_amounts, const std::string &redeem_script); -std::vector get_outputs_from_transaction_by_address(const std::string &tx_json, const std::string &to_address = ""); - }}} // namespace graphene::peerplays_sidechain::bitcoin \ No newline at end of file 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 23c98451..1209ccb9 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 @@ -34,6 +34,7 @@ public: std::string finalizepsbt(std::string const &tx_psbt); std::string getaddressinfo(const std::string &address); std::string getblock(const std::string &block_hash, int32_t verbosity = 2); + std::string getrawtransaction(const std::string &txid, const bool verbose = false); std::string gettransaction(const std::string &txid, const bool include_watch_only = false); void importaddress(const std::string &address_or_script, const std::string &label = "", const bool rescan = true, const bool p2sh = false); std::vector listunspent(const uint32_t minconf = 1, const uint32_t maxconf = 9999999); @@ -85,7 +86,6 @@ public: sidechain_net_handler_bitcoin(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); virtual ~sidechain_net_handler_bitcoin(); - std::string get_current_primary_wallet_address(); bool process_proposal(const proposal_object &po); void process_primary_wallet(); void process_sidechain_addresses(); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 807fc0ba..a47cb244 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -302,6 +302,8 @@ std::string bitcoin_rpc_client::decoderawtransaction(std::string const &tx_hex) boost::property_tree::read_json(ss, json); if (reply.status == 200) { + std::stringstream ss; + boost::property_tree::json_parser::write_json(ss, json.get_child("result")); return ss.str(); } @@ -458,6 +460,34 @@ std::string bitcoin_rpc_client::getblock(const std::string &block_hash, int32_t return ""; } +std::string bitcoin_rpc_client::getrawtransaction(const std::string &txid, const bool verbose) { + std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"getrawtransaction\", \"method\": " + "\"getrawtransaction\", \"params\": ["); + + std::string params = "\"" + txid + "\", " + (verbose ? "true" : "false"); + body = body + params + "] }"; + + const auto reply = send_post_request(body); + + 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 ss.str(); + } + + 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())); + } + return ""; +} + std::string bitcoin_rpc_client::gettransaction(const std::string &txid, const bool include_watch_only) { std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"gettransaction\", \"method\": " "\"gettransaction\", \"params\": ["); @@ -915,22 +945,6 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() { } } -std::string sidechain_net_handler_bitcoin::get_current_primary_wallet_address() { - const auto &idx = database.get_index_type().indices().get(); - auto obj = idx.rbegin(); - if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) { - return ""; - } - - std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->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"); - return pw_address; -} - bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) { ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); @@ -1041,24 +1055,40 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) uint64_t swdo_amount = swdo->sidechain_amount.value; uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1)); - std::string tx_str = bitcoin_client->gettransaction(swdo_txid, true); + std::string tx_str = bitcoin_client->getrawtransaction(swdo_txid, true); std::stringstream tx_ss(tx_str); boost::property_tree::ptree tx_json; boost::property_tree::read_json(tx_ss, tx_json); 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"); - std::string tx_hex = tx_json.get("result.hex"); - std::string tx_hex_json = bitcoin_client->decoderawtransaction(tx_hex); - std::vector pouts = bitcoin::get_outputs_from_transaction_by_address(tx_hex_json, swdo_address); + std::string tx_address = ""; + int64_t tx_amount = -1; + int64_t tx_vout = -1; - bitcoin::prev_out pout; - pout.hash_tx = swdo_txid; - pout.n_vout = swdo_vout; - pout.amount = swdo_amount; + for (auto &input : tx_json.get_child("result.vout")) { + std::string tx_vout_s = input.second.get("n"); + tx_vout = std::stoll(tx_vout_s); + if (tx_vout == swdo_vout) { + for (auto &address : input.second.get_child("scriptPubKey.addresses")) { + if (address.second.data() == swdo_address) { + tx_address = address.second.data(); + break; + } + } + std::string tx_amount_s = input.second.get("value"); + tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); + tx_amount = std::stoll(tx_amount_s); + break; + } + } - process_ok = (std::find(pouts.begin(), pouts.end(), pout) != pouts.end()) && + process_ok = (swdo_txid == tx_txid) && + (swdo_address == tx_address) && + (swdo_amount == tx_amount) && + (swdo_vout == tx_vout) && (gpo.parameters.son_bitcoin_min_tx_confirmations() <= tx_confirmations); } @@ -1079,14 +1109,6 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) } } - if (object_id.is()) { - const auto &idx = database.get_index_type().indices().get(); - const auto swwo = idx.find(object_id); - if (swwo != idx.end()) { - tx_str = create_withdrawal_transaction(*swwo); - } - } - transaction_ok = (op_tx_str == tx_str); } } @@ -1317,7 +1339,7 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() { bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_object &swdo) { - if (proposal_exists(chain::operation::tag::value, swdo.id)) { + if (proposal_exists(chain::operation::tag::value, swdo.id)) { return false; } @@ -1361,7 +1383,7 @@ bool sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_obj bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw_object &swwo) { - if (proposal_exists(chain::operation::tag::value, swwo.id)) { + if (proposal_exists(chain::operation::tag::value, swwo.id)) { return false; } @@ -1423,7 +1445,7 @@ int64_t sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidech return settle_amount; } - std::string tx_str = bitcoin_client->gettransaction(sto.sidechain_transaction, true); + std::string tx_str = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true); std::stringstream tx_ss(tx_str); boost::property_tree::ptree tx_json; boost::property_tree::read_json(tx_ss, tx_json); @@ -1432,19 +1454,35 @@ int64_t sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidech return settle_amount; } + const chain::global_property_object &gpo = database.get_global_properties(); + + using namespace bitcoin; + std::vector> pubkey_weights; + for (auto si : sto.signers) { + std::string pub_key_str = si.sidechain_public_keys.at(sidechain_type::bitcoin); + auto pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(pub_key_str))); + pubkey_weights.push_back(std::make_pair(pub_key, si.weight)); + } + btc_weighted_multisig_address addr(pubkey_weights); + std::string tx_txid = tx_json.get("result.txid"); uint32_t tx_confirmations = tx_json.get("result.confirmations"); - - const chain::global_property_object &gpo = database.get_global_properties(); + std::string tx_address = addr.get_address(); + int64_t tx_amount = -1; if (tx_confirmations >= gpo.parameters.son_bitcoin_min_tx_confirmations()) { if (sto.object_id.is()) { - std::string tx_hex = tx_json.get("result.hex"); - std::string tx_hex_json = bitcoin_client->decoderawtransaction(tx_hex); - std::vector pouts = bitcoin::get_outputs_from_transaction_by_address(tx_hex_json); - if (pouts.size() > 0) { - settle_amount = pouts[0].amount; + for (auto &input : tx_json.get_child("result.vout")) { + for (auto &address : input.second.get_child("scriptPubKey.addresses")) { + if (address.second.data() == tx_address) { + std::string tx_amount_s = input.second.get("value"); + tx_amount_s.erase(std::remove(tx_amount_s.begin(), tx_amount_s.end(), '.'), tx_amount_s.end()); + tx_amount = std::stoll(tx_amount_s); + break; + } + } } + settle_amount = tx_amount; } if (sto.object_id.is()) { @@ -1517,9 +1555,20 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(con } std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_wallet_deposit_object &swdo) { + const auto &idx = database.get_index_type().indices().get(); + auto obj = idx.rbegin(); + if (obj == idx.rend() || obj->addresses.find(sidechain_type::bitcoin) == obj->addresses.end()) { + return ""; + } //Get redeem script for deposit address std::string redeem_script = get_redeemscript_for_userdeposit(swdo.sidechain_to); - std::string pw_address = get_current_primary_wallet_address(); + std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->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 txid = swdo.sidechain_transaction_id; std::string suid = swdo.sidechain_uid; @@ -1667,7 +1716,7 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran signatures.push_back(read_byte_arrays_from_string(sto.signatures[idx].second)); } //Add empty sig for user signature for Deposit transaction - if (sto.object_id.is()) { + if (sto.object_id.type() == son_wallet_deposit_object::type_id) { add_signatures_to_transaction_user_weighted_multisig(tx, signatures); } else { add_signatures_to_transaction_weighted_multisig(tx, signatures);