Added check_bitcoin_transaction_revert_operation

This commit is contained in:
Anton Shkinder 2019-02-11 11:00:33 +03:00 committed by Anzhy Cherrnyavski
parent 7428c10414
commit fa2eff74c2
6 changed files with 152 additions and 18 deletions

View file

@ -132,6 +132,15 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
sidechain_proposal_checker checker( *this ); sidechain_proposal_checker checker( *this );
auto approve_propose = [ & ]( const proposal_id_type& id )
{
proposal_update_operation puo;
puo.fee_paying_account = current_witness.witness_account;
puo.proposal = id;
puo.active_approvals_to_add = { current_witness.witness_account };
_pending_tx.insert( _pending_tx.begin(), create_signed_transaction( private_key, puo ) );
};
for( auto& sidechain_proposal : sidechain_proposal_idx ) { for( auto& sidechain_proposal : sidechain_proposal_idx ) {
const auto& proposal = proposal_idx.find( sidechain_proposal.proposal_id ); const auto& proposal = proposal_idx.find( sidechain_proposal.proposal_id );
@ -143,11 +152,7 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
switch( sidechain_proposal.proposal_type ) { switch( sidechain_proposal.proposal_type ) {
case sidechain_proposal_type::ISSUE_BTC :{ case sidechain_proposal_type::ISSUE_BTC :{
proposal_update_operation puo; approve_propose( proposal->id );
puo.fee_paying_account = current_witness.witness_account;
puo.proposal = proposal->id;
puo.active_approvals_to_add = { current_witness.witness_account };
_pending_tx.insert( _pending_tx.begin(), create_signed_transaction( private_key, puo ) );
break; break;
} }
case sidechain_proposal_type::SEND_BTC_TRANSACTION :{ case sidechain_proposal_type::SEND_BTC_TRANSACTION :{
@ -159,7 +164,12 @@ void database::processing_sidechain_proposals( const witness_object& current_wit
} }
break; break;
} }
case sidechain_proposal_type::RETURN_PBTC_BACK :{} case sidechain_proposal_type::REVERT_BTC_TRANSACTION :{
bitcoin_transaction_revert_operation op = proposal->proposed_transaction.operations.back().get<bitcoin_transaction_revert_operation>();
if( checker.check_bitcoin_transaction_revert_operation( op ) )
approve_propose( proposal->id );
break;
}
} }
} }
} }

View file

@ -55,6 +55,14 @@ namespace graphene { namespace chain {
fc::sha256 transaction_id; fc::sha256 transaction_id;
std::set< fc::sha256 > valid_vins; std::set< fc::sha256 > valid_vins;
bool operator ==( const revert_trx_info& trx_info ){
return this->transaction_id == trx_info.transaction_id && this->valid_vins == trx_info.valid_vins;
}
bool operator !=( const revert_trx_info& trx_info ){
return this->transaction_id != trx_info.transaction_id || this->valid_vins != trx_info.valid_vins;
}
}; };
struct bitcoin_transaction_revert_operation : public base_operation struct bitcoin_transaction_revert_operation : public base_operation

View file

@ -21,6 +21,8 @@ public:
bool check_witness_opportunity_to_approve( const witness_object& current_witness, const proposal_object& proposal ); bool check_witness_opportunity_to_approve( const witness_object& current_witness, const proposal_object& proposal );
bool check_bitcoin_transaction_revert_operation( const bitcoin_transaction_revert_operation& op );
private: private:
bool check_info_for_pw_vin( const info_for_vin& info_for_vin ); bool check_info_for_pw_vin( const info_for_vin& info_for_vin );

View file

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

View file

