From 40e13800f29f045dd630bf0316de47f809a0d299 Mon Sep 17 00:00:00 2001 From: Alexander Suslikov Date: Wed, 6 Feb 2019 10:07:07 +0300 Subject: [PATCH] Added creation and approving propose with issue --- .../chain/bitcoin_transaction_evaluator.cpp | 1 + libraries/chain/db_block.cpp | 15 ++++-- libraries/chain/db_sidechain.cpp | 49 +++++++++++++++++-- .../chain/include/graphene/chain/database.hpp | 2 + .../graphene/chain/proposal_evaluator.hpp | 2 + .../graphene/chain/protocol/sidechain.hpp | 4 +- libraries/chain/proposal_evaluator.cpp | 20 +++++++- libraries/chain/sidechain_evaluator.cpp | 49 +++++++++++-------- .../bitcoin_transaction_confirmations.hpp | 7 ++- .../sidechain/include/sidechain/types.hpp | 4 +- tests/tests/bitcoin_issue_tests.cpp | 15 +++--- 11 files changed, 126 insertions(+), 42 deletions(-) diff --git a/libraries/chain/bitcoin_transaction_evaluator.cpp b/libraries/chain/bitcoin_transaction_evaluator.cpp index 43d37499..d3c8d9d8 100644 --- a/libraries/chain/bitcoin_transaction_evaluator.cpp +++ b/libraries/chain/bitcoin_transaction_evaluator.cpp @@ -102,6 +102,7 @@ void bitcoin_transaction_send_evaluator::send_bitcoin_transaction( const bitcoin database& d = db(); uint32_t skip = d.get_node_properties().skip_flags; if( !(skip & graphene::chain::database::skip_btc_tx_sending) && d.send_btc_tx_flag ){ + idump((btc_tx)); d.send_btc_tx( btc_tx.transaction ); } } diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index ac71667f..35d5f78a 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -398,7 +398,7 @@ signed_block database::_generate_block( size_t total_block_size = max_block_header_size; if( !is_sidechain_fork_needed() ) { - processing_sidechain_proposals( witness_obj, block_signing_private_key ); + processing_sidechain_proposals( witness_obj, block_signing_private_key ); } signed_block pending_block; @@ -418,10 +418,15 @@ signed_block database::_generate_block( _pending_tx_session = _undo_db.start_undo_session(); if( !is_sidechain_fork_needed() ) { - auto op = create_send_btc_tx_proposal( witness_obj ); - if( op.valid() ) { - _pending_tx.insert( _pending_tx.begin(), create_signed_transaction( block_signing_private_key, *op ) ); - } + auto op = create_send_btc_tx_proposal( witness_obj ); + if( op.valid() ) { + _pending_tx.insert( _pending_tx.begin(), create_signed_transaction( block_signing_private_key, *op ) ); + } + + auto iss_op = create_bitcoin_issue_proposals( witness_obj ); + if( iss_op.valid() ) { + _pending_tx.insert( _pending_tx.begin(), create_signed_transaction( block_signing_private_key, *iss_op ) ); + } } send_btc_tx_flag = false; diff --git a/libraries/chain/db_sidechain.cpp b/libraries/chain/db_sidechain.cpp index 6fbf5286..087f70b1 100644 --- a/libraries/chain/db_sidechain.cpp +++ b/libraries/chain/db_sidechain.cpp @@ -2,8 +2,10 @@ #include #include #include -#include #include +#include + +#include #include using namespace sidechain; @@ -133,7 +135,14 @@ void database::processing_sidechain_proposals( const witness_object& current_wit FC_ASSERT( proposal != proposal_idx.end() ); switch( sidechain_proposal.proposal_type ) { - case sidechain_proposal_type::ISSUE_PBTC :{} + 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 ) ); + 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 ) ); @@ -243,7 +252,8 @@ operation database::create_sign_btc_tx_operation( const witness_object& current_ void database::remove_sidechain_proposal_object( const proposal_object& proposal ) { try { if( proposal.proposed_transaction.operations.size() == 1 && - proposal.proposed_transaction.operations.back().which() == operation::tag::value ) + ( proposal.proposed_transaction.operations.back().which() == operation::tag::value || + proposal.proposed_transaction.operations.back().which() == operation::tag::value ) ) { const auto& sidechain_proposal_idx = get_index_type().indices().get(); auto sidechain_proposal_itr = sidechain_proposal_idx.find( proposal.id ); @@ -283,4 +293,37 @@ void database::roll_back_vin_and_vout( const proposal_object& proposal ) } } +fc::optional database::create_bitcoin_issue_proposals( const witness_object& current_witness ) +{ + std::vector trx_ids; + + bitcoin_confirmations.safe_for([&]( btc_tx_confirmations_index::index::type::iterator itr_b, btc_tx_confirmations_index::index::type::iterator itr_e ){ + for(auto iter = itr_b; iter != itr_e; iter++) { + if( !iter->is_confirmed_and_not_used() ) return; + + const auto& btc_trx_idx = get_index_type().indices().get(); + const auto& btc_tx = btc_trx_idx.find( iter->transaction_id ); + if( btc_tx == btc_trx_idx.end() ) continue; + + trx_ids.push_back( iter->transaction_id ); + } + }); + + if( trx_ids.size() ) { + bitcoin_issue_operation issue_op; + issue_op.payer = get_sidechain_account_id(); + issue_op.transaction_ids = trx_ids; + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = current_witness.witness_account; + proposal_op.proposed_ops.push_back( op_wrapper( issue_op ) ); + uint32_t lifetime = ( get_global_properties().parameters.block_interval * get_global_properties().active_witnesses.size() ) * 3; + proposal_op.expiration_time = time_point_sec( head_block_time().sec_since_epoch() + lifetime ); + + return fc::optional( proposal_op ); + } + + return fc::optional(); +} + } } \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 0c01cc65..17856557 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -544,6 +544,8 @@ namespace graphene { namespace chain { void roll_back_vin_and_vout( const proposal_object& proposal ); + fc::optional create_bitcoin_issue_proposals( const witness_object& current_witness ); + fc::signal send_btc_tx; sidechain::input_withdrawal_info i_w_info; diff --git a/libraries/chain/include/graphene/chain/proposal_evaluator.hpp b/libraries/chain/include/graphene/chain/proposal_evaluator.hpp index b2135ed3..6d08c954 100644 --- a/libraries/chain/include/graphene/chain/proposal_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/proposal_evaluator.hpp @@ -43,6 +43,8 @@ namespace graphene { namespace chain { void operator()( const T &v ) const {} void operator()( const bitcoin_transaction_send_operation &v ); + + void operator()( const bitcoin_issue_operation &v ); }; class proposal_create_evaluator : public evaluator diff --git a/libraries/chain/include/graphene/chain/protocol/sidechain.hpp b/libraries/chain/include/graphene/chain/protocol/sidechain.hpp index 825d0b3f..8475fef8 100644 --- a/libraries/chain/include/graphene/chain/protocol/sidechain.hpp +++ b/libraries/chain/include/graphene/chain/protocol/sidechain.hpp @@ -11,7 +11,7 @@ namespace graphene { namespace chain { asset fee; account_id_type payer; - fc::sha256 transaction_id; + std::vector transaction_ids; account_id_type fee_payer()const { return payer; } @@ -25,4 +25,4 @@ namespace graphene { namespace chain { } } // graphene::chain FC_REFLECT( graphene::chain::bitcoin_issue_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::bitcoin_issue_operation, (fee)(payer)(transaction_id) ) +FC_REFLECT( graphene::chain::bitcoin_issue_operation, (fee)(payer)(transaction_ids) ) diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 60aab5d7..b87ceab6 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -165,6 +165,23 @@ void sidechain_hardfork_visitor::operator()( const bitcoin_transaction_send_oper db.pw_vout_manager.mark_as_used_vout( v.pw_vin.identifier ); } +void sidechain_hardfork_visitor::operator()( const bitcoin_issue_operation &v ) +{ + db.create([&]( sidechain_proposal_object& sch_prop ) { + sch_prop.proposal_type = sidechain::sidechain_proposal_type::ISSUE_BTC; + sch_prop.proposal_id = prop_id; + }); + + for( const auto& trx_id : v.transaction_ids ) { + const auto& trx_confirmations = db.bitcoin_confirmations.find( trx_id ); + if( trx_confirmations.valid() ) { + db.bitcoin_confirmations.modify( trx_id, [&]( sidechain::bitcoin_transaction_confirmations& obj ) { + obj.used = true; + }); + } + } +} + void_result proposal_create_evaluator::do_evaluate(const proposal_create_operation& o) { try { const database& d = db(); @@ -180,7 +197,8 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati FC_ASSERT( !o.review_period_seconds || fc::seconds(*o.review_period_seconds) < (o.expiration_time - d.head_block_time()), "Proposal review period must be less than its overall lifetime." ); - bool pbtc_op = o.proposed_ops[0].op.which() == operation::tag::value; + bool pbtc_op = ( o.proposed_ops[0].op.which() == operation::tag::value ) || + ( o.proposed_ops[0].op.which() == operation::tag::value ); if( d.is_sidechain_fork_needed() && pbtc_op ) { FC_THROW( "Currently the operation is unavailable." ); diff --git a/libraries/chain/sidechain_evaluator.cpp b/libraries/chain/sidechain_evaluator.cpp index e04fb285..3e10c936 100644 --- a/libraries/chain/sidechain_evaluator.cpp +++ b/libraries/chain/sidechain_evaluator.cpp @@ -6,46 +6,47 @@ namespace graphene { namespace chain { void_result bitcoin_issue_evaluator::do_evaluate( const bitcoin_issue_operation& op ) -{ +{ try { database& d = db(); const auto& btc_trx_idx = d.get_index_type().indices().get(); const auto& btc_addr_idx = d.get_index_type().indices().get(); const auto& vins_info_idx = d.get_index_type().indices().get(); const auto& vouts_info_idx = d.get_index_type().indices().get(); - FC_ASSERT( op.payer == db().get_sidechain_account_id() ); - const auto& btc_itr = btc_trx_idx.find( op.transaction_id ); - FC_ASSERT( btc_itr != btc_trx_idx.end() ); + for( const auto& id: op.transaction_ids ) { + const auto& btc_itr = btc_trx_idx.find( id ); + FC_ASSERT( btc_itr != btc_trx_idx.end() ); - for( auto& vin_id : btc_itr->vins ){ - FC_ASSERT( vins_info_idx.find( vin_id ) != vins_info_idx.end() ); - - auto addr_itr = btc_addr_idx.find( vins_info_idx.find( vin_id )->address ); - FC_ASSERT( addr_itr != btc_addr_idx.end() ); + for( auto& vin_id : btc_itr->vins ) { + const auto& itr = vins_info_idx.find( vin_id ); + FC_ASSERT( itr != vins_info_idx.end() ); + auto addr_itr = btc_addr_idx.find( itr->address ); + FC_ASSERT( addr_itr != btc_addr_idx.end() ); + } + for( auto& vout_id : btc_itr->vouts ) + FC_ASSERT( vouts_info_idx.find( vout_id ) != vouts_info_idx.end() ); } - for( auto& vout_id : btc_itr->vouts ) - FC_ASSERT( vouts_info_idx.find( vout_id ) != vouts_info_idx.end() ); - return void_result(); -} +} FC_CAPTURE_AND_RETHROW( (op) ) } void_result bitcoin_issue_evaluator::do_apply( const bitcoin_issue_operation& op ) -{ +{ try { database& d = db(); const auto& btc_trx_idx = d.get_index_type().indices().get(); - const auto& btc_obj = *btc_trx_idx.find( op.transaction_id ); - add_issue( btc_obj ); + for( const auto& id: op.transaction_ids ) { + const auto& btc_obj = *btc_trx_idx.find( id ); + add_issue( btc_obj ); - d.pw_vout_manager.confirm_vout( btc_obj.pw_vin ); - - clear_btc_transaction_information( btc_obj ); + d.pw_vout_manager.confirm_vout( btc_obj.pw_vin ); + clear_btc_transaction_information( btc_obj ); + } return void_result(); -} +} FC_CAPTURE_AND_RETHROW( (op) ) } void bitcoin_issue_evaluator::add_issue( const bitcoin_transaction_object& btc_obj ) { @@ -54,6 +55,12 @@ void bitcoin_issue_evaluator::add_issue( const bitcoin_transaction_object& btc_o const auto& accounts_to_issue = get_accounts_to_issue( btc_obj.vins ); const auto& amounts_to_issue = get_amounts_to_issue( btc_obj.vins ); + uint64_t fee_deduction = btc_obj.fee_for_size / ( btc_obj.vins.size() + btc_obj.vouts.size() ); + + if( btc_obj.fee_for_size % ( btc_obj.vins.size() + btc_obj.vouts.size() ) != 0 ) { + fee_deduction += 1; + } + bool skip_fee_old = trx_state->skip_fee; bool skip_fee_schedule_check_old = trx_state->skip_fee_schedule_check; trx_state->skip_fee = true; @@ -62,7 +69,7 @@ void bitcoin_issue_evaluator::add_issue( const bitcoin_transaction_object& btc_o for( size_t i = 0; i < accounts_to_issue.size(); i++ ){ asset_issue_operation issue_op; issue_op.issuer = d.get_sidechain_account_id(); - issue_op.asset_to_issue = asset( amounts_to_issue[i], d.get_sidechain_asset_id() ); + issue_op.asset_to_issue = asset( amounts_to_issue[i] - fee_deduction, d.get_sidechain_asset_id() ); issue_op.issue_to_account = accounts_to_issue[i]; d.apply_operation( *trx_state, issue_op ); diff --git a/libraries/sidechain/include/sidechain/bitcoin_transaction_confirmations.hpp b/libraries/sidechain/include/sidechain/bitcoin_transaction_confirmations.hpp index 35ef7ec8..fbdac0d6 100644 --- a/libraries/sidechain/include/sidechain/bitcoin_transaction_confirmations.hpp +++ b/libraries/sidechain/include/sidechain/bitcoin_transaction_confirmations.hpp @@ -22,18 +22,23 @@ struct bitcoin_transaction_confirmations bitcoin_transaction_confirmations( fc::sha256 trx_id ) : transaction_id( trx_id ) {} + bool is_confirmed_and_not_used() const { return !used && confirmed; } + fc::sha256 transaction_id; uint64_t count_block = 0; bool confirmed = false; bool missing = false; + bool used = false; }; struct by_hash; +struct by_confirmed_and_not_used; using btc_tx_confirmations_index = boost::multi_index_container, member> + ordered_unique, member>, + ordered_non_unique, const_mem_fun< bitcoin_transaction_confirmations, bool, &bitcoin_transaction_confirmations::is_confirmed_and_not_used >> > >; diff --git a/libraries/sidechain/include/sidechain/types.hpp b/libraries/sidechain/include/sidechain/types.hpp index d3b3312b..0364d049 100644 --- a/libraries/sidechain/include/sidechain/types.hpp +++ b/libraries/sidechain/include/sidechain/types.hpp @@ -30,7 +30,7 @@ enum class payment_type enum class sidechain_proposal_type { - ISSUE_PBTC, + ISSUE_BTC, SEND_BTC_TRANSACTION, RETURN_PBTC_BACK }; @@ -45,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)(RETURN_PBTC_BACK) ); +FC_REFLECT_ENUM( sidechain::sidechain_proposal_type, (ISSUE_BTC)(SEND_BTC_TRANSACTION)(RETURN_PBTC_BACK) ); FC_REFLECT( sidechain::prev_out, (hash_tx)(n_vout)(amount) ); diff --git a/tests/tests/bitcoin_issue_tests.cpp b/tests/tests/bitcoin_issue_tests.cpp index 723068e4..e84e6ab8 100644 --- a/tests/tests/bitcoin_issue_tests.cpp +++ b/tests/tests/bitcoin_issue_tests.cpp @@ -45,6 +45,7 @@ void create_bitcoin_issue_operation_environment( database& db ) obj.vins = vins; obj.vouts = vouts; obj.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + obj.fee_for_size = 0; }); } @@ -66,7 +67,7 @@ BOOST_AUTO_TEST_CASE( check_deleting_all_btc_transaction_information ) bitcoin_issue_operation op; op.payer = db.get_sidechain_account_id(); - op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + op.transaction_ids = { fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) }; db.apply_operation( context, op ); FC_ASSERT( btc_trx_idx.size() == 0 ); @@ -84,7 +85,7 @@ BOOST_AUTO_TEST_CASE( check_adding_issue_to_accounts ) bitcoin_issue_operation op; op.payer = db.get_sidechain_account_id(); - op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + op.transaction_ids = { fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) }; db.apply_operation( context, op ); @@ -115,7 +116,7 @@ BOOST_AUTO_TEST_CASE( check_bitcoin_issue_operation_throw ) bitcoin_issue_operation op; op.payer = db.get_sidechain_account_id(); - op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + op.transaction_ids = { fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) }; GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception ); session.undo(); @@ -128,7 +129,7 @@ BOOST_AUTO_TEST_CASE( check_bitcoin_issue_operation_throw ) bitcoin_issue_operation op; op.payer = db.get_sidechain_account_id(); - op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + op.transaction_ids = { fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) }; GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception ); session.undo(); @@ -141,7 +142,7 @@ BOOST_AUTO_TEST_CASE( check_bitcoin_issue_operation_throw ) bitcoin_issue_operation op; op.payer = db.get_sidechain_account_id(); - op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + op.transaction_ids = { fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) }; GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception ); session.undo(); @@ -154,7 +155,7 @@ BOOST_AUTO_TEST_CASE( check_bitcoin_issue_operation_throw ) bitcoin_issue_operation op; op.payer = db.get_sidechain_account_id(); - op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + op.transaction_ids = { fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) }; GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception ); session.undo(); @@ -165,7 +166,7 @@ BOOST_AUTO_TEST_CASE( check_bitcoin_issue_operation_throw ) bitcoin_issue_operation op; op.payer = account_id_type(1); - op.transaction_id = fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ); + op.transaction_ids = { fc::sha256( "1111111111111111111111111111111111111111111111111111111111111111" ) }; GRAPHENE_REQUIRE_THROW( db.apply_operation( context, op ) , fc::exception ); session.undo();