diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 724cad85..98617eec 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -1085,6 +1085,49 @@ void database::init_genesis(const genesis_state_type& genesis_state) p.parameters.current_fees = genesis_state.initial_parameters.current_fees; }); + #ifndef NDEBUG + const son_schedule_object& ssohive = +#endif + create([&](son_schedule_object& _sso) + { + // for scheduled + memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size()); + + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + + auto init_witnesses = get_global_properties().active_witnesses; + + _sso.scheduler = son_scheduler(); + _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); + + + _sso.last_scheduling_block = 0; + + _sso.recent_slots_filled = fc::uint128::max_value(); + }); + assert( ssohive.id == son_schedule_id_type(1) ); + +#ifndef NDEBUG + const son_schedule_object& ssobitcoin = +#endif + create([&](son_schedule_object& _sso) + { + // for scheduled + memset(_sso.rng_seed.begin(), 0, _sso.rng_seed.size()); + + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + + auto init_witnesses = get_global_properties().active_witnesses; + + _sso.scheduler = son_scheduler(); + _sso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); + + + _sso.last_scheduling_block = 0; + + _sso.recent_slots_filled = fc::uint128::max_value(); + }); + assert( ssobitcoin.id == son_schedule_id_type(2) ); // Create FBA counters create([&]( fba_accumulator_object& acc ) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index c1e2287d..8673e405 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -823,6 +823,52 @@ void database::update_active_sons() _sso.scheduler.produce_schedule(rng); } }); + + // for now put the all active_sons in hive schedule object + // later we will make here the change which will take only son's from + // active_sons that are hive + const son_schedule_object& ssohive = son_schedule_id_type(1)(*this); + modify(ssohive, [&](son_schedule_object& _sso) + { + flat_set active_sons; + active_sons.reserve(gpo.active_sons.size()); + std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), + std::inserter(active_sons, active_sons.end()), + [](const son_info& swi) { + return swi.son_id; + }); + _sso.scheduler.update(active_sons); + // similar to witness, produce schedule for sons + if(cur_active_sons.size() == 0 && new_active_sons.size() > 0) + { + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + for( size_t i=0; i active_sons; + active_sons.reserve(gpo.active_sons.size()); + std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), + std::inserter(active_sons, active_sons.end()), + [](const son_info& swi) { + return swi.son_id; + }); + _sso.scheduler.update(active_sons); + // similar to witness, produce schedule for sons + if(cur_active_sons.size() == 0 && new_active_sons.size() > 0) + { + witness_scheduler_rng rng(_sso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + for( size_t i=0; i> 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] ); + } + }); + + modify( ssobitcoin, [&]( son_schedule_object& _sso ) + { + _sso.current_shuffled_sons.clear(); + _sso.current_shuffled_sons.reserve( gpo.active_sons.size() ); + + for( const son_info& w : gpo.active_sons ) + _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] ); + } + }); } } @@ -309,6 +406,8 @@ void database::update_son_schedule(const signed_block& next_block) auto start = fc::time_point::now(); const global_property_object& gpo = get_global_properties(); const son_schedule_object& sso = get(son_schedule_id_type()); + const son_schedule_object& ssohive = get(son_schedule_id_type(1)); + const son_schedule_object& ssobitcoin = get(son_schedule_id_type(2)); uint32_t schedule_needs_filled = gpo.active_sons.size(); uint32_t schedule_slot = get_slot_at_time(next_block.timestamp); @@ -321,9 +420,16 @@ void database::update_son_schedule(const signed_block& next_block) son_id_type first_son; bool slot_is_near = sso.scheduler.get_slot( schedule_slot-1, first_son ); - son_id_type son; + son_id_type first_son_hive; + bool slot_is_near_hive = ssohive.scheduler.get_slot( schedule_slot-1, first_son_hive ); + son_id_type son_hive; + + son_id_type first_son_bitcoin; + bool slot_is_near_bitcoin = ssobitcoin.scheduler.get_slot( schedule_slot-1, first_son_bitcoin ); + son_id_type son_bitcoin; + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); assert( dpo.random.data_size() == witness_scheduler_rng::seed_length ); @@ -361,6 +467,72 @@ void database::update_son_schedule(const signed_block& next_block) (_sso.recent_slots_filled << 1) + 1) << (schedule_slot - 1); }); + + modify(ssohive, [&](son_schedule_object& _sso) + { + _sso.slots_since_genesis += schedule_slot; + witness_scheduler_rng rng(ssohive.rng_seed.data, _sso.slots_since_genesis); + + _sso.scheduler._min_token_count = std::max(int(gpo.active_sons.size()) / 2, 1); + + if( slot_is_near_hive ) + { + uint32_t drain = schedule_slot; + while( drain > 0 ) + { + if( _sso.scheduler.size() == 0 ) + break; + _sso.scheduler.consume_schedule(); + --drain; + } + } + else + { + _sso.scheduler.reset_schedule( first_son_hive ); + } + while( !_sso.scheduler.get_slot(schedule_needs_filled, son_hive) ) + { + 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); + }); + + modify(ssobitcoin, [&](son_schedule_object& _sso) + { + _sso.slots_since_genesis += schedule_slot; + witness_scheduler_rng rng(ssohive.rng_seed.data, _sso.slots_since_genesis); + + _sso.scheduler._min_token_count = std::max(int(gpo.active_sons.size()) / 2, 1); + + if( slot_is_near_bitcoin ) + { + uint32_t drain = schedule_slot; + while( drain > 0 ) + { + if( _sso.scheduler.size() == 0 ) + break; + _sso.scheduler.consume_schedule(); + --drain; + } + } + else + { + _sso.scheduler.reset_schedule( first_son_bitcoin ); + } + while( !_sso.scheduler.get_slot(schedule_needs_filled, son_bitcoin) ) + { + 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; static uint64_t calls = 0; diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 455a0a26..28dbc795 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -258,6 +258,22 @@ namespace graphene { namespace chain { */ son_id_type get_scheduled_son(uint32_t slot_num)const; + /** + * @brief Get the bitcoin or hive son scheduled for block production in a slot. + * + * slot_num always corresponds to a time in the future. + * + * If slot_num == 1, returns the next scheduled son. + * If slot_num == 2, returns the next scheduled son after + * 1 block gap. + * + * Use the get_slot_time() and get_slot_at_time() functions + * to convert between slot_num and timestamp. + * + * Passing slot_num == 0 returns GRAPHENE_NULL_WITNESS + */ + son_id_type get_scheduled_son(sidechain_type type, uint32_t slot_num)const; + /** * Get the time at which the given slot occurs. * diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 26976676..411e7515 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -456,6 +456,16 @@ void peerplays_sidechain_plugin_impl::son_processing() { ilog("Scheduled SON: ${scheduled_son_id} Now: ${now} ", ("scheduled_son_id", scheduled_son_id)("now", now)); + // for the test prove that in hive scheduled son is active son + chain::son_id_type scheduled_hive_son_id = plugin.database().get_scheduled_son(sidechain_type::hive ,1); + ilog("Scheduled SON[!HIVE!]: ${scheduled_son_id} Now: ${now} ", + ("scheduled_son_id", scheduled_hive_son_id)("now", now)); + + // for the test prove that in hive scheduled son is active son + chain::son_id_type scheduled_bitcoin_son_id = plugin.database().get_scheduled_son(sidechain_type::bitcoin ,1); + ilog("Scheduled SON[!HIVE!]: ${scheduled_son_id} Now: ${now} ", + ("scheduled_son_id", scheduled_bitcoin_son_id)("now", now)); + for (son_id_type son_id : plugin.get_sons()) { if (plugin.is_son_deregistered(son_id)) { continue;