@ -57,9 +57,21 @@ bool sidechain_proposal_checker::check_reuse( const operation& op )
std::vector<fc::sha256> user_vin_identifiers; std::vector<fc::sha256> user_vin_identifiers;
std::vector<info_for_vout_id_type> user_vout_ids; std::vector<info_for_vout_id_type> user_vout_ids;
auto get_bto_tx_info = [ & ]( fc::sha256 trx_id ) {
const auto& bto_itr_idx = db.get_index_type<bitcoin_transaction_index>().indices().get<graphene::chain::by_transaction_id>();
const auto& bto_itr = bto_itr_idx.find( trx_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 true;
};
if( op.which() == operation::tag<bitcoin_transaction_send_operation>::value ) { if( op.which() == operation::tag<bitcoin_transaction_send_operation>::value ) {
bitcoin_transaction_send_operation btc_tx_send_op = op.get<bitcoin_transaction_send_operation>(); bitcoin_transaction_send_operation btc_tx_send_op = op.get<bitcoin_transaction_send_operation>();
pw_vin_identifier = btc_tx_send_op.pw_vin.identifier; pw_vin_identifier = btc_tx_send_op.pw_vin.identifier;
user_vout_ids = btc_tx_send_op.vouts; user_vout_ids = btc_tx_send_op.vouts;
for( const auto& vin : btc_tx_send_op.vins ) { for( const auto& vin : btc_tx_send_op.vins ) {
@ -67,17 +79,15 @@ bool sidechain_proposal_checker::check_reuse( const operation& op )
} }
} else if ( op.which() == operation::tag<bitcoin_issue_operation>::value ) { } else if ( op.which() == operation::tag<bitcoin_issue_operation>::value ) {
bitcoin_issue_operation btc_issue_op = op.get<bitcoin_issue_operation>(); 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 ) { for( const auto& id : btc_issue_op.transaction_ids ) {
const auto& bto_itr = bto_itr_idx.find( id ); if ( !get_bto_tx_info( id ) )
if( bto_itr == bto_itr_idx.end() ) {
return false; return false;
} }
} else if ( op.which() == operation::tag<bitcoin_transaction_revert_operation>::value ) {
pw_vin_identifier = bto_itr->pw_vin; bitcoin_transaction_revert_operation btc_tx_revert_op = op.get<bitcoin_transaction_revert_operation>();
user_vout_ids = bto_itr->vouts; for( auto trx_info: btc_tx_revert_op.transactions_info ) {
user_vin_identifiers = bto_itr->vins; if ( !get_bto_tx_info( trx_info.transaction_id ) )
return false;
} }
} }
@ -159,4 +169,20 @@ bool sidechain_proposal_checker::check_witness_opportunity_to_approve( const wit
return is_active_witness() && does_the_witness_have_authority(); return is_active_witness() && does_the_witness_have_authority();
} }
bool sidechain_proposal_checker::check_bitcoin_transaction_revert_operation( const bitcoin_transaction_revert_operation& op )
{
const auto& btc_trx_idx = db.get_index_type<bitcoin_transaction_index>().indices().get<by_transaction_id>();
for( auto trx_info: op.transactions_info )
{
auto value = db.bitcoin_confirmations.find<sidechain::by_hash>( trx_info.transaction_id );
if( !value.valid() ||
btc_trx_idx.find( value->transaction_id ) == btc_trx_idx.end() ||
trx_info != revert_trx_info( value->transaction_id, value->valid_vins ) )
return false;
}
return !op.transactions_info.empty();
}
} }

View file

