From 81db3a5c0dc643c3d17c1da0b29879857e656dfc Mon Sep 17 00:00:00 2001 From: Srdjan Obucina Date: Sun, 5 Apr 2020 06:23:18 +0200 Subject: [PATCH] Creating multisig m-of-n address using libbitcoin --- .../peerplays_sidechain/CMakeLists.txt | 2 +- .../sidechain_net_handler_bitcoin.hpp | 5 ++ .../sidechain_net_handler_bitcoin.cpp | 90 +++++++++++++++++-- 3 files changed, 89 insertions(+), 8 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index e7d9acfe..73c8abf7 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -16,7 +16,7 @@ endif() unset(SUPPORT_MULTIPLE_SONS) unset(SUPPORT_MULTIPLE_SONS CACHE) -target_link_libraries( peerplays_sidechain graphene_chain graphene_app fc zmq ) +target_link_libraries( peerplays_sidechain graphene_chain graphene_app bitcoin fc zmq ) target_include_directories( peerplays_sidechain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) 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 65489598..7182f117 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 @@ -105,10 +105,15 @@ private: fc::future on_changed_objects_task; + std::string create_multisig_address(const std::vector> &son_pubkeys); std::string create_transaction(const std::vector &inputs, const fc::flat_map outputs); std::string sign_transaction(const sidechain_transaction_object &sto, bool &complete); bool send_transaction(const sidechain_transaction_object &sto, std::string &sidechain_transaction); + std::string create_multisig_address_raw(const std::vector> &son_pubkeys); + std::string create_multisig_address_psbt(const std::vector> &son_pubkeys); + std::string create_multisig_address_standalone(const std::vector> &son_pubkeys); + 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); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 92ce2acb..3922a090 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include #include @@ -968,16 +970,12 @@ void sidechain_net_handler_bitcoin::process_primary_wallet() { const chain::global_property_object &gpo = database.get_global_properties(); auto active_sons = gpo.active_sons; - vector son_pubkeys_bitcoin; + vector> son_pubkeys_bitcoin; for (const son_info &si : active_sons) { - son_pubkeys_bitcoin.push_back(si.sidechain_public_keys.at(sidechain_type::bitcoin)); + son_pubkeys_bitcoin.push_back(std::make_pair(si.sidechain_public_keys.at(sidechain_type::bitcoin), si.weight)); } - if (!wallet_password.empty()) { - bitcoin_client->walletpassphrase(wallet_password, 5); - } - uint32_t nrequired = son_pubkeys_bitcoin.size() * 2 / 3 + 1; - string reply_str = bitcoin_client->addmultisigaddress(nrequired, son_pubkeys_bitcoin); + string reply_str = create_multisig_address(son_pubkeys_bitcoin); std::stringstream active_pw_ss(reply_str); boost::property_tree::ptree active_pw_pt; @@ -1252,6 +1250,16 @@ bool sidechain_net_handler_bitcoin::send_sidechain_transaction(const sidechain_t return send_transaction(sto, sidechain_transaction); } +// Creates segwit multisig address +// Function to actually create segwit multisig address should return json string with address info, or empty string in case of failure +std::string sidechain_net_handler_bitcoin::create_multisig_address(const std::vector> &son_pubkeys) { + std::string new_addr = ""; + //new_addr = create_multisig_address_raw(son_pubkeys); + //new_addr = create_multisig_address_psbt(son_pubkeys); + new_addr = create_multisig_address_standalone(son_pubkeys); + return new_addr; +} + // 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) { @@ -1279,6 +1287,74 @@ bool sidechain_net_handler_bitcoin::send_transaction(const sidechain_transaction return send_transaction_psbt(sto, sidechain_transaction); } +std::string sidechain_net_handler_bitcoin::create_multisig_address_raw(const std::vector> &son_pubkeys) { + vector pubkeys; + for (auto s : son_pubkeys) { + pubkeys.push_back(s.first); + } + + if (!wallet_password.empty()) { + bitcoin_client->walletpassphrase(wallet_password, 5); + } + + uint32_t nrequired = pubkeys.size() * 2 / 3 + 1; + return bitcoin_client->addmultisigaddress(nrequired, pubkeys); +} + +std::string sidechain_net_handler_bitcoin::create_multisig_address_psbt(const std::vector> &son_pubkeys) { + vector pubkeys; + for (auto s : son_pubkeys) { + pubkeys.push_back(s.first); + } + + if (!wallet_password.empty()) { + bitcoin_client->walletpassphrase(wallet_password, 5); + } + + uint32_t nrequired = pubkeys.size() * 2 / 3 + 1; + return bitcoin_client->addmultisigaddress(nrequired, pubkeys); +} + +std::string sidechain_net_handler_bitcoin::create_multisig_address_standalone(const std::vector> &son_pubkeys) { + + using namespace libbitcoin; + using namespace libbitcoin::chain; + using namespace libbitcoin::machine; + using namespace libbitcoin::wallet; + + uint32_t nrequired = son_pubkeys.size() * 2 / 3 + 1; + point_list keys; + for (auto son_pubkey : son_pubkeys) { + keys.push_back(ec_public(son_pubkey.first)); + } + script witness_script = script::to_pay_multisig_pattern(nrequired, keys); + + // sha256 of witness script + data_chunk multisig_hash = to_chunk(sha256_hash(witness_script.to_data(0))); + + // redeem script + libbitcoin::machine::operation::list redeemscript_ops{libbitcoin::machine::operation(opcode(0)), libbitcoin::machine::operation(multisig_hash)}; + script redeem_script = script(redeemscript_ops); + + // address + payment_address address = payment_address(redeem_script, payment_address::testnet_p2sh); + + std::stringstream ss; + ss << "{\n \"address\": \"" << address.encoded() + << "\",\n \"redeemScript\": \"" << encode_base16(witness_script.to_data(0)) << "\"\n}\n"; + + std::cout << "Redeem Script Hash: " << encode_base16(address.hash()) << std::endl; + std::cout << "Payment Address: " << address.encoded() << std::endl; + std::cout << "Redeem Script: " << redeem_script.to_string(0) << std::endl; + std::cout << "Witness Script: " << witness_script.to_string(0) << std::endl; + std::cout << "Witness Script: " << encode_base16(witness_script.to_data(0)) << std::endl; + std::cout << "Locking Script: " << P2SH_P2WSH.to_string(0) << std::endl; + + //create_multisig_address_psbt(son_pubkeys); + + return ss.str(); +} + std::string sidechain_net_handler_bitcoin::create_transaction_raw(const std::vector &inputs, const fc::flat_map outputs) { return bitcoin_client->createrawtransaction(inputs, outputs); }