[SON-325] Added check for approving sidechain_transaction_create_operation (#337)
This commit is contained in:
parent
be4b55c4a0
commit
bd1bd842ce
4 changed files with 187 additions and 139 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue