WIP, Moving Bitcoin listener to plugin

- Add missing files
- Remove few parts
This commit is contained in:
Srdjan Obucina 2019-09-17 21:43:44 +02:00
parent b7f117f23c
commit bfa6babfd2
3 changed files with 897 additions and 639 deletions

View file

@ -0,0 +1,258 @@
#include <sidechain/bitcoin_address.hpp>
#include <sstream>
#include <fc/crypto/base58.hpp>
#include <sidechain/segwit_addr.hpp>
#include <sidechain/bitcoin_script.hpp>
namespace sidechain {
bool bitcoin_address::operator==( const bitcoin_address& btc_addr ) const {
return ( this->address == btc_addr.address ) &&
( this->type == btc_addr.type ) &&
( this->raw_address == btc_addr.raw_address );
}
bytes bitcoin_address::get_script() const
{
switch ( type ) {
case payment_type::NULLDATA:
return script_builder() << op::RETURN << raw_address;
case payment_type::P2PK:
return script_builder() << raw_address << op::CHECKSIG;
case payment_type::P2PKH:
return script_builder() << op::DUP << op::HASH160 << raw_address << op::EQUALVERIFY << op::CHECKSIG;
case payment_type::P2SH:
case payment_type::P2SH_WPKH:
case payment_type::P2SH_WSH:
return script_builder() << op::HASH160 << raw_address << op::EQUAL;
case payment_type::P2WPKH:
case payment_type::P2WSH:
return script_builder() << op::_0 << raw_address;
default:
return raw_address;
}
}
payment_type bitcoin_address::determine_type()
{
if( is_p2pk() ) {
return payment_type::P2PK;
} else if( is_p2wpkh() ) {
return payment_type::P2WPKH;
} else if( is_p2wsh() ) {
return payment_type::P2WSH;
} else if( is_p2pkh() ) {
return payment_type::P2PKH;
} else if( is_p2sh() ) {
return payment_type::P2SH;
} else {
return payment_type::NULLDATA;
}
}
bytes bitcoin_address::determine_raw_address()
{
bytes result;
switch( type ) {
case payment_type::P2PK : {
result = parse_hex( address );
break;
}
case payment_type::P2WPKH :
case payment_type::P2WSH : {
std::string prefix( address.compare(0,4,"bcrt") == 0 ? std::string( address.begin(), address.begin() + 4 ) :
std::string( address.begin(), address.begin() + 2 ) );
const auto& decode_bech32 = segwit_addr::decode( prefix, address );
result = bytes( decode_bech32.second.begin(), decode_bech32.second.end() );
break;
}
case payment_type::P2SH_WPKH :
case payment_type::P2SH_WSH :
case payment_type::P2PKH :
case payment_type::P2SH : {
bytes hex_addr = fc::from_base58( address );
result = bytes( hex_addr.begin() + 1, hex_addr.begin() + 21 );
break;
}
case payment_type::NULLDATA : return result;
}
return result;
}
bool bitcoin_address::check_segwit_address( const size_segwit_address& size ) const {
if( !address.compare(0,4,"bcrt") || !address.compare(0,2,"bc") || !address.compare(0,2,"tb") ) {
std::string prefix( !address.compare(0,4,"bcrt") ? std::string(address.begin(), address.begin() + 4) :
std::string(address.begin(), address.begin() + 2) );
const auto& decode_bech32 = segwit_addr::decode( prefix, address );
if( decode_bech32.first == -1 || decode_bech32.second.size() != size ) {
return false;
}
return true;
}
return false;
}
bool bitcoin_address::is_p2pk() const
{
try {
bool prefix = !address.compare(0,2,"02") || !address.compare(0,2,"03");
if( address.size() == 66 && prefix ) {
parse_hex( address );
return true;
}
} catch( fc::exception e ) {
return false;
}
return false;
}
bool bitcoin_address::is_p2wpkh() const
{
return check_segwit_address( size_segwit_address::P2WPKH );
}
bool bitcoin_address::is_p2wsh() const
{
return check_segwit_address( size_segwit_address::P2WSH );
}
bool bitcoin_address::is_p2pkh() const
{
try {
bytes hex_addr = fc::from_base58( address );
if( hex_addr.size() == 25 && ( static_cast<unsigned char>( hex_addr[0] ) == 0x00 ||
static_cast<unsigned char>( hex_addr[0] ) == 0x6f ) ) {
return true;
}
return false;
} catch( fc::exception e ) {
return false;
}
}
bool bitcoin_address::is_p2sh() const
{
try {
bytes hex_addr = fc::from_base58( address );
if( hex_addr.size() == 25 && ( static_cast<unsigned char>( hex_addr[0] ) == 0x05 ||
static_cast<unsigned char>( hex_addr[0] ) == 0xc4 ) ) {
return true;
}
return false;
} catch( fc::exception e ) {
return false;
}
}
btc_multisig_address::btc_multisig_address( const size_t n_required, const accounts_keys& keys ) :
keys_required ( n_required ), witnesses_keys( keys )
{
create_redeem_script();
create_address();
type = payment_type::P2SH;
}
size_t btc_multisig_address::count_intersection( const accounts_keys& keys ) const
{
FC_ASSERT( keys.size() > 0 );
int intersections_count = 0;
for( auto& key : keys ) {
auto witness_key = witnesses_keys.find( key.first );
if( witness_key == witnesses_keys.end() ) continue;
if( key.second == witness_key->second )
intersections_count++;
}
return intersections_count;
}
void btc_multisig_address::create_redeem_script()
{
FC_ASSERT( keys_required > 0 );
FC_ASSERT( keys_required < witnesses_keys.size() );
redeem_script.clear();
redeem_script.push_back( op_num[keys_required - 1] );
for( const auto& key : witnesses_keys ) {
std::stringstream ss;
ss << std::hex << key.second.key_data.size();
auto key_size_hex = sidechain::parse_hex( ss.str() );
redeem_script.insert( redeem_script.end(), key_size_hex.begin(), key_size_hex.end() );
redeem_script.insert( redeem_script.end(), key.second.key_data.begin(), key.second.key_data.end() );
}
redeem_script.push_back( op_num[witnesses_keys.size() - 1] );
redeem_script.push_back( OP_CHECKMULTISIG );
}
void btc_multisig_address::create_address()
{
FC_ASSERT( redeem_script.size() > 0 );
raw_address.clear();
fc::sha256 hash256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() );
fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() );
bytes temp_addr_hash( sidechain::parse_hex( hash160.str() ) );
raw_address.push_back( OP_HASH160 );
std::stringstream ss;
ss << std::hex << temp_addr_hash.size();
auto address_size_hex = sidechain::parse_hex( ss.str() );
raw_address.insert( raw_address.end(), address_size_hex.begin(), address_size_hex.end() );
raw_address.insert( raw_address.end(), temp_addr_hash.begin(), temp_addr_hash.end() );
raw_address.push_back( OP_EQUAL );
}
btc_multisig_segwit_address::btc_multisig_segwit_address( const size_t n_required, const accounts_keys& keys ) :
btc_multisig_address( n_required, keys )
{
create_witness_script();
create_segwit_address();
type = payment_type::P2SH;
}
bool btc_multisig_segwit_address::operator==( const btc_multisig_segwit_address& addr ) const
{
if( address != addr.address || redeem_script != addr.redeem_script ||
witnesses_keys != addr.witnesses_keys || witness_script != addr.witness_script ||
raw_address != addr.raw_address )
return false;
return true;
}
std::vector<public_key_type> btc_multisig_segwit_address::get_keys() {
std::vector<public_key_type> keys;
for( const auto& k : witnesses_keys ) {
keys.push_back( k.second );
}
return keys;
}
void btc_multisig_segwit_address::create_witness_script()
{
const auto redeem_sha256 = fc::sha256::hash( redeem_script.data(), redeem_script.size() );
witness_script.push_back( OP_0 );
witness_script.push_back( 0x20 ); // PUSH_32
witness_script.insert( witness_script.end(), redeem_sha256.data(), redeem_sha256.data() + redeem_sha256.data_size() );
}
void btc_multisig_segwit_address::create_segwit_address()
{
fc::sha256 hash256 = fc::sha256::hash( witness_script.data(), witness_script.size() );
fc::ripemd160 hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_size() );
raw_address = bytes(hash160.data(), hash160.data() + hash160.data_size() );
address = fc::to_base58( get_address_bytes( raw_address ) );
}
bytes btc_multisig_segwit_address::get_address_bytes( const bytes& script_hash )
{
bytes address_bytes( 1, TESTNET_SCRIPT ); // 1 byte version
address_bytes.insert( address_bytes.end(), script_hash.begin(), script_hash.end() );
fc::sha256 hash256 = fc::sha256::hash( fc::sha256::hash( address_bytes.data(), address_bytes.size() ) );
address_bytes.insert( address_bytes.end(), hash256.data(), hash256.data() + 4 ); // 4 byte checksum
return address_bytes;
}
}

