diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 4941ce51..816bf680 100644 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -5,6 +5,7 @@ add_library( peerplays_sidechain sidechain_net_manager.cpp sidechain_net_handler.cpp sidechain_net_handler_bitcoin.cpp + bitcoin_utils.cpp ) target_link_libraries( peerplays_sidechain graphene_chain graphene_app fc zmq ) diff --git a/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp b/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp new file mode 100644 index 00000000..7064ebc9 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +static const unsigned char OP_IF = 0x63; +static const unsigned char OP_ENDIF = 0x68; +static const unsigned char OP_SWAP = 0x7c; +static const unsigned char OP_ADD = 0x93; +static const unsigned char OP_GREATERTHAN = 0xa0; +static const unsigned char OP_CHECKSIG = 0xac; + +class WriteBytesStream{ +public: + WriteBytesStream(bytes& buffer); + + bool write( const char* d, size_t s ) { + storage_.insert(storage_.end(), d, d + s); + return true; + } + + bool put(char c) { + storage_.push_back(c); + return true; + } +private: + bytes& storage_; +}; + + +void add_data_to_script(bytes& script, const bytes& data) +{ + WriteBytesStream str(script); + fc::raw::pack(str, data, 2); +} + +bytes generate_redeem_script(fc::flat_map key_data) +{ + int total_weight = 0; + bytes result; + add_data_to_script(result, {0}); + for(auto& p: key_data) + { + total_weight += p.second; + result.push_back(OP_SWAP); + auto raw_data = p.first.serialize(); + add_data_to_script(result, bytes(raw_data.begin(), raw_data.begin() + raw_data.size())); + result.push_back(OP_CHECKSIG); + result.push_back(OP_IF); + add_data_to_script(result, {static_cast(p.second)}); + result.push_back(OP_ADD); + result.push_back(OP_ENDIF); + } + int threshold_weight = 2 * total_weight / 3; + add_data_to_script(result, {static_cast(threshold_weight)}); + result.push_back(OP_GREATERTHAN); + return result; +} + +std::string p2sh_address_from_redeem_script(const bytes& script, bitcoin_network network) +{ + bytes data; + // add version byte + switch (network) { + case(mainnet): + data.push_back(5); + break; + case(testnet): + data.push_back(196); + break; + case(regtest): + data.push_back(196); + break; + default: + FC_THROW("Unknown bitcoin network type [${type}]", ("type", network)); + } + // add redeem script hash + fc::ripemd160 h = fc::ripemd160::hash(reinterpret_cast(&script[0]), script.size()); + data.insert(data.end(), h.data(), h.data() + h.data_size()); + // calc control sum + fc::sha256 cs = fc::sha256::hash(fc::sha256::hash(reinterpret_cast(&data[0]), data.size())); + // add first 4 bytes of control sum + data.insert(data.end(), cs.data(), cs.data() + 4); + // return base58 encoded data + return fc::to_base58(reinterpret_cast(&data[0]), data.size()); +} + +}} diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp new file mode 100644 index 00000000..4b69ff44 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_utils.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace graphene { namespace peerplays_sidechain { + +enum bitcoin_network { + mainnet, + testnet, + regtest +}; + +bytes generate_redeem_script(fc::flat_map key_data); +std::string p2sh_address_from_redeem_script(const bytes& script, bitcoin_network network = mainnet); + +}} diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp index 3bd94a49..ae1d222c 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/defs.hpp @@ -18,7 +18,7 @@ enum class sidechain_type { peerplays }; -using bytes = std::vector; +using bytes = std::vector; struct prev_out {