intense_tests: Implement generic_scheduler_mc_test
This commit is contained in:
parent
e8154f62a2
commit
b7a44c6e6a
1 changed files with 89 additions and 0 deletions
|
|
@ -26,6 +26,7 @@
|
|||
#include <graphene/chain/key_object.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/witness_schedule_object.hpp>
|
||||
|
||||
#include <fc/crypto/digest.hpp>
|
||||
|
||||
|
|
@ -310,4 +311,92 @@ BOOST_FIXTURE_TEST_CASE( delegate_groups_mc_test, database_fixture )
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To have a secure random number we need to ensure that the same
|
||||
* delegate does not get to produce two blocks in a row. There is
|
||||
* always a chance that the last delegate of one round will be the
|
||||
* first delegate of the next round.
|
||||
*
|
||||
* This means that when we shuffle delegates we need to make sure
|
||||
* that there is at least N/2 delegates between consecutive turns
|
||||
* of the same delegate. This means that durring the random
|
||||
* shuffle we need to restrict the placement of delegates to maintain
|
||||
* this invariant.
|
||||
*
|
||||
* This test checks the requirement using Monte Carlo approach
|
||||
* (produce lots of blocks and check the invariant holds).
|
||||
*/
|
||||
BOOST_FIXTURE_TEST_CASE( generic_scheduler_mc_test, database_fixture )
|
||||
{
|
||||
try {
|
||||
size_t num_witnesses = db.get_global_properties().active_witnesses.size();
|
||||
size_t dmin = num_witnesses >> 1;
|
||||
witness_scheduler_rng rng(
|
||||
// - - - - + - - - - 1 - - - - + - - - - 2 - - - - + - - -
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
);
|
||||
witness_scheduler scheduler;
|
||||
vector< witness_id_type > witness_ids;
|
||||
|
||||
witness_ids.reserve( num_witnesses );
|
||||
for( size_t i=0; i<num_witnesses; i++ )
|
||||
witness_ids.push_back( witness_id_type(i) );
|
||||
|
||||
scheduler._min_token_count = num_witnesses / 2;
|
||||
|
||||
scheduler.insert_all( witness_ids );
|
||||
for( size_t i=0; i<num_witnesses; i++ )
|
||||
scheduler.produce_schedule( rng );
|
||||
|
||||
vector< witness_id_type > cur_round;
|
||||
vector< witness_id_type > full_schedule;
|
||||
// if we make the maximum witness count testable,
|
||||
// we'll need to enlarge this.
|
||||
std::bitset< 0x40 > witness_seen;
|
||||
size_t total_blocks = 1000000;
|
||||
|
||||
cur_round.reserve( num_witnesses );
|
||||
full_schedule.reserve( total_blocks );
|
||||
|
||||
// we assert so the test doesn't continue, which would
|
||||
// corrupt memory
|
||||
assert( num_witnesses <= witness_seen.size() );
|
||||
|
||||
while( full_schedule.size() < total_blocks )
|
||||
{
|
||||
scheduler.produce_schedule( rng );
|
||||
witness_id_type wid = scheduler.consume_schedule();
|
||||
full_schedule.push_back( wid );
|
||||
cur_round.push_back( wid );
|
||||
if( cur_round.size() == num_witnesses )
|
||||
{
|
||||
// check that the current round contains exactly 1 copy
|
||||
// of each witness
|
||||
witness_seen.reset();
|
||||
for( const witness_id_type& w : cur_round )
|
||||
{
|
||||
uint64_t inst = w.instance.value;
|
||||
BOOST_CHECK( !witness_seen.test( inst ) );
|
||||
assert( !witness_seen.test( inst ) );
|
||||
witness_seen.set( inst );
|
||||
}
|
||||
cur_round.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for( size_t i=0,m=full_schedule.size(); i<m; i++ )
|
||||
{
|
||||
for( size_t j=i+1,n=std::min( m, i+dmin ); j<n; j++ )
|
||||
{
|
||||
BOOST_CHECK( full_schedule[i] != full_schedule[j] );
|
||||
assert( full_schedule[i] != full_schedule[j] );
|
||||
}
|
||||
}
|
||||
|
||||
} catch (fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
Loading…
Reference in a new issue