Added mechanism sign bitcoin transaction.

This commit is contained in:
Anzhy Cherrnyavski 2019-01-21 16:12:35 +03:00
parent 9c7694a5e4
commit 7a6fca9180
9 changed files with 653 additions and 214 deletions

View file

@ -1,6 +1,7 @@
#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>
namespace sidechain { namespace sidechain {

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <sidechain/bitcoin_address.hpp> #include <sidechain/bitcoin_address.hpp>
#include <sidechain/serialize.hpp>
namespace sidechain { namespace sidechain {
@ -84,161 +83,6 @@ private:
}; };
template<typename Stream>
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<typename Stream>
inline void unpack( Stream& s, out_point& op )
{
uint64_t hash_size = op.hash.data_size();
std::unique_ptr<char[]> 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<typename Stream>
inline void pack( Stream& s, const tx_in& in )
{
pack( s, in.prevout );
pack( s, in.scriptSig );
pack( s, in.nSequence );
}
template<typename Stream>
inline void unpack( Stream& s, tx_in& in )
{
unpack( s, in.prevout );
unpack( s, in.scriptSig );
unpack( s, in.nSequence );
}
template<typename Stream>
inline void pack( Stream& s, const tx_out& out )
{
pack( s, out.value );
pack( s, out.scriptPubKey );
}
template<typename Stream>
inline void unpack( Stream& s, tx_out& out )
{
unpack( s, out.value );
unpack( s, out.scriptPubKey );
}
template<typename Stream>
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<typename Stream>
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<char> script;
unpack( s, script );
in.scriptWitness.push_back( script );
}
}
}
unpack( s, tx.nLockTime );
}
inline std::vector<char> pack( const bitcoin_transaction& v, bool with_witness = true ) {
fc::datastream<size_t> ps;
pack( ps, v, with_witness );
std::vector<char> vec( ps.tellp() );
if( !vec.empty() ) {
fc::datastream<char*> ds( vec.data(), size_t(vec.size()) );
pack( ds, v, with_witness );
}
return vec;
}
inline bitcoin_transaction unpack( const std::vector<char>& s )
{ try {
bitcoin_transaction tmp;
if( !s.empty() ) {
fc::datastream<const char*> ds( s.data(), size_t(s.size()) );
unpack(ds, tmp);
}
return tmp;
} FC_RETHROW_EXCEPTIONS( warn, "error unpacking ${type}", ("type","transaction" ) ) }
} }
FC_REFLECT( sidechain::out_point, (hash)(n) ) FC_REFLECT( sidechain::out_point, (hash)(n) )

View file

@ -1,104 +1,360 @@
#pragma once #pragma once
#include <sidechain/types.hpp> #include <sidechain/types.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) { {
fc::raw::pack(s, static_cast<uint8_t>(size)); if ( size < 253 ) {
} else if (size <= std::numeric_limits<unsigned short>::max()) { fc::raw::pack( s, static_cast<uint8_t>( size ) );
fc::raw::pack(s, static_cast<uint8_t>(253)); } else if ( size <= std::numeric_limits<unsigned short>::max() ) {
fc::raw::pack(s, htole16(static_cast<uint16_t>(size))); fc::raw::pack( s, static_cast<uint8_t>( 253 ) );
} else if (size <= std::numeric_limits<unsigned int>::max()) { fc::raw::pack( s, htole16( static_cast<uint16_t>( size ) ) );
fc::raw::pack(s, static_cast<uint8_t>(254)); } else if ( size <= std::numeric_limits<unsigned int>::max() ) {
fc::raw::pack(s, htole32(static_cast<uint32_t>(size))); fc::raw::pack( s, static_cast<uint8_t>( 254 ) );
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()); {
if (!v.empty()) pack_compact_size( s, v.size() );
s.write(v.data(), v.size()); if ( !v.empty() )
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); {
v.resize(size); const auto size = unpack_compact_size( s );
if (size) v.resize( size );
s.read(v.data(), size); if ( 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>
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<typename Stream>
inline void unpack( Stream& s, out_point& op )
{
uint64_t hash_size = op.hash.data_size();
std::unique_ptr<char[]> 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<typename Stream>
inline void pack( Stream& s, const tx_in& in )
{
pack( s, in.prevout );
pack( s, in.scriptSig );
pack( s, in.nSequence );
}
template<typename Stream>
inline void unpack( Stream& s, tx_in& in )
{
unpack( s, in.prevout );
unpack( s, in.scriptSig );
unpack( s, in.nSequence );
}
template<typename Stream>
inline void pack( Stream& s, const tx_out& out )
{
pack( s, out.value );
pack( s, out.scriptPubKey );
}
template<typename Stream>
inline void unpack( Stream& s, tx_out& out )
{
unpack( s, out.value );
unpack( s, out.scriptPubKey );
}
template<typename Stream>
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<typename Stream>
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<char> script;
unpack( s, script );
in.scriptWitness.push_back( script );
}
}
}
unpack( s, tx.nLockTime );
}
inline std::vector<char> pack( const bitcoin_transaction& v, bool with_witness = true )
{
fc::datastream<size_t> ps;
pack( ps, v, with_witness );
std::vector<char> vec( ps.tellp() );
if( !vec.empty() ) {
fc::datastream<char*> ds( vec.data(), size_t( vec.size() ) );
pack( ds, v, with_witness );
}
return vec;
}
inline bitcoin_transaction unpack( const std::vector<char>& s )
{ try {
bitcoin_transaction tmp;
if( !s.empty() ) {
fc::datastream<const char*> ds( s.data(), size_t( s.size() ) );
unpack(ds, tmp);
}
return tmp;
} FC_RETHROW_EXCEPTIONS( warn, "error unpacking ${type}", ("type","transaction" ) ) }
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 )
{
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<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 )
{
fc::sha256 hash_prevouts;
fc::sha256 hash_sequence;
fc::sha256 hash_output;
{
fc::datastream<size_t> ps;
for ( const auto in : tx.vin )
pack( ps, in.prevout );
std::vector<char> vec( ps.tellp() );
if ( vec.size() ) {
fc::datastream<char*> 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<size_t> ps;
for ( const auto in : tx.vin )
pack( ps, in.nSequence );
std::vector<char> vec( ps.tellp() );
if ( vec.size() ) {
fc::datastream<char*> 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<size_t> ps;
for ( const auto out : tx.vout )
pack( ps, out );
std::vector<char> vec( ps.tellp() );
if ( vec.size() ) {
fc::datastream<char*> 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 );
} }
} }

