diff --git a/libraries/chain/db_sidechain.cpp b/libraries/chain/db_sidechain.cpp index c7446b9f..a9878d60 100644 --- a/libraries/chain/db_sidechain.cpp +++ b/libraries/chain/db_sidechain.cpp @@ -154,11 +154,12 @@ void database::processing_sidechain_proposals( const witness_object& current_wit case sidechain_proposal_type::ISSUE_BTC :{ approve_propose( proposal->id ); break; - } + } case sidechain_proposal_type::SEND_BTC_TRANSACTION :{ bitcoin_transaction_send_operation op = proposal->proposed_transaction.operations.back().get(); - if( checker.check_bitcoin_transaction_send_operation( op ) && checker.check_witness_opportunity_to_approve( current_witness, *proposal ) ) - { + if( checker.check_bitcoin_transaction_send_operation( op ) && + checker.check_witnesses_keys( current_witness, *proposal ) && + checker.check_witness_opportunity_to_approve( current_witness, *proposal ) ) { 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 ) ); } diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index c9b5c511..f11a3e08 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -530,7 +530,7 @@ namespace graphene { namespace chain { int64_t get_estimated_fee( size_t tx_vsize, uint64_t estimated_feerate ); 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& info_vins, const std::vector& info_vouts, const info_for_vin& info_pw_vin ); diff --git a/libraries/sidechain/include/sidechain/sidechain_proposal_checker.hpp b/libraries/sidechain/include/sidechain/sidechain_proposal_checker.hpp index fcab2b2a..fce1c425 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_witnesses_keys( const witness_object& current_witness, const proposal_object& proposal ); + bool check_bitcoin_transaction_revert_operation( const bitcoin_transaction_revert_operation& op ); private: diff --git a/libraries/sidechain/sidechain_proposal_checker.cpp b/libraries/sidechain/sidechain_proposal_checker.cpp index d70b4093..214a1808 100644 --- a/libraries/sidechain/sidechain_proposal_checker.cpp +++ b/libraries/sidechain/sidechain_proposal_checker.cpp @@ -169,6 +169,32 @@ 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_witnesses_keys( const witness_object& current_witness, const proposal_object& proposal ) +{ + bitcoin_transaction_send_operation op = proposal.proposed_transaction.operations.back().get(); + + auto vins = op.vins; + if( op.pw_vin.identifier.str().compare( 0, 48, SIDECHAIN_NULL_VIN_IDENTIFIER ) != 0 ) { + vins.insert( vins.begin(), op.pw_vin ); + } + + const auto& bitcoin_address_idx = db.get_index_type().indices().get< by_address >(); + + for ( const auto& info_vins : vins ) { + const auto& address_itr = bitcoin_address_idx.find( info_vins.address ); + if ( address_itr != bitcoin_address_idx.end() ) { + const auto& witness_key = current_witness.signing_key; + const auto& witnesses_keys = address_itr->address.witnesses_keys; + const auto& witnesses_keys_itr = witnesses_keys.find( current_witness.witness_account ); + if ( witnesses_keys_itr == witnesses_keys.end() || witnesses_keys_itr->second != witness_key ) { + return false; + } + } + } + + return true; +} + 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(); diff --git a/tests/sidechain_tests/sidechain_proposal_checker_tests.cpp b/tests/sidechain_tests/sidechain_proposal_checker_tests.cpp index c8cf1d1f..62498327 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 #include using namespace sidechain; @@ -245,6 +246,83 @@ 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_AUTO_TEST_CASE ( check_witness_keys_test_normal ) +{ + sidechain_proposal_checker checker( db ); + + auto witnesses_keys = db.get_latest_PW().address.witnesses_keys; + const auto& bitcoin_address = db.create( [&]( bitcoin_address_object& obj ) { + witnesses_keys.erase( ++witnesses_keys.begin() ); + obj.address = sidechain::btc_multisig_segwit_address( SIDECHAIN_DEFAULT_NUMBER_SIG_MULTISIG, witnesses_keys ); + obj.owner = account_id_type( 13 ); + } ); + + info_for_vin vin; + vin.address = bitcoin_address.address.address; + + bitcoin_transaction_send_operation op; + op.vins = { vin }; + + proposal_object proposal; + proposal.proposed_transaction.operations.push_back( op ); + + const witness_id_type& witness_id = *db.get_global_properties().active_witnesses.begin(); + const witness_object witness = witness_id( db ); + + BOOST_CHECK( checker.check_witnesses_keys( witness, proposal ) ); +} + +BOOST_AUTO_TEST_CASE ( check_witnesses_keys_incorrect_witness_test ) +{ + sidechain_proposal_checker checker( db ); + + auto witnesses_keys = db.get_latest_PW().address.witnesses_keys; + const auto& bitcoin_address = db.create( [&]( bitcoin_address_object& obj ) { + witnesses_keys.erase( ++witnesses_keys.begin() ); + obj.address = sidechain::btc_multisig_segwit_address( SIDECHAIN_DEFAULT_NUMBER_SIG_MULTISIG, witnesses_keys ); + obj.owner = account_id_type( 13 ); + } ); + + info_for_vin vin; + vin.address = bitcoin_address.address.address; + + bitcoin_transaction_send_operation op; + op.vins = { vin }; + + proposal_object proposal; + proposal.proposed_transaction.operations.push_back( op ); + + const witness_object witness; + + BOOST_CHECK( !checker.check_witnesses_keys( witness, proposal ) ); +} + +BOOST_AUTO_TEST_CASE ( check_witnesses_keys_nonexistent_witness_test ) +{ + sidechain_proposal_checker checker( db ); + + auto witnesses_keys = db.get_latest_PW().address.witnesses_keys; + const auto& bitcoin_address = db.create( [&]( bitcoin_address_object& obj ) { + witnesses_keys.erase( ++witnesses_keys.begin() ); + obj.address = sidechain::btc_multisig_segwit_address( SIDECHAIN_DEFAULT_NUMBER_SIG_MULTISIG, witnesses_keys ); + obj.owner = account_id_type( 13 ); + } ); + + info_for_vin vin; + vin.address = bitcoin_address.address.address; + + bitcoin_transaction_send_operation op; + op.vins = { vin }; + + proposal_object proposal; + proposal.proposed_transaction.operations.push_back( op ); + + const witness_id_type& witness_id = *++db.get_global_properties().active_witnesses.begin(); + const witness_object witness = witness_id( db ); + + BOOST_CHECK( !checker.check_witnesses_keys( witness, proposal ) ); +} + void create_missing_bto( graphene::chain::database& db, uint32_t amount ) { BOOST_REQUIRE( amount < 9 );