Added class sidechain_proposal_checker

This commit is contained in:
Anzhy Cherrnyavski 2019-02-07 11:49:10 +03:00
parent 0eda7025c9
commit ec3b7e8b80
20 changed files with 508 additions and 53 deletions

View file

@ -52,24 +52,25 @@ object_id_type bitcoin_transaction_send_evaluator::do_apply( const bitcoin_trans
return btc_tx.id;
}
std::vector< info_for_used_vin_id_type > bitcoin_transaction_send_evaluator::create_transaction_vins( bitcoin_transaction_send_operation& op )
std::vector<fc::sha256> bitcoin_transaction_send_evaluator::create_transaction_vins( bitcoin_transaction_send_operation& op )
{
database& d = db();
std::vector< info_for_used_vin_id_type > new_vins;
std::vector<fc::sha256> new_vins;
for( auto itr : op.vins ){
auto itr_id = d.create< info_for_used_vin_object >( [&]( info_for_used_vin_object& obj )
for( auto itr : op.vins ) {
auto info_for_used_vin_itr = d.create< info_for_used_vin_object >( [&]( info_for_used_vin_object& obj )
{
obj.identifier = itr.identifier;
obj.out = itr.out;
obj.address = itr.address;
obj.script = itr.script;
}).get_id();
new_vins.push_back( itr_id );
});
new_vins.push_back( info_for_used_vin_itr.identifier );
auto obj_itr = d.i_w_info.find_info_for_vin( itr.identifier );
if( obj_itr.valid() )
if( obj_itr.valid() ) {
d.i_w_info.remove_info_for_vin( *obj_itr );
}
}
return new_vins;

View file

@ -7,6 +7,7 @@
#include <sidechain/sidechain_condensing_tx.hpp>
#include <sidechain/sign_bitcoin_transaction.hpp>
#include <sidechain/sidechain_proposal_checker.hpp>
using namespace sidechain;
@ -129,11 +130,17 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
const auto& sidechain_proposal_idx = get_index_type<sidechain_proposal_index>().indices().get< by_id >();
const auto& proposal_idx = get_index_type<proposal_index>().indices().get< by_id >();
sidechain_proposal_checker checker( *this );
for( auto& sidechain_proposal : sidechain_proposal_idx ) {
const auto& proposal = proposal_idx.find( sidechain_proposal.proposal_id );
FC_ASSERT( proposal != proposal_idx.end() );
if( !checker.check_reuse( proposal->proposed_transaction.operations.back() ) ) {
continue;
}
switch( sidechain_proposal.proposal_type ) {
case sidechain_proposal_type::ISSUE_BTC :{
proposal_update_operation puo;
@ -144,8 +151,12 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
break;
}
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 ) );
bitcoin_transaction_send_operation op = proposal->proposed_transaction.operations.back().get<bitcoin_transaction_send_operation>();
if( checker.check_bitcoin_transaction_send_operation( op ) )
{
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 :{}
@ -174,7 +185,7 @@ full_btc_transaction database::create_btc_transaction( const std::vector<info_fo
ctx.create_pw_vout( change, pw_address.get_witness_script() );
}
const uint64_t& size_fee = get_estimated_fee( ctx.get_estimate_tx_size( pw_address.witnesses_keys.size() ), estimated_feerate.load() );
const uint64_t& size_fee = get_estimated_fee( sidechain_condensing_tx::get_estimate_tx_size( ctx.get_transaction(), pw_address.witnesses_keys.size() ), estimated_feerate.load() );
ctx.subtract_fee( size_fee, get_sidechain_params().percent_payment_to_witnesses );
return std::make_pair( ctx.get_transaction(), size_fee );

View file

@ -15,7 +15,7 @@ public:
object_id_type do_apply( const bitcoin_transaction_send_operation& op );
std::vector< info_for_used_vin_id_type > create_transaction_vins( bitcoin_transaction_send_operation& op );
std::vector<fc::sha256> create_transaction_vins( bitcoin_transaction_send_operation& op );
void finalize_bitcoin_transaction( bitcoin_transaction_send_operation& op );

View file

@ -16,7 +16,7 @@ class bitcoin_transaction_object : public abstract_object<bitcoin_transaction_ob
fc::sha256 pw_vin;
std::vector< info_for_used_vin_id_type > vins;
std::vector< fc::sha256 > vins;
std::vector< info_for_vout_id_type > vouts;
sidechain::bitcoin_transaction transaction;

View file

@ -18,9 +18,9 @@ struct bitcoin_issue_evaluator : public evaluator< bitcoin_issue_evaluator >
void clear_btc_transaction_information( const bitcoin_transaction_object& btc_obj );
std::vector<uint64_t> get_amounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id );
std::vector<uint64_t> get_amounts_to_issue( std::vector<fc::sha256> vins_identifier );
std::vector<account_id_type> get_accounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id );
std::vector<account_id_type> get_accounts_to_issue( std::vector<fc::sha256> vins_identifier );
};
} } // graphene::chain

