diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp index 524a7ead..b4fde6dc 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp @@ -127,6 +127,10 @@ void bitcoin_transaction_builder::set_locktime(uint32_t lock_time) { tx.nLockTime = lock_time; } +void bitcoin_transaction_builder::add_in(const fc::sha256 &txid, uint32_t n_out, const bytes &script_code, bool front, uint32_t sequence) { + add_in(payment_type::P2WSH, txid, n_out, script_code, front, sequence); +} + void bitcoin_transaction_builder::add_in(payment_type type, const fc::sha256 &txid, uint32_t n_out, const bytes &script_code, bool front, uint32_t sequence) { out_point prevout; prevout.hash = txid; @@ -250,5 +254,4 @@ bytes bitcoin_transaction_builder::get_script_pubkey(payment_type type, const by return script_code; } } - }}} // namespace graphene::peerplays_sidechain::bitcoin diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp index bf953800..edb45c5b 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp @@ -143,4 +143,11 @@ void add_signatures_to_transaction_weighted_multisig(bitcoin_transaction &tx, st } } +void add_signatures_to_transaction_user_weighted_multisig(bitcoin_transaction &tx, std::vector> &signature_set) { + add_signatures_to_transaction_weighted_multisig(tx, signature_set); + for (size_t itr = 0; itr < tx.vin.size(); itr++) { + tx.vin[0].scriptWitness.push_back(bytes()); + } +} + }}} // namespace graphene::peerplays_sidechain::bitcoin diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp index 5c5c74a0..5668ffc2 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/bitcoin_transaction.hpp @@ -70,6 +70,9 @@ public: void set_locktime(uint32_t lock_time); + void add_in(const fc::sha256 &txid, uint32_t n_out, + const bytes &script_code, bool front = false, uint32_t sequence = 0xffffffff); + void add_in(payment_type type, const fc::sha256 &txid, uint32_t n_out, const bytes &script_code, bool front = false, uint32_t sequence = 0xffffffff); diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.hpp index 51844e4c..41808562 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.hpp @@ -30,4 +30,6 @@ void add_signatures_to_transaction_multisig(bitcoin_transaction &tx, std::vector void add_signatures_to_transaction_weighted_multisig(bitcoin_transaction &tx, std::vector> &signature_set); +void add_signatures_to_transaction_user_weighted_multisig(bitcoin_transaction &tx, std::vector> &signature_set); + }}} // namespace graphene::peerplays_sidechain::bitcoin 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 3eb59f2b..67c208d1 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,29 +106,18 @@ private: fc::future on_changed_objects_task; - std::string create_multisig_address_standalone(const std::vector &son_pubkeys); + std::string create_primary_wallet_address(const std::vector &son_pubkeys); std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address); 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 create_transaction(const std::vector &inputs, const fc::flat_map outputs, std::string &redeem_script); std::string sign_transaction(const sidechain_transaction_object &sto); std::string send_transaction(const sidechain_transaction_object &sto); - std::string create_transaction_raw(const std::vector &inputs, const fc::flat_map outputs); - std::string create_transaction_psbt(const std::vector &inputs, const fc::flat_map outputs); - std::string create_transaction_standalone(const std::vector &inputs, const fc::flat_map outputs); - - std::string sign_transaction_raw(const sidechain_transaction_object &sto); - std::string sign_transaction_psbt(const sidechain_transaction_object &sto); - std::string sign_transaction_standalone(const sidechain_transaction_object &sto); - - std::string send_transaction_raw(const sidechain_transaction_object &sto); - std::string send_transaction_psbt(const sidechain_transaction_object &sto); - std::string send_transaction_standalone(const sidechain_transaction_object &sto); - void handle_event(const std::string &event_data); + std::string get_redeemscript_for_userdeposit(const std::string &user_address); std::vector extract_info_from_block(const std::string &_block); void on_changed_objects(const vector &ids, const flat_set &accounts); void on_changed_objects_cb(const vector &ids, const flat_set &accounts); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 077b855c..b413e655 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -25,6 +25,57 @@ namespace graphene { namespace peerplays_sidechain { // ============================================================================= +std::vector read_byte_arrays_from_string(const std::string &string_buf) { + std::stringstream ss(string_buf); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + + std::vector data; + for (auto &v : json) { + std::string hex = v.second.data(); + bitcoin::bytes item; + item.resize(hex.size() / 2); + fc::from_hex(hex, (char *)&item[0], item.size()); + data.push_back(item); + } + return data; +} + +std::string write_transaction_signatures(const std::vector &data) { + std::string res = "["; + for (unsigned int idx = 0; idx < data.size(); ++idx) { + res += "\"" + fc::to_hex((char *)&data[idx][0], data[idx].size()) + "\""; + if (idx != data.size() - 1) + res += ","; + } + res += "]"; + return res; +} + +void read_transaction_data(const std::string &string_buf, std::string &tx_hex, std::vector &in_amounts, std::string &redeem_script) { + std::stringstream ss(string_buf); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + tx_hex = json.get("tx_hex"); + in_amounts.clear(); + for (auto &v : json.get_child("in_amounts")) + in_amounts.push_back(fc::to_uint64(v.second.data())); + redeem_script = json.get("redeem_script"); +} + +std::string write_transaction_data(const std::string &tx, const std::vector &in_amounts, const std::string &redeem_script) { + std::string res = "{\"tx_hex\":\"" + tx + "\",\"in_amounts\":["; + for (unsigned int idx = 0; idx < in_amounts.size(); ++idx) { + res += fc::to_string(in_amounts[idx]); + if (idx != in_amounts.size() - 1) + res += ","; + } + res += "],\"redeem_script\":\"" + redeem_script + "\"}"; + return res; +} + +// ============================================================================= + bitcoin_rpc_client::bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password) : ip(_ip), rpc_port(_rpc), @@ -962,9 +1013,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); } - //uint32_t nrequired = son_pubkeys_bitcoin.size() * 2 / 3 + 1; - string reply_str = create_multisig_address_standalone(active_sons); - //string reply_str = bitcoin_client->createmultisig(nrequired, son_pubkeys_bitcoin); + string reply_str = create_primary_wallet_address(active_sons); std::stringstream active_pw_ss(reply_str); boost::property_tree::ptree active_pw_pt; @@ -1121,9 +1170,7 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { if (!wallet_password.empty()) { bitcoin_client->walletpassphrase(wallet_password, 5); } - uint32_t nrequired = son_pubkeys_bitcoin.size() * 2 / 3 + 1; - string reply_str = create_multisig_address_standalone(active_sons); - //string reply_str = bitcoin_client->createmultisig(nrequired, son_pubkeys_bitcoin); + string reply_str = create_primary_wallet_address(active_sons); std::stringstream active_pw_ss(reply_str); boost::property_tree::ptree active_pw_pt; @@ -1254,20 +1301,6 @@ bool sidechain_net_handler_bitcoin::process_withdrawal(const son_wallet_withdraw } std::string sidechain_net_handler_bitcoin::process_sidechain_transaction(const sidechain_transaction_object &sto) { - //// Uncomment to get signing in order from sto.signers - //son_id_type invalid_signer = son_id_type(0xFFFFFFFF); - //son_id_type next_signer = invalid_signer; - //for (auto &signer : sto.signers) { - // if (signer.second == false) { - // next_signer = signer.first; - // break; - // } - //} - // - //if ((next_signer == invalid_signer) || (next_signer != plugin.get_current_son_id())) { - // return ""; - //} - return sign_transaction(sto); } @@ -1275,7 +1308,7 @@ std::string sidechain_net_handler_bitcoin::send_sidechain_transaction(const side return send_transaction(sto); } -std::string sidechain_net_handler_bitcoin::create_multisig_address_standalone(const std::vector &son_pubkeys) { +std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector &son_pubkeys) { using namespace bitcoin; std::vector> pubkey_weights; @@ -1303,6 +1336,7 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(con 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("address"); + std::string prev_redeem_script = prev_sw_pt.get("redeemScript"); if (prev_pw_address == new_sw_address) { wlog("BTC previous and new primary wallet addresses are same. No funds moving needed [from ${prev_sw} to ${new_sw_address}]", ("prev_swo", prev_swo.id)("active_sw", new_sw_address)); @@ -1333,7 +1367,7 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(con fc::flat_map outputs; outputs[new_sw_address] = double(total_amount - fee_rate) / 100000000.0; - return create_transaction(inputs, outputs); + return create_transaction(inputs, outputs, prev_redeem_script); } std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_wallet_deposit_object &swdo) { @@ -1342,7 +1376,8 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_ 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_json = obj->addresses.find(sidechain_type::bitcoin)->second; std::stringstream ss(pw_address_json); @@ -1367,13 +1402,13 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_ btc_txout utxo; utxo.txid_ = txid; utxo.out_num_ = std::stoul(nvout); + utxo.amount_ = swdo.sidechain_amount.value; inputs.push_back(utxo); outputs[pw_address] = transfer_amount; - //return create_transaction(inputs, outputs); - return create_transaction_psbt(inputs, outputs); + return create_transaction(inputs, outputs, redeem_script); } std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const son_wallet_withdraw_object &swwo) { @@ -1390,6 +1425,7 @@ std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const s boost::property_tree::read_json(ss, json); std::string pw_address = json.get("address"); + std::string redeem_script = json.get("redeemScript"); uint64_t fee_rate = bitcoin_client->estimatesmartfee(); uint64_t min_fee_rate = 1000; @@ -1413,510 +1449,91 @@ std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const s } fc::flat_map outputs; - outputs[swwo.withdraw_address] = swwo.withdraw_amount.value / 100000000.0; + outputs[swwo.withdraw_address] = (swwo.withdraw_amount.value - fee_rate) / 100000000.0; if ((total_amount - fee_rate) > 0.0) { - outputs[pw_address] = double(total_amount - swwo.withdraw_amount.value - fee_rate) / 100000000.0; + outputs[pw_address] = double(total_amount - swwo.withdraw_amount.value) / 100000000.0; } - return create_transaction(inputs, outputs); + return create_transaction(inputs, outputs, redeem_script); } -// 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) { - std::string new_tx = ""; - //new_tx = create_transaction_raw(inputs, outputs); - //new_tx = create_transaction_psbt(inputs, outputs); - new_tx = create_transaction_standalone(inputs, outputs); - return new_tx; -} - -// 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 sidechain_transaction_object &sto) { - std::string new_tx = ""; - //new_tx = sign_transaction_raw(sto); - if (sto.object_id.type() == 30) { - new_tx = sign_transaction_psbt(sto); - } else { - new_tx = sign_transaction_standalone(sto); - } - return new_tx; -} - -std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_transaction_object &sto) { - //return send_transaction_raw(sto); - //return send_transaction_psbt(sto); - if (sto.object_id.type() == 30) { - return send_transaction_psbt(sto); - } else { - return send_transaction_standalone(sto); - } -} - -std::vector read_byte_arrays_from_string(const std::string &string_buf) { - std::stringstream ss(string_buf); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - - std::vector data; - for (auto &v : json) { - std::string hex = v.second.data(); - bitcoin::bytes item; - item.resize(hex.size() / 2); - fc::from_hex(hex, (char *)&item[0], item.size()); - data.push_back(item); - } - return data; -} - -std::string write_byte_arrays_to_string(const std::vector &data) { - std::string res = "["; - for (unsigned int idx = 0; idx < data.size(); ++idx) { - res += "\"" + fc::to_hex((char *)&data[idx][0], data[idx].size()) + "\""; - if (idx != data.size() - 1) - res += ","; - } - res += "]"; - return res; -} - -void read_tx_data_from_string(const std::string &string_buf, std::vector &tx, std::vector &in_amounts) { - std::stringstream ss(string_buf); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - std::string tx_hex = json.get("tx_hex"); - tx.clear(); - tx.resize(tx_hex.size() / 2); - fc::from_hex(tx_hex, (char *)&tx[0], tx.size()); - in_amounts.clear(); - for (auto &v : json.get_child("in_amounts")) - in_amounts.push_back(fc::to_uint64(v.second.data())); -} - -void read_tx_data_from_string(const std::string &string_buf, std::string &tx_hex, std::vector &in_amounts) { - std::stringstream ss(string_buf); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - tx_hex = json.get("tx_hex"); - in_amounts.clear(); - for (auto &v : json.get_child("in_amounts")) - in_amounts.push_back(fc::to_uint64(v.second.data())); -} - -std::string save_tx_data_to_string(const std::vector &tx, const std::vector &in_amounts) { - std::string res = "{\"tx_hex\":\"" + fc::to_hex((const char *)&tx[0], tx.size()) + "\",\"in_amounts\":["; - for (unsigned int idx = 0; idx < in_amounts.size(); ++idx) { - res += fc::to_string(in_amounts[idx]); - if (idx != in_amounts.size() - 1) - res += ","; - } - res += "]}"; - return res; -} - -std::string save_tx_data_to_string(const std::string &tx, const std::vector &in_amounts) { - std::string res = "{\"tx_hex\":\"" + tx + "\",\"in_amounts\":["; - for (unsigned int idx = 0; idx < in_amounts.size(); ++idx) { - res += fc::to_string(in_amounts[idx]); - if (idx != in_amounts.size() - 1) - res += ","; - } - res += "]}"; - return res; -} - -std::string sidechain_net_handler_bitcoin::create_transaction_raw(const std::vector &inputs, const fc::flat_map outputs) { - return bitcoin_client->createrawtransaction(inputs, outputs); -} - -std::string sidechain_net_handler_bitcoin::create_transaction_psbt(const std::vector &inputs, const fc::flat_map outputs) { - return bitcoin_client->createpsbt(inputs, outputs); -} - -std::string sidechain_net_handler_bitcoin::create_transaction_standalone(const std::vector &inputs, const fc::flat_map outputs) { +std::string sidechain_net_handler_bitcoin::create_transaction(const std::vector &inputs, const fc::flat_map outputs, std::string &redeem_script) { using namespace bitcoin; bitcoin_transaction_builder tb; std::vector in_amounts; tb.set_version(2); + // Set vins for (auto in : inputs) { - tb.add_in(payment_type::P2WSH, fc::sha256(in.txid_), in.out_num_, bitcoin::bytes()); + tb.add_in(fc::sha256(in.txid_), in.out_num_, bitcoin::bytes()); in_amounts.push_back(in.amount_); } - + // Set vouts for (auto out : outputs) { uint64_t satoshis = out.second * 100000000.0; tb.add_out_all_type(satoshis, out.first); - //tb.add_out( bitcoin_address( out.first ).get_type(), satoshis, out.first); } const auto tx = tb.get_transaction(); - std::string hex_tx = fc::to_hex(pack(tx)); - - std::string tx_raw = save_tx_data_to_string(hex_tx, in_amounts); - + std::string tx_raw = write_transaction_data(hex_tx, in_amounts, redeem_script); ilog("Raw transaction ${tx}", ("tx", tx_raw)); - return tx_raw; } -/*std::string create_transaction_standalone_multisig(const std::vector &inputs, const fc::flat_map outputs) { - // Examples - - // Transaction with no inputs and outputs - //bitcoin-core.cli -rpcuser=1 -rpcpassword=1 -rpcwallet="" createrawtransaction '[]' '[]' - //02000000000000000000 - //bitcoin-core.cli -rpcuser=1 -rpcpassword=1 -rpcwallet="" decoderawtransaction 02000000000000000000 - //{ - // "txid": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a", - // "hash": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a", - // "version": 2, - // "size": 10, - // "vsize": 10, - // "weight": 40, - // "locktime": 0, - // "vin": [ - // ], - // "vout": [ - // ] - //} - - // Transaction with input and output - //{ - // "txid": "ff60f48f767bbf70d79efc1347b5554b481f14fda68709839091286e035e669b", - // "hash": "ff60f48f767bbf70d79efc1347b5554b481f14fda68709839091286e035e669b", - // "version": 2, - // "size": 83, - // "vsize": 83, - // "weight": 332, - // "locktime": 0, - // "vin": [ - // { - // "txid": "3d322dc2640239a2e68e182b254d19c88e5172a61947f94a105c3f57618092ff", - // "vout": 0, - // "scriptSig": { - // "asm": "", - // "hex": "" - // }, - // "sequence": 4294967295 - // } - // ], - // "vout": [ - // { - // "value": 1.00000000, - // "n": 0, - // "scriptPubKey": { - // "asm": "OP_HASH160 b87c323018cae236eb03a1f63000c85b672270f6 OP_EQUAL", - // "hex": "a914b87c323018cae236eb03a1f63000c85b672270f687", - // "reqSigs": 1, - // "type": "scripthash", - // "addresses": [ - // "2NA4h6sc9oZ4ogfNKU9Wp6fkqPZLZPqqpgf" - // ] - // } - // } - // ] - //} +// 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 sidechain_transaction_object &sto) { using namespace bitcoin; - const chain::global_property_object &gpo = database.get_global_properties(); - - accounts_keys son_pubkeys; - for (auto& son: gpo.active_sons) { - std::string pub_key = son.sidechain_public_keys.at(sidechain_type::bitcoin); - son_pubkeys[son.son_id] = create_public_key_data( parse_hex(pub_key) ); - } - - uint32_t nrequired = gpo.active_sons.size() * 2 / 3 + 1; - btc_multisig_segwit_address pw_address(nrequired, son_pubkeys); - - bitcoin_transaction_builder tb; - std::vector in_amounts; - - std::string script = "22" + fc::to_hex(pw_address.get_witness_script()); - bitcoin::bytes witness_script = parse_hex(script); - - tb.set_version( 2 ); - for (auto in : inputs) { - tb.add_in( payment_type::P2SH_WSH, fc::sha256(in.txid_), in.out_num_, witness_script ); - in_amounts.push_back(in.amount_); - } - - for (auto out : outputs) { - uint64_t satoshis = out.second * 100000000.0; - tb.add_out( bitcoin_address( out.first ).get_type(), satoshis, out.first); - } - - const auto tx = tb.get_transaction(); - - std::string hex_tx = fc::to_hex( pack( tx ) ); - - std::string tx_raw = save_tx_data_to_string(hex_tx, in_amounts); - - ilog("Raw transaction ${tx}", ("tx", tx_raw)); - - return tx_raw; -}*/ - -std::string sidechain_net_handler_bitcoin::sign_transaction_raw(const sidechain_transaction_object &sto) { - if (sto.transaction.empty()) { - elog("Signing failed, tx string is empty"); - return ""; - } - - if (!wallet_password.empty()) { - bitcoin_client->walletpassphrase(wallet_password, 5); - } - - std::string reply_str = bitcoin_client->signrawtransactionwithwallet(sto.transaction); - - std::stringstream ss(reply_str); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - 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", sto.transaction)); - return ""; - } - - std::string new_tx_raw = json_res.get("hex"); - bool complete_raw = json_res.get("complete"); - - if (complete_raw) { - return new_tx_raw; - } - return new_tx_raw; -} - -std::string sidechain_net_handler_bitcoin::sign_transaction_psbt(const sidechain_transaction_object &sto) { - if (sto.transaction.empty()) { - elog("Signing failed, tx string is empty"); - return ""; - } - - if (!wallet_password.empty()) { - bitcoin_client->walletpassphrase(wallet_password, 5); - } - - std::string reply_str = bitcoin_client->walletprocesspsbt(sto.transaction); - - std::stringstream ss(reply_str); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - 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", sto.transaction)); - return ""; - } - - std::string new_tx_psbt = json_res.get("psbt"); - bool complete_psbt = json_res.get("complete"); - - if (!complete_psbt) { - // Try to combine and finalize - vector psbts; - for (auto signature : sto.signatures) { - if (!signature.second.empty()) { - psbts.push_back(signature.second); - } - } - psbts.push_back(new_tx_psbt); - - std::string reply_str = bitcoin_client->combinepsbt(psbts); - - std::stringstream ss(reply_str); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - if (json.count("error") && json.get_child("error").empty()) { - - std::string new_tx_psbt = json.get("result"); - - std::string reply_str_fin = bitcoin_client->finalizepsbt(new_tx_psbt); - std::stringstream ss_fin(reply_str_fin); - boost::property_tree::ptree json_fin; - boost::property_tree::read_json(ss_fin, json_fin); - boost::property_tree::ptree json_res = json_fin.get_child("result"); - - if (json_res.count("hex") && json_res.count("complete")) { - complete_psbt = json_res.get("complete"); - } - } - } - - return new_tx_psbt; -} - -std::string sidechain_net_handler_bitcoin::sign_transaction_standalone(const sidechain_transaction_object &sto) { std::string pubkey = plugin.get_current_son_object().sidechain_public_keys.at(sidechain); std::string prvkey = get_private_key(pubkey); - using namespace bitcoin; std::vector in_amounts; std::string tx_hex; - - //const auto privkey_signing = get_privkey_bytes( prvkey ); + std::string redeem_script; fc::optional btc_private_key = graphene::utilities::wif_to_key(prvkey); if (!btc_private_key) { elog("Invalid private key ${pk}", ("pk", prvkey)); return ""; } - const auto secret = btc_private_key->get_secret(); bitcoin::bytes privkey_signing(secret.data(), secret.data() + secret.data_size()); - read_tx_data_from_string(sto.transaction, tx_hex, in_amounts); + read_transaction_data(sto.transaction, tx_hex, in_amounts, redeem_script); ilog("Sign transaction retreived: ${s}", ("s", tx_hex)); - std::vector> pubkey_weights; - for (auto &son : sto.signers) { - std::string pub_key_str = son.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, son.weight)); - } - - btc_weighted_multisig_address pw_address(pubkey_weights); - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - - bitcoin::bytes rscript = pw_address.get_redeem_script(); - - std::vector redeem_scripts(tx.vin.size(), rscript); - + std::vector redeem_scripts(tx.vin.size(), parse_hex(redeem_script)); auto sigs = sign_witness_transaction_part(tx, redeem_scripts, in_amounts, privkey_signing, btc_context(), 1); - - std::string tx_signature = write_byte_arrays_to_string(sigs); + std::string tx_signature = write_transaction_signatures(sigs); ilog("Signatures: son-id = ${son}, pkey = ${prvkey}, tx_signature = ${s}", ("son", plugin.get_current_son_id())("prvkey", prvkey)("s", tx_signature)); return tx_signature; } -/*std::string sign_transaction_standalone_multisig(const sidechain_transaction_object &sto) { - std::string pubkey = plugin.get_current_son_object().sidechain_public_keys.at(sidechain); - std::string prvkey = get_private_key(pubkey); +std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_transaction_object &sto) { using namespace bitcoin; std::vector in_amounts; std::string tx_hex; + std::string redeem_script; - //const auto privkey_signing = get_privkey_bytes( prvkey ); - - fc::optional btc_private_key = graphene::utilities::wif_to_key(prvkey); - if (!btc_private_key) - { - elog("Invalid private key ${pk}", ("pk", prvkey)); - return ""; - } - - const auto secret = btc_private_key->get_secret(); - bitcoin::bytes privkey_signing(secret.data(), secret.data() + secret.data_size()); - - read_tx_data_from_string(sto.transaction, tx_hex, in_amounts); - - ilog("Sign transaction retreived: ${s}", ("s", tx_hex)); - - accounts_keys son_pubkeys; - for (auto& son: sto.signers) { - std::string pub_key = son.sidechain_public_keys.at(sidechain_type::bitcoin); - son_pubkeys[son.son_id] = create_public_key_data( parse_hex(pub_key) ); - } - - uint32_t nrequired = sto.signers.size() * 2 / 3 + 1; - btc_multisig_segwit_address pw_address(nrequired, son_pubkeys); - - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - - bitcoin::bytes rscript = pw_address.get_redeem_script(); - - std::vector redeem_scripts(tx.vin.size(), rscript); - - auto sigs = sign_witness_transaction_part( tx, redeem_scripts, in_amounts, privkey_signing, btc_context(), 1 ); - - std::string tx_signature = write_byte_arrays_to_string(sigs); - - ilog("Signatures: son-id = ${son}, pkey = ${prvkey}, tx_signature = ${s}", ("son", plugin.get_current_son_id())("prvkey", prvkey)("s", tx_signature)); - - return tx_signature; -}*/ - -std::string sidechain_net_handler_bitcoin::send_transaction_raw(const sidechain_transaction_object &sto) { - return bitcoin_client->sendrawtransaction(sto.transaction); -} - -std::string sidechain_net_handler_bitcoin::send_transaction_psbt(const sidechain_transaction_object &sto) { - vector psbts; - for (auto signature : sto.signatures) { - if (!signature.second.empty()) { - psbts.push_back(signature.second); - } - } - - std::string reply_str = bitcoin_client->combinepsbt(psbts); - - std::stringstream ss(reply_str); - boost::property_tree::ptree json; - boost::property_tree::read_json(ss, json); - - if (json.count("error") && !json.get_child("error").empty()) { - elog("Failed to combine psbt transactions from ${sto}", ("sto", sto)); - return ""; - } - - std::string new_tx_psbt = json.get("result"); - - std::string reply_str_fin = bitcoin_client->finalizepsbt(new_tx_psbt); - std::stringstream ss_fin(reply_str_fin); - boost::property_tree::ptree json_fin; - boost::property_tree::read_json(ss_fin, json_fin); - boost::property_tree::ptree json_res = json_fin.get_child("result"); - - if ((json_res.count("hex") == 0) || (json_res.count("complete") == 0)) { - elog("Failed to finalize psbt transaction ${tx}", ("tx", new_tx_psbt)); - return ""; - } - - std::string new_tx_raw = json_res.get("hex"); - bool complete_raw = json_res.get("complete"); - - if (complete_raw) { - return bitcoin_client->sendrawtransaction(new_tx_raw); - } - - return ""; -} - -std::string sidechain_net_handler_bitcoin::send_transaction_standalone(const sidechain_transaction_object &sto) { - using namespace bitcoin; - std::vector in_amounts; - std::string tx_hex; - - read_tx_data_from_string(sto.transaction, tx_hex, in_amounts); + read_transaction_data(sto.transaction, tx_hex, in_amounts, redeem_script); ilog("Send transaction retreived: ${s}", ("s", tx_hex)); - std::vector> pubkey_weights; - for (auto &son : sto.signers) { - std::string pub_key_str = son.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, son.weight)); - } - - btc_weighted_multisig_address pw_address(pubkey_weights); - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - bitcoin::bytes rscript = pw_address.get_redeem_script(); - - std::vector redeem_scripts(tx.vin.size(), rscript); + std::vector redeem_scripts(tx.vin.size(), parse_hex(redeem_script)); uint32_t inputs_number = in_amounts.size(); vector dummy; dummy.resize(inputs_number); - + //Organise weighted address signatures + //Add dummies for empty signatures vector> signatures; for (unsigned idx = 0; idx < sto.signatures.size(); ++idx) { if (sto.signatures[idx].second.empty()) @@ -1924,63 +1541,22 @@ std::string sidechain_net_handler_bitcoin::send_transaction_standalone(const sid else signatures.push_back(read_byte_arrays_from_string(sto.signatures[idx].second)); } - - add_signatures_to_transaction_weighted_multisig(tx, signatures); - + //Add empty sig for user signature for Deposit transaction + 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); + } + //Add redeemscripts to vins and make tx ready for sending sign_witness_transaction_finalize(tx, redeem_scripts, false); - std::string final_tx_hex = fc::to_hex(pack(tx)); - std::string res = bitcoin_client->sendrawtransaction(final_tx_hex); - ilog("Send_transaction_standalone: ${tx}, [${res}]", ("tx", final_tx_hex)("res", res)); + ilog("Send transaction: ${tx}, [${res}]", ("tx", final_tx_hex)("res", res)); return res; } -/*std::string send_transaction_standalone_multisig(const sidechain_transaction_object &sto) { - using namespace bitcoin; - std::vector in_amounts; - std::string tx_hex; - - read_tx_data_from_string(sto.transaction, tx_hex, in_amounts); - - ilog("Send transaction retreived: ${s}", ("s", tx_hex)); - - accounts_keys son_pubkeys; - for (auto& son: sto.signers) { - std::string pub_key = son.sidechain_public_keys.at(sidechain_type::bitcoin); - son_pubkeys[son.son_id] = create_public_key_data( parse_hex(pub_key) ); - } - - uint32_t nrequired = sto.signers.size() * 2 / 3 + 1; - btc_multisig_segwit_address pw_address(nrequired, son_pubkeys); - - bitcoin_transaction tx = unpack(parse_hex(tx_hex)); - - bitcoin::bytes rscript = pw_address.get_redeem_script(); - - std::vector redeem_scripts(tx.vin.size(), rscript); - - vector> signatures; - for (unsigned idx = 0; idx < sto.signatures.size(); ++idx) { - if(!sto.signatures[idx].second.empty()) - signatures.push_back(read_byte_arrays_from_string(sto.signatures[idx].second)); - } - - add_signatures_to_transaction_multisig(tx, signatures); - - sign_witness_transaction_finalize(tx, redeem_scripts); - - std::string final_tx_hex = fc::to_hex( pack( tx ) ); - - std::string res = bitcoin_client->sendrawtransaction(final_tx_hex); - - ilog("Send_transaction_standalone: ${tx}, [${res}]", ("tx", final_tx_hex)("res", res)); - - return res; -}*/ - void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) { std::string block = bitcoin_client->getblock(event_data); if (block != "") { @@ -2018,6 +1594,31 @@ void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) } } +std::string sidechain_net_handler_bitcoin::get_redeemscript_for_userdeposit(const std::string &user_address) { + using namespace bitcoin; + const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); + const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, user_address)); + if (addr_itr == sidechain_addresses_idx.end()) { + return ""; + } + + 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::vector> pubkey_weights; + for (auto &son : obj->sons) { + std::string pub_key_str = son.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, son.weight)); + } + auto user_pub_key = fc::ecc::public_key(create_public_key_data(parse_hex(addr_itr->deposit_public_key))); + btc_one_or_weighted_multisig_address deposit_addr(user_pub_key, pubkey_weights); + return fc::to_hex(deposit_addr.get_redeem_script()); +} + std::vector sidechain_net_handler_bitcoin::extract_info_from_block(const std::string &_block) { std::stringstream ss(_block); boost::property_tree::ptree block;