View file

@ -1,279 +1,279 @@
#include <sidechain/bitcoin_transaction.hpp> //#include <sidechain/bitcoin_transaction.hpp>
#include <fc/crypto/base58.hpp> //#include <fc/crypto/base58.hpp>
#include <sidechain/bitcoin_script.hpp> //#include <sidechain/bitcoin_script.hpp>
#include <sidechain/serialize.hpp> //#include <sidechain/serialize.hpp>
//
namespace sidechain { //namespace sidechain {
//
bool out_point::operator==( const out_point& op ) const //bool out_point::operator==( const out_point& op ) const
{ //{
if( this->hash == op.hash && // if( this->hash == op.hash &&
this->n == op.n ) // this->n == op.n )
{ // {
return true; // return true;
} // }
return false; // return false;
} //}
//
bool tx_in::operator==( const tx_in& ti ) const //bool tx_in::operator==( const tx_in& ti ) const
{ //{
if( this->prevout == ti.prevout && // if( this->prevout == ti.prevout &&
this->scriptSig == ti.scriptSig && // this->scriptSig == ti.scriptSig &&
this->nSequence == ti.nSequence ) // this->nSequence == ti.nSequence )
{ // {
return true; // return true;
} // }
return false; // return false;
} //}
//
bool tx_out::operator==( const tx_out& to ) const //bool tx_out::operator==( const tx_out& to ) const
{ //{
if( this->value == to.value && // if( this->value == to.value &&
this->scriptPubKey == to.scriptPubKey ) // this->scriptPubKey == to.scriptPubKey )
{ // {
return true; // return true;
} // }
return false; // return false;
} //}
//
bool tx_out::is_p2wsh() const //bool tx_out::is_p2wsh() const
{ //{
if( scriptPubKey.size() == 34 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x20) ) { // if( scriptPubKey.size() == 34 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x20) ) {
return true; // return true;
} // }
return false; // return false;
} //}
//
bool tx_out::is_p2wpkh() const //bool tx_out::is_p2wpkh() const
{ //{
if( scriptPubKey.size() == 22 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x14) ) { // if( scriptPubKey.size() == 22 && scriptPubKey[0] == static_cast<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x14) ) {
return true; // return true;
} // }
return false; // return false;
} //}
//
bool tx_out::is_p2pkh() const //bool tx_out::is_p2pkh() const
{ //{
if( scriptPubKey.size() == 25 && scriptPubKey[0] == static_cast<char>(0x76) && scriptPubKey[1] == static_cast<char>(0xa9) && // if( scriptPubKey.size() == 25 && scriptPubKey[0] == static_cast<char>(0x76) && scriptPubKey[1] == static_cast<char>(0xa9) &&
scriptPubKey[2] == static_cast<char>(0x14) && scriptPubKey[23] == static_cast<char>(0x88) && scriptPubKey[24] == static_cast<char>(0xac) ) { // scriptPubKey[2] == static_cast<char>(0x14) && scriptPubKey[23] == static_cast<char>(0x88) && scriptPubKey[24] == static_cast<char>(0xac) ) {
return true; // return true;
} // }
return false; // return false;
} //}
//
bool tx_out::is_p2sh() const //bool tx_out::is_p2sh() const
{ //{
if( scriptPubKey.size() == 23 && scriptPubKey[0] == static_cast<char>(0xa9) && // if( scriptPubKey.size() == 23 && scriptPubKey[0] == static_cast<char>(0xa9) &&
scriptPubKey[1] == static_cast<char>(0x14) && scriptPubKey[22] == static_cast<char>(0x87) ) { // scriptPubKey[1] == static_cast<char>(0x14) && scriptPubKey[22] == static_cast<char>(0x87) ) {
return true; // return true;
} // }
return false; // return false;
} //}
//
bool tx_out::is_p2pk() const //bool tx_out::is_p2pk() const
{ //{
if( scriptPubKey.size() == 35 && scriptPubKey[0] == static_cast<char>(0x21) && scriptPubKey[34] == static_cast<char>(0xac) ) { // if( scriptPubKey.size() == 35 && scriptPubKey[0] == static_cast<char>(0x21) && scriptPubKey[34] == static_cast<char>(0xac) ) {
return true; // return true;
} // }
return false; // return false;
} //}
//
bytes tx_out::get_data_or_script() const //bytes tx_out::get_data_or_script() const
{ //{
if( is_p2pkh() ) { // if( is_p2pkh() ) {
return bytes( scriptPubKey.begin() + 3, scriptPubKey.begin() + 23 ); // return bytes( scriptPubKey.begin() + 3, scriptPubKey.begin() + 23 );
} else if( is_p2sh() || is_p2wpkh() ) { // } else if( is_p2sh() || is_p2wpkh() ) {
return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 22 ); // return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 22 );
} else if( is_p2wsh() ) { // } else if( is_p2wsh() ) {
return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 34 ); // return bytes( scriptPubKey.begin() + 2, scriptPubKey.begin() + 34 );
} else if( is_p2pk() ) { // } else if( is_p2pk() ) {
return bytes( scriptPubKey.begin() + 1, scriptPubKey.begin() + 34 ); // return bytes( scriptPubKey.begin() + 1, scriptPubKey.begin() + 34 );
} // }
return scriptPubKey; // return scriptPubKey;
} //}
//
bool bitcoin_transaction::operator!=( const bitcoin_transaction& bt ) const //bool bitcoin_transaction::operator!=( const bitcoin_transaction& bt ) const
{ //{
if( this->nVersion != bt.nVersion || // if( this->nVersion != bt.nVersion ||
this->vin != bt.vin || // this->vin != bt.vin ||
this->vout != bt.vout || // this->vout != bt.vout ||
this->nLockTime != bt.nLockTime ) // this->nLockTime != bt.nLockTime )
{ // {
return true; // return true;
} // }
return false; // return false;
} //}
//
fc::sha256 bitcoin_transaction::get_hash() const //fc::sha256 bitcoin_transaction::get_hash() const
{ //{
const auto bytes = pack( *this, true) ; // const auto bytes = pack( *this, true) ;
const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); // const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) );
std::reverse( hash.data(), hash.data() + hash.data_size() ); // std::reverse( hash.data(), hash.data() + hash.data_size() );
return hash; // return hash;
} //}
//
fc::sha256 bitcoin_transaction::get_txid() const //fc::sha256 bitcoin_transaction::get_txid() const
{ //{
const auto bytes = pack( *this, false ); // const auto bytes = pack( *this, false );
const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) ); // const auto hash = fc::sha256::hash( fc::sha256::hash(bytes.data(), bytes.size()) );
std::reverse( hash.data(), hash.data() + hash.data_size() ); // std::reverse( hash.data(), hash.data() + hash.data_size() );
return hash; // return hash;
} //}
//
size_t bitcoin_transaction::get_vsize() const //size_t bitcoin_transaction::get_vsize() const
{ //{
static const auto witness_scale_factor = 4; // static const auto witness_scale_factor = 4;
//
fc::datastream<size_t> no_wit_ds; // fc::datastream<size_t> no_wit_ds;
pack( no_wit_ds, *this, false ); // pack( no_wit_ds, *this, false );
//
fc::datastream<size_t> wit_ds; // fc::datastream<size_t> wit_ds;
pack( wit_ds, *this, true ); // pack( wit_ds, *this, true );
//
const size_t weight = no_wit_ds.tellp() * ( witness_scale_factor - 1 ) + wit_ds.tellp(); // 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; // const size_t vsize = ( weight + witness_scale_factor - 1 ) / witness_scale_factor;
//
return vsize; // return vsize;
} //}
//
void bitcoin_transaction_builder::set_version( int32_t version ) //void bitcoin_transaction_builder::set_version( int32_t version )
{ //{
tx.nVersion = version; // tx.nVersion = version;
} //}
//
void bitcoin_transaction_builder::set_locktime(uint32_t lock_time) //void bitcoin_transaction_builder::set_locktime(uint32_t lock_time)
{ //{
tx.nLockTime = 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 ) //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; // out_point prevout;
prevout.hash = txid; // prevout.hash = txid;
prevout.n = n_out; // prevout.n = n_out;
//
tx_in txin; // tx_in txin;
txin.prevout = prevout; // txin.prevout = prevout;
txin.nSequence = sequence; // txin.nSequence = sequence;
//
add_in( type, txin, script_code, front ); // 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 ) //void bitcoin_transaction_builder::add_in( payment_type type, tx_in txin, const bytes& script_code, bool front )
{ //{
switch ( type ) { // switch ( type ) {
case payment_type::P2SH_WPKH: // case payment_type::P2SH_WPKH:
case payment_type::P2SH_WSH: // case payment_type::P2SH_WSH:
FC_ASSERT( script_code != bytes() ); // FC_ASSERT( script_code != bytes() );
txin.scriptSig = script_code; // txin.scriptSig = script_code;
break; // break;
default:{ // default:{
if( txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000") ) { //coinbase // if( txin.prevout.hash == fc::sha256("0000000000000000000000000000000000000000000000000000000000000000") ) { //coinbase
FC_ASSERT( script_code != bytes() ); // FC_ASSERT( script_code != bytes() );
txin.scriptSig = script_code; // txin.scriptSig = script_code;
} // }
break; // break;
} // }
} // }
//
if( front ) { // if( front ) {
tx.vin.insert( tx.vin.begin(), txin ); // tx.vin.insert( tx.vin.begin(), txin );
} else { // } else {
tx.vin.push_back( txin ); // tx.vin.push_back( txin );
} // }
} //}
//
void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const std::string& base58_address, bool front ) //void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const std::string& base58_address, bool front )
{ //{
// TODO: add checks // // TODO: add checks
const auto address_bytes = fc::from_base58(base58_address); // const auto address_bytes = fc::from_base58(base58_address);
add_out( type, amount, bytes( address_bytes.begin() + 1, address_bytes.begin() + 1 + 20 ), front ); // 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 ) //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 ) ); // FC_ASSERT( is_payment_to_pubkey( type ) );
//
if ( type == payment_type::P2PK ) { // if ( type == payment_type::P2PK ) {
const auto pubkey_bytes = bytes( pubkey.begin(), pubkey.begin() + pubkey.size() ); // const auto pubkey_bytes = bytes( pubkey.begin(), pubkey.begin() + pubkey.size() );
add_out( type, amount, pubkey_bytes, front ); // add_out( type, amount, pubkey_bytes, front );
} else { // } else {
const auto hash256 = fc::sha256::hash( pubkey.begin(), pubkey.size() ); // const auto hash256 = fc::sha256::hash( pubkey.begin(), pubkey.size() );
const auto hash160 = fc::ripemd160::hash( hash256.data(), hash256.data_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 ); // 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 ) //void bitcoin_transaction_builder::add_out( payment_type type, int64_t amount, const bytes& script_code, bool front )
{ //{
tx_out out; // tx_out out;
out.value = amount; // out.value = amount;
out.scriptPubKey = get_script_pubkey( type, script_code ); // out.scriptPubKey = get_script_pubkey( type, script_code );
//
if( front ) { // if( front ) {
tx.vout.insert( tx.vout.begin(), out ); // tx.vout.insert( tx.vout.begin(), out );
} else { // } else {
tx.vout.push_back( out ); // tx.vout.push_back( out );
} // }
} //}
//
void bitcoin_transaction_builder::add_out_all_type( const uint64_t& amount, const bitcoin_address& address, bool front ) //void bitcoin_transaction_builder::add_out_all_type( const uint64_t& amount, const bitcoin_address& address, bool front )
{ //{
switch( address.get_type() ) { // switch( address.get_type() ) {
case payment_type::P2PK: { // case payment_type::P2PK: {
bytes raw_address( address.get_raw_address() ); // bytes raw_address( address.get_raw_address() );
fc::ecc::public_key_data public_key; // fc::ecc::public_key_data public_key;
std::copy( raw_address.begin(), raw_address.end(), public_key.begin() ); // std::copy( raw_address.begin(), raw_address.end(), public_key.begin() );
add_out( address.get_type(), amount, public_key, front ); // add_out( address.get_type(), amount, public_key, front );
break; // break;
} // }
case payment_type::P2PKH: // case payment_type::P2PKH:
case payment_type::P2SH: // case payment_type::P2SH:
case payment_type::P2SH_WPKH: // case payment_type::P2SH_WPKH:
case payment_type::P2SH_WSH: { // case payment_type::P2SH_WSH: {
add_out( address.get_type(), amount, address.get_address(), front ); // add_out( address.get_type(), amount, address.get_address(), front );
break; // break;
} // }
case payment_type::P2WPKH: // case payment_type::P2WPKH:
case payment_type::P2WSH: { // case payment_type::P2WSH: {
add_out( address.get_type(), amount, address.get_raw_address(), front ); // add_out( address.get_type(), amount, address.get_raw_address(), front );
break; // break;
} // }
} // }
} //}
//
inline bool bitcoin_transaction_builder::is_payment_to_pubkey( payment_type type ) //inline bool bitcoin_transaction_builder::is_payment_to_pubkey( payment_type type )
{ //{
switch ( type ) { // switch ( type ) {
case payment_type::P2PK: // case payment_type::P2PK:
case payment_type::P2PKH: // case payment_type::P2PKH:
case payment_type::P2WPKH: // case payment_type::P2WPKH:
case payment_type::P2SH_WPKH: // case payment_type::P2SH_WPKH:
return true; // return true;
default: // default:
return false; // return false;
} // }
} //}
//
bytes bitcoin_transaction_builder::get_script_pubkey( payment_type type, const bytes& script_code ) //bytes bitcoin_transaction_builder::get_script_pubkey( payment_type type, const bytes& script_code )
{ //{
switch ( type ) { // switch ( type ) {
case payment_type::NULLDATA: // case payment_type::NULLDATA:
return script_builder() << op::RETURN << script_code; // return script_builder() << op::RETURN << script_code;
case payment_type::P2PK: // case payment_type::P2PK:
return script_builder() << script_code << op::CHECKSIG; // return script_builder() << script_code << op::CHECKSIG;
case payment_type::P2PKH: // case payment_type::P2PKH:
return script_builder() << op::DUP << op::HASH160 << script_code << op::EQUALVERIFY << op::CHECKSIG; // return script_builder() << op::DUP << op::HASH160 << script_code << op::EQUALVERIFY << op::CHECKSIG;
case payment_type::P2SH: // case payment_type::P2SH:
case payment_type::P2SH_WPKH: // case payment_type::P2SH_WPKH:
case payment_type::P2SH_WSH: // case payment_type::P2SH_WSH:
return script_builder() << op::HASH160 << script_code << op::EQUAL; // return script_builder() << op::HASH160 << script_code << op::EQUAL;
case payment_type::P2WPKH: // case payment_type::P2WPKH:
case payment_type::P2WSH: // case payment_type::P2WSH:
return script_builder() << op::_0 << script_code; // return script_builder() << op::_0 << script_code;
default: // default:
return script_code; // return script_code;
} // }
} //}
//
} //}

View file

@ -1,360 +1,360 @@
#pragma once //#pragma once
//
#include <sidechain/types.hpp> //#include <sidechain/types.hpp>
#include <sidechain/bitcoin_transaction.hpp> //#include <sidechain/bitcoin_transaction.hpp>
//
namespace sidechain { //namespace sidechain {
//
inline void write_compact_size( bytes& vec, size_t size ) //inline void write_compact_size( bytes& vec, size_t size )
{ //{
bytes sb; // bytes sb;
sb.reserve( 2 ); // sb.reserve( 2 );
if ( size < 253 ) { // if ( size < 253 ) {
sb.insert( sb.end(), static_cast<uint8_t>( size ) ); // sb.insert( sb.end(), static_cast<uint8_t>( size ) );
} else if ( size <= std::numeric_limits<unsigned short>::max() ) { // } else if ( size <= std::numeric_limits<unsigned short>::max() ) {
uint16_t tmp = htole16( static_cast<uint16_t>( size ) ); // uint16_t tmp = htole16( static_cast<uint16_t>( size ) );
sb.insert( sb.end(), static_cast<uint8_t>( 253 ) ); // sb.insert( sb.end(), static_cast<uint8_t>( 253 ) );
sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) ); // sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) );
} else if ( size <= std::numeric_limits<unsigned int>::max() ) { // } else if ( size <= std::numeric_limits<unsigned int>::max() ) {
uint32_t tmp = htole32( static_cast<uint32_t>( size ) ); // uint32_t tmp = htole32( static_cast<uint32_t>( size ) );
sb.insert( sb.end(), static_cast<uint8_t>( 254 ) ); // sb.insert( sb.end(), static_cast<uint8_t>( 254 ) );
sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) ); // sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) );
} else { // } else {
uint64_t tmp = htole64( static_cast<uint64_t>( size ) ); // uint64_t tmp = htole64( static_cast<uint64_t>( size ) );
sb.insert( sb.end(), static_cast<uint8_t>( 255 ) ); // sb.insert( sb.end(), static_cast<uint8_t>( 255 ) );
sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) ); // sb.insert( sb.end(), reinterpret_cast<const char*>( tmp ), reinterpret_cast<const char*>( tmp ) + sizeof( tmp ) );
} // }
vec.insert( vec.end(), sb.begin(), sb.end() ); // vec.insert( vec.end(), sb.begin(), sb.end() );
} //}
//
template<typename Stream> //template<typename Stream>
inline void pack_compact_size(Stream& s, size_t size) //inline void pack_compact_size(Stream& s, size_t size)
{ //{
if ( size < 253 ) { // if ( size < 253 ) {
fc::raw::pack( s, static_cast<uint8_t>( size ) ); // fc::raw::pack( s, static_cast<uint8_t>( size ) );
} else if ( size <= std::numeric_limits<unsigned short>::max() ) { // } else if ( size <= std::numeric_limits<unsigned short>::max() ) {
fc::raw::pack( s, static_cast<uint8_t>( 253 ) ); // fc::raw::pack( s, static_cast<uint8_t>( 253 ) );
fc::raw::pack( s, htole16( static_cast<uint16_t>( size ) ) ); // fc::raw::pack( s, htole16( static_cast<uint16_t>( size ) ) );
} else if ( size <= std::numeric_limits<unsigned int>::max() ) { // } else if ( size <= std::numeric_limits<unsigned int>::max() ) {
fc::raw::pack( s, static_cast<uint8_t>( 254 ) ); // fc::raw::pack( s, static_cast<uint8_t>( 254 ) );
fc::raw::pack( s, htole32(static_cast<uint32_t>( size ) ) ); // fc::raw::pack( s, htole32(static_cast<uint32_t>( size ) ) );
} else { // } else {
fc::raw::pack( s, static_cast<uint8_t>( 255 ) ); // fc::raw::pack( s, static_cast<uint8_t>( 255 ) );
fc::raw::pack( s, htole64( static_cast<uint64_t>( size ) ) ); // fc::raw::pack( s, htole64( static_cast<uint64_t>( size ) ) );
} // }
} //}
//
template<typename Stream> //template<typename Stream>
inline uint64_t unpack_compact_size( Stream& s ) //inline uint64_t unpack_compact_size( Stream& s )
{ //{
uint8_t size; // uint8_t size;
uint64_t size_ret; // uint64_t size_ret;
//
fc::raw::unpack( s, size ); // fc::raw::unpack( s, size );
//
if (size < 253) { // if (size < 253) {
size_ret = size; // size_ret = size;
} else if ( size == 253 ) { // } else if ( size == 253 ) {
uint16_t tmp; // uint16_t tmp;
fc::raw::unpack( s, tmp ); // fc::raw::unpack( s, tmp );
size_ret = le16toh( tmp ); // size_ret = le16toh( tmp );
if ( size_ret < 253 ) // if ( size_ret < 253 )
FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); // FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" );
} else if ( size == 254 ) { // } else if ( size == 254 ) {
uint32_t tmp; // uint32_t tmp;
fc::raw::unpack( s, tmp ); // fc::raw::unpack( s, tmp );
size_ret = le32toh( tmp ); // size_ret = le32toh( tmp );
if ( size_ret < 0x10000u ) // if ( size_ret < 0x10000u )
FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); // FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" );
} else { // } else {
uint32_t tmp; // uint32_t tmp;
fc::raw::unpack( s, tmp ); // fc::raw::unpack( s, tmp );
size_ret = le64toh( tmp ); // size_ret = le64toh( tmp );
if ( size_ret < 0x100000000ULL ) // if ( size_ret < 0x100000000ULL )
FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" ); // FC_THROW_EXCEPTION( fc::parse_error_exception, "non-canonical unpack_compact_size()" );
} // }
//
if ( size_ret > 0x08000000 ) // if ( size_ret > 0x08000000 )
FC_THROW_EXCEPTION( fc::parse_error_exception, "unpack_compact_size(): size too large" ); // FC_THROW_EXCEPTION( fc::parse_error_exception, "unpack_compact_size(): size too large" );
//
return size_ret; // return size_ret;
} //}
//
template<typename Stream> //template<typename Stream>
inline void pack( Stream& s, const std::vector<char>& v ) //inline void pack( Stream& s, const std::vector<char>& v )
{ //{
pack_compact_size( s, v.size() ); // pack_compact_size( s, v.size() );
if ( !v.empty() ) // if ( !v.empty() )
s.write( v.data(), v.size() ); // s.write( v.data(), v.size() );
} //}
//
template<typename Stream> //template<typename Stream>
inline void unpack( Stream& s, std::vector<char>& v ) //inline void unpack( Stream& s, std::vector<char>& v )
{ //{
const auto size = unpack_compact_size( s ); // const auto size = unpack_compact_size( s );
v.resize( size ); // v.resize( size );
if ( size ) // if ( size )
s.read( v.data(), size ); // s.read( v.data(), size );
} //}
//
template<typename Stream, typename T> //template<typename Stream, typename T>
inline void pack( Stream& s, const T& val ) //inline void pack( Stream& s, const T& val )
{ //{
fc::raw::pack( s, val ); // fc::raw::pack( s, val );
} //}
//
template<typename Stream, typename T> //template<typename Stream, typename T>
inline void unpack( Stream& s, T& val ) //inline void unpack( Stream& s, T& val )
{ //{
fc::raw::unpack( s, val ); // fc::raw::unpack( s, val );
} //}
//
template<typename Stream> //template<typename Stream>
inline void pack( Stream& s, const out_point& op ) //inline void pack( Stream& s, const out_point& op )
{ //{
fc::sha256 reversed( op.hash ); // fc::sha256 reversed( op.hash );
std::reverse( reversed.data(), reversed.data() + reversed.data_size() ); // std::reverse( reversed.data(), reversed.data() + reversed.data_size() );
s.write( reversed.data(), reversed.data_size() ); // s.write( reversed.data(), reversed.data_size() );
pack( s, op.n ); // pack( s, op.n );
} //}
//
template<typename Stream> //template<typename Stream>
inline void unpack( Stream& s, out_point& op ) //inline void unpack( Stream& s, out_point& op )
{ //{
uint64_t hash_size = op.hash.data_size(); // uint64_t hash_size = op.hash.data_size();
std::unique_ptr<char[]> hash_data( new char[hash_size] ); // std::unique_ptr<char[]> hash_data( new char[hash_size] );
s.read( hash_data.get(), hash_size ); // s.read( hash_data.get(), hash_size );
std::reverse( hash_data.get(), hash_data.get() + hash_size ); // std::reverse( hash_data.get(), hash_data.get() + hash_size );
//
op.hash = fc::sha256( hash_data.get(), hash_size ); // op.hash = fc::sha256( hash_data.get(), hash_size );
unpack( s, op.n ); // unpack( s, op.n );
} //}
//
template<typename Stream> //template<typename Stream>
inline void pack( Stream& s, const tx_in& in ) //inline void pack( Stream& s, const tx_in& in )
{ //{
pack( s, in.prevout ); // pack( s, in.prevout );
pack( s, in.scriptSig ); // pack( s, in.scriptSig );
pack( s, in.nSequence ); // pack( s, in.nSequence );
} //}
//
template<typename Stream> //template<typename Stream>
inline void unpack( Stream& s, tx_in& in ) //inline void unpack( Stream& s, tx_in& in )
{ //{
unpack( s, in.prevout ); // unpack( s, in.prevout );
unpack( s, in.scriptSig ); // unpack( s, in.scriptSig );
unpack( s, in.nSequence ); // unpack( s, in.nSequence );
} //}
//
template<typename Stream> //template<typename Stream>
inline void pack( Stream& s, const tx_out& out ) //inline void pack( Stream& s, const tx_out& out )
{ //{
pack( s, out.value ); // pack( s, out.value );
pack( s, out.scriptPubKey ); // pack( s, out.scriptPubKey );
} //}
//
template<typename Stream> //template<typename Stream>
inline void unpack( Stream& s, tx_out& out ) //inline void unpack( Stream& s, tx_out& out )
{ //{
unpack( s, out.value ); // unpack( s, out.value );
unpack( s, out.scriptPubKey ); // unpack( s, out.scriptPubKey );
} //}
//
template<typename Stream> //template<typename Stream>
inline void pack( Stream& s, const bitcoin_transaction& tx, bool with_witness = true ) //inline void pack( Stream& s, const bitcoin_transaction& tx, bool with_witness = true )
{ //{
uint8_t flags = 0; // uint8_t flags = 0;
//
if ( with_witness ) { // if ( with_witness ) {
for ( const auto& in : tx.vin ) { // for ( const auto& in : tx.vin ) {
if ( !in.scriptWitness.empty() ) { // if ( !in.scriptWitness.empty() ) {
flags |= 1; // flags |= 1;
break; // break;
} // }
} // }
} // }
//
pack( s, tx.nVersion ); // pack( s, tx.nVersion );
//
if ( flags ) { // if ( flags ) {
pack_compact_size( s, 0 ); // pack_compact_size( s, 0 );
pack( s, flags ); // pack( s, flags );
} // }
//
pack_compact_size( s, tx.vin.size() ); // pack_compact_size( s, tx.vin.size() );
for ( const auto& in : tx.vin ) // for ( const auto& in : tx.vin )
pack( s, in ); // pack( s, in );
//
pack_compact_size( s, tx.vout.size() ); // pack_compact_size( s, tx.vout.size() );
for ( const auto& out : tx.vout ) // for ( const auto& out : tx.vout )
pack( s, out ); // pack( s, out );
//
if ( flags & 1 ) { // if ( flags & 1 ) {
for ( const auto in : tx.vin ) { // for ( const auto in : tx.vin ) {
pack_compact_size( s, in.scriptWitness.size() ); // pack_compact_size( s, in.scriptWitness.size() );
for ( const auto& sc : in.scriptWitness ) // for ( const auto& sc : in.scriptWitness )
pack( s, sc ); // pack( s, sc );
} // }
} // }
//
pack( s, tx.nLockTime ); // pack( s, tx.nLockTime );
} //}
//
template<typename Stream> //template<typename Stream>
inline void unpack( Stream& s, bitcoin_transaction& tx ) //inline void unpack( Stream& s, bitcoin_transaction& tx )
{ //{
uint8_t flags = 0; // uint8_t flags = 0;
//
unpack( s, tx.nVersion ); // unpack( s, tx.nVersion );
//
auto vin_size = unpack_compact_size( s ); // auto vin_size = unpack_compact_size( s );
if ( vin_size == 0 ) { // if ( vin_size == 0 ) {
unpack( s, flags ); // unpack( s, flags );
vin_size = unpack_compact_size( s ); // vin_size = unpack_compact_size( s );
} // }
//
tx.vin.reserve( vin_size ); // tx.vin.reserve( vin_size );
for ( size_t i = 0; i < vin_size; i++ ) { // for ( size_t i = 0; i < vin_size; i++ ) {
tx_in in; // tx_in in;
unpack( s, in ); // unpack( s, in );
tx.vin.push_back( in ); // tx.vin.push_back( in );
} // }
//
const auto vout_size = unpack_compact_size( s ); // const auto vout_size = unpack_compact_size( s );
tx.vout.reserve( vout_size ); // tx.vout.reserve( vout_size );
for ( size_t i = 0; i < vout_size; i++ ) { // for ( size_t i = 0; i < vout_size; i++ ) {
tx_out out; // tx_out out;
unpack( s, out ); // unpack( s, out );
tx.vout.push_back( out ); // tx.vout.push_back( out );
} // }
//
if ( flags & 1 ) { // if ( flags & 1 ) {
for ( auto& in : tx.vin ) { // for ( auto& in : tx.vin ) {
uint64_t stack_size = unpack_compact_size( s ); // uint64_t stack_size = unpack_compact_size( s );
in.scriptWitness.reserve( stack_size ); // in.scriptWitness.reserve( stack_size );
for ( uint64_t i = 0; i < stack_size; i++ ) { // for ( uint64_t i = 0; i < stack_size; i++ ) {
std::vector<char> script; // std::vector<char> script;
unpack( s, script ); // unpack( s, script );
in.scriptWitness.push_back( script ); // in.scriptWitness.push_back( script );
} // }
} // }
} // }
//
unpack( s, tx.nLockTime ); // unpack( s, tx.nLockTime );
} //}
//
inline std::vector<char> pack( const bitcoin_transaction& v, bool with_witness = true ) //inline std::vector<char> pack( const bitcoin_transaction& v, bool with_witness = true )
{ //{
fc::datastream<size_t> ps; // fc::datastream<size_t> ps;
pack( ps, v, with_witness ); // pack( ps, v, with_witness );
std::vector<char> vec( ps.tellp() ); // std::vector<char> vec( ps.tellp() );
//
if( !vec.empty() ) { // if( !vec.empty() ) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); // fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) );
pack( ds, v, with_witness ); // pack( ds, v, with_witness );
} // }
return vec; // return vec;
} //}
//
inline bitcoin_transaction unpack( const std::vector<char>& s ) //inline bitcoin_transaction unpack( const std::vector<char>& s )
{ try { //{ try {
bitcoin_transaction tmp; // bitcoin_transaction tmp;
if( !s.empty() ) { // if( !s.empty() ) {
fc::datastream<const char*> ds( s.data(), size_t( s.size() ) ); // fc::datastream<const char*> ds( s.data(), size_t( s.size() ) );
unpack(ds, tmp); // unpack(ds, tmp);
} // }
return tmp; // return tmp;
} FC_RETHROW_EXCEPTIONS( warn, "error unpacking ${type}", ("type","transaction" ) ) } //} FC_RETHROW_EXCEPTIONS( warn, "error unpacking ${type}", ("type","transaction" ) ) }
//
template<typename Stream> //template<typename Stream>
inline void pack_tx_signature( Stream& s, const std::vector<char>& scriptPubKey, const bitcoin_transaction& tx, unsigned int in_index, int hash_type ) //inline void pack_tx_signature( Stream& s, const std::vector<char>& scriptPubKey, const bitcoin_transaction& tx, unsigned int in_index, int hash_type )
{ //{
pack( s, tx.nVersion ); // pack( s, tx.nVersion );
//
pack_compact_size( s, tx.vin.size() ); // pack_compact_size( s, tx.vin.size() );
for ( size_t i = 0; i < tx.vin.size(); i++ ) { // for ( size_t i = 0; i < tx.vin.size(); i++ ) {
const auto& in = tx.vin[i]; // const auto& in = tx.vin[i];
pack( s, in.prevout ); // pack( s, in.prevout );
if ( i == in_index ) // if ( i == in_index )
pack( s, scriptPubKey ); // pack( s, scriptPubKey );
else // else
pack_compact_size( s, 0 ); // Blank signature // pack_compact_size( s, 0 ); // Blank signature
pack( s, in.nSequence ); // pack( s, in.nSequence );
} // }
//
pack_compact_size( s, tx.vout.size() ); // pack_compact_size( s, tx.vout.size() );
for ( const auto& out : tx.vout ) // for ( const auto& out : tx.vout )
pack( s, out ); // pack( s, out );
//
pack( s, tx.nLockTime ); // pack( s, tx.nLockTime );
pack( s, hash_type ); // pack( s, hash_type );
} //}
//
template<typename Stream> //template<typename Stream>
inline void pack_tx_witness_signature( Stream& s, const std::vector<char>& scriptCode, const bitcoin_transaction& tx, unsigned int in_index, int64_t amount, int hash_type ) //inline void pack_tx_witness_signature( Stream& s, const std::vector<char>& scriptCode, const bitcoin_transaction& tx, unsigned int in_index, int64_t amount, int hash_type )
{ //{
//
fc::sha256 hash_prevouts; // fc::sha256 hash_prevouts;
fc::sha256 hash_sequence; // fc::sha256 hash_sequence;
fc::sha256 hash_output; // fc::sha256 hash_output;
//
{ // {
fc::datastream<size_t> ps; // fc::datastream<size_t> ps;
for ( const auto in : tx.vin ) // for ( const auto in : tx.vin )
pack( ps, in.prevout ); // pack( ps, in.prevout );
//
std::vector<char> vec( ps.tellp() ); // std::vector<char> vec( ps.tellp() );
if ( vec.size() ) { // if ( vec.size() ) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); // fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) );
for ( const auto in : tx.vin ) // for ( const auto in : tx.vin )
pack( ds, in.prevout ); // pack( ds, in.prevout );
} // }
//
hash_prevouts = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); // hash_prevouts = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) );
} // }
//
{ // {
fc::datastream<size_t> ps; // fc::datastream<size_t> ps;
for ( const auto in : tx.vin ) // for ( const auto in : tx.vin )
pack( ps, in.nSequence ); // pack( ps, in.nSequence );
//
std::vector<char> vec( ps.tellp() ); // std::vector<char> vec( ps.tellp() );
if ( vec.size() ) { // if ( vec.size() ) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); // fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) );
for ( const auto in : tx.vin ) // for ( const auto in : tx.vin )
pack( ds, in.nSequence ); // pack( ds, in.nSequence );
} // }
//
hash_sequence = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); // hash_sequence = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) );
}; // };
//
{ // {
fc::datastream<size_t> ps; // fc::datastream<size_t> ps;
for ( const auto out : tx.vout ) // for ( const auto out : tx.vout )
pack( ps, out ); // pack( ps, out );
//
std::vector<char> vec( ps.tellp() ); // std::vector<char> vec( ps.tellp() );
if ( vec.size() ) { // if ( vec.size() ) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) ); // fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) );
for ( const auto out : tx.vout ) // for ( const auto out : tx.vout )
pack( ds, out ); // pack( ds, out );
} // }
//
hash_output = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) ); // hash_output = fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) );
} // }
//
pack( s, tx.nVersion ); // pack( s, tx.nVersion );
pack( s, hash_prevouts ); // pack( s, hash_prevouts );
pack( s, hash_sequence ); // pack( s, hash_sequence );
//
pack( s, tx.vin[in_index].prevout ); // pack( s, tx.vin[in_index].prevout );
pack( s, scriptCode ); // pack( s, scriptCode );
pack( s, amount ); // pack( s, amount );
pack( s, tx.vin[in_index].nSequence ); // pack( s, tx.vin[in_index].nSequence );
//
pack( s, hash_output ); // pack( s, hash_output );
pack( s, tx.nLockTime ); // pack( s, tx.nLockTime );
pack( s, hash_type ); // pack( s, hash_type );
} //}
//
} //}