View file

@ -0,0 +1,26 @@
#pragma once
#include <sidechain/types.hpp>
#include <sidechain/input_withdrawal_info.hpp>
#include <secp256k1.h>
namespace sidechain {
class bitcoin_transaction;
fc::sha256 get_signature_hash( const bitcoin_transaction& tx, const bytes& scriptPubKey, int64_t amount,
size_t in_index, int hash_type, bool is_witness );
std::vector<char> privkey_sign( const bytes& privkey, const fc::sha256 &hash, const secp256k1_context_t* context_sign = nullptr );
std::vector< bytes > sign_witness_transaction_part( const bitcoin_transaction& tx, const std::vector<info_for_vin>& info_vins,
const bytes& privkey, const secp256k1_context_t* context_sign = nullptr, int hash_type = 1 );
void sign_witness_transaction_finalize( bitcoin_transaction& tx, const std::vector< bytes >& redeemScripts );
bool verify_sig( const bytes& sig, const bytes& pubkey, const bytes& msg, const secp256k1_context_t* context );
std::vector<std::vector<bytes>> sort_sigs( const bitcoin_transaction& tx, const std::vector<info_for_vin>& info_vins,
const secp256k1_context_t* context );
}

View file

@ -7,4 +7,6 @@ namespace sidechain {
bytes parse_hex( const std::string& str ); bytes parse_hex( const std::string& str );
std::vector<bytes> get_pubkey_from_redeemScript( bytes script );
} }

View file