View file

@ -11,7 +11,7 @@ void_result bitcoin_issue_evaluator::do_evaluate( const bitcoin_issue_operation&
const auto& btc_trx_idx = d.get_index_type<bitcoin_transaction_index>().indices().get<by_transaction_id>();
const auto& btc_addr_idx = d.get_index_type<bitcoin_address_index>().indices().get<by_address>();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
const auto& vouts_info_idx = d.get_index_type<info_for_vout_index>().indices().get<by_id>();
FC_ASSERT( op.payer == db().get_sidechain_account_id() );
@ -82,7 +82,7 @@ void bitcoin_issue_evaluator::add_issue( const bitcoin_transaction_object& btc_o
void bitcoin_issue_evaluator::clear_btc_transaction_information( const bitcoin_transaction_object& btc_obj )
{
database& d = db();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
const auto& vouts_info_idx = d.get_index_type<info_for_vout_index>().indices().get<by_id>();
for( auto& vin_id : btc_obj.vins ) {
@ -103,31 +103,31 @@ void bitcoin_issue_evaluator::clear_btc_transaction_information( const bitcoin_t
d.remove( btc_obj );
}
std::vector<uint64_t> bitcoin_issue_evaluator::get_amounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id )
std::vector<uint64_t> bitcoin_issue_evaluator::get_amounts_to_issue( std::vector<fc::sha256> vins_identifier )
{
database& d = db();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
std::vector<uint64_t> result;
for( auto& id : vins_id ) {
auto vin_itr = vins_info_idx.find( id );
for( auto& identifier : vins_identifier ) {
auto vin_itr = vins_info_idx.find( identifier );
result.push_back( vin_itr->out.amount );
}
return result;
}
std::vector<account_id_type> bitcoin_issue_evaluator::get_accounts_to_issue( std::vector<info_for_used_vin_id_type> vins_id )
std::vector<account_id_type> bitcoin_issue_evaluator::get_accounts_to_issue( std::vector<fc::sha256> vins_identifier )
{
database& d = db();
const auto& btc_addr_idx = d.get_index_type<bitcoin_address_index>().indices().get<by_address>();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_id>();
const auto& vins_info_idx = d.get_index_type<info_for_used_vin_index>().indices().get<by_identifier>();
std::vector<account_id_type> result;
for( auto& id : vins_id ) {
auto vin_itr = vins_info_idx.find( id );
for( auto& identifier : vins_identifier ) {
auto vin_itr = vins_info_idx.find( identifier );
auto addr_itr = btc_addr_idx.find( vin_itr->address );
result.push_back( addr_itr->owner );

View file

@ -2,9 +2,31 @@
#include <sstream>
#include <fc/crypto/base58.hpp>
#include <sidechain/segwit_addr.hpp>
#include <sidechain/bitcoin_script.hpp>
namespace sidechain {
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() ) {
@ -22,7 +44,7 @@ payment_type bitcoin_address::determine_type()
}
}
bytes bitcoin_address::determine_raw_address( const payment_type& type )
bytes bitcoin_address::determine_raw_address()
{
bytes result;
switch( type ) {
@ -192,6 +214,14 @@ bool btc_multisig_segwit_address::operator==( const btc_multisig_segwit_address&
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() );

View file

@ -5,6 +5,37 @@
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<char>(0x00) && scriptPubKey[1] == static_cast<char>(0x20) ) {
@ -61,6 +92,18 @@ bytes tx_out::get_data_or_script() const
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) ;

View file

@ -17,7 +17,7 @@ public:
bitcoin_address() = default;
bitcoin_address( const std::string& addr ) : address( addr ), type( determine_type() ),
raw_address( determine_raw_address( type ) ) {}
raw_address( determine_raw_address() ) {}
payment_type get_type() const { return type; }
@ -25,13 +25,15 @@ public:
bytes get_raw_address() const { return raw_address; }
bytes get_script() const;
private:
enum size_segwit_address { P2WSH = 32, P2WPKH = 20 };
payment_type determine_type();
bytes determine_raw_address( const payment_type& type );
bytes determine_raw_address();
bool check_segwit_address( const size_segwit_address& size ) const;
@ -103,6 +105,8 @@ public:
bytes get_witness_script() const { return witness_script; }
std::vector<public_key_type> get_keys();
private:
void create_witness_script();

View file

@ -8,9 +8,13 @@ struct out_point {
uint32_t n = 0;
out_point() = default;
out_point( fc::sha256 _hash, uint32_t _n ) : hash( _hash ), n( _n ) {}
bool operator==( const out_point& op ) const;
};
struct tx_in {
bool operator==( const tx_in& ti ) const;
out_point prevout;
bytes scriptSig;
uint32_t nSequence = 0xffffffff;
@ -21,6 +25,8 @@ struct tx_out {
int64_t value = 0;
bytes scriptPubKey;
bool operator==( const tx_out& to ) const;
bool is_p2wsh() const;
bool is_p2wpkh() const;
@ -35,14 +41,17 @@ struct tx_out {
};
struct bitcoin_transaction {
int32_t nVersion = 1;
std::vector<tx_in> vin;
std::vector<tx_out> vout;
uint32_t nLockTime = 0;
fc::sha256 get_hash() const;
fc::sha256 get_txid() const;
size_t get_vsize() const;
bool operator!=( const bitcoin_transaction& bt ) const;
int32_t nVersion = 1;
std::vector<tx_in> vin;
std::vector<tx_out> vout;
uint32_t nLockTime = 0;
fc::sha256 get_hash() const;
fc::sha256 get_txid() const;
size_t get_vsize() const;
};
class bitcoin_transaction_builder

View file

@ -22,10 +22,9 @@ struct info_for_vin
{
info_for_vin() = default;
info_for_vin( const prev_out& _out, const std::string& _address, bytes _script = bytes() ) :
id( count_id_info_for_vin++ ), out( _out ), address( _address ), script( _script ) {
identifier = fc::sha256::hash( out.hash_tx + std::to_string( out.n_vout ) );
}
info_for_vin( const prev_out& _out, const std::string& _address, bytes _script = bytes() );
bool operator!=( const info_for_vin& obj ) const;
struct comparer {
bool operator() ( const info_for_vin& lhs, const info_for_vin& rhs ) const;

View file

@ -19,7 +19,7 @@ public:
void create_vouts_for_witness_fee( const accounts_keys& witness_active_keys, bool front = true );
uint64_t get_estimate_tx_size( size_t number_witness ) const;
static uint64_t get_estimate_tx_size( bitcoin_transaction tx, size_t number_witness );
void subtract_fee( const uint64_t& fee, const uint16_t& witnesses_percentage );

View file

@ -0,0 +1,45 @@
#pragma once
#include <sidechain/types.hpp>
#include <sidechain/input_withdrawal_info.hpp>
#include <graphene/chain/protocol/bitcoin_transaction.hpp>
#include <graphene/chain/protocol/operations.hpp>
namespace graphene { namespace chain { class database; } };
namespace sidechain {
class sidechain_proposal_checker
{
public:
sidechain_proposal_checker( graphene::chain::database& _db ) : db(_db) {}
bool check_bitcoin_transaction_send_operation( const bitcoin_transaction_send_operation& op );
bool check_reuse( const graphene::chain::operation& op );
private:
bool check_info_for_pw_vin( const info_for_vin& info_for_vin );
bool check_info_for_vins( const std::vector<info_for_vin>& info_for_vins );
bool check_info_for_vouts( const std::vector<info_for_vout_id_type>& info_for_vout_ids );
bool check_transaction( const bitcoin_transaction_send_operation& btc_trx_op );
bool check_reuse_pw_vin( const fc::sha256& pw_vin );
bool check_reuse_user_vins( const std::vector<fc::sha256>& user_vin_identifiers );
bool check_reuse_vouts( const std::vector<info_for_vout_id_type>& user_vout_ids );
std::set<fc::sha256> pw_vin_ident;
std::set<fc::sha256> user_vin_ident;
std::set<info_for_vout_id_type> vout_ids;
graphene::chain::database& db;
};
}

View file

@ -37,6 +37,17 @@ enum class sidechain_proposal_type
struct prev_out
{
bool operator!=( const prev_out& obj ) const
{
if( this->hash_tx != obj.hash_tx ||
this->n_vout != obj.n_vout ||
this->amount != obj.amount )
{
return true;
}
return false;
}
std::string hash_tx;
uint32_t n_vout;
uint64_t amount;

View file

@ -9,6 +9,26 @@ namespace sidechain {
uint64_t info_for_vin::count_id_info_for_vin = 0;
uint64_t bitcoin_transaction_confirmations::count_id_tx_conf = 0;
info_for_vin::info_for_vin( const prev_out& _out, const std::string& _address, bytes _script ) :
id( count_id_info_for_vin++ ), out( _out ), address( _address ), script( _script )
{
identifier = fc::sha256::hash( out.hash_tx + std::to_string( out.n_vout ) );
}
bool info_for_vin::operator!=( const info_for_vin& obj ) const
{
if( this->identifier != obj.identifier ||
this->out.hash_tx != obj.out.hash_tx ||
this->out.n_vout != obj.out.n_vout ||
this->out.amount != obj.out.amount ||
this->address != obj.address ||
this->script != obj.script )
{
return true;
}
return false;
}
bool info_for_vin::comparer::operator() ( const info_for_vin& lhs, const info_for_vin& rhs ) const
{
if( lhs.used != rhs.used ) {
@ -92,8 +112,6 @@ fc::optional<info_for_vin> input_withdrawal_info::find_info_for_vin( fc::sha256
std::vector<info_for_vin> input_withdrawal_info::get_info_for_vins()
{
std::vector<info_for_vin> result;
const auto& addr_idx = db.get_index_type<bitcoin_address_index>().indices().get<by_address>();
const auto max_vins = db.get_sidechain_params().maximum_condensing_tx_vins;
info_for_vins.safe_for<by_id_and_not_used>( [&]( info_for_vin_index::index<by_id_and_not_used>::type::iterator itr_b,
@ -106,9 +124,7 @@ std::vector<info_for_vin> input_withdrawal_info::get_info_for_vins()
vin.out.n_vout = itr_b->out.n_vout;
vin.out.amount = itr_b->out.amount;
vin.address = itr_b->address;
const auto& address_itr = addr_idx.find( itr_b->address );
FC_ASSERT( address_itr != addr_idx.end() );
vin.script = address_itr->address.get_witness_script();
vin.script = itr_b->script;
result.push_back( vin );
++itr_b;

View file

@ -49,8 +49,11 @@ void sidechain_net_manager::update_tx_infos( const std::string& block_hash )
std::string block = bitcoin_client->receive_full_block( block_hash );
if( block != "" ) {
const auto& vins = extract_info_from_block( block );
const auto& addr_idx = db->get_index_type<bitcoin_address_index>().indices().get<by_address>();
for( const auto& v : vins ) {
db->i_w_info.insert_info_for_vin( prev_out{ v.out.hash_tx, v.out.n_vout, v.out.amount }, v.address );
const auto& addr_itr = addr_idx.find( v.address );
FC_ASSERT( addr_itr != addr_idx.end() );
db->i_w_info.insert_info_for_vin( prev_out{ v.out.hash_tx, v.out.n_vout, v.out.amount }, v.address, addr_itr->address.get_witness_script() );
}
}
}

View file

@ -50,7 +50,7 @@ void sidechain_condensing_tx::create_vouts_for_witness_fee( const accounts_keys&
}
}
uint64_t sidechain_condensing_tx::get_estimate_tx_size( size_t number_witness ) const
uint64_t sidechain_condensing_tx::get_estimate_tx_size( bitcoin_transaction tx, size_t number_witness )
{
bytes temp_sig(72, 0x00);
bytes temp_key(34, 0x00);
@ -60,12 +60,11 @@ uint64_t sidechain_condensing_tx::get_estimate_tx_size( size_t number_witness )
}
std::vector<bytes> temp_scriptWitness = { {},{temp_sig},{temp_sig},{temp_sig},{temp_sig},{temp_sig},{temp_script} };
bitcoin_transaction temp_tx = get_transaction();
for( auto& vin : temp_tx.vin ) {
for( auto& vin : tx.vin ) {
vin.scriptWitness = temp_scriptWitness;
}
return temp_tx.get_vsize();
return tx.get_vsize();
}
void sidechain_condensing_tx::subtract_fee( const uint64_t& fee, const uint16_t& witnesses_percentage )

View file

@ -0,0 +1,144 @@
#include <sidechain/sidechain_proposal_checker.hpp>
#include <sidechain/sidechain_condensing_tx.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/primary_wallet_vout_object.hpp>
#include <graphene/chain/bitcoin_address_object.hpp>
#include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/bitcoin_transaction_object.hpp>
#include <graphene/chain/info_for_used_vin_object.hpp>
namespace sidechain {
bool sidechain_proposal_checker::check_bitcoin_transaction_send_operation( const bitcoin_transaction_send_operation& op )
{
bool info_for_pw_vin = check_info_for_pw_vin( op.pw_vin );
bool info_for_vins = check_info_for_vins( op.vins );
bool info_for_vouts = check_info_for_vouts( op.vouts );
bool transaction = check_transaction( op );
return info_for_pw_vin && info_for_vins && info_for_vouts && transaction;
}
bool sidechain_proposal_checker::check_reuse_pw_vin( const fc::sha256& pw_vin )
{
const auto& pw_vin_status = pw_vin_ident.insert( pw_vin );
if( !pw_vin_status.second ) {
return false;
}
return true;
}
bool sidechain_proposal_checker::check_reuse_user_vins( const std::vector<fc::sha256>& user_vin_identifiers )
{
for( const auto& vin : user_vin_identifiers ) {
const auto& user_vin_status = user_vin_ident.insert( vin );
if( !user_vin_status.second ) {
return false;
}
}
return true;
}
bool sidechain_proposal_checker::check_reuse_vouts( const std::vector<info_for_vout_id_type>& user_vout_ids )
{
for( const auto& vout : user_vout_ids ) {
const auto& user_vout_status = vout_ids.insert( vout );
if( !user_vout_status.second ) {
return false;
}
}
return true;
}
bool sidechain_proposal_checker::check_reuse( const operation& op )
{
fc::sha256 pw_vin_identifier;
std::vector<fc::sha256> user_vin_identifiers;
std::vector<info_for_vout_id_type> user_vout_ids;
if( op.which() == operation::tag<bitcoin_transaction_send_operation>::value ) {
bitcoin_transaction_send_operation btc_tx_send_op = op.get<bitcoin_transaction_send_operation>();
pw_vin_identifier = btc_tx_send_op.pw_vin.identifier;
user_vout_ids = btc_tx_send_op.vouts;
for( const auto& vin : btc_tx_send_op.vins ) {
user_vin_identifiers.push_back( vin.identifier );
}
} else if ( op.which() == operation::tag<bitcoin_issue_operation>::value ) {
bitcoin_issue_operation btc_issue_op = op.get<bitcoin_issue_operation>();
const auto& bto_itr_idx = db.get_index_type<bitcoin_transaction_index>().indices().get<graphene::chain::by_transaction_id>();
for( const auto& id : btc_issue_op.transaction_ids ) {
const auto& bto_itr = bto_itr_idx.find( id );
if( bto_itr == bto_itr_idx.end() ) {
return false;
}
pw_vin_identifier = bto_itr->pw_vin;
user_vout_ids = bto_itr->vouts;
user_vin_identifiers = bto_itr->vins;
}
}
return check_reuse_pw_vin( pw_vin_identifier ) &&
check_reuse_user_vins( user_vin_identifiers ) &&
check_reuse_vouts( user_vout_ids );
}
bool sidechain_proposal_checker::check_info_for_pw_vin( const info_for_vin& info_for_vin )
{
const auto& prevout = db.pw_vout_manager.get_vout( info_for_vin.identifier );
const auto& pw_address = db.get_latest_PW().address;
if( !prevout.valid() || info_for_vin.out != prevout->vout ||
info_for_vin.address != pw_address.get_address() || info_for_vin.script != pw_address.get_witness_script() ) {
return false;
}
return true;
}
bool sidechain_proposal_checker::check_info_for_vins( const std::vector<info_for_vin>& info_for_vins )
{
for( const auto& vin : info_for_vins ) {
const auto& v = db.i_w_info.find_info_for_vin( vin.identifier );
if( !v.valid() || *v != vin ) {
return false;
}
}
return true;
}
bool sidechain_proposal_checker::check_info_for_vouts( const std::vector<info_for_vout_id_type>& info_for_vout_ids )
{
const auto& info_for_vout_idx = db.get_index_type<info_for_vout_index>().indices().get<graphene::chain::by_id>();
for( const auto& id : info_for_vout_ids ) {
const auto& itr = info_for_vout_idx.find( id );
if( itr == info_for_vout_idx.end() ) {
return false;
}
}
return true;
}
bool sidechain_proposal_checker::check_transaction( const bitcoin_transaction_send_operation& btc_trx_op )
{
std::vector<info_for_vout> info_vouts;
const auto& info_for_vout_idx = db.get_index_type<info_for_vout_index>().indices().get<graphene::chain::by_id>();
for( const auto& vout_id : btc_trx_op.vouts ) {
const auto& vout_itr = info_for_vout_idx.find( vout_id );
if( vout_itr == info_for_vout_idx.end() ) {
return false;
}
info_vouts.push_back( *vout_itr );
}
const auto& temp_full_tx = db.create_btc_transaction( btc_trx_op.vins, info_vouts, btc_trx_op.pw_vin );
if( temp_full_tx.first != btc_trx_op.transaction || temp_full_tx.second != btc_trx_op.fee_for_size ) {
return false;
}
return true;
}
}

View file

@ -15,7 +15,7 @@ BOOST_FIXTURE_TEST_SUITE( bitcoin_issue_tests, database_fixture )
void create_bitcoin_issue_operation_environment( database& db )
{
std::vector< info_for_used_vin_id_type > vins;
std::vector< fc::sha256 > vins;
std::vector< info_for_vout_id_type > vouts;
for( auto i = 0; i < 3; i++ ){
@ -25,10 +25,10 @@ void create_bitcoin_issue_operation_environment( database& db )
});
auto vin_id = db.create<info_for_used_vin_object>([&]( info_for_used_vin_object& obj ) {
obj.identifier = fc::sha256( std::to_string( i ) );
obj.identifier = fc::sha256( std::string( 64, std::to_string( i )[0] ) );
obj.out.amount = 100000 + i * 100000;
obj.address = std::to_string( i );
}).get_id();
});
auto vout_id = db.create<info_for_vout_object>([&]( info_for_vout_object& obj ) {
obj.payer = account_id_type( i );
@ -36,7 +36,7 @@ void create_bitcoin_issue_operation_environment( database& db )
obj.address = std::to_string( i );
}).get_id();
vins.push_back( vin_id );
vins.push_back( vin_id.identifier );
vouts.push_back( vout_id );
}

View file

@ -0,0 +1,140 @@
#include <boost/test/unit_test.hpp>
#include "../common/database_fixture.hpp"
#include <sidechain/sidechain_proposal_checker.hpp>
using namespace sidechain;
BOOST_FIXTURE_TEST_SUITE( sidechain_proposal_checker_tests, database_fixture )
class test_environment
{
public:
test_environment( database& db )
{
for( size_t i = 1; i < 6; i++ ) {
prev_out out{ std::string( 64, std::to_string( i )[0] ), static_cast<uint32_t>( i ), static_cast<uint64_t>( i * 10000 ) };
db.i_w_info.insert_info_for_vin( out, std::to_string( i ), { 0x00, 0x01, 0x02 } );
db.i_w_info.insert_info_for_vout( account_id_type( i ), "2Mt57VSFqBe7UpDad9QaYHev21E1VscAZMU", i * 5000 );
}
vins = db.i_w_info.get_info_for_vins();
pw_vin = *db.i_w_info.get_info_for_pw_vin();
vouts = db.i_w_info.get_info_for_vouts();
full_tx = db.create_btc_transaction( vins, vouts, pw_vin );
}
std::vector<info_for_vin> vins;
info_for_vin pw_vin;
std::vector<info_for_vout> vouts;
full_btc_transaction full_tx;
};
BOOST_AUTO_TEST_CASE( check_reuse_normal_test )
{
sidechain_proposal_checker checker( db );
bitcoin_transaction_send_operation op;
op.pw_vin = info_for_vin( { std::string( 64, '1' ), 0, 0 }, "", bytes() );
for( size_t i = 0; i < 5; i++ ) {
op.vins.push_back( info_for_vin( { std::string( 64, std::to_string( i )[0] ), 0, 0 }, "", bytes() ) );
op.vouts.push_back( info_for_vout_id_type( i ) );
}
BOOST_CHECK( checker.check_reuse( op ) );
}
BOOST_AUTO_TEST_CASE( check_reuse_not_normal_test )
{
sidechain_proposal_checker checker( db );
bitcoin_transaction_send_operation op;
op.pw_vin = info_for_vin( { std::string( 64, '1' ), 0, 0 }, "", bytes() );
for( size_t i = 0; i < 5; i++ ) {
op.vins.push_back( info_for_vin( { std::string( 64, std::to_string( i )[0] ), 0, 0 }, "", bytes() ) );
op.vouts.push_back( info_for_vout_id_type( i ) );
}
BOOST_CHECK( checker.check_reuse( op ) );
BOOST_CHECK( !checker.check_reuse( op ) );
}
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_normal_test )
{
sidechain_proposal_checker checker( db );
test_environment env( db );
bitcoin_transaction_send_operation op;
op.pw_vin = env.pw_vin;
op.vins = env.vins;
for( const auto& vout : env.vouts ) {
op.vouts.push_back( vout.get_id() );
}
op.transaction = env.full_tx.first;
op.fee_for_size = env.full_tx.second;
BOOST_CHECK( checker.check_bitcoin_transaction_send_operation( op ) );
}
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_incorrect_info_for_vin_test )
{
sidechain_proposal_checker checker( db );
test_environment env( db );
env.vins[3].out.amount = 13;
bitcoin_transaction_send_operation op;
op.pw_vin = env.pw_vin;
op.vins = env.vins;
for( const auto& vout : env.vouts ) {
op.vouts.push_back( vout.get_id() );
}
op.transaction = env.full_tx.first;
op.fee_for_size = env.full_tx.second;
BOOST_CHECK( !checker.check_bitcoin_transaction_send_operation( op ) );
}
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_incorrect_info_for_pw_vin_test )
{
sidechain_proposal_checker checker( db );
test_environment env( db );
env.pw_vin.out.amount = 13;
bitcoin_transaction_send_operation op;
op.pw_vin = env.pw_vin;
op.vins = env.vins;
for( const auto& vout : env.vouts ) {
op.vouts.push_back( vout.get_id() );
}
op.transaction = env.full_tx.first;
op.fee_for_size = env.full_tx.second;
BOOST_CHECK( !checker.check_bitcoin_transaction_send_operation( op ) );
}
BOOST_AUTO_TEST_CASE( check_btc_tx_send_op_incorrect_tx_test )
{
sidechain_proposal_checker checker( db );
test_environment env( db );
bitcoin_transaction_send_operation op;
op.pw_vin = env.pw_vin;
op.vins = env.vins;
for( const auto& vout : env.vouts ) {
op.vouts.push_back( vout.get_id() );
}
env.full_tx.first.vout[0].value = 13;
op.transaction = env.full_tx.first;
op.fee_for_size = env.full_tx.second;
BOOST_CHECK( !checker.check_bitcoin_transaction_send_operation( op ) );
}
BOOST_AUTO_TEST_SUITE_END()