[SON-325] Added check for approving sidechain_transaction_create_operation (#337)

This commit is contained in:
obucina 2020-04-06 18:09:01 +02:00 committed by GitHub
parent be4b55c4a0
commit bd1bd842ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 187 additions and 139 deletions

View file

@ -106,6 +106,10 @@ private:
fc::future<void> 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<btc_txout> &inputs, const fc::flat_map<std::string, double> outputs);
std::string sign_transaction(const sidechain_transaction_object &sto, bool &complete);
bool send_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction);

View file

@ -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<chain::son_wallet_update_operation>::value: {
should_process = (op_obj_idx_0.get<son_wallet_update_operation>().sidechain == sidechain);

View file

@ -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<chain::son_wallet_update_operation>::value: {
@ -1011,12 +1004,46 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po)
}
case chain::operation::tag<chain::son_wallet_withdraw_process_operation>::value: {
should_approve = true;
should_approve = false;
break;
}
case chain::operation::tag<chain::sidechain_transaction_create_operation>::value: {
should_approve = true;
object_id_type object_id = op_obj_idx_0.get<sidechain_transaction_create_operation>().object_id;
std::string op_tx_str = op_obj_idx_0.get<sidechain_transaction_create_operation>().transaction;
const auto &st_idx = database.get_index_type<sidechain_transaction_index>().indices().get<by_object_id>();
const auto st = st_idx.find(object_id);
if (st == st_idx.end()) {
std::string tx_str = "";
if (object_id.is<son_wallet_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_index>().indices().get<by_id>();
const auto swo = idx.find(object_id);
if (swo != idx.end()) {
tx_str = create_primary_wallet_transaction();
}
}
if (object_id.is<son_wallet_deposit_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_deposit_index>().indices().get<by_id>();
const auto swdo = idx.find(object_id);
if (swdo != idx.end()) {
tx_str = create_deposit_transaction(*swdo);
}
}
if (object_id.is<son_wallet_withdraw_id_type>()) {
const auto &idx = database.get_index_type<son_wallet_withdraw_index>().indices().get<by_id>();
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<std::string>("address");
std::string prev_pw_address = prev_sw_pt.get<std::string>("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<btc_txout> 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<std::string, double> 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<son_wallet_index>().indices().get<by_id>();
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<std::string>("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<btc_txout> inputs;
fc::flat_map<std::string, double> 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<son_wallet_index>().indices().get<by_id>();
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<std::string>("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<btc_txout> 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<std::string, double> 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<son_wallet_index>().indices().get<by_id>();
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<std::string>("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<std::string>("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<btc_txout> 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<std::string, double> 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<son_wallet_index>().indices().get<by_id>();
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<std::string>("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<btc_txout> inputs;
fc::flat_map<std::string, double> 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<son_wallet_index>().indices().get<by_id>();
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<std::string>("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<btc_txout> 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<std::string, double> 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<btc_txout> &inputs, const fc::flat_map<std::string, double> outputs) {

View file

@ -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<chain::son_wallet_update_operation>::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<chain::sidechain_transaction_create_operation>::value: {
should_approve = true;
should_approve = false;
break;
}