diff --git a/libraries/chain/db_sidechain.cpp b/libraries/chain/db_sidechain.cpp index aef371a8..52083a6b 100644 --- a/libraries/chain/db_sidechain.cpp +++ b/libraries/chain/db_sidechain.cpp @@ -132,6 +132,15 @@ void database::processing_sidechain_proposals( const witness_object& current_wit 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 ) { 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 ) { case sidechain_proposal_type::ISSUE_BTC :{ - proposal_update_operation puo; - 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 ) ); + approve_propose( proposal->id ); break; } case sidechain_proposal_type::SEND_BTC_TRANSACTION :{ @@ -159,7 +164,12 @@ void database::processing_sidechain_proposals( const witness_object& current_wit } 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(); + if( checker.check_bitcoin_transaction_revert_operation( op ) ) + approve_propose( proposal->id ); + break; + } } } } diff --git a/libraries/chain/include/graphene/chain/protocol/bitcoin_transaction.hpp b/libraries/chain/include/graphene/chain/protocol/bitcoin_transaction.hpp index 654b2fcb..a9852c7f 100644 --- a/libraries/chain/include/graphene/chain/protocol/bitcoin_transaction.hpp +++ b/libraries/chain/include/graphene/chain/protocol/bitcoin_transaction.hpp @@ -55,6 +55,14 @@ namespace graphene { namespace chain { fc::sha256 transaction_id; 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 diff --git a/libraries/sidechain/include/sidechain/sidechain_proposal_checker.hpp b/libraries/sidechain/include/sidechain/sidechain_proposal_checker.hpp index 4fe601a5..fcab2b2a 100644 --- a/libraries/sidechain/include/sidechain/sidechain_proposal_checker.hpp +++ b/libraries/sidechain/include/sidechain/sidechain_proposal_checker.hpp @@ -21,6 +21,8 @@ public: 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: bool check_info_for_pw_vin( const info_for_vin& info_for_vin ); diff --git a/libraries/sidechain/include/sidechain/types.hpp b/libraries/sidechain/include/sidechain/types.hpp index 63317798..bbe3ec4c 100644 --- a/libraries/sidechain/include/sidechain/types.hpp +++ b/libraries/sidechain/include/sidechain/types.hpp @@ -32,7 +32,7 @@ enum class sidechain_proposal_type { ISSUE_BTC, SEND_BTC_TRANSACTION, - RETURN_PBTC_BACK + REVERT_BTC_TRANSACTION }; 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::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) ); diff --git a/libraries/sidechain/sidechain_proposal_checker.cpp b/libraries/sidechain/sidechain_proposal_checker.cpp index d3615138..d70b4093 100644 --- a/libraries/sidechain/sidechain_proposal_checker.cpp +++ b/libraries/sidechain/sidechain_proposal_checker.cpp @@ -57,9 +57,21 @@ bool sidechain_proposal_checker::check_reuse( const operation& op ) std::vector user_vin_identifiers; std::vector user_vout_ids; + auto get_bto_tx_info = [ & ]( fc::sha256 trx_id ) { + const auto& bto_itr_idx = db.get_index_type().indices().get(); + 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::value ) { bitcoin_transaction_send_operation btc_tx_send_op = op.get(); - 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 ) { @@ -67,17 +79,15 @@ bool sidechain_proposal_checker::check_reuse( const operation& op ) } } else if ( op.which() == operation::tag::value ) { bitcoin_issue_operation btc_issue_op = op.get(); - const auto& bto_itr_idx = db.get_index_type().indices().get(); - 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() ) { + if ( !get_bto_tx_info( id ) ) + return false; + } + } else if ( op.which() == operation::tag::value ) { + bitcoin_transaction_revert_operation btc_tx_revert_op = op.get(); + for( auto trx_info: btc_tx_revert_op.transactions_info ) { + if ( !get_bto_tx_info( trx_info.transaction_id ) ) return false; - } - - pw_vin_identifier = bto_itr->pw_vin; - user_vout_ids = bto_itr->vouts; - user_vin_identifiers = bto_itr->vins; } } @@ -159,4 +169,20 @@ bool sidechain_proposal_checker::check_witness_opportunity_to_approve( const wit 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().indices().get(); + + for( auto trx_info: op.transactions_info ) + { + auto value = db.bitcoin_confirmations.find( 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(); +} + } diff --git a/tests/sidechain_tests/sidechain_proposal_checker_tests.cpp b/tests/sidechain_tests/sidechain_proposal_checker_tests.cpp index efc3432e..c8cf1d1f 100644 --- a/tests/sidechain_tests/sidechain_proposal_checker_tests.cpp +++ b/tests/sidechain_tests/sidechain_proposal_checker_tests.cpp @@ -5,6 +5,7 @@ #include #include #include +#include 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() ) ); } +void create_missing_bto( graphene::chain::database& db, uint32_t amount ) +{ + BOOST_REQUIRE( amount < 9 ); + while( amount-- > 0 ) { + std::set 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& 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::type::iterator; + std::vector< revert_trx_info > transactions_info; + const auto& btc_trx_idx = db.get_index_type().indices().get(); + BOOST_CHECK_EQUAL( btc_trx_idx.size() , amount ); + + db.bitcoin_confirmations.safe_for([&]( 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 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& 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()