From bd1bd842cea47f489f4737e6db5ee10895c2d0bf Mon Sep 17 00:00:00 2001 From: obucina <11353193+obucina@users.noreply.github.com> Date: Mon, 6 Apr 2020 18:09:01 +0200 Subject: [PATCH] [SON-325] Added check for approving sidechain_transaction_create_operation (#337) --- .../sidechain_net_handler_bitcoin.hpp | 4 + .../sidechain_net_handler.cpp | 7 - .../sidechain_net_handler_bitcoin.cpp | 304 +++++++++++------- .../sidechain_net_handler_peerplays.cpp | 11 +- 4 files changed, 187 insertions(+), 139 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 b3a157db..e1635765 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 @@ -106,6 +106,10 @@ private: fc::future on_changed_objects_task; + std::string create_primary_wallet_transaction(); + 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 sign_transaction(const sidechain_transaction_object &sto, bool &complete); bool send_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index 13e7b2bf..ff98694f 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -196,19 +196,12 @@ void sidechain_net_handler::process_proposals() { int32_t op_idx_0 = -1; chain::operation op_obj_idx_0; - int32_t op_idx_1 = -1; - chain::operation op_obj_idx_1; if (po->proposed_transaction.operations.size() >= 1) { op_idx_0 = po->proposed_transaction.operations[0].which(); op_obj_idx_0 = po->proposed_transaction.operations[0]; } - if (po->proposed_transaction.operations.size() >= 2) { - op_idx_1 = po->proposed_transaction.operations[1].which(); - op_obj_idx_1 = po->proposed_transaction.operations[1]; - } - switch (op_idx_0) { case chain::operation::tag::value: { should_process = (op_obj_idx_0.get().sidechain == sidechain); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index ff09de87..adb349a5 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -911,19 +911,12 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) int32_t op_idx_0 = -1; chain::operation op_obj_idx_0; - //int32_t op_idx_1 = -1; - //chain::operation op_obj_idx_1; if (po.proposed_transaction.operations.size() >= 1) { op_idx_0 = po.proposed_transaction.operations[0].which(); op_obj_idx_0 = po.proposed_transaction.operations[0]; } - if (po.proposed_transaction.operations.size() >= 2) { - //op_idx_1 = po.proposed_transaction.operations[1].which(); - //op_obj_idx_1 = po.proposed_transaction.operations[1]; - } - switch (op_idx_0) { case chain::operation::tag::value: { @@ -1011,12 +1004,46 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) } case chain::operation::tag::value: { - should_approve = true; + should_approve = false; break; } case chain::operation::tag::value: { - should_approve = true; + object_id_type object_id = op_obj_idx_0.get().object_id; + std::string op_tx_str = op_obj_idx_0.get().transaction; + + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(object_id); + if (swo != idx.end()) { + tx_str = create_primary_wallet_transaction(); + } + } + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swdo = idx.find(object_id); + if (swdo != idx.end()) { + tx_str = create_deposit_transaction(*swdo); + } + } + + 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); + } + } + + should_approve = (op_tx_str == tx_str); + } break; } @@ -1082,46 +1109,12 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { return; } + //======================================================================== + const auto &prev_sw = std::next(active_sw); if (prev_sw != swi.rend()) { - std::stringstream prev_sw_ss(prev_sw->addresses.at(sidechain_type::bitcoin)); - boost::property_tree::ptree prev_sw_pt; - boost::property_tree::read_json(prev_sw_ss, prev_sw_pt); - std::string active_pw_address = active_pw_pt.get_child("result").get("address"); - std::string prev_pw_address = prev_sw_pt.get("address"); - - if (prev_pw_address == active_pw_address) { - elog("BTC previous and new primary wallet addresses are same. No funds moving needed [from ${prev_sw} to ${active_sw}]", ("prev_sw", prev_sw->id)("active_sw", active_sw->id)); - return; - } - - uint64_t fee_rate = bitcoin_client->estimatesmartfee(); - uint64_t min_fee_rate = 1000; - fee_rate = std::max(fee_rate, min_fee_rate); - - double min_amount = ((double)fee_rate / 100000000.0); // Account only for relay fee for now - double total_amount = 0.0; - std::vector inputs = bitcoin_client->listunspent_by_address_and_amount(prev_pw_address, 0); - - if (inputs.size() == 0) { - elog("Failed to find UTXOs to spend for ${pw}", ("pw", prev_pw_address)); - return; - } else { - for (const auto &utx : inputs) { - total_amount += utx.amount_; - } - - if (min_amount >= total_amount) { - elog("Failed not enough BTC to transfer from ${fa}", ("fa", prev_pw_address)); - return; - } - } - - fc::flat_map outputs; - outputs[active_pw_address] = total_amount - min_amount; - - std::string tx_str = create_transaction(inputs, outputs); + std::string tx_str = create_primary_wallet_transaction(); if (!tx_str.empty()) { @@ -1155,42 +1148,8 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { } bool sidechain_net_handler_bitcoin::process_deposit(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 false; - } - 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; - 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(); - uint64_t min_fee_rate = 1000; - fee_rate = std::max(fee_rate, min_fee_rate); - deposit_amount -= fee_rate; // Deduct minimum relay fee - double transfer_amount = (double)deposit_amount / 100000000.0; - - std::vector inputs; - fc::flat_map outputs; - - btc_txout utxo; - utxo.txid_ = txid; - utxo.out_num_ = std::stoul(nvout); - - inputs.push_back(utxo); - - outputs[pw_address] = transfer_amount; - - std::string tx_str = create_transaction(inputs, outputs); + std::string tx_str = create_deposit_transaction(swdo); if (!tx_str.empty()) { const chain::global_property_object &gpo = database.get_global_properties(); @@ -1224,49 +1183,8 @@ 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) { - 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 false; - } - 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"); - - uint64_t fee_rate = bitcoin_client->estimatesmartfee(); - uint64_t min_fee_rate = 1000; - fee_rate = std::max(fee_rate, min_fee_rate); - - double min_amount = ((double)(swwo.withdraw_amount.value + fee_rate) / 100000000.0); // Account only for relay fee for now - double total_amount = 0.0; - std::vector inputs = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0); - - if (inputs.size() == 0) { - elog("Failed to find UTXOs to spend for ${pw}", ("pw", pw_address)); - return ""; - } else { - for (const auto &utx : inputs) { - total_amount += utx.amount_; - } - - if (min_amount > total_amount) { - elog("Failed not enough BTC to spend for ${pw}", ("pw", pw_address)); - return ""; - } - } - - fc::flat_map outputs; - outputs[swwo.withdraw_address] = swwo.withdraw_amount.value / 100000000.0; - if ((total_amount - min_amount) > 0.0) { - outputs[pw_address] = total_amount - min_amount; - } - - std::string tx_str = create_transaction(inputs, outputs); + std::string tx_str = create_withdrawal_transaction(swwo); if (!tx_str.empty()) { const chain::global_property_object &gpo = database.get_global_properties(); @@ -1325,6 +1243,146 @@ bool sidechain_net_handler_bitcoin::send_sidechain_transaction(const sidechain_t return send_transaction(sto, sidechain_transaction); } +std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction() { + const auto &swi = database.get_index_type().indices().get(); + const auto &active_sw = swi.rbegin(); + if (active_sw == swi.rend() || active_sw->addresses.find(sidechain_type::bitcoin) == active_sw->addresses.end()) { + return ""; + } + + const auto &prev_sw = std::next(active_sw); + if (prev_sw == swi.rend()) { + return ""; + } + + std::stringstream active_pw_ss(active_sw->addresses.find(sidechain_type::bitcoin)->second); + boost::property_tree::ptree active_pw_pt; + boost::property_tree::read_json(active_pw_ss, active_pw_pt); + std::string active_pw_address = active_pw_pt.get_child("result").get("address"); + + std::stringstream prev_sw_ss(prev_sw->addresses.find(sidechain_type::bitcoin)->second); + 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_child("result").get("address"); + + if (prev_pw_address == active_pw_address) { + wlog("BTC previous and new primary wallet addresses are same. No funds moving needed [from ${prev_sw} to ${active_sw}]", ("prev_sw", prev_sw->id)("active_sw", active_sw->id)); + return ""; + } + + uint64_t fee_rate = bitcoin_client->estimatesmartfee(); + uint64_t min_fee_rate = 1000; + fee_rate = std::max(fee_rate, min_fee_rate); + + double min_amount = ((double)fee_rate / 100000000.0); // Account only for relay fee for now + double total_amount = 0.0; + std::vector inputs = bitcoin_client->listunspent_by_address_and_amount(prev_pw_address, 0); + + if (inputs.size() == 0) { + elog("Failed to find UTXOs to spend for ${pw}", ("pw", prev_pw_address)); + return ""; + } else { + for (const auto &utx : inputs) { + total_amount += utx.amount_; + } + + if (min_amount >= total_amount) { + elog("Failed not enough BTC to transfer from ${fa}", ("fa", prev_pw_address)); + return ""; + } + } + + fc::flat_map outputs; + outputs[active_pw_address] = total_amount - min_amount; + + return create_transaction(inputs, outputs); +} + +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 ""; + } + + 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; + 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(); + uint64_t min_fee_rate = 1000; + fee_rate = std::max(fee_rate, min_fee_rate); + deposit_amount -= fee_rate; // Deduct minimum relay fee + double transfer_amount = (double)deposit_amount / 100000000.0; + + std::vector inputs; + fc::flat_map outputs; + + btc_txout utxo; + utxo.txid_ = txid; + utxo.out_num_ = std::stoul(nvout); + + inputs.push_back(utxo); + + outputs[pw_address] = transfer_amount; + + return create_transaction(inputs, outputs); +} + +std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { + 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"); + + uint64_t fee_rate = bitcoin_client->estimatesmartfee(); + uint64_t min_fee_rate = 1000; + fee_rate = std::max(fee_rate, min_fee_rate); + + double min_amount = ((double)(swwo.withdraw_amount.value + fee_rate) / 100000000.0); // Account only for relay fee for now + double total_amount = 0.0; + std::vector inputs = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0); + + if (inputs.size() == 0) { + elog("Failed to find UTXOs to spend for ${pw}", ("pw", pw_address)); + return ""; + } else { + for (const auto &utx : inputs) { + total_amount += utx.amount_; + } + + if (min_amount > total_amount) { + elog("Failed not enough BTC to spend for ${pw}", ("pw", pw_address)); + return ""; + } + } + + fc::flat_map outputs; + outputs[swwo.withdraw_address] = swwo.withdraw_amount.value / 100000000.0; + if ((total_amount - min_amount) > 0.0) { + outputs[pw_address] = total_amount - min_amount; + } + + return create_transaction(inputs, outputs); +} + // Creates transaction in any format // Function to actually create transaction should return transaction string, or empty string in case of failure std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector &inputs, const fc::flat_map outputs) { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp index c9c47e4b..e481800f 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp @@ -39,23 +39,16 @@ bool sidechain_net_handler_peerplays::process_proposal(const proposal_object &po int32_t op_idx_0 = -1; chain::operation op_obj_idx_0; - //int32_t op_idx_1 = -1; - //chain::operation op_obj_idx_1; if (po.proposed_transaction.operations.size() >= 1) { op_idx_0 = po.proposed_transaction.operations[0].which(); op_obj_idx_0 = po.proposed_transaction.operations[0]; } - if (po.proposed_transaction.operations.size() >= 2) { - //op_idx_1 = po.proposed_transaction.operations[1].which(); - //op_obj_idx_1 = po.proposed_transaction.operations[1]; - } - switch (op_idx_0) { case chain::operation::tag::value: { - should_approve = true; + should_approve = false; break; } @@ -122,7 +115,7 @@ bool sidechain_net_handler_peerplays::process_proposal(const proposal_object &po } case chain::operation::tag::value: { - should_approve = true; + should_approve = false; break; }