diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c443fe98..3ec040bc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,8 +29,6 @@ build-mainnet: - build/libraries/ - build/programs/ - build/tests/ - rules: - - if: $CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH == "beatrice" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "beatrice" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" tags: - builder @@ -81,9 +79,7 @@ build-testnet: - build/libraries/ - build/programs/ - build/tests/ - rules: - - if: $CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH == "beatrice" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "beatrice" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" - when: manual + when: manual tags: - builder @@ -155,16 +151,19 @@ test-e2e: - python3 -m venv venv - source venv/bin/activate - pip3 install -r requirements.txt - - python3 main.py --stop + - docker-compose down --remove-orphans - docker ps -a - docker pull $IMAGE - docker tag $IMAGE peerplays-base:latest - docker image ls -a + - docker-compose build - python3 main.py --start all - docker ps -a - python3 -m pytest test_btc_init_state.py test_hive_inital_state.py test_pp_inital_state.py - python3 main.py --stop - deactivate - docker ps -a + after_script: + - docker rmi $(docker images -a | grep -v 'hive-for-peerplays\|ethereum-for-peerplays\|bitcoin-for-peerplays\|ubuntu-for-peerplays' | awk '{print $3}') tags: - python-tests diff --git a/libraries/chain/confidential_evaluator.cpp b/libraries/chain/confidential_evaluator.cpp index fa4ac515..0526c116 100644 --- a/libraries/chain/confidential_evaluator.cpp +++ b/libraries/chain/confidential_evaluator.cpp @@ -33,45 +33,163 @@ namespace graphene { namespace chain { void_result transfer_to_blind_evaluator::do_evaluate( const transfer_to_blind_operation& o ) { try { - return void_result(); + const auto& d = db(); + if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) + { + const auto& atype = o.amount.asset_id(d); + FC_ASSERT( atype.allow_confidential() ); + FC_ASSERT( !atype.is_transfer_restricted() ); + FC_ASSERT( !(atype.options.flags & white_list) ); + + for( const auto& out : o.outputs ) + { + for( const auto& a : out.owner.account_auths ) + a.first(d); // verify all accounts exist and are valid + } + } + + return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } -void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_operation& o ) +void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_operation& o ) { try { - return void_result(); + if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + db().adjust_balance(o.from, -o.amount); + + const auto &add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset + db().modify(add, [&](asset_dynamic_data_object &obj) { + obj.confidential_supply += o.amount.amount; + FC_ASSERT(obj.confidential_supply >= 0); + }); + for (const auto &out : o.outputs) { + db().create([&](blinded_balance_object &obj) { + obj.asset_id = o.amount.asset_id; + obj.owner = out.owner; + obj.commitment = out.commitment; + }); + } + } + return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } void transfer_to_blind_evaluator::pay_fee() { + const auto& d = db(); + if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + if (d.head_block_time() >= HARDFORK_563_TIME) + pay_fba_fee(fba_accumulator_id_transfer_to_blind); + else + generic_evaluator::pay_fee(); + } } void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o ) { try { - return void_result(); + const auto& d = db(); + if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + o.fee.asset_id(d); // verify fee is a legit asset + const auto &bbi = d.get_index_type(); + const auto &cidx = bbi.indices().get(); + for (const auto &in : o.inputs) { + auto itr = cidx.find(in.commitment); + FC_ASSERT(itr != cidx.end()); + FC_ASSERT(itr->asset_id == o.fee.asset_id); + FC_ASSERT(itr->owner == in.owner); + } + } + return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } -void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_operation& o ) +void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_operation& o ) { try { - return void_result(); + if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + db().adjust_balance(o.fee_payer(), o.fee); + db().adjust_balance(o.to, o.amount); + const auto &bbi = db().get_index_type(); + const auto &cidx = bbi.indices().get(); + for (const auto &in : o.inputs) { + auto itr = cidx.find(in.commitment); + FC_ASSERT(itr != cidx.end()); + db().remove(*itr); + } + const auto &add = o.amount.asset_id(db()).dynamic_asset_data_id(db()); // verify fee is a legit asset + db().modify(add, [&](asset_dynamic_data_object &obj) { + obj.confidential_supply -= o.amount.amount + o.fee.amount; + FC_ASSERT(obj.confidential_supply >= 0); + }); + } + return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } void transfer_from_blind_evaluator::pay_fee() { + const auto& d = db(); + if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + if (d.head_block_time() >= HARDFORK_563_TIME) + pay_fba_fee(fba_accumulator_id_transfer_from_blind); + else + generic_evaluator::pay_fee(); + } } void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o ) { try { - return void_result(); + const auto& d = db(); + if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + o.fee.asset_id(d); // verify fee is a legit asset + const auto &bbi = d.get_index_type(); + const auto &cidx = bbi.indices().get(); + for (const auto &out : o.outputs) { + for (const auto &a : out.owner.account_auths) + a.first(d); // verify all accounts exist and are valid + } + for (const auto &in : o.inputs) { + auto itr = cidx.find(in.commitment); + GRAPHENE_ASSERT(itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment", in.commitment)); + FC_ASSERT(itr->asset_id == o.fee.asset_id); + FC_ASSERT(itr->owner == in.owner); + } + } + return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } -void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& o ) +void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& o ) { try { - return void_result(); + if( db().head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + db().adjust_balance(o.fee_payer(), o.fee); // deposit the fee to the temp account + const auto &bbi = db().get_index_type(); + const auto &cidx = bbi.indices().get(); + for (const auto &in : o.inputs) { + auto itr = cidx.find(in.commitment); + GRAPHENE_ASSERT(itr != cidx.end(), blind_transfer_unknown_commitment, "", ("commitment", in.commitment)); + db().remove(*itr); + } + for (const auto &out : o.outputs) { + db().create([&](blinded_balance_object &obj) { + obj.asset_id = o.fee.asset_id; + obj.owner = out.owner; + obj.commitment = out.commitment; + }); + } + const auto &add = o.fee.asset_id(db()).dynamic_asset_data_id(db()); + db().modify(add, [&](asset_dynamic_data_object &obj) { + obj.confidential_supply -= o.fee.amount; + FC_ASSERT(obj.confidential_supply >= 0); + }); + } + return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } void blind_transfer_evaluator::pay_fee() { + const auto& d = db(); + if( d.head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME ) { + if (d.head_block_time() >= HARDFORK_563_TIME) + pay_fba_fee(fba_accumulator_id_blind_transfer); + else + generic_evaluator::pay_fee(); + } } } } // graphene::chain diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index adabcffe..79b24464 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -739,13 +739,11 @@ void database::_apply_block( const signed_block& next_block ) if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) { update_witness_schedule(next_block); - bool need_to_update_son_schedule = false; - for(const auto& active_sons : global_props.active_sons){ - if(!active_sons.second.empty()) - need_to_update_son_schedule = true; - } - if(need_to_update_son_schedule) { - update_son_schedule(next_block); + + for(const auto& active_sons : global_props.active_sons) { + if(!active_sons.second.empty()) { + update_son_schedule(active_sons.first, next_block); + } } } @@ -783,15 +781,11 @@ void database::_apply_block( const signed_block& next_block ) if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) { update_witness_schedule(); - bool need_update_son_schedule = false; for(const auto& active_sidechain_type : active_sidechain_types(dynamic_global_props.time)) { if(global_props.active_sons.at(active_sidechain_type).size() > 0) { - need_update_son_schedule = true; + update_son_schedule(active_sidechain_type); } } - if(need_update_son_schedule) { - update_son_schedule(); - } } if( !_node_property_object.debug_updates.empty() ) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 9510692c..af3635c0 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -305,16 +305,14 @@ bool database::is_son_dereg_valid( son_id_type son_id ) } bool status_son_dereg_valid = true; - for(const auto& status : son->statuses) - { - const auto& sidechain = status.first; - if(status.second != son_status::in_maintenance) + for (const auto &active_sidechain_type : active_sidechain_types(head_block_time())) { + if(son->statuses.at(active_sidechain_type) != son_status::in_maintenance) status_son_dereg_valid = false; if(status_son_dereg_valid) { - if(son->statistics(*this).last_active_timestamp.contains(sidechain)) { - if (head_block_time() - son->statistics(*this).last_active_timestamp.at(sidechain) < fc::seconds(get_global_properties().parameters.son_deregister_time())) { + if(son->statistics(*this).last_active_timestamp.contains(active_sidechain_type)) { + if (head_block_time() - son->statistics(*this).last_active_timestamp.at(active_sidechain_type) < fc::seconds(get_global_properties().parameters.son_deregister_time())) { status_son_dereg_valid = false; } } diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index e4ccc45d..7df4f403 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -185,13 +185,109 @@ void database::update_worker_votes() } } -void database::pay_sons() +void database::pay_sons_before_hf_ethereum() +{ + const auto now = head_block_time(); + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + // Current requirement is that we have to pay every 24 hours, so the following check + if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time()))) + { + const sidechain_type st = sidechain_type::bitcoin; + const auto sons = sort_votable_objects(st, get_global_properties().parameters.maximum_son_count()); + + // After SON2 HF + uint64_t total_votes = 0; + for( const son_object& son : sons ) + { + FC_ASSERT(son.get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", son)); + total_votes += _vote_tally_buffer[*son.get_sidechain_vote_id(st)]; + } + const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0); + auto get_weight = [&bits_to_drop]( uint64_t son_votes ) { + const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); + return weight; + }; + + // Before SON2 HF + auto get_weight_before_son2_hf = []( uint64_t son_votes ) { + const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0); + const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); + return weight; + }; + + uint64_t weighted_total_txs_signed = 0; + const share_type son_budget = dpo.son_budget; + get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &st](const object& o) { + const son_statistics_object& s = static_cast(o); + const auto& idx = get_index_type().indices().get(); + const auto son_obj = idx.find( s.owner ); + uint16_t son_weight = 0; + FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj)); + if( now >= HARDFORK_SON2_TIME ) { + son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); + } + else { + son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); + } + const uint64_t txs_signed_bitcoin = s.txs_signed.contains(sidechain_type::bitcoin) ? s.txs_signed.at(sidechain_type::bitcoin) : 0; + const uint64_t txs_signed_hive = s.txs_signed.contains(sidechain_type::hive) ? s.txs_signed.at(sidechain_type::hive) : 0; + weighted_total_txs_signed += ((txs_signed_bitcoin + txs_signed_hive) * son_weight); + }); + + // Now pay off each SON proportional to the number of transactions signed. + get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &st](const object& o) { + const son_statistics_object& s = static_cast(o); + const uint64_t txs_signed_bitcoin = s.txs_signed.contains(sidechain_type::bitcoin) ? s.txs_signed.at(sidechain_type::bitcoin) : 0; + const uint64_t txs_signed_hive = s.txs_signed.contains(sidechain_type::hive) ? s.txs_signed.at(sidechain_type::hive) : 0; + + if(txs_signed_bitcoin > 0 || txs_signed_hive > 0) { + const auto& idx = get_index_type().indices().get(); + auto son_obj = idx.find( s.owner ); + uint16_t son_weight = 0; + FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj)); + if( now >= HARDFORK_SON2_TIME ) { + son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); + } + else { + son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); + } + const share_type pay = ((txs_signed_bitcoin + txs_signed_hive) * son_weight * son_budget.value)/weighted_total_txs_signed; + modify( *son_obj, [&]( son_object& _son_obj) + { + _son_obj.pay_son_fee(pay, *this); + }); + //Remove the amount paid out to SON from global SON Budget + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.son_budget -= pay; + } ); + //Reset the tx counter in each son statistics object + modify( s, [&]( son_statistics_object& _s) + { + if(_s.txs_signed.contains(sidechain_type::bitcoin)) + _s.txs_signed.at(sidechain_type::bitcoin) = 0; + if(_s.txs_signed.contains(sidechain_type::hive)) + _s.txs_signed.at(sidechain_type::hive) = 0; + }); + } + }); + + //Note the last son pay out time + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.last_son_payout_time = now; + }); + } +} + +void database::pay_sons_after_hf_ethereum() { const time_point_sec now = head_block_time(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); // Current requirement is that we have to pay every 24 hours, so the following check if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time()))) { + flat_map bits_to_drop; for(const auto& active_sidechain_type : active_sidechain_types(now)) { assert( _son_count_histogram_buffer.at(active_sidechain_type).size() > 0 ); @@ -209,93 +305,72 @@ void database::pay_sons() } } - const sidechain_type st = [&now, &active_sidechain_type]{ - if( now < HARDFORK_SON_FOR_ETHEREUM_TIME ) - return sidechain_type::bitcoin; - else - return active_sidechain_type; - }(); - - const auto sons = sort_votable_objects(st, - (std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)) - ); + const auto sons = sort_votable_objects(active_sidechain_type, (std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count))); // After SON2 HF uint64_t total_votes = 0; for( const son_object& son : sons ) { - FC_ASSERT(son.get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", son)); - total_votes += _vote_tally_buffer[*son.get_sidechain_vote_id(st)]; + FC_ASSERT(son.get_sidechain_vote_id(active_sidechain_type).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", active_sidechain_type)("son", son)); + total_votes += _vote_tally_buffer[*son.get_sidechain_vote_id(active_sidechain_type)]; } - const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0); - auto get_weight = [&bits_to_drop]( uint64_t son_votes ) { - const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); - return weight; - }; - // Before SON2 HF - auto get_weight_before_son2_hf = []( uint64_t son_votes ) { - const int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(son_votes)) - 15, 0); - const uint16_t weight = std::max((son_votes >> bits_to_drop), uint64_t(1) ); - return weight; - }; - uint64_t weighted_total_txs_signed = 0; - const share_type son_budget = dpo.son_budget; - get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now, &get_weight_before_son2_hf, &active_sidechain_type, &st](const object& o) { - const son_statistics_object& s = static_cast(o); - const auto& idx = get_index_type().indices().get(); - const auto son_obj = idx.find( s.owner ); - uint16_t son_weight = 0; - FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj)); - if( now >= HARDFORK_SON2_TIME ) { - son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); - } - else { - son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); - } + bits_to_drop[active_sidechain_type] = std::max(int(boost::multiprecision::detail::find_msb(total_votes)) - 15, 0); + } + + auto get_weight = [&bits_to_drop]( sidechain_type sidechain, uint64_t son_votes ) { + const uint16_t weight = std::max((son_votes >> bits_to_drop.at(sidechain)), uint64_t(1) ); + return weight; + }; + + // Calculate weighted_total_txs_signed + uint64_t weighted_total_txs_signed = 0; + get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &get_weight, &now](const object& o) { + for(const auto& active_sidechain_type : active_sidechain_types(now)) { + const son_statistics_object &s = static_cast(o); + const auto &idx = get_index_type().indices().get(); + const auto son_obj = idx.find(s.owner); + FC_ASSERT(son_obj->get_sidechain_vote_id(active_sidechain_type).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", active_sidechain_type)("son", *son_obj)); + const uint16_t son_weight = get_weight(active_sidechain_type, _vote_tally_buffer[*son_obj->get_sidechain_vote_id(active_sidechain_type)]); const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0; weighted_total_txs_signed += (txs_signed * son_weight); - }); + } + }); + + // Now pay off each SON proportional to the number of transactions signed + const share_type son_budget = dpo.son_budget; + get_index_type().inspect_all_objects([this, &now, &get_weight, &weighted_total_txs_signed, &dpo, &son_budget](const object& o) { + for(const auto& active_sidechain_type : active_sidechain_types(now)) { + const son_statistics_object &s = static_cast(o); - // Now pay off each SON proportional to the number of transactions signed. - get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now, &active_sidechain_type, &st](const object& o) { - const son_statistics_object& s = static_cast(o); const uint64_t txs_signed = s.txs_signed.contains(active_sidechain_type) ? s.txs_signed.at(active_sidechain_type) : 0; - - if(txs_signed > 0) { - const auto& idx = get_index_type().indices().get(); - auto son_obj = idx.find( s.owner ); + if (txs_signed > 0) { + const auto &idx = get_index_type().indices().get(); + auto son_obj = idx.find(s.owner); uint16_t son_weight = 0; - FC_ASSERT(son_obj->get_sidechain_vote_id(st).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", st)("son", *son_obj)); - if( now >= HARDFORK_SON2_TIME ) { - son_weight += get_weight(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); - } - else { - son_weight += get_weight_before_son2_hf(_vote_tally_buffer[*son_obj->get_sidechain_vote_id(st)]); - } - const share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed; - modify( *son_obj, [&]( son_object& _son_obj) - { - _son_obj.pay_son_fee(pay, *this); + FC_ASSERT(son_obj->get_sidechain_vote_id(active_sidechain_type).valid(), "Invalid vote id, sidechain: ${sidechain}, son: ${son}", ("sidechain", active_sidechain_type)("son", *son_obj)); + son_weight += get_weight(active_sidechain_type, _vote_tally_buffer[*son_obj->get_sidechain_vote_id(active_sidechain_type)]); + const share_type pay = (txs_signed * son_weight * son_budget.value) / weighted_total_txs_signed; + modify(*son_obj, [&](son_object &_son_obj) { + _son_obj.pay_son_fee(pay, *this); }); - //Remove the amount paid out to SON from global SON Budget - modify( dpo, [&]( dynamic_global_property_object& _dpo ) - { - _dpo.son_budget -= pay; - } ); - //Reset the tx counter in each son statistics object - modify( s, [&]( son_statistics_object& _s) - { - if(_s.txs_signed.contains(active_sidechain_type)) + // Remove the amount paid out to SON from global SON Budget + modify(dpo, [&](dynamic_global_property_object &_dpo) { + _dpo.son_budget -= pay; + }); + // Reset the tx counter in each son statistics object + modify(s, [&](son_statistics_object &_s) { + if (_s.txs_signed.contains(active_sidechain_type)) _s.txs_signed.at(active_sidechain_type) = 0; }); } - }); - //Note the last son pay out time - modify( dpo, [&]( dynamic_global_property_object& _dpo ) - { - _dpo.last_son_payout_time = now; - }); - } + } + }); + + //Note the last son pay out time + modify( dpo, [&]( dynamic_global_property_object& _dpo ) + { + _dpo.last_son_payout_time = now; + }); } } @@ -2152,7 +2227,7 @@ void database::perform_son_tasks() }); } // create HIVE asset here because son_account is the issuer of the HIVE - if (gpo.parameters.hive_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) + if (gpo.parameters.hive_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) { const asset_dynamic_data_object& dyn_asset = create([](asset_dynamic_data_object& a) { @@ -2192,7 +2267,10 @@ void database::perform_son_tasks() // Before making a budget we should pay out SONs // This function should check if its time to pay sons // and modify the global son funds accordingly, whatever is left is passed on to next budget - pay_sons(); + if(head_block_time() < HARDFORK_SON_FOR_ETHEREUM_TIME) + pay_sons_before_hf_ethereum(); + else + pay_sons_after_hf_ethereum(); } // Split vote_ids diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 12d4a6dd..d4874b29 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -200,44 +200,41 @@ void database::update_witness_schedule() } } -void database::update_son_schedule() +void database::update_son_schedule(sidechain_type type) { const global_property_object& gpo = get_global_properties(); - for(const auto& active_sidechain_type : active_sidechain_types(head_block_time())) + const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(type))); + if( gpo.active_sons.at(type).size() != 0 && + head_block_num() % gpo.active_sons.at(type).size() == 0) { - const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type))); - if( gpo.active_sons.at(active_sidechain_type).size() != 0 && - head_block_num() % gpo.active_sons.at(active_sidechain_type).size() == 0) + modify( sidechain_sso, [&]( son_schedule_object& _sso ) { - modify( sidechain_sso, [&]( son_schedule_object& _sso ) + _sso.current_shuffled_sons.clear(); + _sso.current_shuffled_sons.reserve( gpo.active_sons.at(type).size() ); + + for ( const auto &w : gpo.active_sons.at(type) ) { + _sso.current_shuffled_sons.push_back(w.son_id); + } + + auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; + + for (uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i) { - _sso.current_shuffled_sons.clear(); - _sso.current_shuffled_sons.reserve( gpo.active_sons.at(active_sidechain_type).size() ); + /// High performance random generator + /// http://xorshift.di.unimi.it/ + uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL; + k ^= (k >> 12); + k ^= (k << 25); + k ^= (k >> 27); + k *= 2685821657736338717ULL; - for ( const auto &w : gpo.active_sons.at(active_sidechain_type) ) { - _sso.current_shuffled_sons.push_back(w.son_id); - } - - auto now_hi = uint64_t(head_block_time().sec_since_epoch()) << 32; - - for (uint32_t i = 0; i < _sso.current_shuffled_sons.size(); ++i) - { - /// High performance random generator - /// http://xorshift.di.unimi.it/ - uint64_t k = now_hi + uint64_t(i) * 2685821657736338717ULL; - k ^= (k >> 12); - k ^= (k << 25); - k ^= (k >> 27); - k *= 2685821657736338717ULL; - - uint32_t jmax = _sso.current_shuffled_sons.size() - i; - uint32_t j = i + k % jmax; - std::swap(_sso.current_shuffled_sons[i], - _sso.current_shuffled_sons[j]); - } - }); - } + uint32_t jmax = _sso.current_shuffled_sons.size() - i; + uint32_t j = i + k % jmax; + std::swap(_sso.current_shuffled_sons[i], + _sso.current_shuffled_sons[j]); + } + }); } } @@ -321,23 +318,15 @@ void database::update_witness_schedule(const signed_block& next_block) idump( ( double(total_time/1000000.0)/calls) ); } -void database::update_son_schedule(const signed_block& next_block) +void database::update_son_schedule(sidechain_type type, const signed_block& next_block) { auto start = fc::time_point::now(); #ifndef NDEBUG const son_schedule_object& sso = get(son_schedule_id_type()); #endif const global_property_object& gpo = get_global_properties(); - const flat_map schedule_needs_filled = [&gpo]() - { - flat_map schedule_needs_filled; - for(const auto& sidechain_active_sons : gpo.active_sons) - { - schedule_needs_filled[sidechain_active_sons.first] = sidechain_active_sons.second.size(); - } - return schedule_needs_filled; - }(); - uint32_t schedule_slot = get_slot_at_time(next_block.timestamp); + const uint32_t schedule_needs_filled = gpo.active_sons.at(type).size(); + const uint32_t schedule_slot = get_slot_at_time(next_block.timestamp); // We shouldn't be able to generate _pending_block with timestamp // in the past, and incoming blocks from the network with timestamp @@ -351,46 +340,43 @@ void database::update_son_schedule(const signed_block& next_block) assert( dpo.random.data_size() == witness_scheduler_rng::seed_length ); assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() ); - for(const auto& active_sidechain_type : active_sidechain_types(head_block_time())) + const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(type))); + son_id_type first_son; + bool slot_is_near = sidechain_sso.scheduler.get_slot( schedule_slot-1, first_son ); + son_id_type son_id; + + modify(sidechain_sso, [&](son_schedule_object& _sso) { - const son_schedule_object& sidechain_sso = get(son_schedule_id_type(get_son_schedule_id(active_sidechain_type))); - son_id_type first_son; - bool slot_is_near = sidechain_sso.scheduler.get_slot( schedule_slot-1, first_son ); - son_id_type son_id; + _sso.slots_since_genesis += schedule_slot; + witness_scheduler_rng rng(_sso.rng_seed.data, _sso.slots_since_genesis); - modify(sidechain_sso, [&](son_schedule_object& _sso) - { - _sso.slots_since_genesis += schedule_slot; - witness_scheduler_rng rng(_sso.rng_seed.data, _sso.slots_since_genesis); + _sso.scheduler._min_token_count = std::max(int(gpo.active_sons.at(type).size()) / 2, 1); - _sso.scheduler._min_token_count = std::max(int(gpo.active_sons.at(active_sidechain_type).size()) / 2, 1); - - if( slot_is_near ) + if( slot_is_near ) + { + uint32_t drain = schedule_slot; + while( drain > 0 ) { - uint32_t drain = schedule_slot; - while( drain > 0 ) - { - if( _sso.scheduler.size() == 0 ) - break; - _sso.scheduler.consume_schedule(); - --drain; - } + if( _sso.scheduler.size() == 0 ) + break; + _sso.scheduler.consume_schedule(); + --drain; } - else - { - _sso.scheduler.reset_schedule( first_son ); - } - while( !_sso.scheduler.get_slot(schedule_needs_filled.at(active_sidechain_type), son_id) ) - { - if( _sso.scheduler.produce_schedule(rng) & emit_turn ) - memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size()); - } - _sso.last_scheduling_block = next_block.block_num(); - _sso.recent_slots_filled = ( - (_sso.recent_slots_filled << 1) - + 1) << (schedule_slot - 1); - }); - } + } + else + { + _sso.scheduler.reset_schedule( first_son ); + } + while( !_sso.scheduler.get_slot(schedule_needs_filled, son_id) ) + { + if( _sso.scheduler.produce_schedule(rng) & emit_turn ) + memcpy(_sso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size()); + } + _sso.last_scheduling_block = next_block.block_num(); + _sso.recent_slots_filled = ( + (_sso.recent_slots_filled << 1) + + 1) << (schedule_slot - 1); + }); auto end = fc::time_point::now(); static uint64_t total_time = 0; diff --git a/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf b/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf index e6d8a9cb..1caf70c2 100644 --- a/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf +++ b/libraries/chain/hardfork.d/SON_FOR_ETHEREUM.hf @@ -1,7 +1,7 @@ #ifndef HARDFORK_SON_FOR_ETHEREUM_TIME #ifdef BUILD_PEERPLAYS_TESTNET -#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-06-05T12:00:00")) +#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-07-17T12:00:00")) #else -#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-07-05T12:00:00")) +#define HARDFORK_SON_FOR_ETHEREUM_TIME (fc::time_point_sec::from_iso_string("2023-07-31T12:00:00")) #endif #endif diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index c8e1f214..24fb32d4 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -292,8 +292,8 @@ namespace graphene { namespace chain { vector get_near_witness_schedule()const; void update_witness_schedule(); void update_witness_schedule(const signed_block& next_block); - void update_son_schedule(); - void update_son_schedule(const signed_block& next_block); + void update_son_schedule(sidechain_type type); + void update_son_schedule(sidechain_type type, const signed_block& next_block); void check_lottery_end_by_participants( asset_id_type asset_id ); void check_ending_lotteries(); @@ -579,7 +579,8 @@ namespace graphene { namespace chain { void initialize_budget_record( fc::time_point_sec now, budget_record& rec )const; void process_budget(); void pay_workers( share_type& budget ); - void pay_sons(); + void pay_sons_before_hf_ethereum(); + void pay_sons_after_hf_ethereum(); void perform_son_tasks(); void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props); void update_active_witnesses(); diff --git a/libraries/chain/include/graphene/chain/exceptions.hpp b/libraries/chain/include/graphene/chain/exceptions.hpp index 92c7c5dd..406a235e 100644 --- a/libraries/chain/include/graphene/chain/exceptions.hpp +++ b/libraries/chain/include/graphene/chain/exceptions.hpp @@ -182,6 +182,9 @@ namespace graphene { namespace chain { GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( override_transfer ); GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( not_permitted, override_transfer, 1, "not permitted" ) + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( blind_transfer ); + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( unknown_commitment, blind_transfer, 1, "Attempting to claim an unknown prior commitment" ); + /* FC_DECLARE_DERIVED_EXCEPTION( addition_overflow, graphene::chain::chain_exception, 30002, "addition overflow" ) FC_DECLARE_DERIVED_EXCEPTION( subtraction_overflow, graphene::chain::chain_exception, 30003, "subtraction overflow" ) diff --git a/libraries/chain/include/graphene/chain/protocol/confidential.hpp b/libraries/chain/include/graphene/chain/protocol/confidential.hpp index d1a28da3..86628f3b 100644 --- a/libraries/chain/include/graphene/chain/protocol/confidential.hpp +++ b/libraries/chain/include/graphene/chain/protocol/confidential.hpp @@ -158,9 +158,7 @@ struct transfer_to_blind_operation : public base_operation blind_factor_type blinding_factor; vector outputs; - account_id_type fee_payer()const { return account_id_type{}; } - - //account_id_type fee_payer()const { return from; } + account_id_type fee_payer()const { return from; } //void validate()const; //share_type calculate_fee(const fee_parameters_type& )const; }; @@ -181,9 +179,7 @@ struct transfer_from_blind_operation : public base_operation blind_factor_type blinding_factor; vector inputs; - account_id_type fee_payer()const { return account_id_type{}; } - - //account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; } + account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; } //void validate()const; //void get_required_authorities( vector& a )const //{ @@ -246,10 +242,8 @@ struct blind_transfer_operation : public base_operation vector inputs; vector outputs; - account_id_type fee_payer()const { return account_id_type{}; } - /** graphene TEMP account */ - //account_id_type fee_payer()const; + account_id_type fee_payer()const { return GRAPHENE_TEMP_ACCOUNT; } //void validate()const; //share_type calculate_fee( const fee_parameters_type& k )const; //void get_required_authorities( vector& a )const diff --git a/libraries/chain/son_wallet_evaluator.cpp b/libraries/chain/son_wallet_evaluator.cpp index 138f8e57..03e2edc1 100644 --- a/libraries/chain/son_wallet_evaluator.cpp +++ b/libraries/chain/son_wallet_evaluator.cpp @@ -97,10 +97,18 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); FC_ASSERT( op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer." ); + const son_wallet_id_type son_wallet_id = [&]{ + if(db().head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) + { + const auto ast = active_sidechain_types(db().head_block_time()); + const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size(); + return son_wallet_id_type{ id }; + } + + return op.son_wallet_id; + }(); + const auto& idx = db().get_index_type().indices().get(); - const auto ast = active_sidechain_types(db().head_block_time()); - const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size(); - const son_wallet_id_type son_wallet_id{ id }; FC_ASSERT( idx.find(son_wallet_id) != idx.end() ); //auto itr = idx.find(op.son_wallet_id); //FC_ASSERT( itr->addresses.find(op.sidechain) == itr->addresses.end() || @@ -110,10 +118,18 @@ void_result update_son_wallet_evaluator::do_evaluate(const son_wallet_update_ope object_id_type update_son_wallet_evaluator::do_apply(const son_wallet_update_operation& op) { try { + const son_wallet_id_type son_wallet_id = [&]{ + if(db().head_block_time() >= HARDFORK_SON_FOR_ETHEREUM_TIME) + { + const auto ast = active_sidechain_types(db().head_block_time()); + const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size(); + return son_wallet_id_type{ id }; + } + + return op.son_wallet_id; + }(); + const auto& idx = db().get_index_type().indices().get(); - const auto ast = active_sidechain_types(db().head_block_time()); - const auto id = (op.son_wallet_id.instance.value - std::distance(ast.begin(), ast.find(op.sidechain))) / ast.size(); - const son_wallet_id_type son_wallet_id{ id }; auto itr = idx.find(son_wallet_id); if (itr != idx.end()) { diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index f762da49..0d19b179 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -680,8 +680,7 @@ void sidechain_net_handler::on_applied_block(const signed_block &b) { const bool is_tracked_asset = ((sidechain == sidechain_type::bitcoin) && (transfer_op.amount.asset_id == gpo.parameters.btc_asset())) || ((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id == gpo.parameters.eth_asset())) || - ((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id != gpo.parameters.btc_asset()) - && (transfer_op.amount.asset_id != gpo.parameters.hbd_asset()) && (transfer_op.amount.asset_id != gpo.parameters.hive_asset())) || + ((sidechain == sidechain_type::ethereum) && (transfer_op.amount.asset_id != gpo.parameters.btc_asset()) && (transfer_op.amount.asset_id != gpo.parameters.hbd_asset()) && (transfer_op.amount.asset_id != gpo.parameters.hive_asset())) || ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) || ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset())); diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 76e23ab0..974670ea 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -674,7 +674,7 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain uint32_t rpc_port = options.at("bitcoin-node-rpc-port").as(); std::string rpc_user = options.at("bitcoin-node-rpc-user").as(); std::string rpc_password = options.at("bitcoin-node-rpc-password").as(); - + if (options.count("use-bitcoind-client")) { use_bitcoind_client = options.at("use-bitcoind-client").as(); } diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 0da34705..0d671a62 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -574,7 +574,7 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::hive), 12); BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::ethereum), 18); // Check that Alice and Bob are paid for signing the transactions in the previous day/cycle - BOOST_REQUIRE_EQUAL(db.get_balance(obj1->son_account, asset_id_type()).amount.value, 80+obj1_balance); + BOOST_REQUIRE_EQUAL(db.get_balance(obj1->son_account, asset_id_type()).amount.value, 79+obj1_balance); BOOST_REQUIRE_EQUAL(db.get_balance(obj2->son_account, asset_id_type()).amount.value, 120+obj2_balance); // Check the SON Budget is again allocated after maintenance BOOST_CHECK( dpo.son_budget.value == 200);