diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp index 4dd05325..5814b208 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp @@ -32,8 +32,8 @@ public: void send_sidechain_transactions(); virtual void recreate_primary_wallet() = 0; - virtual std::string process_deposit(const son_wallet_deposit_object &swdo) = 0; - virtual std::string process_withdrawal(const son_wallet_withdraw_object &swwo) = 0; + virtual bool process_deposit(const son_wallet_deposit_object &swdo) = 0; + virtual bool process_withdrawal(const son_wallet_withdraw_object &swwo) = 0; virtual std::string process_sidechain_transaction(const sidechain_transaction_object &sto, bool &complete) = 0; virtual bool send_sidechain_transaction(const sidechain_transaction_object &sto) = 0; 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 bc7b685a..1df76375 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 @@ -83,8 +83,8 @@ public: virtual ~sidechain_net_handler_bitcoin(); void recreate_primary_wallet(); - std::string process_deposit(const son_wallet_deposit_object &swdo); - std::string process_withdrawal(const son_wallet_withdraw_object &swwo); + 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, bool &complete); bool send_sidechain_transaction(const sidechain_transaction_object &sto); @@ -112,10 +112,6 @@ private: std::string sign_transaction_psbt(const std::string &tx, bool &complete); std::string sign_transaction_standalone(const std::string &tx, bool &complete); - std::string transfer_all_btc(const std::string &from_address, const std::string &to_address); - std::string transfer_deposit_to_primary_wallet(const son_wallet_deposit_object &swdo); - std::string transfer_withdrawal_from_primary_wallet(const son_wallet_withdraw_object &swwo); - void handle_event(const std::string &event_data); std::vector extract_info_from_block(const std::string &_block); }; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp index 4db19d7a..157dc421 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp @@ -14,8 +14,8 @@ public: virtual ~sidechain_net_handler_peerplays(); void recreate_primary_wallet(); - std::string process_deposit(const son_wallet_deposit_object &swdo); - std::string process_withdrawal(const son_wallet_withdraw_object &swwo); + 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, bool &complete); bool send_sidechain_transaction(const sidechain_transaction_object &sto); diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 61626a08..2cbcad61 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -377,7 +377,7 @@ void peerplays_sidechain_plugin_impl::son_processing() { //process_leftover_sidechain_transactions(); ??? } } -} // namespace detail +} void peerplays_sidechain_plugin_impl::approve_proposals() { @@ -421,42 +421,61 @@ void peerplays_sidechain_plugin_impl::approve_proposals() { continue; } - if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag::value) { - approve_proposal(get_current_son_id(), proposal.id); - continue; + if (proposal.proposed_transaction.operations.size() == 1) { + int32_t op_idx_0 = proposal.proposed_transaction.operations[0].which(); + + if (op_idx_0 == chain::operation::tag::value) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } + + if (op_idx_0 == chain::operation::tag::value) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } + + if (op_idx_0 == chain::operation::tag::value) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } + + if (op_idx_0 == chain::operation::tag::value) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } + + if (op_idx_0 == chain::operation::tag::value) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } + + if (op_idx_0 == chain::operation::tag::value) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } + + if (op_idx_0 == chain::operation::tag::value) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } } - if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag::value) { - approve_proposal(get_current_son_id(), proposal.id); - continue; + if (proposal.proposed_transaction.operations.size() == 2) { + int32_t op_idx_0 = proposal.proposed_transaction.operations[0].which(); + int32_t op_idx_1 = proposal.proposed_transaction.operations[1].which(); + + if ((op_idx_0 == chain::operation::tag::value) && + (op_idx_1 == chain::operation::tag::value)) { + approve_proposal(get_current_son_id(), proposal.id); + continue; + } } - if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag::value) { - approve_proposal(get_current_son_id(), proposal.id); - continue; - } - - if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag::value) { - approve_proposal(get_current_son_id(), proposal.id); - continue; - } - - if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag::value) { - approve_proposal(get_current_son_id(), proposal.id); - continue; - } - - if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag::value) { - approve_proposal(get_current_son_id(), proposal.id); - continue; - } - - if (proposal.proposed_transaction.operations.size() == 1 && proposal.proposed_transaction.operations[0].which() == chain::operation::tag::value) { - approve_proposal(get_current_son_id(), proposal.id); - continue; - } - - approve_proposal(get_current_son_id(), proposal.id); + ilog("=================================================="); + ilog("=================================================="); + ilog("Proposal not approved ${proposal}", ("proposal", proposal)); + ilog("=================================================="); + ilog("=================================================="); } } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index 14d936b0..613a9b70 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -94,7 +94,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(son_id), proposal_op); try { database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) @@ -140,7 +140,7 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(son_id), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(son_id), proposal_op); try { database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) @@ -157,51 +157,42 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ } void sidechain_net_handler::process_deposits() { - const auto &idx = plugin.database().get_index_type().indices().get(); + const auto &idx = database.get_index_type().indices().get(); const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, false)); std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_deposit_object &swdo) { ilog("Deposit to process: ${swdo}", ("swdo", swdo)); - std::string sidechain_tx = process_deposit(swdo); + bool process_deposit_result = process_deposit(swdo); - if (sidechain_tx.empty()) { + if (!process_deposit_result) { wlog("Deposit not processed: ${swdo}", ("swdo", swdo)); return; } const chain::global_property_object &gpo = database.get_global_properties(); - auto active_sons = gpo.active_sons; - std::vector signers; - for (const son_info &si : active_sons) { - signers.push_back(si.son_id); - } - - sidechain_transaction_create_operation stc_op; - stc_op.payer = GRAPHENE_SON_ACCOUNT; - //stc_op.son_wallet_id = ; // not set, not needed - stc_op.son_wallet_deposit_id = swdo.id; - //stc_op.son_wallet_withdraw_id = ; // not set, not needed - stc_op.sidechain = sidechain; - stc_op.transaction = sidechain_tx; - stc_op.signers = signers; - son_wallet_deposit_process_operation swdp_op; swdp_op.payer = GRAPHENE_SON_ACCOUNT; swdp_op.son_wallet_deposit_id = swdo.id; + transfer_operation t_op; + t_op.fee = asset(2000000); + t_op.from = swdo.peerplays_to; // GRAPHENE_SON_ACCOUNT + t_op.to = swdo.peerplays_from; + t_op.amount = swdo.peerplays_asset; + proposal_create_operation proposal_op; proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account; - proposal_op.proposed_ops.emplace_back(op_wrapper(stc_op)); proposal_op.proposed_ops.emplace_back(op_wrapper(swdp_op)); + proposal_op.proposed_ops.emplace_back(op_wrapper(t_op)); uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(plugin.database().head_block_time().sec_since_epoch() + lifetime); + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); trx.validate(); try { - plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); } catch (fc::exception e) { @@ -211,51 +202,35 @@ void sidechain_net_handler::process_deposits() { } void sidechain_net_handler::process_withdrawals() { - const auto &idx = plugin.database().get_index_type().indices().get(); + const auto &idx = database.get_index_type().indices().get(); const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, false)); std::for_each(idx_range.first, idx_range.second, [&](const son_wallet_withdraw_object &swwo) { ilog("Withdraw to process: ${swwo}", ("swwo", swwo)); - std::string sidechain_tx = process_withdrawal(swwo); + bool process_withdrawal_result = process_withdrawal(swwo); - if (sidechain_tx.empty()) { + if (!process_withdrawal_result) { wlog("Withdraw not processed: ${swwo}", ("swwo", swwo)); return; } const chain::global_property_object &gpo = database.get_global_properties(); - auto active_sons = gpo.active_sons; - std::vector signers; - for (const son_info &si : active_sons) { - signers.push_back(si.son_id); - } - - sidechain_transaction_create_operation stc_op; - stc_op.payer = GRAPHENE_SON_ACCOUNT; - //stc_op.son_wallet_id = ; // not set, not needed - //stc_op.son_wallet_deposit_id = ; // not set, not needed - stc_op.son_wallet_withdraw_id = swwo.id; - stc_op.sidechain = sidechain; - stc_op.transaction = sidechain_tx; - stc_op.signers = signers; - son_wallet_withdraw_process_operation swwp_op; swwp_op.payer = GRAPHENE_SON_ACCOUNT; swwp_op.son_wallet_withdraw_id = swwo.id; proposal_create_operation proposal_op; proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account; - proposal_op.proposed_ops.emplace_back(op_wrapper(stc_op)); proposal_op.proposed_ops.emplace_back(op_wrapper(swwp_op)); uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(plugin.database().head_block_time().sec_since_epoch() + lifetime); + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); trx.validate(); try { - plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); } catch (fc::exception e) { @@ -265,7 +240,7 @@ void sidechain_net_handler::process_withdrawals() { } void sidechain_net_handler::process_sidechain_transactions() { - const auto &idx = plugin.database().get_index_type().indices().get(); + const auto &idx = database.get_index_type().indices().get(); const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, false)); std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { @@ -285,10 +260,10 @@ void sidechain_net_handler::process_sidechain_transactions() { sts_op.transaction = processed_sidechain_tx; sts_op.complete = complete; - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op); trx.validate(); try { - plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); } catch (fc::exception e) { @@ -298,7 +273,7 @@ void sidechain_net_handler::process_sidechain_transactions() { } void sidechain_net_handler::send_sidechain_transactions() { - const auto &idx = plugin.database().get_index_type().indices().get(); + const auto &idx = database.get_index_type().indices().get(); const auto &idx_range = idx.equal_range(std::make_tuple(sidechain, true, false)); std::for_each(idx_range.first, idx_range.second, [&](const sidechain_transaction_object &sto) { @@ -315,10 +290,10 @@ void sidechain_net_handler::send_sidechain_transactions() { sts_op.payer = plugin.get_son_object(plugin.get_current_son_id()).son_account; sts_op.sidechain_transaction_id = sto.id; - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op); + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), sts_op); trx.validate(); try { - plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); if (plugin.app().p2p_node()) plugin.app().p2p_node()->broadcast(net::trx_message(trx)); } catch (fc::exception e) { @@ -331,11 +306,11 @@ void sidechain_net_handler::recreate_primary_wallet() { FC_ASSERT(false, "recreate_primary_wallet not implemented"); } -std::string sidechain_net_handler::process_deposit(const son_wallet_deposit_object &swdo) { +bool sidechain_net_handler::process_deposit(const son_wallet_deposit_object &swdo) { FC_ASSERT(false, "process_deposit not implemented"); } -std::string sidechain_net_handler::process_withdrawal(const son_wallet_withdraw_object &swwo) { +bool sidechain_net_handler::process_withdrawal(const son_wallet_withdraw_object &swwo) { FC_ASSERT(false, "process_withdrawal not implemented"); } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 93cc7d86..52354e9f 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -828,44 +828,68 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() { std::string active_pw_address = active_pw_pt.get_child("result").get("address"); std::string prev_pw_address = prev_sw_pt.get("address"); - std::string sidechain_tx = transfer_all_btc(prev_pw_address, active_pw_address); - - if (sidechain_tx.empty()) { + if (prev_pw_address == active_pw_address) { elog("BTC Primary wallet funds not transfered from ${prev_sw} to ${active_sw}", ("prev_sw", *prev_sw)("active_sw", *active_sw)); return; } - const chain::global_property_object &gpo = database.get_global_properties(); + uint64_t fee_rate = bitcoin_client->estimatesmartfee(); + uint64_t min_fee_rate = 1000; + fee_rate = std::max(fee_rate, min_fee_rate); - auto active_sons = gpo.active_sons; - std::vector signers; - for (const son_info &si : active_sons) { - signers.push_back(si.son_id); + 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; + } } - sidechain_transaction_create_operation stc_op; - stc_op.payer = GRAPHENE_SON_ACCOUNT; - stc_op.son_wallet_id = (*prev_sw).id; - //stc_op.son_wallet_deposit_id = ; // not set, not needed - //stc_op.son_wallet_withdraw_id = ; // not set, not needed - stc_op.sidechain = sidechain; - stc_op.transaction = sidechain_tx; - stc_op.signers = signers; + fc::flat_map outputs; + outputs[active_pw_address] = total_amount - min_amount; - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account; - proposal_op.proposed_ops.emplace_back(op_wrapper(stc_op)); - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(plugin.database().head_block_time().sec_since_epoch() + lifetime); + std::string tx_str = create_transaction(inputs, outputs); - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - trx.validate(); - try { - plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - } catch (fc::exception e) { - elog("Sending proposal for withdrawal sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + if (!tx_str.empty()) { + + auto active_sons = gpo.active_sons; + std::vector signers; + for (const son_info &si : active_sons) { + signers.push_back(si.son_id); + } + + sidechain_transaction_create_operation stc_op; + stc_op.payer = GRAPHENE_SON_ACCOUNT; + stc_op.son_wallet_id = (*prev_sw).id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = signers; + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account; + proposal_op.proposed_ops.emplace_back(op_wrapper(stc_op)); + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + trx.validate(); + try { + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + } catch (fc::exception e) { + elog("Sending proposal for withdrawal sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + } } } } @@ -873,12 +897,161 @@ void sidechain_net_handler_bitcoin::recreate_primary_wallet() { } } -std::string sidechain_net_handler_bitcoin::process_deposit(const son_wallet_deposit_object &swdo) { - return transfer_deposit_to_primary_wallet(swdo); +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); + + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); + + auto active_sons = gpo.active_sons; + std::vector signers; + for (const son_info &si : active_sons) { + signers.push_back(si.son_id); + } + + sidechain_transaction_create_operation stc_op; + stc_op.payer = GRAPHENE_SON_ACCOUNT; + stc_op.son_wallet_deposit_id = swdo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = signers; + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account; + proposal_op.proposed_ops.emplace_back(op_wrapper(stc_op)); + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + trx.validate(); + try { + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; } -std::string sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw_object &swwo) { - return transfer_withdrawal_from_primary_wallet(swwo); +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); + + if (!tx_str.empty()) { + const chain::global_property_object &gpo = database.get_global_properties(); + + auto active_sons = gpo.active_sons; + std::vector signers; + for (const son_info &si : active_sons) { + signers.push_back(si.son_id); + } + + sidechain_transaction_create_operation stc_op; + stc_op.payer = GRAPHENE_SON_ACCOUNT; + stc_op.son_wallet_withdraw_id = swwo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = signers; + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account; + proposal_op.proposed_ops.emplace_back(op_wrapper(stc_op)); + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + trx.validate(); + try { + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception e) { + elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + } + return false; } std::string sidechain_net_handler_bitcoin::process_sidechain_transaction(const sidechain_transaction_object &sto, bool &complete) { @@ -916,16 +1089,16 @@ std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector< // Adds signature to transaction // Function to actually add signature should return transaction with added signature string, or empty string in case of failure -std::string sidechain_net_handler_bitcoin::sign_transaction(const std::string &tx, bool &complete) { +std::string sidechain_net_handler_bitcoin::sign_transaction(const std::string &tx_str, bool &complete) { std::string new_tx = ""; //new_tx = sign_transaction_raw(tx, complete); - new_tx = sign_transaction_psbt(tx, complete); + new_tx = sign_transaction_psbt(tx_str, complete); //new_tx = sign_transaction_standalone(tx, complete); return new_tx; } -bool sidechain_net_handler_bitcoin::send_transaction(const std::string &tx) { - return bitcoin_client->sendrawtransaction(tx); +bool sidechain_net_handler_bitcoin::send_transaction(const std::string &tx_str) { + return bitcoin_client->sendrawtransaction(tx_str); } std::string sidechain_net_handler_bitcoin::create_transaction_raw(const std::vector &inputs, const fc::flat_map outputs) { @@ -997,8 +1170,8 @@ std::string sidechain_net_handler_bitcoin::create_transaction_standalone(const s return ""; } -std::string sidechain_net_handler_bitcoin::sign_transaction_raw(const std::string &tx, bool &complete) { - if (tx.empty()) { +std::string sidechain_net_handler_bitcoin::sign_transaction_raw(const std::string &tx_str, bool &complete) { + if (tx_str.empty()) { elog("Signing failed, tx string is empty"); return ""; } @@ -1007,7 +1180,7 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_raw(const std::strin bitcoin_client->walletpassphrase(wallet_password, 5); } - std::string reply_str = bitcoin_client->signrawtransactionwithwallet(tx); + std::string reply_str = bitcoin_client->signrawtransactionwithwallet(tx_str); std::stringstream ss(reply_str); boost::property_tree::ptree json; @@ -1015,7 +1188,7 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_raw(const std::strin boost::property_tree::ptree json_res = json.get_child("result"); if ((json_res.count("hex") == 0) || (json_res.count("complete") == 0)) { - elog("Failed to process raw transaction ${tx}", ("tx", tx)); + elog("Failed to process raw transaction ${tx}", ("tx", tx_str)); return ""; } @@ -1030,8 +1203,8 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_raw(const std::strin return new_tx_raw; } -std::string sidechain_net_handler_bitcoin::sign_transaction_psbt(const std::string &tx, bool &complete) { - if (tx.empty()) { +std::string sidechain_net_handler_bitcoin::sign_transaction_psbt(const std::string &tx_str, bool &complete) { + if (tx_str.empty()) { elog("Signing failed, tx string is empty"); return ""; } @@ -1040,7 +1213,7 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_psbt(const std::stri bitcoin_client->walletpassphrase(wallet_password, 5); } - std::string reply_str = bitcoin_client->walletprocesspsbt(tx); + std::string reply_str = bitcoin_client->walletprocesspsbt(tx_str); std::stringstream ss(reply_str); boost::property_tree::ptree json; @@ -1048,7 +1221,7 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_psbt(const std::stri boost::property_tree::ptree json_res = json.get_child("result"); if ((json_res.count("psbt") == 0) || (json_res.count("complete") == 0)) { - elog("Failed to process psbt transaction ${tx}", ("tx", tx)); + elog("Failed to process psbt transaction ${tx}", ("tx", tx_str)); return ""; } @@ -1064,7 +1237,7 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_psbt(const std::stri boost::property_tree::ptree json_res = json.get_child("result"); if ((json_res.count("hex") == 0) || (json_res.count("complete") == 0)) { - elog("Failed to finalize psbt transaction ${tx}", ("tx", tx)); + elog("Failed to finalize psbt transaction ${tx}", ("tx", tx_str)); return ""; } @@ -1080,130 +1253,11 @@ std::string sidechain_net_handler_bitcoin::sign_transaction_psbt(const std::stri return new_tx_psbt; } -std::string sidechain_net_handler_bitcoin::sign_transaction_standalone(const std::string &tx, bool &complete) { +std::string sidechain_net_handler_bitcoin::sign_transaction_standalone(const std::string &tx_str, bool &complete) { complete = true; return ""; } -std::string sidechain_net_handler_bitcoin::transfer_all_btc(const std::string &from_address, const std::string &to_address) { - - if (from_address == to_address) { - 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(from_address, 0); - - if (inputs.size() == 0) { - elog("Failed to find UTXOs to spend for ${pw}", ("pw", from_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", from_address)); - return ""; - } - } - - fc::flat_map outputs; - outputs[to_address] = total_amount - min_amount; - - return create_transaction(inputs, outputs); -} - -std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet(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::transfer_withdrawal_from_primary_wallet(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 unspent_utxo = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0); - - if (unspent_utxo.size() == 0) { - elog("Failed to find UTXOs to spend for ${pw}", ("pw", pw_address)); - return ""; - } else { - for (const auto &utx : unspent_utxo) { - 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 outs; - outs[swwo.withdraw_address] = swwo.withdraw_amount.value / 100000000.0; - if ((total_amount - min_amount) > 0.0) { - outs[pw_address] = total_amount - min_amount; - } - - return create_transaction(unspent_utxo, outs); -} - void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) { std::string block = bitcoin_client->getblock(event_data); if (block != "") { @@ -1222,7 +1276,7 @@ void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) std::string sidechain_uid = ss.str(); sidechain_event_data sed; - sed.timestamp = plugin.database().head_block_time(); + sed.timestamp = database.head_block_time(); sed.sidechain = addr_itr->sidechain; sed.sidechain_uid = sidechain_uid; sed.sidechain_transaction_id = v.out.hash_tx; diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp index 0cb15d5a..cbd6f841 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp @@ -21,7 +21,7 @@ namespace graphene { namespace peerplays_sidechain { sidechain_net_handler_peerplays::sidechain_net_handler_peerplays(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::peerplays; - plugin.database().applied_block.connect([&](const signed_block &b) { + database.applied_block.connect([&](const signed_block &b) { on_applied_block(b); }); } @@ -33,46 +33,17 @@ void sidechain_net_handler_peerplays::recreate_primary_wallet() { return; } -std::string sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_object &swdo) { - - std::string res = ""; - - const chain::global_property_object &gpo = database.get_global_properties(); - - transfer_operation t_op; - t_op.fee = asset(2000000); - t_op.from = swdo.peerplays_to; // GRAPHENE_SON_ACCOUNT - t_op.to = swdo.peerplays_from; - t_op.amount = swdo.peerplays_asset; - - proposal_create_operation proposal_op; - proposal_op.fee_paying_account = plugin.get_son_object(plugin.get_current_son_id()).son_account; - proposal_op.proposed_ops.emplace_back(op_wrapper(t_op)); - uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; - proposal_op.expiration_time = time_point_sec(plugin.database().head_block_time().sec_since_epoch() + lifetime); - - signed_transaction trx = plugin.database().create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); - trx.validate(); - try { - plugin.database().push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - res = trx.id().str(); - } catch (fc::exception e) { - elog("Sending proposal for transfer operation failed with exception ${e}", ("e", e.what())); - } - - return res; +bool sidechain_net_handler_peerplays::process_deposit(const son_wallet_deposit_object &swdo) { + return true; } -std::string sidechain_net_handler_peerplays::process_withdrawal(const son_wallet_withdraw_object &swwo) { - return "Withdraw not supported"; +bool sidechain_net_handler_peerplays::process_withdrawal(const son_wallet_withdraw_object &swwo) { + return true; } std::string sidechain_net_handler_peerplays::process_sidechain_transaction(const sidechain_transaction_object &sto, bool &complete) { complete = true; return sto.transaction; - ; } bool sidechain_net_handler_peerplays::send_sidechain_transaction(const sidechain_transaction_object &sto) { @@ -96,18 +67,18 @@ void sidechain_net_handler_peerplays::on_applied_block(const signed_block &b) { std::string sidechain_uid = ss.str(); sidechain_event_data sed; - sed.timestamp = plugin.database().head_block_time(); + sed.timestamp = database.head_block_time(); sed.sidechain = sidechain_type::peerplays; sed.sidechain_uid = sidechain_uid; sed.sidechain_transaction_id = trx.id().str(); sed.sidechain_from = fc::to_string(transfer_op.from.space_id) + "." + fc::to_string(transfer_op.from.type_id) + "." + fc::to_string((uint64_t)transfer_op.from.instance); sed.sidechain_to = fc::to_string(transfer_op.to.space_id) + "." + fc::to_string(transfer_op.to.type_id) + "." + fc::to_string((uint64_t)transfer_op.to.instance); - sed.sidechain_currency = fc::to_string(transfer_op.amount.asset_id.space_id) + "." + fc::to_string(transfer_op.amount.asset_id.type_id) + "." + fc::to_string((uint64_t)transfer_op.amount.asset_id.instance); //transfer_op.amount.asset_id(plugin.database()).symbol; + sed.sidechain_currency = fc::to_string(transfer_op.amount.asset_id.space_id) + "." + fc::to_string(transfer_op.amount.asset_id.type_id) + "." + fc::to_string((uint64_t)transfer_op.amount.asset_id.instance); //transfer_op.amount.asset_id(database).symbol; sed.sidechain_amount = transfer_op.amount.amount; sed.peerplays_from = transfer_op.from; sed.peerplays_to = transfer_op.to; // We should calculate exchange rate between CORE/TEST and other Peerplays asset - sed.peerplays_asset = asset(transfer_op.amount.amount / transfer_op.amount.asset_id(plugin.database()).options.core_exchange_rate.quote.amount); + sed.peerplays_asset = asset(transfer_op.amount.amount / transfer_op.amount.asset_id(database).options.core_exchange_rate.quote.amount); sidechain_event_data_received(sed); } }