Signature bitcoin transaction and confirmation proposal

This commit is contained in:
Anzhy Cherrnyavski 2019-01-31 14:50:31 +03:00
parent 38ba47bdd5
commit 810051e7c9
12 changed files with 217 additions and 101 deletions

View file

@ -9,7 +9,8 @@
#include <sidechain/sign_bitcoin_transaction.hpp>
#include <sidechain/input_withdrawal_info.hpp>
#include <graphene/chain/bitcoin_address_object.hpp>
#include <graphene/chain/primary_wallet_vout_object.hpp>
namespace graphene { namespace chain {
@ -25,7 +26,6 @@ object_id_type bitcoin_transaction_send_evaluator::do_apply( const bitcoin_trans
{
bitcoin_transaction_send_operation& mutable_op = const_cast<bitcoin_transaction_send_operation&>( op );
database& d = db();
sidechain::bytes wit_script;
finalize_bitcoin_transaction( mutable_op );
@ -43,6 +43,7 @@ object_id_type bitcoin_transaction_send_evaluator::do_apply( const bitcoin_trans
});
sidechain::prev_out new_pw_vout = { "", 0, 0 };
sidechain::bytes wit_script = d.get_latest_PW().address.get_witness_script();
if( btc_tx.transaction.vout[0].is_p2wsh() && btc_tx.transaction.vout[0].scriptPubKey == wit_script )
new_pw_vout = { btc_tx.transaction.get_txid(), 0, btc_tx.transaction.vout[0].value };
@ -71,19 +72,34 @@ std::vector< info_for_used_vin_id_type > bitcoin_transaction_send_evaluator::cre
if( obj_itr.valid() )
d.i_w_info.remove_info_for_vin( *obj_itr );
}
return new_vins;
}
void bitcoin_transaction_send_evaluator::finalize_bitcoin_transaction( bitcoin_transaction_send_operation& op )
{
database& d = db();
std::vector<std::vector<sidechain::bytes>> new_stacks( sidechain::sort_sigs( op.transaction, op.vins, d.context_verify ) );
auto vins = op.vins;
if( op.pw_vin.str().compare( 0, 24, SIDECHAIN_NULL_VIN_IDENTIFIER ) != 0 ) {
const auto& pw_vout = d.pw_vout_manager.get_vout( op.pw_vin );
info_for_vin vin;
vin.out = pw_vout->vout;
vin.address = d.get_latest_PW().address.get_address();
vin.identifier = pw_vout->hash_id;
vins.insert( vins.begin(), vin );
}
std::vector<bytes> redeem_scripts( d.i_w_info.get_redeem_scripts( vins ) );
std::vector<uint64_t> amounts( d.i_w_info.get_amounts( vins ) );
std::vector<std::vector<sidechain::bytes>> new_stacks( sidechain::sort_sigs( op.transaction, redeem_scripts, amounts, d.context_verify ) );
for( size_t i = 0; i < new_stacks.size(); i++ ) {
op.transaction.vin[i].scriptWitness = new_stacks[i];
}
sidechain::sign_witness_transaction_finalize( op.transaction, op.vins );
sidechain::sign_witness_transaction_finalize( op.transaction, redeem_scripts );
}
void bitcoin_transaction_send_evaluator::send_bitcoin_transaction( const bitcoin_transaction_object& btc_tx )
@ -99,18 +115,16 @@ void_result bitcoin_transaction_sign_evaluator::do_evaluate( const bitcoin_trans
{
database& d = db();
const auto& sidechain_proposal_idx = d.get_index_type<sidechain_proposal_index>().indices().get<by_id>();
const auto& sidechain_proposal_itr = sidechain_proposal_idx.find( op.sidechain_proposal_id );
FC_ASSERT( sidechain_proposal_idx.end() != sidechain_proposal_itr,
"sidechain_proposal not found");
const auto& proposal_idx = d.get_index_type<proposal_index>().indices().get<by_id>();
const auto& proposal_itr = proposal_idx.find( op.proposal_id );
FC_ASSERT( proposal_idx.end() != proposal_itr, "proposal not found");
witness_id_type scheduled_witness = d.get_scheduled_witness( 1 );
const auto& witness_obj = d.get< witness_object >( scheduled_witness );
FC_ASSERT( witness_obj.witness_account == op.payer, "Incorrect witness." );
sidechain::bytes public_key( public_key_data_to_bytes( witness_obj.signing_key.key_data ) );
const auto& proposal = sidechain_proposal_itr->proposal_id( d );
auto btc_send_op = proposal.proposed_transaction.operations[0].get<bitcoin_transaction_send_operation>();
auto btc_send_op = proposal_itr->proposed_transaction.operations[0].get<bitcoin_transaction_send_operation>();
FC_ASSERT( check_sigs( public_key, op.signatures, btc_send_op.vins, btc_send_op.transaction ) ); // Add pw_vin
// const auto& proposal = sidechain_proposal_itr->proposal_id( d );
@ -122,9 +136,7 @@ void_result bitcoin_transaction_sign_evaluator::do_evaluate( const bitcoin_trans
void_result bitcoin_transaction_sign_evaluator::do_apply( const bitcoin_transaction_sign_operation& op )
{
database& d = db();
const auto& sidechain_proposal = op.sidechain_proposal_id( d );
const auto& proposal = sidechain_proposal.proposal_id( d );
const auto& proposal = op.proposal_id( d );
d.modify( proposal, [&]( proposal_object& po ) {
auto bitcoin_transaction_send_op = po.proposed_transaction.operations[0].get<bitcoin_transaction_send_operation>();
@ -145,7 +157,7 @@ void bitcoin_transaction_sign_evaluator::update_proposal( const bitcoin_transact
proposal_update_operation update_op;
update_op.fee_paying_account = op.payer;
update_op.proposal = op.sidechain_proposal_id( d ).proposal_id;
update_op.proposal = op.proposal_id;
update_op.active_approvals_to_add = { op.payer };
bool skip_fee_old = trx_state->skip_fee;
@ -164,9 +176,12 @@ bool bitcoin_transaction_sign_evaluator::check_sigs( const bytes& key_data, cons
const bitcoin_transaction& tx )
{
FC_ASSERT( sigs.size() == info_for_vins.size() && sigs.size() == tx.vin.size() );
const auto& bitcoin_address_idx = db().get_index_type<bitcoin_address_index>().indices().get< by_address >();
for( size_t i = 0; i < tx.vin.size(); i++ ) {
const bytes& script = info_for_vins[i].script;
const auto pbtc_address = bitcoin_address_idx.find( info_for_vins[i].address );
const bytes& script = pbtc_address->address.get_redeem_script();
const auto& sighash_str = get_signature_hash( tx, script, static_cast<int64_t>( info_for_vins[i].out.amount ), i, 1, true ).str();
const bytes& sighash_hex = parse_hex( sighash_str );

View file

@ -394,6 +394,10 @@ signed_block database::_generate_block(
auto maximum_block_size = get_global_properties().parameters.maximum_block_size;
size_t total_block_size = max_block_header_size;
if( !is_sidechain_fork_needed() ) {
processing_sidechain_proposals( witness_obj, block_signing_private_key );
}
signed_block pending_block;
//

View file

@ -4,6 +4,7 @@
#include <graphene/chain/proposal_object.hpp>
#include <sidechain/sidechain_condensing_tx.hpp>
#include <graphene/chain/protocol/asset.hpp>
#include <sidechain/sign_bitcoin_transaction.hpp>
using namespace sidechain;
@ -133,8 +134,11 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
switch( sidechain_proposal.proposal_type ) {
case sidechain_proposal_type::ISSUE_PBTC :{}
case sidechain_proposal_type::SEND_BTC_TRANSACTION :{}
case sidechain_proposal_type::WITHDRAW_PBTC :{}
case sidechain_proposal_type::SEND_BTC_TRANSACTION :{
const auto& sign_operation = create_sign_btc_tx_operation( current_witness, private_key, proposal->id );
_pending_tx.insert( _pending_tx.begin(), create_signed_transaction( private_key, sign_operation ) );
break;
}
case sidechain_proposal_type::RETURN_PBTC_BACK :{}
}
}
@ -142,12 +146,13 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
full_btc_transaction database::create_btc_transaction( const std::vector<info_for_vin>& info_vins,
const std::vector<info_for_vout>& info_vouts,
const fc::optional<info_for_vin>& info_pw_vin )
const info_for_vin& info_pw_vin )
{
sidechain_condensing_tx ctx( info_vins, info_vouts );
if( info_pw_vin->identifier.str().compare( 0, 24, SIDECHAIN_NULL_VIN_IDENTIFIER ) == 0 ) {
ctx.create_pw_vin( *info_pw_vin );
if( info_pw_vin.identifier.str().compare( 0, 24, SIDECHAIN_NULL_VIN_IDENTIFIER ) == 0 ) {
ctx.create_pw_vin( info_pw_vin );
}
const auto& pw_address = get_latest_PW().address;
@ -173,7 +178,7 @@ fc::optional<operation> database::create_send_btc_tx_proposal( const witness_obj
const auto& info_pw_vin = i_w_info.get_info_for_pw_vin();
if( info_pw_vin.valid() && ( info_vins.size() || info_vouts.size() ) ) {
const auto& btc_tx_and_size_fee = create_btc_transaction( info_vins, info_vouts, info_pw_vin );
const auto& btc_tx_and_size_fee = create_btc_transaction( info_vins, info_vouts, *info_pw_vin );
bitcoin_transaction_send_operation btc_send_op;
btc_send_op.payer = get_sidechain_account_id();
@ -209,6 +214,37 @@ signed_transaction database::create_signed_transaction( const private_key& signi
return processed_trx;
}
operation database::create_sign_btc_tx_operation( const witness_object& current_witness, const private_key_type& privkey,
const proposal_id_type& proposal_id )
{
const auto& proposal_idx = get_index_type<proposal_index>().indices().get<by_id>();
const auto& proposal_itr = proposal_idx.find( proposal_id );
bitcoin_transaction_send_operation op = proposal_itr->proposed_transaction.operations.back().get<bitcoin_transaction_send_operation>();
bitcoin_transaction_sign_operation sign_operation;
sign_operation.payer = current_witness.witness_account;
sign_operation.proposal_id = proposal_id;
const auto secret = privkey.get_secret();
bytes key(secret.data(), secret.data() + secret.data_size());
auto vins = op.vins;
if( op.pw_vin.str().compare( 0, 24, SIDECHAIN_NULL_VIN_IDENTIFIER ) != 0 ) {
const auto& pw_vout = pw_vout_manager.get_vout( op.pw_vin );
info_for_vin vin;
vin.out = pw_vout->vout;
vin.address = get_latest_PW().address.get_address();
vin.identifier = pw_vout->hash_id;
vins.insert( vins.begin(), vin );
}
std::vector<bytes> redeem_scripts( i_w_info.get_redeem_scripts( vins ) );
std::vector<uint64_t> amounts( i_w_info.get_amounts( vins ) );
sign_operation.signatures = sign_witness_transaction_part( op.transaction, redeem_scripts, amounts, key, context_sign, 1 );
return sign_operation;
}
void database::remove_sidechain_proposal_object( const proposal_object& proposal )
{ try {
if( proposal.proposed_transaction.operations.size() == 1 &&

View file

@ -51,6 +51,9 @@
#include <secp256k1.h>
using namespace fc::ecc;
using sidechain::bitcoin_transaction;
using sidechain::info_for_vin;
using sidechain::info_for_vout;
namespace graphene { namespace chain {
using graphene::db::abstract_object;
@ -528,10 +531,12 @@ namespace graphene { namespace chain {
void processing_sidechain_proposals( const witness_object& current_witness, const private_key& signing_private_key );
sidechain::full_btc_transaction create_btc_transaction( const std::vector<sidechain::info_for_vin>& info_vins,
const std::vector<sidechain::info_for_vout>& info_vouts,
const fc::optional<sidechain::info_for_vin>& info_pw_vin );
sidechain::full_btc_transaction create_btc_transaction( const std::vector<info_for_vin>& info_vins,
const std::vector<info_for_vout>& info_vouts,
const info_for_vin& info_pw_vin );
fc::optional<operation> create_send_btc_tx_proposal( const witness_object& current_witness );
operation create_sign_btc_tx_operation( const witness_object& current_witness, const private_key_type& privkey,
const proposal_id_type& proposal_id );
signed_transaction create_signed_transaction( const private_key& signing_private_key, const operation& op );
void remove_sidechain_proposal_object( const proposal_object& proposal );
@ -539,7 +544,7 @@ namespace graphene { namespace chain {
void roll_back_vin_and_vout( const proposal_object& proposal );
fc::signal<void( const sidechain::bitcoin_transaction& )> send_btc_tx;
fc::signal<void( const bitcoin_transaction& )> send_btc_tx;
sidechain::input_withdrawal_info i_w_info;

View file

@ -41,7 +41,7 @@ namespace graphene { namespace chain {
asset fee;
account_id_type payer;
sidechain_proposal_id_type sidechain_proposal_id;
proposal_id_type proposal_id;
std::vector<sidechain::bytes> signatures;
account_id_type fee_payer()const { return payer; }
@ -55,4 +55,4 @@ FC_REFLECT( graphene::chain::bitcoin_transaction_send_operation::fee_parameters_
FC_REFLECT( graphene::chain::bitcoin_transaction_send_operation, (fee)(payer)(vins)(vouts)(transaction)(fee_for_size) )
FC_REFLECT( graphene::chain::bitcoin_transaction_sign_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::bitcoin_transaction_sign_operation, (fee)(payer)(sidechain_proposal_id)(signatures) )
FC_REFLECT( graphene::chain::bitcoin_transaction_sign_operation, (fee)(payer)(proposal_id)(signatures) )

View file

@ -61,8 +61,15 @@ class input_withdrawal_info
public:
input_withdrawal_info( graphene::chain::database& _db ) : db( _db ) {}
std::vector<sidechain::bytes> get_redeem_scripts( const std::vector<info_for_vin>& info_vins );
std::vector<uint64_t> get_amounts( const std::vector<info_for_vin>& info_vins );
fc::optional<info_for_vin> get_info_for_pw_vin();
void insert_info_for_vin( const prev_out& out, const std::string& address, bytes script = bytes() );
void modify_info_for_vin( const info_for_vin& obj, const std::function<void( info_for_vin& e )>& func );

View file

@ -13,14 +13,15 @@ fc::sha256 get_signature_hash( const bitcoin_transaction& tx, const bytes& scrip
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 );
std::vector<bytes> sign_witness_transaction_part( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts,
const std::vector<uint64_t>& amounts, 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<info_for_vin>& info_vins );
void sign_witness_transaction_finalize( bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts );
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 );
std::vector<std::vector<bytes>> sort_sigs( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts,
const std::vector<uint64_t>& amounts, const secp256k1_context_t* context );
}

View file

@ -32,7 +32,6 @@ enum class sidechain_proposal_type
{
ISSUE_PBTC,
SEND_BTC_TRANSACTION,
WITHDRAW_PBTC,
RETURN_PBTC_BACK
};
@ -46,5 +45,5 @@ struct prev_out
}
FC_REFLECT_ENUM( sidechain::payment_type, (NULLDATA)(P2PK)(P2PKH)(P2SH)(P2WPKH)(P2WSH)(P2SH_WPKH)(P2SH_WSH) );
FC_REFLECT_ENUM( sidechain::sidechain_proposal_type, (ISSUE_PBTC)(SEND_BTC_TRANSACTION)(WITHDRAW_PBTC)(RETURN_PBTC_BACK) );
FC_REFLECT_ENUM( sidechain::sidechain_proposal_type, (ISSUE_PBTC)(SEND_BTC_TRANSACTION)(RETURN_PBTC_BACK) );
FC_REFLECT( sidechain::prev_out, (hash_tx)(n_vout)(amount) );

View file

@ -15,6 +15,26 @@ bool info_for_vin::comparer::operator() ( const info_for_vin& lhs, const info_fo
return lhs.id < rhs.id;
}
std::vector<bytes> input_withdrawal_info::get_redeem_scripts( const std::vector<info_for_vin>& info_vins )
{
std::vector<bytes> redeem_scripts;
const auto& bitcoin_address_idx = db.get_index_type<bitcoin_address_index>().indices().get< by_address >();
for( const auto& v : info_vins ) {
const auto& pbtc_address = bitcoin_address_idx.find( v.address );
redeem_scripts.push_back( pbtc_address->address.get_redeem_script() );
}
return redeem_scripts;
}
std::vector<uint64_t> input_withdrawal_info::get_amounts( const std::vector<info_for_vin>& info_vins )
{
std::vector<uint64_t> amounts;
for( const auto& v : info_vins ) {
amounts.push_back( v.out.amount );
}
return amounts;
}
fc::optional<info_for_vin> input_withdrawal_info::get_info_for_pw_vin()
{
fc::optional< primary_wallet_vout_object > vout = db.pw_vout_manager.get_latest_unused_vout();

View file

@ -113,7 +113,6 @@ void sidechain_net_manager::send_btc_tx( const sidechain::bitcoin_transaction& t
FC_ASSERT( !bitcoin_client->connection_is_not_defined() );
const auto tx_hex = fc::to_hex( pack( trx ) );
idump((tx_hex));
auto reply = bitcoin_client->send_btc_tx( tx_hex );

View file

@ -44,15 +44,16 @@ std::vector<char> privkey_sign( const bytes& privkey, const fc::sha256 &hash, co
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 )
std::vector<bytes> sign_witness_transaction_part( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts,
const std::vector<uint64_t>& amounts, const bytes& privkey,
const secp256k1_context_t* context_sign, int hash_type )
{
FC_ASSERT( tx.vin.size() == info_vins.size() );
FC_ASSERT( tx.vin.size() == redeem_scripts.size() && tx.vin.size() == amounts.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 );
const auto sighash = get_signature_hash( tx, redeem_scripts[i], static_cast<int64_t>( amounts[i] ), i, hash_type, true );
auto sig = privkey_sign( privkey, sighash, context_sign );
sig.push_back( static_cast<uint8_t>( hash_type ) );
@ -61,13 +62,13 @@ std::vector<bytes> sign_witness_transaction_part( const bitcoin_transaction& tx,
return signatures;
}
void sign_witness_transaction_finalize( bitcoin_transaction& tx, const std::vector<info_for_vin>& info_vins )
void sign_witness_transaction_finalize( bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts )
{
FC_ASSERT( tx.vin.size() == info_vins.size() );
FC_ASSERT( tx.vin.size() == redeem_scripts.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( info_vins[i].script );
tx.vin[i].scriptWitness.push_back( redeem_scripts[i] );
}
}
@ -81,8 +82,11 @@ bool verify_sig( const bytes& sig, const bytes& pubkey, const bytes& msg, const
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 )
std::vector<std::vector<bytes>> sort_sigs( const bitcoin_transaction& tx, const std::vector<bytes>& redeem_scripts,
const std::vector<uint64_t>& amounts, const secp256k1_context_t* context )
{
FC_ASSERT( redeem_scripts.size() == amounts.size() );
using data = std::pair<size_t, bytes>;
struct comp {
bool operator() (const data& lhs, const data& rhs) const { return lhs.first < rhs.first; }
@ -90,9 +94,9 @@ std::vector<std::vector<bytes>> sort_sigs( const bitcoin_transaction& tx, const
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();
for( size_t i = 0; i < redeem_scripts.size(); i++ ) {
const std::vector<bytes>& keys = get_pubkey_from_redeemScript( redeem_scripts[i] );
const auto& sighash = get_signature_hash( tx, redeem_scripts[i], static_cast<int64_t>( amounts[i] ), i, 1, true ).str();
bytes sighash_temp( parse_hex( sighash ) );
std::vector<bytes> stack( tx.vin[i].scriptWitness );

File diff suppressed because one or more lines are too long