@ -5,6 +5,7 @@
#include <graphene/chain/proposal_object.hpp> #include <graphene/chain/proposal_object.hpp>
#include <graphene/chain/proposal_evaluator.hpp> #include <graphene/chain/proposal_evaluator.hpp>
#include <graphene/chain/witness_object.hpp> #include <graphene/chain/witness_object.hpp>
#include <graphene/chain/bitcoin_transaction_object.hpp>
using namespace sidechain; using namespace sidechain;
@ -244,4 +245,91 @@ BOOST_AUTO_TEST_CASE( not_account_auths_wit_try_to_approve_btc_send_test )
BOOST_CHECK( !checker.check_witness_opportunity_to_approve( *itr, *proposal_idx.begin() ) ); BOOST_CHECK( !checker.check_witness_opportunity_to_approve( *itr, *proposal_idx.begin() ) );
} }
void create_missing_bto( graphene::chain::database& db, uint32_t amount )
{
BOOST_REQUIRE( amount < 9 );
while( amount-- > 0 ) {
std::set<fc::sha256> vins { fc::sha256( std::string( 64,'1' + amount ) ), fc::sha256( std::string( 64,'2' + amount ) ) };
sidechain::bitcoin_transaction_confirmations btc_trx_conf ( fc::sha256( std::string( 64,'1' + amount ) ), vins );
btc_trx_conf.missing = true;
db.bitcoin_confirmations.insert( btc_trx_conf );
db.create<graphene::chain::bitcoin_transaction_object>( [&]( graphene::chain::bitcoin_transaction_object& obj ){
obj.transaction_id = fc::sha256( std::string( 64,'1' + amount ) );
} );
}
}
std::vector< revert_trx_info > get_transactions_info( graphene::chain::database& db, uint32_t amount )
{
using iter_by_missing = btc_tx_confirmations_index::index<by_missing_first>::type::iterator;
std::vector< revert_trx_info > transactions_info;
const auto& btc_trx_idx = db.get_index_type<graphene::chain::bitcoin_transaction_index>().indices().get<graphene::chain::by_transaction_id>();
BOOST_CHECK_EQUAL( btc_trx_idx.size() , amount );
db.bitcoin_confirmations.safe_for<by_missing_first>([&]( iter_by_missing itr_b, iter_by_missing itr_e ){
for(auto iter = itr_b; iter != itr_e; iter++) {
if( !iter->missing ) return;
const auto& btc_tx = btc_trx_idx.find( iter->transaction_id );
if( btc_tx == btc_trx_idx.end() ) continue;
transactions_info.push_back( revert_trx_info( iter->transaction_id, iter->valid_vins ) );
}
});
return transactions_info;
}
BOOST_AUTO_TEST_CASE( bitcoin_transaction_revert_operation_checker_test )
{
using namespace graphene::chain;
const uint32_t amount = 5;
create_missing_bto( db, amount );
sidechain_proposal_checker checker( db );
bitcoin_transaction_revert_operation op;
std::vector< revert_trx_info > transactions_info = get_transactions_info( db, amount );
op.transactions_info = transactions_info;
BOOST_CHECK_EQUAL( transactions_info.size(), amount );
BOOST_CHECK( checker.check_bitcoin_transaction_revert_operation( op ) );
}
BOOST_AUTO_TEST_CASE( bitcoin_transaction_revert_operation_checker_failed_test )
{
using namespace graphene::chain;
const uint32_t amount = 5;
create_missing_bto( db, amount );
std::set<fc::sha256> vins { fc::sha256( std::string( 64,'1' + 6 ) ), fc::sha256( std::string( 64,'1' + 8 ) ) };
fc::sha256 trx_id( std::string( 64,'1' + 8 ) );
sidechain::bitcoin_transaction_confirmations btc_trx_conf ( trx_id, vins );
db.bitcoin_confirmations.insert( btc_trx_conf );
db.create<graphene::chain::bitcoin_transaction_object>( [&]( graphene::chain::bitcoin_transaction_object& obj ){
obj.transaction_id = fc::sha256( std::string( 64,'1' + 7 ) );
} );
sidechain_proposal_checker checker( db );
bitcoin_transaction_revert_operation op;
std::vector< revert_trx_info > transactions_info = get_transactions_info( db, amount + 1 );
op.transactions_info = transactions_info;
op.transactions_info.push_back( revert_trx_info( trx_id, vins) );
BOOST_CHECK_EQUAL( op.transactions_info.size(), amount + 1 );
BOOST_CHECK( !checker.check_bitcoin_transaction_revert_operation( op ) );
}
BOOST_AUTO_TEST_CASE( no_btc_trx_to_revert_test )
{
sidechain_proposal_checker checker( db );
bitcoin_transaction_revert_operation op;
BOOST_CHECK( !checker.check_bitcoin_transaction_revert_operation( op ) );
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()