From 9e30f8866acb93ae9af021c2abf03fce15677170 Mon Sep 17 00:00:00 2001 From: satyakoneru Date: Thu, 20 Feb 2020 13:45:59 +0000 Subject: [PATCH] SON261 - Withdrawal transfer ( PW -> user address ), addition of bitcoin public private key to config.ini for multiple sons mode --- .../sidechain_net_handler_bitcoin.hpp | 4 +- .../peerplays_sidechain_plugin.cpp | 5 +- .../sidechain_net_handler_bitcoin.cpp | 110 ++++++++++++++++-- 3 files changed, 107 insertions(+), 12 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index 8a9b50bf..41dae863 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 @@ -29,11 +29,12 @@ public: void send_btc_tx( const std::string& tx_hex ); std::string add_multisig_address( const std::vector public_keys ); bool connection_is_not_defined() const; - std::string create_raw_transaction(const sidechain_event_data& sed, const std::string& pw_address); + std::string create_raw_transaction(const std::string& txid, const std::string& vout, const std::string& out_address, double transfer_amount); std::string sign_raw_transaction_with_wallet(const std::string& tx_hash); std::string sign_raw_transaction_with_privkey(const std::string& tx_hash, const std::string& private_key); void import_address( const std::string& address_or_script); std::vector list_unspent(); + std::vector list_unspent_by_address_and_amount(const std::string& address, double transfer_amount); std::string prepare_tx(const std::vector& ins, const fc::flat_map outs); private: @@ -83,6 +84,7 @@ public: std::string sign_transaction( const std::string& transaction ); std::string send_transaction( const std::string& transaction ); std::string transfer_deposit_to_primary_wallet (const sidechain_event_data& sed); + std::string transfer_withdrawal_from_primary_wallet(const std::string& user_address, int64_t sidechain_amount); private: std::string ip; diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index a32d9dd8..afc297ed 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -106,6 +106,9 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( ("bitcoin-address", bpo::value()->default_value("2N911a7smwDzUGARg8s7Q1ViizFCw6gWcbR"), "Bitcoin address") ("bitcoin-public-key", bpo::value()->default_value("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772"), "Bitcoin public key") ("bitcoin-private-key", bpo::value()->default_value("cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr"), "Bitcoin private key") + ("bitcoin-private-keys", bpo::value>()->composing()->multitoken()-> + DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")), + "Tuple of [Bitcoin PublicKey, Bitcoin Private key] (may specify multiple times)") ; cfg.add(cli); } @@ -120,7 +123,7 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt config_ready_son = config_ready_son && !_sons.empty(); #ifndef SUPPORT_MULTIPLE_SONS - FC_ASSERT( _sons.size() == 1, "Multiple SONs not supported" ); + //FC_ASSERT( _sons.size() == 1, "Multiple SONs not supported" ); #endif if( options.count("peerplays-private-key") ) diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 4b025cf1..dffc725d 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -170,19 +170,12 @@ std::string bitcoin_rpc_client::add_multisig_address( const std::vector bitcoin_rpc_client::list_unspent() return result; } +std::vector bitcoin_rpc_client::list_unspent_by_address_and_amount(const std::string& address, double minimum_amount) +{ + std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"pp_plugin\", \"method\": \"listunspent\", \"params\": ["); + body += std::string("1,999999,[\""); + body += address; + body += std::string("\"],true,{\"minimumAmount\":"); + body += std::to_string(minimum_amount); + body += std::string("}] }"); + + ilog(body); + + const auto reply = send_post_request( body ); + + std::vector result; + if( reply.body.empty() ) + { + wlog("Failed to list unspent txo"); + return result; + } + + std::string reply_str( reply.body.begin(), reply.body.end() ); + + std::stringstream ss(reply_str); + boost::property_tree::ptree json; + boost::property_tree::read_json( ss, json ); + + if( reply.status == 200 ) { + idump((reply_str)); + if( json.count( "result" ) ) + { + for(auto& entry: json.get_child("result")) + { + btc_txout txo; + txo.txid_ = entry.second.get_child("txid").get_value(); + txo.out_num_ = entry.second.get_child("vout").get_value(); + txo.amount_ = entry.second.get_child("amount").get_value(); + result.push_back(txo); + } + } + } else if( json.count( "error" ) && !json.get_child( "error" ).empty() ) { + wlog( "Failed to list unspent txo! Reply: ${msg}", ("msg", reply_str) ); + } + return result; +} + std::string bitcoin_rpc_client::prepare_tx(const std::vector &ins, const fc::flat_map outs) { std::string body("{\"jsonrpc\": \"1.0\", \"id\":\"pp_plugin\", \"method\": \"createrawtransaction\", \"params\": ["); @@ -553,7 +591,15 @@ std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet ( std::string pw_address = json.get("address"); - std::string reply_str = bitcoin_client->create_raw_transaction(sed, pw_address); + std::string txid = sed.sidechain_transaction_id; + std::string suid = sed.sidechain_uid; + std::string nvout = suid.substr(suid.find_last_of("-")+1); + int64_t deposit_amount = sed.sidechain_amount; + deposit_amount -= 1000; // Deduct minimum relay fee + double transfer_amount = (double)deposit_amount/100000000.0; + + std::string reply_str = bitcoin_client->create_raw_transaction(txid, nvout, pw_address, transfer_amount); + ilog(reply_str); std::stringstream ss_utx(reply_str); @@ -583,6 +629,50 @@ std::string sidechain_net_handler_bitcoin::transfer_deposit_to_primary_wallet ( return reply_str; } +std::string sidechain_net_handler_bitcoin::transfer_withdrawal_from_primary_wallet(const std::string& user_address, int64_t sidechain_amount) { + 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"); + + double total_amount = (((double)sidechain_amount*1000.0)+1000.0)/100000000.0; // Account only for relay fee for now + double transfer_amount = ((double)sidechain_amount*1000.0)/100000000.0; + std::vector unspent_utxo= bitcoin_client->list_unspent_by_address_and_amount(pw_address, total_amount); + + if(unspent_utxo.size() == 0) + { + return ""; + } + + btc_txout utxo = unspent_utxo[0]; + std::string reply_str = bitcoin_client->create_raw_transaction(utxo.txid_, std::to_string(utxo.out_num_), user_address, transfer_amount); + ilog(reply_str); + + std::stringstream ss_utx(reply_str); + boost::property_tree::ptree pt; + boost::property_tree::read_json( ss_utx, pt ); + + if( !(pt.count( "error" ) && pt.get_child( "error" ).empty()) || !pt.count("result") ) { + return ""; + } + + std::string unsigned_tx_hex = pt.get("result"); + + std::cout << unsigned_tx_hex << std::endl; + + return unsigned_tx_hex; +} + void sidechain_net_handler_bitcoin::handle_event( const std::string& event_data ) { ilog("peerplays sidechain plugin: sidechain_net_handler_bitcoin::handle_event"); ilog(" event_data: ${event_data}", ("event_data", event_data));