From f175b4561cecb41a63fa2c35a35d05c59cd26c88 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Mon, 6 Jul 2015 14:35:59 -0400 Subject: [PATCH] Properly re-initialize witness scheduler state after a long block gap --- libraries/chain/db_witness_schedule.cpp | 22 ++++++++---- .../graphene/chain/witness_scheduler.hpp | 34 +++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 5095ac1b..a6d82bf6 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -106,6 +106,8 @@ void database::update_witness_schedule(signed_block next_block) // triggering FC_ASSERT elsewhere assert( schedule_slot > 0 ); + witness_id_type first_witness; + bool slot_is_near = wso.scheduler.get_slot( schedule_slot-1, first_witness ); witness_id_type wit; @@ -119,13 +121,21 @@ void database::update_witness_schedule(signed_block next_block) witness_scheduler_rng rng(wso.rng_seed.data, _wso.slots_since_genesis); _wso.scheduler._min_token_count = std::max(int(gpo.active_witnesses.size()) / 2, 1); - uint32_t drain = schedule_slot; - while( drain > 0 ) + + if( slot_is_near ) { - if( _wso.scheduler.size() == 0 ) - break; - _wso.scheduler.consume_schedule(); - --drain; + uint32_t drain = schedule_slot; + while( drain > 0 ) + { + if( _wso.scheduler.size() == 0 ) + break; + _wso.scheduler.consume_schedule(); + --drain; + } + } + else + { + _wso.scheduler.reset_schedule( first_witness ); } while( !_wso.scheduler.get_slot(schedule_needs_filled, wit) ) { diff --git a/libraries/chain/include/graphene/chain/witness_scheduler.hpp b/libraries/chain/include/graphene/chain/witness_scheduler.hpp index 77f67478..ec595922 100644 --- a/libraries/chain/include/graphene/chain/witness_scheduler.hpp +++ b/libraries/chain/include/graphene/chain/witness_scheduler.hpp @@ -313,6 +313,40 @@ class generic_witness_scheduler return true; } + /** + * Reset the schedule, then re-schedule the given witness as the + * first witness. + */ + void reset_schedule( WitnessID first_witness ) + { + _schedule.clear(); + for( const WitnessID& wid : _ineligible_no_turn ) + { + _eligible.push_back( wid ); + } + _turns += _ineligible_no_turn.size(); + _ineligible_no_turn.clear(); + for( const auto& item : _ineligible_waiting_for_token ) + { + _eligible.push_back( item.first ); + _turns += (item.second ? 0 : 1); + } + _tokens += _ineligible_waiting_for_token.size(); + _ineligible_waiting_for_token.clear(); + if( debug ) check_invariant(); + + auto it = std::find( _eligible.begin(), _eligible.end(), first_witness ); + assert( it != _eligible.end() ); + + _schedule.push_back( *it ); + _ineligible_waiting_for_token.emplace_back( *it, false ); + _eligible.erase( it ); + _turns--; + _tokens--; + if( debug ) check_invariant(); + return; + } + // keep track of total turns / tokens in existence CountType _turns = 0; CountType _tokens = 0;