diff --git a/libraries/plugins/peerplays_sidechain/bitcoin_address.cpp b/libraries/plugins/peerplays_sidechain/bitcoin_address.cpp index f4a234c4..d24ff2c7 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin_address.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin_address.cpp @@ -1,8 +1,8 @@ -#include +#include #include #include -#include -#include +#include +#include namespace sidechain { diff --git a/libraries/plugins/peerplays_sidechain/bitcoin_script.cpp b/libraries/plugins/peerplays_sidechain/bitcoin_script.cpp new file mode 100644 index 00000000..b71e8387 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/bitcoin_script.cpp @@ -0,0 +1,60 @@ +#include +#include + +namespace sidechain { + +script_builder& script_builder::operator<<( op opcode ) +{ + const auto op_byte = static_cast( opcode ); + if ( op_byte < 0 || op_byte > 0xff ) + throw std::runtime_error( "script_builder::operator<<(OP): invalid opcode" ); + script.push_back( op_byte ); + return *this; +} + +script_builder& script_builder::operator<<( uint8_t number ) +{ + FC_ASSERT( 0 <= number && number <= 16 ); + + if ( number == 0 ) + script.push_back( static_cast( op::_0 ) ); + else + script.push_back( static_cast( op::_1 ) + number - 1 ); + + return *this; +} + +script_builder& script_builder::operator<<( size_t size ) +{ + sidechain::write_compact_size( script, size ); + return *this; +} + +script_builder& script_builder::operator<<( const bytes& sc ) { + sidechain::write_compact_size( script, sc.size() ); + script.insert( script.end(), sc.begin(), sc.end() ); + return *this; +} + +script_builder& script_builder::operator<<( const fc::sha256& hash ) +{ + sidechain::write_compact_size( script, hash.data_size() ); + script.insert( script.end(), hash.data(), hash.data() + hash.data_size() ); + return *this; +} + +script_builder& script_builder::operator<<( const fc::ripemd160& hash ) +{ + sidechain::write_compact_size( script, hash.data_size() ); + script.insert( script.end(), hash.data(), hash.data() + hash.data_size() ); + return *this; +} + +script_builder& script_builder::operator<<( const fc::ecc::public_key_data& pubkey_data ) +{ + sidechain::write_compact_size( script, pubkey_data.size() ); + script.insert( script.end(), pubkey_data.begin(), pubkey_data.begin() + pubkey_data.size() ); + return *this; +} + +} diff --git a/libraries/plugins/peerplays_sidechain/bitcoin_transaction.cpp b/libraries/plugins/peerplays_sidechain/bitcoin_transaction.cpp index 4f44a096..9d7407de 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin_transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin_transaction.cpp @@ -1,279 +1,279 @@ -//#include -//#include -//#include -//#include -// -//namespace sidechain { -// -//bool out_point::operator==( const out_point& op ) const -//{ -// if( this->hash == op.hash && -// this->n == op.n ) -// { -// return true; -// } -// return false; -//} -// -//bool tx_in::operator==( const tx_in& ti ) const -//{ -// if( this->prevout == ti.prevout && -// this->scriptSig == ti.scriptSig && -// this->nSequence == ti.nSequence ) -// { -// return true; -// } -// return false; -//} -// -//bool tx_out::operator==( const tx_out& to ) const -//{ -// if( this->value == to.value && -// this->scriptPubKey == to.scriptPubKey ) -// { -// return true; -// } -// return false; -//} -// -//bool tx_out::is_p2wsh() const -//{ -// if( scriptPubKey.size() == 34 && scriptPubKey[0] == static_cast(0x00) && scriptPubKey[1] == static_cast(0x20) ) { -// return true; -// } -// return false; -//} -// -//bool tx_out::is_p2wpkh() const -//{ -// if( scriptPubKey.size() == 22 && scriptPubKey[0] == static_cast(0x00) && scriptPubKey[1] == static_cast(0x14) ) { -// return true; -// } -// return false; -//} -// -//bool tx_out::is_p2pkh() const -//{ -// if( scriptPubKey.size() == 25 && scriptPubKey[0] == static_cast(0x76) && scriptPubKey[1] == static_cast(0xa9) && -// scriptPubKey[2] == static_cast(0x14) && scriptPubKey[23] == static_cast(0x88) && scriptPubKey[24] == static_cast(0xac) ) { -// return true; -// } -// return false; -//} -// -//bool tx_out::is_p2sh() const -//{ -// if( scriptPubKey.size() == 23 && scriptPubKey[0] == static_cast(0xa9) && -// scriptPubKey[1] == static_cast(0x14) && scriptPubKey[22] == static_cast(0x87) ) { -// return true; -// } -// return false; -//} -// -//bool tx_out::is_p2pk() const -//{ -// if( scriptPubKey.size() == 35 && scriptPubKey[0] == static_cast(0x21) && scriptPubKey[34] == static_cast(0xac) ) { -// return true; -// } -// return false; -//} -// -//bytes tx_out::get_data_or_script() const -//{ -// if( is_p2pkh() ) { -// return bytes( scriptPubKey.begin() + 3, scriptPubKey.begin() + 23 ); -// } else if( is_p2sh() || is_p2wpkh() ) { -// return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 22 ); -// } else if( is_p2wsh() ) { -// return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 34 ); -// } else if( is_p2pk() ) { -// return bytes( scriptPubKey.begin() + 1, scriptPubKey.begin() + 34 ); -// } -// return scriptPubKey; -//} -// -//bool bitcoin_transaction::operator!=( const bitcoin_transaction& bt ) const -//{ -// if( this->nVersion != bt.nVersion || -// this->vin != bt.vin || -// this->vout != bt.vout || -// this->nLockTime != bt.nLockTime ) -// { -// return true; -// } -// return false; -//} -// -//fc::sha256 bitcoin_transaction::get_hash() const -//{ -// const auto bytes = pack( *this, true) ; -// const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); -// std::reverse( hash.data(), hash.data() + hash.data_size() ); -// return hash; -//} -// -//fc::sha256 bitcoin_transaction::get_txid() const -//{ -// const auto bytes = pack( *this, false ); -// const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); -// std::reverse( hash.data(), hash.data() + hash.data_size() ); -// return hash; -//} -// -//size_t bitcoin_transaction::get_vsize() const -//{ -// static const auto witness_scale_factor = 4; -// -// fc::datastream no_wit_ds; -// pack( no_wit_ds, *this, false ); -// -// fc::datastream wit_ds; -// pack( wit_ds, *this, true ); -// -// const size_t weight = no_wit_ds.tellp() * ( witness_scale_factor - 1 ) + wit_ds.tellp(); -// const size_t vsize = ( weight + witness_scale_factor - 1 ) / witness_scale_factor; -// -// return vsize; -//} -// -//void bitcoin_transaction_builder::set_version( int32_t version ) -//{ -// tx.nVersion = version; -//} -// -//void bitcoin_transaction_builder::set_locktime(uint32_t lock_time) -//{ -// tx.nLockTime = lock_time; -//} -// -//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; -// prevout.n = n_out; -// -// tx_in txin; -// txin.prevout = prevout; -// txin.nSequence = sequence; -// -// add_in( type, txin, script_code, front ); -//} -// -//void bitcoin_transaction_builder::add_in( payment_type type, tx_in txin, const bytes& script_code, bool front ) -//{ -// switch ( type ) { -// case payment_type::P2SH_WPKH: -// case payment_type::P2SH_WSH: -// FC_ASSERT( script_code != bytes() ); -// txin.scriptSig = script_code; -// break; -// default:{ -// if( txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000") ) { //coinbase -// FC_ASSERT( script_code != bytes() ); -// txin.scriptSig = script_code; -// } -// break; -// } -// } -// -// if( front ) { -// tx.vin.insert( tx.vin.begin(), txin ); -// } else { -// tx.vin.push_back( txin ); -// } -//} -// -//void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const std::string& base58_address, bool front ) -//{ -// // TODO: add checks -// const auto address_bytes = fc::from_base58(base58_address); -// add_out( type, amount, bytes( address_bytes.begin() + 1, address_bytes.begin() + 1 + 20 ), front ); -//} -// -//void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const fc::ecc::public_key_data& pubkey, bool front ) -//{ -// FC_ASSERT( is_payment_to_pubkey( type ) ); -// -// if ( type == payment_type::P2PK ) { -// const auto pubkey_bytes = bytes( pubkey.begin(), pubkey.begin() + pubkey.size() ); -// add_out( type, amount, pubkey_bytes, front ); -// } else { -// const auto hash256 = fc::sha256::hash( pubkey.begin(), pubkey.size() ); -// const auto hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); -// add_out( type, amount, bytes( hash160.data(), hash160.data() + hash160.data_size() ), front ); -// } -//} -// -//void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const bytes& script_code, bool front ) -//{ -// tx_out out; -// out.value = amount; -// out.scriptPubKey = get_script_pubkey( type, script_code ); -// -// if( front ) { -// tx.vout.insert( tx.vout.begin(), out ); -// } else { -// tx.vout.push_back( out ); -// } -//} -// -//void bitcoin_transaction_builder::add_out_all_type( const uint64_t& amount, const bitcoin_address& address, bool front ) -//{ -// switch( address.get_type() ) { -// case payment_type::P2PK: { -// bytes raw_address( address.get_raw_address() ); -// fc::ecc::public_key_data public_key; -// std::copy( raw_address.begin(), raw_address.end(), public_key.begin() ); -// add_out( address.get_type(), amount, public_key, front ); -// break; -// } -// case payment_type::P2PKH: -// case payment_type::P2SH: -// case payment_type::P2SH_WPKH: -// case payment_type::P2SH_WSH: { -// add_out( address.get_type(), amount, address.get_address(), front ); -// break; -// } -// case payment_type::P2WPKH: -// case payment_type::P2WSH: { -// add_out( address.get_type(), amount, address.get_raw_address(), front ); -// break; -// } -// } -//} -// -//inline bool bitcoin_transaction_builder::is_payment_to_pubkey( payment_type type ) -//{ -// switch ( type ) { -// case payment_type::P2PK: -// case payment_type::P2PKH: -// case payment_type::P2WPKH: -// case payment_type::P2SH_WPKH: -// return true; -// default: -// return false; -// } -//} -// -//bytes bitcoin_transaction_builder::get_script_pubkey( payment_type type, const bytes& script_code ) -//{ -// switch ( type ) { -// case payment_type::NULLDATA: -// return script_builder() << op::RETURN << script_code; -// case payment_type::P2PK: -// return script_builder() << script_code << op::CHECKSIG; -// case payment_type::P2PKH: -// return script_builder() << op::DUP << op::HASH160 << script_code << op::EQUALVERIFY << op::CHECKSIG; -// case payment_type::P2SH: -// case payment_type::P2SH_WPKH: -// case payment_type::P2SH_WSH: -// return script_builder() << op::HASH160 << script_code << op::EQUAL; -// case payment_type::P2WPKH: -// case payment_type::P2WSH: -// return script_builder() << op::_0 << script_code; -// default: -// return script_code; -// } -//} -// -//} +#include +#include +#include +#include + +namespace sidechain { + +bool out_point::operator==( const out_point& op ) const +{ + if( this->hash == op.hash && + this->n == op.n ) + { + return true; + } + return false; +} + +bool tx_in::operator==( const tx_in& ti ) const +{ + if( this->prevout == ti.prevout && + this->scriptSig == ti.scriptSig && + this->nSequence == ti.nSequence ) + { + return true; + } + return false; +} + +bool tx_out::operator==( const tx_out& to ) const +{ + if( this->value == to.value && + this->scriptPubKey == to.scriptPubKey ) + { + return true; + } + return false; +} + +bool tx_out::is_p2wsh() const +{ + if( scriptPubKey.size() == 34 && scriptPubKey[0] == static_cast(0x00) && scriptPubKey[1] == static_cast(0x20) ) { + return true; + } + return false; +} + +bool tx_out::is_p2wpkh() const +{ + if( scriptPubKey.size() == 22 && scriptPubKey[0] == static_cast(0x00) && scriptPubKey[1] == static_cast(0x14) ) { + return true; + } + return false; +} + +bool tx_out::is_p2pkh() const +{ + if( scriptPubKey.size() == 25 && scriptPubKey[0] == static_cast(0x76) && scriptPubKey[1] == static_cast(0xa9) && + scriptPubKey[2] == static_cast(0x14) && scriptPubKey[23] == static_cast(0x88) && scriptPubKey[24] == static_cast(0xac) ) { + return true; + } + return false; +} + +bool tx_out::is_p2sh() const +{ + if( scriptPubKey.size() == 23 && scriptPubKey[0] == static_cast(0xa9) && + scriptPubKey[1] == static_cast(0x14) && scriptPubKey[22] == static_cast(0x87) ) { + return true; + } + return false; +} + +bool tx_out::is_p2pk() const +{ + if( scriptPubKey.size() == 35 && scriptPubKey[0] == static_cast(0x21) && scriptPubKey[34] == static_cast(0xac) ) { + return true; + } + return false; +} + +bytes tx_out::get_data_or_script() const +{ + if( is_p2pkh() ) { + return bytes( scriptPubKey.begin() + 3, scriptPubKey.begin() + 23 ); + } else if( is_p2sh() || is_p2wpkh() ) { + return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 22 ); + } else if( is_p2wsh() ) { + return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 34 ); + } else if( is_p2pk() ) { + return bytes( scriptPubKey.begin() + 1, scriptPubKey.begin() + 34 ); + } + return scriptPubKey; +} + +bool bitcoin_transaction::operator!=( const bitcoin_transaction& bt ) const +{ + if( this->nVersion != bt.nVersion || + this->vin != bt.vin || + this->vout != bt.vout || + this->nLockTime != bt.nLockTime ) + { + return true; + } + return false; +} + +fc::sha256 bitcoin_transaction::get_hash() const +{ + const auto bytes = pack( *this, true) ; + const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); + std::reverse( hash.data(), hash.data() + hash.data_size() ); + return hash; +} + +fc::sha256 bitcoin_transaction::get_txid() const +{ + const auto bytes = pack( *this, false ); + const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); + std::reverse( hash.data(), hash.data() + hash.data_size() ); + return hash; +} + +size_t bitcoin_transaction::get_vsize() const +{ + static const auto witness_scale_factor = 4; + + fc::datastream no_wit_ds; + pack( no_wit_ds, *this, false ); + + fc::datastream wit_ds; + pack( wit_ds, *this, true ); + + const size_t weight = no_wit_ds.tellp() * ( witness_scale_factor - 1 ) + wit_ds.tellp(); + const size_t vsize = ( weight + witness_scale_factor - 1 ) / witness_scale_factor; + + return vsize; +} + +void bitcoin_transaction_builder::set_version( int32_t version ) +{ + tx.nVersion = version; +} + +void bitcoin_transaction_builder::set_locktime(uint32_t lock_time) +{ + tx.nLockTime = lock_time; +} + +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; + prevout.n = n_out; + + tx_in txin; + txin.prevout = prevout; + txin.nSequence = sequence; + + add_in( type, txin, script_code, front ); +} + +void bitcoin_transaction_builder::add_in( payment_type type, tx_in txin, const bytes& script_code, bool front ) +{ + switch ( type ) { + case payment_type::P2SH_WPKH: + case payment_type::P2SH_WSH: + FC_ASSERT( script_code != bytes() ); + txin.scriptSig = script_code; + break; + default:{ + if( txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000") ) { //coinbase + FC_ASSERT( script_code != bytes() ); + txin.scriptSig = script_code; + } + break; + } + } + + if( front ) { + tx.vin.insert( tx.vin.begin(), txin ); + } else { + tx.vin.push_back( txin ); + } +} + +void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const std::string& base58_address, bool front ) +{ + // TODO: add checks + const auto address_bytes = fc::from_base58(base58_address); + add_out( type, amount, bytes( address_bytes.begin() + 1, address_bytes.begin() + 1 + 20 ), front ); +} + +void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const fc::ecc::public_key_data& pubkey, bool front ) +{ + FC_ASSERT( is_payment_to_pubkey( type ) ); + + if ( type == payment_type::P2PK ) { + const auto pubkey_bytes = bytes( pubkey.begin(), pubkey.begin() + pubkey.size() ); + add_out( type, amount, pubkey_bytes, front ); + } else { + const auto hash256 = fc::sha256::hash( pubkey.begin(), pubkey.size() ); + const auto hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() ); + add_out( type, amount, bytes( hash160.data(), hash160.data() + hash160.data_size() ), front ); + } +} + +void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const bytes& script_code, bool front ) +{ + tx_out out; + out.value = amount; + out.scriptPubKey = get_script_pubkey( type, script_code ); + + if( front ) { + tx.vout.insert( tx.vout.begin(), out ); + } else { + tx.vout.push_back( out ); + } +} + +void bitcoin_transaction_builder::add_out_all_type( const uint64_t& amount, const bitcoin_address& address, bool front ) +{ + switch( address.get_type() ) { + case payment_type::P2PK: { + bytes raw_address( address.get_raw_address() ); + fc::ecc::public_key_data public_key; + std::copy( raw_address.begin(), raw_address.end(), public_key.begin() ); + add_out( address.get_type(), amount, public_key, front ); + break; + } + case payment_type::P2PKH: + case payment_type::P2SH: + case payment_type::P2SH_WPKH: + case payment_type::P2SH_WSH: { + add_out( address.get_type(), amount, address.get_address(), front ); + break; + } + case payment_type::P2WPKH: + case payment_type::P2WSH: { + add_out( address.get_type(), amount, address.get_raw_address(), front ); + break; + } + } +} + +inline bool bitcoin_transaction_builder::is_payment_to_pubkey( payment_type type ) +{ + switch ( type ) { + case payment_type::P2PK: + case payment_type::P2PKH: + case payment_type::P2WPKH: + case payment_type::P2SH_WPKH: + return true; + default: + return false; + } +} + +bytes bitcoin_transaction_builder::get_script_pubkey( payment_type type, const bytes& script_code ) +{ + switch ( type ) { + case payment_type::NULLDATA: + return script_builder() << op::RETURN << script_code; + case payment_type::P2PK: + return script_builder() << script_code << op::CHECKSIG; + case payment_type::P2PKH: + return script_builder() << op::DUP << op::HASH160 << script_code << op::EQUALVERIFY << op::CHECKSIG; + case payment_type::P2SH: + case payment_type::P2SH_WPKH: + case payment_type::P2SH_WSH: + return script_builder() << op::HASH160 << script_code << op::EQUAL; + case payment_type::P2WPKH: + case payment_type::P2WSH: + return script_builder() << op::_0 << script_code; + default: + return script_code; + } +} + +} diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_script.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_script.hpp new file mode 100644 index 00000000..42db8974 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/bitcoin_script.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include + +namespace sidechain { + +enum class op { + // push value + _0 = 0x00, + _1 = 0x51, + _2 = 0x52, + _3 = 0x53, + _4 = 0x54, + _5 = 0x55, + _6 = 0x56, + _7 = 0x57, + _8 = 0x58, + _9 = 0x59, + _10 = 0x5a, + _11 = 0x5b, + _12 = 0x5c, + _13 = 0x5d, + _14 = 0x5e, + _15 = 0x5f, + _16 = 0x60, + + // control + RETURN = 0x6a, + + // stack ops + DUP = 0x76, + + // bit logic + EQUAL = 0x87, + EQUALVERIFY = 0x88, + + // crypto + HASH160 = 0xa9, + CHECKSIG = 0xac, + CHECKMULTISIG = 0xae, +}; + +class script_builder { + +public: + + script_builder& operator<<( op opcode ); + + script_builder& operator<<( uint8_t number ); + + script_builder& operator<<( size_t size ); + + script_builder& operator<<( const bytes& sc ); + + script_builder& operator<<( const fc::sha256& hash ); + + script_builder& operator<<( const fc::ripemd160& hash ); + + script_builder& operator<<( const fc::ecc::public_key_data& pubkey_data ); + + operator bytes() const { return std::move( script ); } + +private: + + bytes script; + +}; + +} diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/segwit_addr.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/segwit_addr.hpp new file mode 100644 index 00000000..d115e035 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/segwit_addr.hpp @@ -0,0 +1,34 @@ +/* Copyright (c) 2017 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +namespace sidechain { namespace segwit_addr { + +/** Decode a SegWit address. Returns (witver, witprog). witver = -1 means failure. */ +std::pair > decode(const std::string& hrp, const std::string& addr); + +/** Encode a SegWit address. Empty string means failure. */ +std::string encode(const std::string& hrp, int witver, const std::vector& witprog); + +} } diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/serialize.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/serialize.hpp index c8984b4a..7853a673 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/serialize.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/serialize.hpp @@ -1,360 +1,360 @@ -//#pragma once -// -//#include -//#include -// -//namespace sidechain { -// -//inline void write_compact_size( bytes& vec, size_t size ) -//{ -// bytes sb; -// sb.reserve( 2 ); -// if ( size < 253 ) { -// sb.insert( sb.end(), static_cast( size ) ); -// } else if ( size <= std::numeric_limits::max() ) { -// uint16_t tmp = htole16( static_cast( size ) ); -// sb.insert( sb.end(), static_cast( 253 ) ); -// sb.insert( sb.end(), reinterpret_cast( tmp ), reinterpret_cast( tmp ) + sizeof( tmp ) ); -// } else if ( size <= std::numeric_limits::max() ) { -// uint32_t tmp = htole32( static_cast( size ) ); -// sb.insert( sb.end(), static_cast( 254 ) ); -// sb.insert( sb.end(), reinterpret_cast( tmp ), reinterpret_cast( tmp ) + sizeof( tmp ) ); -// } else { -// uint64_t tmp = htole64( static_cast( size ) ); -// sb.insert( sb.end(), static_cast( 255 ) ); -// sb.insert( sb.end(), reinterpret_cast( tmp ), reinterpret_cast( tmp ) + sizeof( tmp ) ); -// } -// vec.insert( vec.end(), sb.begin(), sb.end() ); -//} -// -//template -//inline void pack_compact_size(Stream& s, size_t size) -//{ -// if ( size < 253 ) { -// fc::raw::pack( s, static_cast( size ) ); -// } else if ( size <= std::numeric_limits::max() ) { -// fc::raw::pack( s, static_cast( 253 ) ); -// fc::raw::pack( s, htole16( static_cast( size ) ) ); -// } else if ( size <= std::numeric_limits::max() ) { -// fc::raw::pack( s, static_cast( 254 ) ); -// fc::raw::pack( s, htole32(static_cast( size ) ) ); -// } else { -// fc::raw::pack( s, static_cast( 255 ) ); -// fc::raw::pack( s, htole64( static_cast( size ) ) ); -// } -//} -// -//template -//inline uint64_t unpack_compact_size( Stream& s ) -//{ -// uint8_t size; -// uint64_t size_ret; -// -// fc::raw::unpack( s, size ); -// -// if (size < 253) { -// size_ret = size; -// } else if ( size == 253 ) { -// uint16_t tmp; -// fc::raw::unpack( s, tmp ); -// size_ret = le16toh( tmp ); -// if ( size_ret < 253 ) -// FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); -// } else if ( size == 254 ) { -// uint32_t tmp; -// fc::raw::unpack( s, tmp ); -// size_ret = le32toh( tmp ); -// if ( size_ret < 0x10000u ) -// FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); -// } else { -// uint32_t tmp; -// fc::raw::unpack( s, tmp ); -// size_ret = le64toh( tmp ); -// if ( size_ret < 0x100000000ULL ) -// FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); -// } -// -// if ( size_ret > 0x08000000 ) -// FC_THROW_EXCEPTION( fc::parse_error_exception, "unpack_compact_size(): size too large" ); -// -// return size_ret; -//} -// -//template -//inline void pack( Stream& s, const std::vector& v ) -//{ -// pack_compact_size( s, v.size() ); -// if ( !v.empty() ) -// s.write( v.data(), v.size() ); -//} -// -//template -//inline void unpack( Stream& s, std::vector& v ) -//{ -// const auto size = unpack_compact_size( s ); -// v.resize( size ); -// if ( size ) -// s.read( v.data(), size ); -//} -// -//template -//inline void pack( Stream& s, const T& val ) -//{ -// fc::raw::pack( s, val ); -//} -// -//template -//inline void unpack( Stream& s, T& val ) -//{ -// fc::raw::unpack( s, val ); -//} -// -//template -//inline void pack( Stream& s, const out_point& op ) -//{ -// fc::sha256 reversed( op.hash ); -// std::reverse( reversed.data(), reversed.data() + reversed.data_size() ); -// s.write( reversed.data(), reversed.data_size() ); -// pack( s, op.n ); -//} -// -//template -//inline void unpack( Stream& s, out_point& op ) -//{ -// uint64_t hash_size = op.hash.data_size(); -// std::unique_ptr hash_data( new char[hash_size] ); -// s.read( hash_data.get(), hash_size ); -// std::reverse( hash_data.get(), hash_data.get() + hash_size ); -// -// op.hash = fc::sha256( hash_data.get(), hash_size ); -// unpack( s, op.n ); -//} -// -//template -//inline void pack( Stream& s, const tx_in& in ) -//{ -// pack( s, in.prevout ); -// pack( s, in.scriptSig ); -// pack( s, in.nSequence ); -//} -// -//template -//inline void unpack( Stream& s, tx_in& in ) -//{ -// unpack( s, in.prevout ); -// unpack( s, in.scriptSig ); -// unpack( s, in.nSequence ); -//} -// -//template -//inline void pack( Stream& s, const tx_out& out ) -//{ -// pack( s, out.value ); -// pack( s, out.scriptPubKey ); -//} -// -//template -//inline void unpack( Stream& s, tx_out& out ) -//{ -// unpack( s, out.value ); -// unpack( s, out.scriptPubKey ); -//} -// -//template -//inline void pack( Stream& s, const bitcoin_transaction& tx, bool with_witness = true ) -//{ -// uint8_t flags = 0; -// -// if ( with_witness ) { -// for ( const auto& in : tx.vin ) { -// if ( !in.scriptWitness.empty() ) { -// flags |= 1; -// break; -// } -// } -// } -// -// pack( s, tx.nVersion ); -// -// if ( flags ) { -// pack_compact_size( s, 0 ); -// pack( s, flags ); -// } -// -// pack_compact_size( s, tx.vin.size() ); -// for ( const auto& in : tx.vin ) -// pack( s, in ); -// -// pack_compact_size( s, tx.vout.size() ); -// for ( const auto& out : tx.vout ) -// pack( s, out ); -// -// if ( flags & 1 ) { -// for ( const auto in : tx.vin ) { -// pack_compact_size( s, in.scriptWitness.size() ); -// for ( const auto& sc : in.scriptWitness ) -// pack( s, sc ); -// } -// } -// -// pack( s, tx.nLockTime ); -//} -// -//template -//inline void unpack( Stream& s, bitcoin_transaction& tx ) -//{ -// uint8_t flags = 0; -// -// unpack( s, tx.nVersion ); -// -// auto vin_size = unpack_compact_size( s ); -// if ( vin_size == 0 ) { -// unpack( s, flags ); -// vin_size = unpack_compact_size( s ); -// } -// -// tx.vin.reserve( vin_size ); -// for ( size_t i = 0; i < vin_size; i++ ) { -// tx_in in; -// unpack( s, in ); -// tx.vin.push_back( in ); -// } -// -// const auto vout_size = unpack_compact_size( s ); -// tx.vout.reserve( vout_size ); -// for ( size_t i = 0; i < vout_size; i++ ) { -// tx_out out; -// unpack( s, out ); -// tx.vout.push_back( out ); -// } -// -// if ( flags & 1 ) { -// for ( auto& in : tx.vin ) { -// uint64_t stack_size = unpack_compact_size( s ); -// in.scriptWitness.reserve( stack_size ); -// for ( uint64_t i = 0; i < stack_size; i++ ) { -// std::vector script; -// unpack( s, script ); -// in.scriptWitness.push_back( script ); -// } -// } -// } -// -// unpack( s, tx.nLockTime ); -//} -// -//inline std::vector pack( const bitcoin_transaction& v, bool with_witness = true ) -//{ -// fc::datastream ps; -// pack( ps, v, with_witness ); -// std::vector vec( ps.tellp() ); -// -// if( !vec.empty() ) { -// fc::datastream ds( vec.data(), size_t( vec.size() ) ); -// pack( ds, v, with_witness ); -// } -// return vec; -//} -// -//inline bitcoin_transaction unpack( const std::vector& s ) -//{ try { -// bitcoin_transaction tmp; -// if( !s.empty() ) { -// fc::datastream ds( s.data(), size_t( s.size() ) ); -// unpack(ds, tmp); -// } -// return tmp; -//} FC_RETHROW_EXCEPTIONS( warn, "error unpacking ${type}", ("type","transaction" ) ) } -// -//template -//inline void pack_tx_signature( Stream& s, const std::vector& scriptPubKey, const bitcoin_transaction& tx, unsigned int in_index, int hash_type ) -//{ -// pack( s, tx.nVersion ); -// -// pack_compact_size( s, tx.vin.size() ); -// for ( size_t i = 0; i < tx.vin.size(); i++ ) { -// const auto& in = tx.vin[i]; -// pack( s, in.prevout ); -// if ( i == in_index ) -// pack( s, scriptPubKey ); -// else -// pack_compact_size( s, 0 ); // Blank signature -// pack( s, in.nSequence ); -// } -// -// pack_compact_size( s, tx.vout.size() ); -// for ( const auto& out : tx.vout ) -// pack( s, out ); -// -// pack( s, tx.nLockTime ); -// pack( s, hash_type ); -//} -// -//template -//inline void pack_tx_witness_signature( Stream& s, const std::vector& scriptCode, const bitcoin_transaction& tx, unsigned int in_index, int64_t amount, int hash_type ) -//{ -// -// fc::sha256 hash_prevouts; -// fc::sha256 hash_sequence; -// fc::sha256 hash_output; -// -// { -// fc::datastream ps; -// for ( const auto in : tx.vin ) -// pack( ps, in.prevout ); -// -// std::vector vec( ps.tellp() ); -// if ( vec.size() ) { -// fc::datastream ds( vec.data(), size_t( vec.size() ) ); -// for ( const auto in : tx.vin ) -// pack( ds, in.prevout ); -// } -// -// hash_prevouts = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); -// } -// -// { -// fc::datastream ps; -// for ( const auto in : tx.vin ) -// pack( ps, in.nSequence ); -// -// std::vector vec( ps.tellp() ); -// if ( vec.size() ) { -// fc::datastream ds( vec.data(), size_t( vec.size() ) ); -// for ( const auto in : tx.vin ) -// pack( ds, in.nSequence ); -// } -// -// hash_sequence = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); -// }; -// -// { -// fc::datastream ps; -// for ( const auto out : tx.vout ) -// pack( ps, out ); -// -// std::vector vec( ps.tellp() ); -// if ( vec.size() ) { -// fc::datastream ds( vec.data(), size_t( vec.size() ) ); -// for ( const auto out : tx.vout ) -// pack( ds, out ); -// } -// -// hash_output = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); -// } -// -// pack( s, tx.nVersion ); -// pack( s, hash_prevouts ); -// pack( s, hash_sequence ); -// -// pack( s, tx.vin[in_index].prevout ); -// pack( s, scriptCode ); -// pack( s, amount ); -// pack( s, tx.vin[in_index].nSequence ); -// -// pack( s, hash_output ); -// pack( s, tx.nLockTime ); -// pack( s, hash_type ); -//} -// -//} +#pragma once + +#include +#include + +namespace sidechain { + +inline void write_compact_size( bytes& vec, size_t size ) +{ + bytes sb; + sb.reserve( 2 ); + if ( size < 253 ) { + sb.insert( sb.end(), static_cast( size ) ); + } else if ( size <= std::numeric_limits::max() ) { + uint16_t tmp = htole16( static_cast( size ) ); + sb.insert( sb.end(), static_cast( 253 ) ); + sb.insert( sb.end(), reinterpret_cast( tmp ), reinterpret_cast( tmp ) + sizeof( tmp ) ); + } else if ( size <= std::numeric_limits::max() ) { + uint32_t tmp = htole32( static_cast( size ) ); + sb.insert( sb.end(), static_cast( 254 ) ); + sb.insert( sb.end(), reinterpret_cast( tmp ), reinterpret_cast( tmp ) + sizeof( tmp ) ); + } else { + uint64_t tmp = htole64( static_cast( size ) ); + sb.insert( sb.end(), static_cast( 255 ) ); + sb.insert( sb.end(), reinterpret_cast( tmp ), reinterpret_cast( tmp ) + sizeof( tmp ) ); + } + vec.insert( vec.end(), sb.begin(), sb.end() ); +} + +template +inline void pack_compact_size(Stream& s, size_t size) +{ + if ( size < 253 ) { + fc::raw::pack( s, static_cast( size ) ); + } else if ( size <= std::numeric_limits::max() ) { + fc::raw::pack( s, static_cast( 253 ) ); + fc::raw::pack( s, htole16( static_cast( size ) ) ); + } else if ( size <= std::numeric_limits::max() ) { + fc::raw::pack( s, static_cast( 254 ) ); + fc::raw::pack( s, htole32(static_cast( size ) ) ); + } else { + fc::raw::pack( s, static_cast( 255 ) ); + fc::raw::pack( s, htole64( static_cast( size ) ) ); + } +} + +template +inline uint64_t unpack_compact_size( Stream& s ) +{ + uint8_t size; + uint64_t size_ret; + + fc::raw::unpack( s, size ); + + if (size < 253) { + size_ret = size; + } else if ( size == 253 ) { + uint16_t tmp; + fc::raw::unpack( s, tmp ); + size_ret = le16toh( tmp ); + if ( size_ret < 253 ) + FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); + } else if ( size == 254 ) { + uint32_t tmp; + fc::raw::unpack( s, tmp ); + size_ret = le32toh( tmp ); + if ( size_ret < 0x10000u ) + FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); + } else { + uint32_t tmp; + fc::raw::unpack( s, tmp ); + size_ret = le64toh( tmp ); + if ( size_ret < 0x100000000ULL ) + FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); + } + + if ( size_ret > 0x08000000 ) + FC_THROW_EXCEPTION( fc::parse_error_exception, "unpack_compact_size(): size too large" ); + + return size_ret; +} + +template +inline void pack( Stream& s, const std::vector& v ) +{ + pack_compact_size( s, v.size() ); + if ( !v.empty() ) + s.write( v.data(), v.size() ); +} + +template +inline void unpack( Stream& s, std::vector& v ) +{ + const auto size = unpack_compact_size( s ); + v.resize( size ); + if ( size ) + s.read( v.data(), size ); +} + +template +inline void pack( Stream& s, const T& val ) +{ + fc::raw::pack( s, val ); +} + +template +inline void unpack( Stream& s, T& val ) +{ + fc::raw::unpack( s, val ); +} + +template +inline void pack( Stream& s, const out_point& op ) +{ + fc::sha256 reversed( op.hash ); + std::reverse( reversed.data(), reversed.data() + reversed.data_size() ); + s.write( reversed.data(), reversed.data_size() ); + pack( s, op.n ); +} + +template +inline void unpack( Stream& s, out_point& op ) +{ + uint64_t hash_size = op.hash.data_size(); + std::unique_ptr hash_data( new char[hash_size] ); + s.read( hash_data.get(), hash_size ); + std::reverse( hash_data.get(), hash_data.get() + hash_size ); + + op.hash = fc::sha256( hash_data.get(), hash_size ); + unpack( s, op.n ); +} + +template +inline void pack( Stream& s, const tx_in& in ) +{ + pack( s, in.prevout ); + pack( s, in.scriptSig ); + pack( s, in.nSequence ); +} + +template +inline void unpack( Stream& s, tx_in& in ) +{ + unpack( s, in.prevout ); + unpack( s, in.scriptSig ); + unpack( s, in.nSequence ); +} + +template +inline void pack( Stream& s, const tx_out& out ) +{ + pack( s, out.value ); + pack( s, out.scriptPubKey ); +} + +template +inline void unpack( Stream& s, tx_out& out ) +{ + unpack( s, out.value ); + unpack( s, out.scriptPubKey ); +} + +template +inline void pack( Stream& s, const bitcoin_transaction& tx, bool with_witness = true ) +{ + uint8_t flags = 0; + + if ( with_witness ) { + for ( const auto& in : tx.vin ) { + if ( !in.scriptWitness.empty() ) { + flags |= 1; + break; + } + } + } + + pack( s, tx.nVersion ); + + if ( flags ) { + pack_compact_size( s, 0 ); + pack( s, flags ); + } + + pack_compact_size( s, tx.vin.size() ); + for ( const auto& in : tx.vin ) + pack( s, in ); + + pack_compact_size( s, tx.vout.size() ); + for ( const auto& out : tx.vout ) + pack( s, out ); + + if ( flags & 1 ) { + for ( const auto in : tx.vin ) { + pack_compact_size( s, in.scriptWitness.size() ); + for ( const auto& sc : in.scriptWitness ) + pack( s, sc ); + } + } + + pack( s, tx.nLockTime ); +} + +template +inline void unpack( Stream& s, bitcoin_transaction& tx ) +{ + uint8_t flags = 0; + + unpack( s, tx.nVersion ); + + auto vin_size = unpack_compact_size( s ); + if ( vin_size == 0 ) { + unpack( s, flags ); + vin_size = unpack_compact_size( s ); + } + + tx.vin.reserve( vin_size ); + for ( size_t i = 0; i < vin_size; i++ ) { + tx_in in; + unpack( s, in ); + tx.vin.push_back( in ); + } + + const auto vout_size = unpack_compact_size( s ); + tx.vout.reserve( vout_size ); + for ( size_t i = 0; i < vout_size; i++ ) { + tx_out out; + unpack( s, out ); + tx.vout.push_back( out ); + } + + if ( flags & 1 ) { + for ( auto& in : tx.vin ) { + uint64_t stack_size = unpack_compact_size( s ); + in.scriptWitness.reserve( stack_size ); + for ( uint64_t i = 0; i < stack_size; i++ ) { + std::vector script; + unpack( s, script ); + in.scriptWitness.push_back( script ); + } + } + } + + unpack( s, tx.nLockTime ); +} + +inline std::vector pack( const bitcoin_transaction& v, bool with_witness = true ) +{ + fc::datastream ps; + pack( ps, v, with_witness ); + std::vector vec( ps.tellp() ); + + if( !vec.empty() ) { + fc::datastream ds( vec.data(), size_t( vec.size() ) ); + pack( ds, v, with_witness ); + } + return vec; +} + +inline bitcoin_transaction unpack( const std::vector& s ) +{ try { + bitcoin_transaction tmp; + if( !s.empty() ) { + fc::datastream ds( s.data(), size_t( s.size() ) ); + unpack(ds, tmp); + } + return tmp; +} FC_RETHROW_EXCEPTIONS( warn, "error unpacking ${type}", ("type","transaction" ) ) } + +template +inline void pack_tx_signature( Stream& s, const std::vector& scriptPubKey, const bitcoin_transaction& tx, unsigned int in_index, int hash_type ) +{ + pack( s, tx.nVersion ); + + pack_compact_size( s, tx.vin.size() ); + for ( size_t i = 0; i < tx.vin.size(); i++ ) { + const auto& in = tx.vin[i]; + pack( s, in.prevout ); + if ( i == in_index ) + pack( s, scriptPubKey ); + else + pack_compact_size( s, 0 ); // Blank signature + pack( s, in.nSequence ); + } + + pack_compact_size( s, tx.vout.size() ); + for ( const auto& out : tx.vout ) + pack( s, out ); + + pack( s, tx.nLockTime ); + pack( s, hash_type ); +} + +template +inline void pack_tx_witness_signature( Stream& s, const std::vector& scriptCode, const bitcoin_transaction& tx, unsigned int in_index, int64_t amount, int hash_type ) +{ + + fc::sha256 hash_prevouts; + fc::sha256 hash_sequence; + fc::sha256 hash_output; + + { + fc::datastream ps; + for ( const auto in : tx.vin ) + pack( ps, in.prevout ); + + std::vector vec( ps.tellp() ); + if ( vec.size() ) { + fc::datastream ds( vec.data(), size_t( vec.size() ) ); + for ( const auto in : tx.vin ) + pack( ds, in.prevout ); + } + + hash_prevouts = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); + } + + { + fc::datastream ps; + for ( const auto in : tx.vin ) + pack( ps, in.nSequence ); + + std::vector vec( ps.tellp() ); + if ( vec.size() ) { + fc::datastream ds( vec.data(), size_t( vec.size() ) ); + for ( const auto in : tx.vin ) + pack( ds, in.nSequence ); + } + + hash_sequence = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); + }; + + { + fc::datastream ps; + for ( const auto out : tx.vout ) + pack( ps, out ); + + std::vector vec( ps.tellp() ); + if ( vec.size() ) { + fc::datastream ds( vec.data(), size_t( vec.size() ) ); + for ( const auto out : tx.vout ) + pack( ds, out ); + } + + hash_output = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); + } + + pack( s, tx.nVersion ); + pack( s, hash_prevouts ); + pack( s, hash_sequence ); + + pack( s, tx.vin[in_index].prevout ); + pack( s, scriptCode ); + pack( s, amount ); + pack( s, tx.vin[in_index].nSequence ); + + pack( s, hash_output ); + pack( s, tx.nLockTime ); + pack( s, hash_type ); +} + +} diff --git a/libraries/plugins/peerplays_sidechain/segwit_addr.cpp b/libraries/plugins/peerplays_sidechain/segwit_addr.cpp new file mode 100644 index 00000000..2401f1ae --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/segwit_addr.cpp @@ -0,0 +1,81 @@ +/* Copyright (c) 2017 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +namespace +{ + +typedef std::vector data; + +/** Convert from one power-of-2 number base to another. */ +template +bool convertbits(data& out, const data& in) { + int acc = 0; + int bits = 0; + const int maxv = (1 << tobits) - 1; + const int max_acc = (1 << (frombits + tobits - 1)) - 1; + for (size_t i = 0; i < in.size(); ++i) { + int value = in[i]; + acc = ((acc << frombits) | value) & max_acc; + bits += frombits; + while (bits >= tobits) { + bits -= tobits; + out.push_back((acc >> bits) & maxv); + } + } + if (pad) { + if (bits) out.push_back((acc << (tobits - bits)) & maxv); + } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { + return false; + } + return true; +} + +} + +namespace sidechain { namespace segwit_addr { + +/** Decode a SegWit address. */ +std::pair decode(const std::string& hrp, const std::string& addr) { + std::pair dec = sidechain::bech32::Decode(addr); + if (dec.first != hrp || dec.second.size() < 1) return std::make_pair(-1, data()); + data conv; + if (!convertbits<5, 8, false>(conv, data(dec.second.begin() + 1, dec.second.end())) || + conv.size() < 2 || conv.size() > 40 || dec.second[0] > 16 || (dec.second[0] == 0 && + conv.size() != 20 && conv.size() != 32)) { + return std::make_pair(-1, data()); + } + return std::make_pair(dec.second[0], conv); +} + +/** Encode a SegWit address. */ +std::string encode(const std::string& hrp, int witver, const data& witprog) { + data enc; + enc.push_back(witver); + convertbits<8, 5, true>(enc, witprog); + std::string ret = sidechain::bech32::Encode(hrp, enc); + if (decode(hrp, ret).first == -1) return ""; + return ret; +} + +} } diff --git a/libraries/plugins/peerplays_sidechain/zmq_listener.cpp b/libraries/plugins/peerplays_sidechain/zmq_listener.cpp index 33d64a29..36f076e8 100644 --- a/libraries/plugins/peerplays_sidechain/zmq_listener.cpp +++ b/libraries/plugins/peerplays_sidechain/zmq_listener.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include