@ -0,0 +1,121 @@
#include <sidechain/sign_bitcoin_transaction.hpp>
#include <sidechain/serialize.hpp>
namespace sidechain {
fc::sha256 get_signature_hash( const bitcoin_transaction& tx, const bytes& scriptCode, int64_t amount,
size_t in_index, int hash_type, bool is_witness )
{
fc::datastream<size_t> ps;
if ( is_witness )
pack_tx_witness_signature( ps, scriptCode, tx, in_index, amount, hash_type );
else
pack_tx_signature( ps, scriptCode, tx, in_index, hash_type );
std::vector<char> vec( ps.tellp() );
if ( !vec.empty() ) {
fc::datastream<char*> ds( vec.data(), vec.size() );
if ( is_witness )
pack_tx_witness_signature( ds, scriptCode, tx, in_index, amount, hash_type );
else
pack_tx_signature( ds, scriptCode, tx, in_index, hash_type );
}
return fc::sha256::hash( fc::sha256::hash( vec.data(), vec.size() ) );
}
std::vector<char> privkey_sign( const bytes& privkey, const fc::sha256 &hash, const secp256k1_context_t* context_sign )
{
bytes sig;
sig.resize( 72 );
int sig_len = sig.size();
FC_ASSERT( secp256k1_ecdsa_sign(
context_sign,
reinterpret_cast<unsigned char*>( hash.data() ),
reinterpret_cast<unsigned char*>( sig.data() ),
&sig_len,
reinterpret_cast<const unsigned char*>( privkey.data() ),
secp256k1_nonce_function_rfc6979,
nullptr ) ); // TODO: replace assert with exception
sig.resize( sig_len );
return sig;
}
std::vector<bytes> sign_witness_transaction_part( const bitcoin_transaction& tx, const std::vector<info_for_vin>& info_vins,
const bytes& privkey, const secp256k1_context_t* context_sign, int hash_type )
{
FC_ASSERT( tx.vin.size() == info_vins.size() );
FC_ASSERT( !privkey.empty() );
std::vector< bytes > signatures;
for( size_t i = 0; i < tx.vin.size(); i++ ) {
const auto sighash = get_signature_hash( tx, info_vins[i].script, static_cast<int64_t>( info_vins[i].out.amount ), i, hash_type, true );
auto sig = privkey_sign( privkey, sighash, context_sign );
sig.push_back( static_cast<uint8_t>( hash_type ) );
signatures.push_back( sig );
}
return signatures;
}
void sign_witness_transaction_finalize( bitcoin_transaction& tx, const std::vector<bytes>& redeemScripts )
{
FC_ASSERT( tx.vin.size() == redeemScripts.size() );
for( size_t i = 0; i < tx.vin.size(); i++ ) {
tx.vin[i].scriptWitness.insert( tx.vin[i].scriptWitness.begin(), bytes() ); // Bitcoin workaround CHECKMULTISIG bug
tx.vin[i].scriptWitness.push_back( redeemScripts[i] );
}
}
bool verify_sig( const bytes& sig, const bytes& pubkey, const bytes& msg, const secp256k1_context_t* context )
{
std::vector<unsigned char> sig_temp( sig.begin(), sig.end() );
std::vector<unsigned char> pubkey_temp( pubkey.begin(), pubkey.end() );
std::vector<unsigned char> msg_temp( msg.begin(), msg.end() );
int result = secp256k1_ecdsa_verify( context, msg_temp.data(), sig_temp.data(), sig_temp.size(), pubkey_temp.data(), pubkey_temp.size() );
return result == 1;
}
std::vector<std::vector<bytes>> sort_sigs( const bitcoin_transaction& tx, const std::vector<info_for_vin>& info_vins, const secp256k1_context_t* context )
{
using data = std::pair<size_t, bytes>;
struct comp {
bool operator() (const data& lhs, const data& rhs) const { return lhs.first < rhs.first; }
};
std::vector<std::vector<bytes>> new_stacks;
for( size_t i = 0; i < info_vins.size(); i++ ) {
const std::vector<bytes>& keys = get_pubkey_from_redeemScript( info_vins[i].script );
const auto& sighash = get_signature_hash( tx, info_vins[i].script, static_cast<int64_t>( info_vins[i].out.amount ), i, 1, true ).str();
bytes sighash_temp( parse_hex( sighash ) );
std::vector<bytes> stack( tx.vin[i].scriptWitness );
std::vector<bool> marker( tx.vin[i].scriptWitness.size(), false );
std::set<data, comp> sigs;
for( size_t j = 0; j < keys.size(); j++ ) {
for( size_t l = 0; l < stack.size(); l++ ) {
if( !verify_sig( stack[l], keys[j], sighash_temp, context ) || marker[l] )
continue;
sigs.insert(std::make_pair(j, stack[l]));
marker[l] = true;
break;
}
}
std::vector<bytes> temp_sig;
for( auto s : sigs ) {
temp_sig.push_back( s.second );
}
new_stacks.push_back( temp_sig );
}
return new_stacks;
}
}

View file

@ -9,4 +9,19 @@ bytes parse_hex( const std::string& str )
return vec; return vec;
} }
std::vector<bytes> get_pubkey_from_redeemScript( bytes script )
{
FC_ASSERT( script.size() >= 37 );
script.erase( script.begin() );
script.erase( script.end() - 2, script.end() );
std::vector<bytes> result;
uint64_t count = script.size() / 34;
for( size_t i = 0; i < count; i++ ) {
result.push_back( bytes( script.begin() + (34 * i) + 1, script.begin() + (34 * (i + 1)) ) );
}
return result;
}
} }

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <sidechain/utils.hpp> #include <sidechain/utils.hpp>
#include <sidechain/bitcoin_transaction.hpp> #include <sidechain/bitcoin_transaction.hpp>
#include <sidechain/serialize.hpp>
using namespace sidechain; using namespace sidechain;