SON207 - Introduce scheduling for SONs similar to witnesses (#251)

This commit is contained in:
satyakoneru 2019-12-24 00:30:49 +11:00 committed by Bobinson K B
parent 6d5b86a8e5
commit a347e97649
7 changed files with 266 additions and 10 deletions

View file

@ -649,8 +649,13 @@ void database::_apply_block( const signed_block& next_block )
_current_virtual_op = 0;
}
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM)
update_witness_schedule(next_block);
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM) {
update_witness_schedule(next_block);
if(global_props.active_sons.size() > 0) {
update_son_schedule(next_block);
}
}
const uint32_t missed = update_witness_missed_blocks( next_block );
update_global_dynamic_data( next_block, missed );
update_signing_witness(signing_witness, next_block);
@ -678,8 +683,13 @@ void database::_apply_block( const signed_block& next_block )
// update_global_dynamic_data() as perhaps these methods only need
// to be called for header validation?
update_maintenance_flag( maint_needed );
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM)
update_witness_schedule();
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM) {
update_witness_schedule();
if(global_props.active_sons.size() > 0) {
update_son_schedule();
}
}
if( !_node_property_object.debug_updates.empty() )
apply_debug_updates();

View file

@ -314,6 +314,7 @@ void database::initialize_indexes()
add_index< primary_index<flat_index< block_summary_object >> >();
add_index< primary_index<simple_index<chain_property_object > > >();
add_index< primary_index<simple_index<witness_schedule_object > > >();
add_index< primary_index<simple_index<son_schedule_object > > >();
add_index< primary_index<simple_index<budget_record_object > > >();
add_index< primary_index< special_authority_index > >();
add_index< primary_index< buyback_index > >();
@ -947,6 +948,29 @@ void database::init_genesis(const genesis_state_type& genesis_state)
});
assert( wso.id == witness_schedule_id_type() );
// Initialize witness schedule
#ifndef NDEBUG
const son_schedule_object& sso =
#endif
create<son_schedule_object>([&](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( sso.id == son_schedule_id_type() );
// Enable fees
modify(get_global_properties(), [&genesis_state](global_property_object& p) {
p.parameters.current_fees = genesis_state.initial_parameters.current_fees;

View file

@ -455,11 +455,12 @@ void database::update_active_sons()
});
});
//const witness_schedule_object& wso = witness_schedule_id_type()(*this);
//modify(wso, [&](witness_schedule_object& _wso)
//{
// _wso.scheduler.update(gpo.active_witnesses);
//});
const son_schedule_object& sso = son_schedule_id_type()(*this);
modify(sso, [&](son_schedule_object& _sso)
{
flat_set<son_id_type> active_sons(gpo.active_sons.begin(), gpo.active_sons.end());
_sso.scheduler.update(active_sons);
});
} FC_CAPTURE_AND_RETHROW() }
void database::initialize_budget_record( fc::time_point_sec now, budget_record& rec )const

View file

