diff --git a/tests/intense/block_tests.cpp b/tests/intense/block_tests.cpp index f603fb74..eec68d4e 100644 --- a/tests/intense/block_tests.cpp +++ b/tests/intense/block_tests.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -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 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