@ -26,6 +26,7 @@
#include <graphene/chain/global_property_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/son_object.hpp>
namespace graphene { namespace chain {
@ -72,6 +73,47 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const
return wid;
}
son_id_type database::get_scheduled_son( uint32_t slot_num )const
{
son_id_type sid;
const global_property_object& gpo = get_global_properties();
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM)
{
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
const son_schedule_object& sso = son_schedule_id_type()(*this);
uint64_t current_aslot = dpo.current_aslot + slot_num;
return sso.current_shuffled_sons[ current_aslot % sso.current_shuffled_sons.size() ];
}
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM &&
slot_num != 0 )
{
const son_schedule_object& sso = son_schedule_id_type()(*this);
// ask the near scheduler who goes in the given slot
bool slot_is_near = sso.scheduler.get_slot(slot_num-1, sid);
if(! slot_is_near)
{
// if the near scheduler doesn't know, we have to extend it to
// a far scheduler.
// n.b. instantiating it is slow, but block gaps long enough to
// need it are likely pretty rare.
witness_scheduler_rng far_rng(sso.rng_seed.begin(), GRAPHENE_FAR_SCHEDULE_CTR_IV);
far_future_son_scheduler far_scheduler =
far_future_son_scheduler(sso.scheduler, far_rng);
if(!far_scheduler.get_slot(slot_num-1, sid))
{
// no scheduled son -- somebody set up us the bomb
// n.b. this code path is impossible, the present
// implementation of far_future_son_scheduler
// returns true unconditionally
assert( false );
}
}
}
return sid;
}
fc::time_point_sec database::get_slot_time(uint32_t slot_num)const
{
if( slot_num == 0 )
@ -146,6 +188,41 @@ void database::update_witness_schedule()
}
}
void database::update_son_schedule()
{
const son_schedule_object& sso = son_schedule_id_type()(*this);
const global_property_object& gpo = get_global_properties();
if( head_block_num() % gpo.active_sons.size() == 0 )
{
modify( sso, [&]( son_schedule_object& _sso )
{
_sso.current_shuffled_sons.clear();
_sso.current_shuffled_sons.reserve( gpo.active_sons.size() );
for( const son_id_type& w : gpo.active_sons )
_sso.current_shuffled_sons.push_back( w );
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] );
}
});
}
}
vector<witness_id_type> database::get_near_witness_schedule()const
{
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
@ -226,6 +303,71 @@ 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)
{
auto start = fc::time_point::now();
const global_property_object& gpo = get_global_properties();
const son_schedule_object& sso = get(son_schedule_id_type());
uint32_t schedule_needs_filled = gpo.active_sons.size();
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
// in the past shouldn't be able to make it this far without
// triggering FC_ASSERT elsewhere
assert( schedule_slot > 0 );
son_id_type first_son;
bool slot_is_near = sso.scheduler.get_slot( schedule_slot-1, first_son );
son_id_type son;
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
assert( dpo.random.data_size() == witness_scheduler_rng::seed_length );
assert( witness_scheduler_rng::seed_length == sso.rng_seed.size() );
modify(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.size()) / 2, 1);
if( slot_is_near )
{
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 );
}
while( !_sso.scheduler.get_slot(schedule_needs_filled, son) )
{
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;
total_time += (end - start).count();
if( ++calls % 1000 == 0 )
idump( ( double(total_time/1000000.0)/calls) );
}
uint32_t database::update_witness_missed_blocks( const signed_block& b )
{
uint32_t missed_blocks = get_slot_at_time( b.timestamp );

View file

@ -240,6 +240,22 @@ namespace graphene { namespace chain {
*/
witness_id_type get_scheduled_witness(uint32_t slot_num)const;
/**
* @brief Get the 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(uint32_t slot_num)const;
/**
* Get the time at which the given slot occurs.
*
@ -263,6 +279,8 @@ namespace graphene { namespace chain {
vector<witness_id_type> 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 check_lottery_end_by_participants( asset_id_type asset_id );
void check_ending_lotteries();

View file

@ -177,7 +177,8 @@ namespace graphene { namespace chain {
impl_global_betting_statistics_object_type,
impl_lottery_balance_object_type,
impl_sweeps_vesting_balance_object_type,
impl_son_statistics_object_type
impl_son_statistics_object_type,
impl_son_schedule_object_type
};
//typedef fc::unsigned_int object_id_type;
@ -264,6 +265,7 @@ namespace graphene { namespace chain {
class lottery_balance_object;
class sweeps_vesting_balance_object;
class son_statistics_object;
class son_schedule_object;
typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type;
typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type;
@ -293,6 +295,7 @@ namespace graphene { namespace chain {
typedef object_id< implementation_ids, impl_lottery_balance_object_type, lottery_balance_object > lottery_balance_id_type;
typedef object_id< implementation_ids, impl_sweeps_vesting_balance_object_type, sweeps_vesting_balance_object> sweeps_vesting_balance_id_type;
typedef object_id< implementation_ids, impl_son_statistics_object_type, son_statistics_object > son_statistics_id_type;
typedef object_id< implementation_ids, impl_son_schedule_object_type, son_schedule_object> son_schedule_id_type;
typedef fc::array<char, GRAPHENE_MAX_ASSET_SYMBOL_LENGTH> symbol_type;
typedef fc::ripemd160 block_id_type;
@ -453,6 +456,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type,
(impl_lottery_balance_object_type)
(impl_sweeps_vesting_balance_object_type)
(impl_son_statistics_object_type)
(impl_son_schedule_object_type)
)
FC_REFLECT_TYPENAME( graphene::chain::share_type )

View file

@ -31,6 +31,7 @@
namespace graphene { namespace chain {
class witness_schedule_object;
class son_schedule_object;
typedef hash_ctr_rng<
/* HashClass = */ fc::sha256,
@ -53,6 +54,22 @@ typedef generic_far_future_witness_scheduler<
/* debug = */ true
> far_future_witness_scheduler;
typedef generic_witness_scheduler<
/* WitnessID = */ son_id_type,
/* RNG = */ witness_scheduler_rng,
/* CountType = */ decltype( chain_parameters::maximum_son_count ),
/* OffsetType = */ uint32_t,
/* debug = */ true
> son_scheduler;
typedef generic_far_future_witness_scheduler<
/* WitnessID = */ son_id_type,
/* RNG = */ witness_scheduler_rng,
/* CountType = */ decltype( chain_parameters::maximum_son_count ),
/* OffsetType = */ uint32_t,
/* debug = */ true
> far_future_son_scheduler;
class witness_schedule_object : public graphene::db::abstract_object<witness_schedule_object>
{
public:
@ -73,6 +90,26 @@ class witness_schedule_object : public graphene::db::abstract_object<witness_sch
fc::uint128 recent_slots_filled;
};
class son_schedule_object : public graphene::db::abstract_object<son_schedule_object>
{
public:
static const uint8_t space_id = implementation_ids;
static const uint8_t type_id = impl_son_schedule_object_type;
vector< son_id_type > current_shuffled_sons;
son_scheduler scheduler;
uint32_t last_scheduling_block;
uint64_t slots_since_genesis = 0;
fc::array< char, sizeof(secret_hash_type) > rng_seed;
/**
* Not necessary for consensus, but used for figuring out the participation rate.
* The nth bit is 0 if the nth slot was unfilled, else it is 1.
*/
fc::uint128 recent_slots_filled;
};
} }
@ -96,3 +133,23 @@ FC_REFLECT_DERIVED(
(recent_slots_filled)
(current_shuffled_witnesses)
)
FC_REFLECT( graphene::chain::son_scheduler,
(_turns)
(_tokens)
(_min_token_count)
(_ineligible_waiting_for_token)
(_ineligible_no_turn)
(_eligible)
(_schedule)
(_lame_duck)
)
FC_REFLECT_DERIVED(
graphene::chain::son_schedule_object,
(graphene::db::object),
(scheduler)
(last_scheduling_block)
(slots_since_genesis)
(rng_seed)
(recent_slots_filled)
(current_shuffled_sons)
)