From 6c052294e18f7520469931af973d1a8588f6140a Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 25 Aug 2015 17:54:04 -0400 Subject: [PATCH] Remove block randomness and rewrite witness scheduling --- libraries/app/api.cpp | 1 - libraries/chain/db_block.cpp | 21 - libraries/chain/db_init.cpp | 31 +- libraries/chain/db_maint.cpp | 8 +- libraries/chain/db_management.cpp | 1 + libraries/chain/db_update.cpp | 27 +- libraries/chain/db_witness_schedule.cpp | 175 +++----- .../chain/include/graphene/chain/config.hpp | 3 + .../chain/include/graphene/chain/database.hpp | 8 - .../graphene/chain/global_property_object.hpp | 27 +- .../include/graphene/chain/protocol/block.hpp | 5 +- .../include/graphene/chain/protocol/types.hpp | 5 - .../include/graphene/chain/witness_object.hpp | 4 +- .../chain/witness_schedule_object.hpp | 88 ---- .../graphene/chain/witness_scheduler.hpp | 417 ------------------ .../graphene/chain/witness_scheduler_rng.hpp | 124 ------ libraries/wallet/wallet.cpp | 1 - programs/size_checker/main.cpp | 1 + tests/intense/block_tests.cpp | 1 - tests/tests/basic_tests.cpp | 130 ------ tests/tests/block_tests.cpp | 30 +- tests/tests/operation_tests2.cpp | 37 +- 22 files changed, 123 insertions(+), 1022 deletions(-) delete mode 100644 libraries/chain/include/graphene/chain/witness_schedule_object.hpp delete mode 100644 libraries/chain/include/graphene/chain/witness_scheduler.hpp delete mode 100644 libraries/chain/include/graphene/chain/witness_scheduler_rng.hpp diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index ef7f3a13..a946491d 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -781,7 +781,6 @@ namespace graphene { namespace app { break; } case impl_block_summary_object_type:{ } case impl_account_transaction_history_object_type:{ - } case impl_witness_schedule_object_type: { } case impl_chain_property_object_type: { } } diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 94b02511..a78fb506 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -267,24 +267,6 @@ signed_block database::_generate_block( _pending_block.timestamp = when; - // Genesis witnesses start with a default initial secret - if( witness_obj.next_secret_hash == secret_hash_type::hash( secret_hash_type() ) ) - { - _pending_block.previous_secret = secret_hash_type(); - } - else - { - secret_hash_type::encoder last_enc; - fc::raw::pack( last_enc, block_signing_private_key ); - fc::raw::pack( last_enc, witness_obj.previous_secret ); - _pending_block.previous_secret = last_enc.result(); - } - - secret_hash_type::encoder next_enc; - fc::raw::pack( next_enc, block_signing_private_key ); - fc::raw::pack( next_enc, _pending_block.previous_secret ); - _pending_block.next_secret_hash = secret_hash_type::hash(next_enc.result()); - _pending_block.transaction_merkle_root = _pending_block.calculate_merkle_root(); _pending_block.witness = witness_id; @@ -404,7 +386,6 @@ void database::_apply_block( const signed_block& next_block ) ++_current_trx_in_block; } - update_witness_schedule(next_block); update_global_dynamic_data(next_block); update_signing_witness(signing_witness, next_block); @@ -555,8 +536,6 @@ const witness_object& database::validate_block_header( uint32_t skip, const sign FC_ASSERT( _pending_block.previous == next_block.previous, "", ("pending.prev",_pending_block.previous)("next.prev",next_block.previous) ); FC_ASSERT( _pending_block.timestamp <= next_block.timestamp, "", ("_pending_block.timestamp",_pending_block.timestamp)("next",next_block.timestamp)("blocknum",next_block.block_num()) ); const witness_object& witness = next_block.witness(*this); - FC_ASSERT( secret_hash_type::hash( next_block.previous_secret ) == witness.next_secret_hash, "", - ("previous_secret", next_block.previous_secret)("next_secret_hash", witness.next_secret_hash)); if( !(skip&skip_witness_signature) ) FC_ASSERT( next_block.validate_signee( witness.signing_key ) ); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 3b7a07f3..3376b2b8 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -107,9 +106,6 @@ const uint8_t withdraw_permission_object::type_id; const uint8_t witness_object::space_id; const uint8_t witness_object::type_id; -const uint8_t witness_schedule_object::space_id; -const uint8_t witness_schedule_object::type_id; - const uint8_t worker_object::space_id; const uint8_t worker_object::type_id; @@ -193,7 +189,6 @@ void database::initialize_indexes() add_index< primary_index> >(); add_index< primary_index> >(); add_index< primary_index> >(); - add_index< primary_index> >(); add_index< primary_index > >(); } @@ -317,6 +312,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) p.time = genesis_state.initial_timestamp; p.dynamic_flags = 0; p.witness_budget = 0; + p.recent_slots_filled = fc::uint128::max_value(); }); FC_ASSERT( (genesis_state.immutable_parameters.min_witness_count & 1) == 1, "min_witness_count must be odd" ); @@ -538,31 +534,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) } }); - // Initialize witness schedule -#ifndef NDEBUG - const witness_schedule_object& wso = -#endif - create([&](witness_schedule_object& _wso) - { - memset(_wso.rng_seed.begin(), 0, _wso.rng_seed.size()); - - witness_scheduler_rng rng(_wso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); - - auto init_witnesses = get_global_properties().active_witnesses; - - _wso.scheduler = witness_scheduler(); - _wso.scheduler._min_token_count = std::max(int(init_witnesses.size()) / 2, 1); - _wso.scheduler.update(init_witnesses); - - for( size_t i=0; i + #include #include @@ -27,7 +29,6 @@ #include #include #include -#include #include namespace graphene { namespace chain { @@ -206,11 +207,6 @@ void database::update_active_witnesses() }); }); - const witness_schedule_object& wso = witness_schedule_id_type()(*this); - modify(wso, [&](witness_schedule_object& _wso) - { - _wso.scheduler.update(gpo.active_witnesses); - }); } FC_CAPTURE_AND_RETHROW() } void database::update_active_committee_members() diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index 52bc39b0..0a6c75ce 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -22,6 +22,7 @@ #include #include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index ded6a04a..e4f8ab86 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -36,25 +36,18 @@ void database::update_global_dynamic_data( const signed_block& b ) const dynamic_global_property_object& _dgp = dynamic_global_property_id_type(0)(*this); - const auto& global_props = get_global_properties(); - auto delta_time = b.timestamp - _dgp.time; - auto missed_blocks = (delta_time.to_seconds() / global_props.parameters.block_interval) - 1; - if( _dgp.head_block_number == 0 ) - missed_blocks = 0; + uint32_t missed_blocks = get_slot_at_time( b.timestamp ); + assert( missed_blocks != 0 ); + missed_blocks--; // dynamic global properties updating modify( _dgp, [&]( dynamic_global_property_object& dgp ){ - secret_hash_type::encoder enc; - fc::raw::pack( enc, dgp.random ); - fc::raw::pack( enc, b.previous_secret ); - dgp.random = enc.result(); - if( _checkpoints.size() && _checkpoints.rbegin()->first >= b.block_num() ) dgp.recently_missed_count = 0; else if( missed_blocks ) - dgp.recently_missed_count += 4*missed_blocks; - else if( dgp.recently_missed_count > 4 ) - dgp.recently_missed_count -= 3; + dgp.recently_missed_count += GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT*missed_blocks; + else if( dgp.recently_missed_count > GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT ) + dgp.recently_missed_count -= GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT; else if( dgp.recently_missed_count > 0 ) dgp.recently_missed_count--; @@ -62,6 +55,10 @@ void database::update_global_dynamic_data( const signed_block& b ) dgp.head_block_id = b.id(); dgp.time = b.timestamp; dgp.current_witness = b.witness; + dgp.recent_slots_filled = ( + (dgp.recent_slots_filled << 1) + + 1) << missed_blocks; + dgp.current_aslot += missed_blocks+1; }); if( !(get_node_properties().skip_flags & skip_undo_history_check) ) @@ -80,6 +77,7 @@ void database::update_signing_witness(const witness_object& signing_witness, con { const global_property_object& gpo = get_global_properties(); const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + uint64_t new_block_aslot = dpo.current_aslot + get_slot_at_time( new_block.timestamp ); share_type witness_pay = std::min( gpo.parameters.witness_pay_per_block, dpo.witness_budget ); @@ -92,8 +90,7 @@ void database::update_signing_witness(const witness_object& signing_witness, con modify( signing_witness, [&]( witness_object& _wit ) { - _wit.previous_secret = new_block.previous_secret; - _wit.next_secret_hash = new_block.next_secret_hash; + _wit.last_aslot = new_block_aslot; } ); } diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 90aab09e..d12bf69e 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -15,45 +15,87 @@ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#pragma once #include - #include -#include +#include namespace graphene { namespace chain { -witness_id_type database::get_scheduled_witness(uint32_t slot_num)const +using boost::container::flat_set; + +witness_id_type database::get_scheduled_witness( uint32_t slot_num )const { - if( slot_num == 0 ) - return witness_id_type(); + // + // Each witness gets an arbitration key H(time, witness_id). + // The witness with the smallest key is selected to go first. + // + // As opposed to just using H(time) to determine an index into + // an array of eligible witnesses, this has the following desirable + // properties: + // + // - Avoid dynamic memory allocation + // - Decreases (but does not eliminate) the probability that a + // missed block will change the witness assigned to a future slot + // + // The hash function is xorshift* as given in + // [1] https://en.wikipedia.org/wiki/Xorshift#Xorshift.2A + // - const witness_schedule_object& wso = witness_schedule_id_type()(*this); + const flat_set< witness_id_type >& active_witnesses = get_global_properties().active_witnesses; + uint32_t n = active_witnesses.size(); + uint64_t min_witness_separation = (n / 2)+1; + uint64_t current_aslot = get_dynamic_global_properties().current_aslot + slot_num; - // ask the near scheduler who goes in the given slot - witness_id_type wid; - bool slot_is_near = wso.scheduler.get_slot(slot_num-1, wid); - if( ! slot_is_near ) + uint64_t start_of_current_round_aslot = current_aslot - (current_aslot % n); + uint64_t first_ineligible_aslot = std::min( + start_of_current_round_aslot, current_aslot - min_witness_separation ); + // + // overflow analysis of above subtraction: + // + // we always have min_witness_separation <= n, so + // if current_aslot < min_witness_separation it follows that + // start_of_current_round_aslot == 0 + // + // therefore result of above min() is 0 when subtraction overflows + // + + first_ineligible_aslot = std::max( first_ineligible_aslot, uint64_t( 1 ) ); + + uint64_t best_k = 0; + witness_id_type best_wit; + bool success = false; + + uint64_t now_hi = get_slot_time( slot_num ).sec_since_epoch(); + now_hi <<= 32; + + for( const witness_id_type& wit_id : active_witnesses ) { - // 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. + const witness_object& wit = wit_id(*this); + if( wit.last_aslot >= first_ineligible_aslot ) + continue; - witness_scheduler_rng far_rng(wso.rng_seed.begin(), GRAPHENE_FAR_SCHEDULE_CTR_IV); - - far_future_witness_scheduler far_scheduler = - far_future_witness_scheduler(wso.scheduler, far_rng); - if( !far_scheduler.get_slot(slot_num-1, wid) ) + uint64_t k = now_hi + uint64_t(wit_id); + k ^= (k >> 12); + k ^= (k << 25); + k ^= (k >> 27); + k *= 2685821657736338717ULL; + if( k >= best_k ) { - // no scheduled witness -- somebody set up us the bomb - // n.b. this code path is impossible, the present - // implementation of far_future_witness_scheduler - // returns true unconditionally - assert( false ); + best_k = k; + best_wit = wit_id; + success = true; } } - return wid; + + // the above loop should choose at least 1 because + // at most K elements are susceptible to the filter, + // otherwise we have an inconsistent database (such as + // wit.last_aslot values that are non-unique or in the future) + + assert( success ); + return best_wit; } fc::time_point_sec database::get_slot_time(uint32_t slot_num)const @@ -98,89 +140,10 @@ uint32_t database::get_slot_at_time(fc::time_point_sec when)const return (when - first_slot_time).to_seconds() / block_interval() + 1; } -vector database::get_near_witness_schedule()const -{ - const witness_schedule_object& wso = witness_schedule_id_type()(*this); - - vector result; - result.reserve(wso.scheduler.size()); - uint32_t slot_num = 0; - witness_id_type wid; - - while( wso.scheduler.get_slot(slot_num++, wid) ) - result.emplace_back(wid); - - return result; -} - -void database::update_witness_schedule(const signed_block& next_block) -{ - auto start = fc::time_point::now(); - const global_property_object& gpo = get_global_properties(); - const witness_schedule_object& wso = get(witness_schedule_id_type()); - uint32_t schedule_needs_filled = gpo.active_witnesses.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 ); - witness_id_type first_witness; - bool slot_is_near = wso.scheduler.get_slot( schedule_slot-1, first_witness ); - - witness_id_type wit; - - 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 == wso.rng_seed.size() ); - - modify(wso, [&](witness_schedule_object& _wso) - { - _wso.slots_since_genesis += schedule_slot; - 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); - - if( slot_is_near ) - { - 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) ) - { - if( _wso.scheduler.produce_schedule(rng) & emit_turn ) - memcpy(_wso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size()); - } - _wso.last_scheduling_block = next_block.block_num(); - _wso.recent_slots_filled = ( - (_wso.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::witness_participation_rate()const { - const witness_schedule_object& wso = get(witness_schedule_id_type()); - return uint64_t(GRAPHENE_100_PERCENT) * wso.recent_slots_filled.popcount() / 128; + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + return uint64_t(GRAPHENE_100_PERCENT) * dpo.recent_slots_filled.popcount() / 128; } } } diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index f77f7144..38d3db6d 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -139,6 +139,9 @@ #define GRAPHENE_MAX_INTEREST_APR uint16_t( 10000 ) +#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4 +#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3 + /** * Reserved Account IDs with special meaning */ diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 99df3cb0..ec197889 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -244,11 +244,6 @@ namespace graphene { namespace chain { */ uint32_t get_slot_at_time(fc::time_point_sec when)const; - /** - * Get the near schedule. - */ - vector get_near_witness_schedule()const; - //////////////////// db_getter.cpp //////////////////// const chain_id_type& get_chain_id()const; @@ -451,9 +446,6 @@ namespace graphene { namespace chain { void update_maintenance_flag( bool new_maintenance_flag ); void update_withdraw_permissions(); - //////////////////// db_witness_schedule.cpp //////////////////// - void update_witness_schedule(const signed_block& next_block); /// no-op except for scheduling blocks - ///Steps performed only at maintenance intervals ///@{ diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index dacb5ce2..c52997fb 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -42,7 +42,7 @@ namespace graphene { namespace chain { chain_parameters parameters; optional pending_parameters; - uint32_t next_available_vote_id = 0; + uint32_t next_available_vote_id = 0; vector active_committee_members; // updated once per maintenance interval flat_set active_witnesses; // updated once per maintenance interval // n.b. witness scheduling is done by witness_schedule object @@ -64,7 +64,6 @@ namespace graphene { namespace chain { static const uint8_t space_id = implementation_ids; static const uint8_t type_id = impl_dynamic_global_property_object_type; - secret_hash_type random; uint32_t head_block_number = 0; block_id_type head_block_id; time_point_sec time; @@ -74,13 +73,28 @@ namespace graphene { namespace chain { share_type witness_budget; uint32_t accounts_registered_this_interval = 0; /** - * Every time a block is missed this increases by 2, every time a block is found it decreases by 1 it is - * never less than 0 + * Every time a block is missed this increases by + * RECENTLY_MISSED_COUNT_INCREMENT, + * every time a block is found it decreases by + * RECENTLY_MISSED_COUNT_DECREMENT. It is + * never less than 0. * - * If the recently_missed_count hits 2*UNDO_HISTORY then no ew blocks may be pushed. + * If the recently_missed_count hits 2*UNDO_HISTORY then no new blocks may be pushed. */ uint32_t recently_missed_count = 0; + /** + * The current absolute slot number. Equal to the total + * number of slots since genesis. Also equal to the total + * number of missed slots plus head_block_number. + */ + uint64_t current_aslot = 0; + + /** + * used to compute witness participation. + */ + fc::uint128_t recent_slots_filled; + /** * dynamic_flags specifies chain state properties that can be * expressed in one bit. @@ -104,7 +118,6 @@ namespace graphene { namespace chain { }} FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene::db::object), - (random) (head_block_number) (head_block_id) (time) @@ -113,6 +126,8 @@ FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene:: (witness_budget) (accounts_registered_this_interval) (recently_missed_count) + (current_aslot) + (recent_slots_filled) (dynamic_flags) ) diff --git a/libraries/chain/include/graphene/chain/protocol/block.hpp b/libraries/chain/include/graphene/chain/protocol/block.hpp index d9e882a1..34b0cfc2 100644 --- a/libraries/chain/include/graphene/chain/protocol/block.hpp +++ b/libraries/chain/include/graphene/chain/protocol/block.hpp @@ -27,8 +27,6 @@ namespace graphene { namespace chain { uint32_t block_num()const { return num_from_id(previous) + 1; } fc::time_point_sec timestamp; witness_id_type witness; - secret_hash_type next_secret_hash; - secret_hash_type previous_secret; checksum_type transaction_merkle_root; extensions_type extensions; @@ -53,7 +51,6 @@ namespace graphene { namespace chain { } } // graphene::chain -FC_REFLECT( graphene::chain::block_header, (previous)(timestamp)(witness) - (next_secret_hash)(previous_secret)(transaction_merkle_root)(extensions) ) +FC_REFLECT( graphene::chain::block_header, (previous)(timestamp)(witness)(transaction_merkle_root)(extensions) ) FC_REFLECT_DERIVED( graphene::chain::signed_block_header, (graphene::chain::block_header), (witness_signature) ) FC_REFLECT_DERIVED( graphene::chain::signed_block, (graphene::chain::signed_block_header), (transactions) ) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index af8a2ace..17b4049c 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -140,7 +140,6 @@ namespace graphene { namespace chain { impl_transaction_object_type, impl_block_summary_object_type, impl_account_transaction_history_object_type, - impl_witness_schedule_object_type, impl_blinded_balance_object_type, impl_chain_property_object_type }; @@ -165,7 +164,6 @@ namespace graphene { namespace chain { class operation_history_object; class withdraw_permission_object; class vesting_balance_object; - class witness_schedule_object; class worker_object; class balance_object; @@ -209,7 +207,6 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_account_transaction_history_object_type, account_transaction_history_object> account_transaction_history_id_type; - typedef object_id< implementation_ids, impl_witness_schedule_object_type, witness_schedule_object > witness_schedule_id_type; typedef object_id< implementation_ids, impl_chain_property_object_type, chain_property_object> chain_property_id_type; typedef fc::array symbol_type; @@ -286,7 +283,6 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, (impl_transaction_object_type) (impl_block_summary_object_type) (impl_account_transaction_history_object_type) - (impl_witness_schedule_object_type) (impl_blinded_balance_object_type) (impl_chain_property_object_type) ) @@ -317,7 +313,6 @@ FC_REFLECT_TYPENAME( graphene::chain::account_statistics_id_type ) FC_REFLECT_TYPENAME( graphene::chain::transaction_obj_id_type ) FC_REFLECT_TYPENAME( graphene::chain::block_summary_id_type ) FC_REFLECT_TYPENAME( graphene::chain::account_transaction_history_id_type ) -FC_REFLECT_TYPENAME( graphene::chain::witness_schedule_id_type ) FC_REFLECT( graphene::chain::void_t, ) FC_REFLECT_ENUM( graphene::chain::asset_issuer_permission_flags, (charge_market_fee)(white_list)(transfer_restricted)(override_authority)(disable_force_settle)(global_settle)(disable_confidential) ) diff --git a/libraries/chain/include/graphene/chain/witness_object.hpp b/libraries/chain/include/graphene/chain/witness_object.hpp index 17b94ed5..0576df6c 100644 --- a/libraries/chain/include/graphene/chain/witness_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_object.hpp @@ -32,6 +32,7 @@ namespace graphene { namespace chain { static const uint8_t type_id = witness_object_type; account_id_type witness_account; + uint64_t last_aslot = 0; public_key_type signing_key; secret_hash_type next_secret_hash; secret_hash_type previous_secret; @@ -64,9 +65,8 @@ namespace graphene { namespace chain { FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object), (witness_account) + (last_aslot) (signing_key) - (next_secret_hash) - (previous_secret) (pay_vb) (vote_id) (total_votes) diff --git a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp deleted file mode 100644 index cd11ebca..00000000 --- a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2015, Cryptonomex, Inc. - * All rights reserved. - * - * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and - * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, - * are permitted until September 8, 2015, provided that the following conditions are met: - * - * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#pragma once - -// needed to serialize witness_scheduler -#include -#include - -#include -#include -#include - -namespace graphene { namespace chain { - -typedef hash_ctr_rng< - /* HashClass = */ fc::sha256, - /* SeedLength = */ GRAPHENE_RNG_SEED_LENGTH - > witness_scheduler_rng; - -typedef generic_witness_scheduler< - /* WitnessID = */ witness_id_type, - /* RNG = */ witness_scheduler_rng, - /* CountType = */ decltype( chain_parameters::maximum_witness_count ), - /* OffsetType = */ uint32_t, - /* debug = */ true - > witness_scheduler; - -typedef generic_far_future_witness_scheduler< - /* WitnessID = */ witness_id_type, - /* RNG = */ witness_scheduler_rng, - /* CountType = */ decltype( chain_parameters::maximum_witness_count ), - /* OffsetType = */ uint32_t, - /* debug = */ true - > far_future_witness_scheduler; - -class witness_schedule_object : public abstract_object -{ - public: - static const uint8_t space_id = implementation_ids; - static const uint8_t type_id = impl_witness_schedule_object_type; - - witness_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; -}; - -} } - -FC_REFLECT( graphene::chain::witness_scheduler, - (_turns) - (_tokens) - (_min_token_count) - (_ineligible_waiting_for_token) - (_ineligible_no_turn) - (_eligible) - (_schedule) - (_lame_duck) - ) - -FC_REFLECT_DERIVED( graphene::chain::witness_schedule_object, (graphene::chain::object), - (scheduler) - (last_scheduling_block) - (slots_since_genesis) - (rng_seed) - (recent_slots_filled) - ) diff --git a/libraries/chain/include/graphene/chain/witness_scheduler.hpp b/libraries/chain/include/graphene/chain/witness_scheduler.hpp deleted file mode 100644 index 5feef417..00000000 --- a/libraries/chain/include/graphene/chain/witness_scheduler.hpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (c) 2015, Cryptonomex, Inc. - * All rights reserved. - * - * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and - * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, - * are permitted until September 8, 2015, provided that the following conditions are met: - * - * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#pragma once - -#include -#include -#include -#include - -#include - -namespace graphene { namespace chain { - -//using boost::container::flat_set; - -enum witness_scheduler_relax_flags -{ - emit_turn = 0x01, - emit_token = 0x02 -}; - -template< typename WitnessID, typename RNG, typename CountType, typename OffsetType, bool debug = true > -class generic_witness_scheduler -{ - public: - void check_invariant() const - { -#ifndef NDEBUG - CountType tokens = _ineligible_no_turn.size() + _eligible.size(); - CountType turns = _eligible.size(); - for( const std::pair< WitnessID, bool >& item : _ineligible_waiting_for_token ) - turns += (item.second ? 1 : 0 ); - - assert( _tokens == tokens ); - assert( _turns == turns ); -#endif - - set< WitnessID > witness_set; - // make sure each witness_id occurs only once among the three states - auto process_id = [&]( WitnessID item ) - { - assert( witness_set.find( item ) == witness_set.end() ); - witness_set.insert( item ); - } ; - - for( const std::pair< WitnessID, bool >& item : _ineligible_waiting_for_token ) - process_id( item.first ); - for( const WitnessID& item : _ineligible_no_turn ) - process_id( item ); - for( const WitnessID& item : _eligible ) - process_id( item ); - return; - } - - /** - * Deterministically evolve over time - */ - uint32_t relax() - { - uint32_t relax_flags = 0; - - if( debug ) check_invariant(); - assert( _min_token_count > 0 ); - - // turn distribution - if( _turns == 0 ) - { - relax_flags |= emit_turn; - for( const WitnessID& item : _ineligible_no_turn ) - _eligible.push_back( item ); - _turns += _ineligible_no_turn.size(); - _ineligible_no_turn.clear(); - if( debug ) check_invariant(); - - for( std::pair< WitnessID, bool >& item : _ineligible_waiting_for_token ) - { - assert( item.second == false ); - item.second = true; - } - _turns += _ineligible_waiting_for_token.size(); - if( debug ) check_invariant(); - } - - // token distribution - while( true ) - { - if( _ineligible_waiting_for_token.empty() ) - { - // eligible must be non-empty - assert( !_eligible.empty() ); - return relax_flags; - } - - if( _tokens >= _min_token_count ) - { - if( !_eligible.empty() ) - return relax_flags; - } - - const std::pair< WitnessID, bool >& item = _ineligible_waiting_for_token.front(); - if( item.second ) - _eligible.push_back( item.first ); - else - _ineligible_no_turn.push_back( item.first ); - _ineligible_waiting_for_token.pop_front(); - relax_flags |= emit_token; - _tokens++; - if( debug ) check_invariant(); - } - - return relax_flags; - } - - /** - * Add another element to _schedule - */ - uint32_t produce_schedule( RNG& rng ) - { - uint32_t relax_flags = relax(); - if( debug ) check_invariant(); - if( _eligible.empty() ) - return relax_flags; - - decltype( rng( _eligible.size() ) ) pos = rng( _eligible.size() ); - assert( (pos >= 0) && (pos < _eligible.size()) ); - auto it = _eligible.begin() + pos; - _schedule.push_back( *it ); - _ineligible_waiting_for_token.emplace_back( *it, false ); - _eligible.erase( it ); - _turns--; - _tokens--; - if( debug ) check_invariant(); - return relax_flags; - } - - /** - * Pull an element from _schedule - */ - WitnessID consume_schedule() - { - assert( _schedule.size() > 0 ); - - WitnessID result = _schedule.front(); - _schedule.pop_front(); - - auto it = _lame_duck.find( result ); - if( it != _lame_duck.end() ) - _lame_duck.erase( it ); - if( debug ) check_invariant(); - return result; - } - - /** - * Remove all witnesses in the removal_set from - * future scheduling (but not from the current schedule). - */ - template< typename T > - void remove_all( const T& removal_set ) - { - if( debug ) check_invariant(); - - _ineligible_waiting_for_token.erase( - std::remove_if( - _ineligible_waiting_for_token.begin(), - _ineligible_waiting_for_token.end(), - [&]( const std::pair< WitnessID, bool >& item ) -> bool - { - bool found = removal_set.find( item.first ) != removal_set.end(); - _turns -= (found & item.second) ? 1 : 0; - return found; - } ), - _ineligible_waiting_for_token.end() ); - if( debug ) check_invariant(); - - _ineligible_no_turn.erase( - std::remove_if( - _ineligible_no_turn.begin(), - _ineligible_no_turn.end(), - [&]( WitnessID item ) -> bool - { - bool found = (removal_set.find( item ) != removal_set.end()); - _tokens -= (found ? 1 : 0); - return found; - } ), - _ineligible_no_turn.end() ); - if( debug ) check_invariant(); - - _eligible.erase( - std::remove_if( - _eligible.begin(), - _eligible.end(), - [&]( WitnessID item ) -> bool - { - bool found = (removal_set.find( item ) != removal_set.end()); - _tokens -= (found ? 1 : 0); - _turns -= (found ? 1 : 0); - return found; - } ), - _eligible.end() ); - if( debug ) check_invariant(); - - return; - } - - /** - * Convenience function to call insert_all() and remove_all() - * as needed to update to the given revised_set. - */ - template< typename T > - void insert_all( const T& insertion_set ) - { - if( debug ) check_invariant(); - for( const WitnessID wid : insertion_set ) - { - _eligible.push_back( wid ); - } - _turns += insertion_set.size(); - _tokens += insertion_set.size(); - if( debug ) check_invariant(); - return; - } - - /** - * Convenience function to call insert_all() and remove_all() - * as needed to update to the given revised_set. - * - * This function calls find() on revised_set for all current - * witnesses. Running time is O(n*log(n)) if the revised_set - * implementation of find() is O(log(n)). - * - * TODO: Rewriting to use std::set_difference may marginally - * increase efficiency, but a benchmark is needed to justify this. - */ - template< typename T > - void update( const T& revised_set ) - { - set< WitnessID > current_set; - set< WitnessID > schedule_set; - - /* current_set.reserve( - _ineligible_waiting_for_token.size() - + _ineligible_no_turn.size() - + _eligible.size() - + _schedule.size() ); - */ - for( const auto& item : _ineligible_waiting_for_token ) - current_set.insert( item.first ); - for( const WitnessID& item : _ineligible_no_turn ) - current_set.insert( item ); - for( const WitnessID& item : _eligible ) - current_set.insert( item ); - for( const WitnessID& item : _schedule ) - { - current_set.insert( item ); - schedule_set.insert( item ); - } - - set< WitnessID > insertion_set; - //insertion_set.reserve( revised_set.size() ); - for( const WitnessID& item : revised_set ) - { - if( current_set.find( item ) == current_set.end() ) - insertion_set.insert( item ); - } - - set< WitnessID > removal_set; - //removal_set.reserve( current_set.size() ); - for( const WitnessID& item : current_set ) - { - if( revised_set.find( item ) == revised_set.end() ) - { - if( schedule_set.find( item ) == schedule_set.end() ) - removal_set.insert( item ); - else - _lame_duck.insert( item ); - } - } - - insert_all( insertion_set ); - remove_all( removal_set ); - - return; - } - - /** - * Get the number of scheduled witnesses - */ - - size_t size( )const - { - return _schedule.size(); - } - - bool get_slot( OffsetType offset, WitnessID& wit )const - { - if( offset >= _schedule.size() ) - return false; - wit = _schedule[ offset ]; - 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; - - // new tokens handed out when _tokens < _min_token_count - CountType _min_token_count; - - // WitnessID appears in exactly one of the following: - // has no token; second indicates whether we have a turn or not: - std::deque < std::pair< WitnessID, bool > > _ineligible_waiting_for_token; // ".." | "T." - // has token, but no turn - std::vector< WitnessID > _ineligible_no_turn; // ".t" - // has token and turn - std::vector< WitnessID > _eligible; // "Tt" - - // scheduled - std::deque < WitnessID > _schedule; - - // in _schedule, but not to be replaced - set< WitnessID > _lame_duck; -}; - -template< typename WitnessID, typename RNG, typename CountType, typename OffsetType, bool debug = true > -class generic_far_future_witness_scheduler -{ - public: - generic_far_future_witness_scheduler( - const generic_witness_scheduler< WitnessID, RNG, CountType, OffsetType, debug >& base_scheduler, - RNG rng - ) - { - generic_witness_scheduler< WitnessID, RNG, CountType, OffsetType, debug > extended_scheduler = base_scheduler; - _begin_offset = base_scheduler.size()+1; - while( (extended_scheduler.produce_schedule( rng ) & emit_turn) == 0 ) - _begin_offset++; - assert( _begin_offset == extended_scheduler.size() ); - - _end_offset = _begin_offset; - while( (extended_scheduler.produce_schedule( rng ) & emit_turn) == 0 ) - _end_offset++; - assert( _end_offset == extended_scheduler.size()-1 ); - _schedule.resize( extended_scheduler._schedule.size() ); - std::copy( extended_scheduler._schedule.begin(), - extended_scheduler._schedule.end(), - _schedule.begin() ); - return; - } - - bool get_slot( OffsetType offset, WitnessID& wit )const - { - if( offset <= _end_offset ) - wit = _schedule[ offset ]; - else - wit = _schedule[ _begin_offset + - ( - (offset - _begin_offset) % - (_end_offset + 1 - _begin_offset) - ) ]; - return true; - } - - std::vector< WitnessID > _schedule; - OffsetType _begin_offset; - OffsetType _end_offset; -}; - -} } diff --git a/libraries/chain/include/graphene/chain/witness_scheduler_rng.hpp b/libraries/chain/include/graphene/chain/witness_scheduler_rng.hpp deleted file mode 100644 index e7467010..00000000 --- a/libraries/chain/include/graphene/chain/witness_scheduler_rng.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2015, Cryptonomex, Inc. - * All rights reserved. - * - * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and - * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, - * are permitted until September 8, 2015, provided that the following conditions are met: - * - * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#pragma once - -#include - -namespace graphene { namespace chain { - -/** - * Always returns 0. Useful for testing. - */ -class nullary_rng -{ - public: - nullary_rng() {} - virtual ~nullary_rng() {} - - template< typename T > T operator()( T max ) - { return T(0); } -} ; - -/** - * The sha256_ctr_rng generates bits using SHA256 in counter (CTR) - * mode. - */ -template< class HashClass, int SeedLength=sizeof(secret_hash_type) > -class hash_ctr_rng -{ - public: - hash_ctr_rng( const char* seed, uint64_t counter = 0 ) - : _counter( counter ), _current_offset( 0 ) - { - memcpy( _seed, seed, SeedLength ); - _reset_current_value(); - return; - } - - virtual ~hash_ctr_rng() {} - - uint64_t get_bits( uint8_t count ) - { - uint64_t result = 0; - uint64_t mask = 1; - // grab the requested number of bits - while( count > 0 ) - { - result |= - ( - ( - ( - _current_value.data()[ (_current_offset >> 3) & 0x1F ] - & ( 1 << (_current_offset & 0x07) ) - ) - != 0 - ) ? mask : 0 - ); - mask += mask; - --count; - ++_current_offset; - if( _current_offset == (_current_value.data_size() << 3) ) - { - _counter++; - _current_offset = 0; - _reset_current_value(); - } - } - return result; - } - - uint64_t operator()( uint64_t bound ) - { - if( bound <= 1 ) - return 0; - uint8_t bitcount = boost::multiprecision::detail::find_msb( bound ) + 1; - - // probability of loop exiting is >= 1/2, so probability of - // running N times is bounded above by (1/2)^N - while( true ) - { - uint64_t result = get_bits( bitcount ); - if( result < bound ) - return result; - } - } - - // convenience method which does casting for types other than uint64_t - template< typename T > T operator()( T bound ) - { return (T) ( (*this)(uint64_t( bound )) ); } - - void _reset_current_value() - { - // internal implementation detail, called to update - // _current_value when _counter changes - typename HashClass::encoder enc; - enc.write( _seed , SeedLength ); - enc.write( (char *) &_counter, 8 ); - _current_value = enc.result(); - return; - } - - uint64_t _counter; - char _seed[ SeedLength ]; - HashClass _current_value; - uint16_t _current_offset; - - static const int seed_length = SeedLength; -} ; - -} } diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index a7567c57..47aeed33 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -478,7 +478,6 @@ public: result["chain_id"] = chain_props.chain_id; result["active_witnesses"] = global_props.active_witnesses; result["active_committee_members"] = global_props.active_committee_members; - result["entropy"] = dynamic_props.random; return result; } chain_property_object get_chain_properties() const diff --git a/programs/size_checker/main.cpp b/programs/size_checker/main.cpp index 5950f6aa..9ef4420a 100644 --- a/programs/size_checker/main.cpp +++ b/programs/size_checker/main.cpp @@ -85,6 +85,7 @@ int main( int argc, char** argv ) std::cout << "\n"; } std::cout << "]\n"; + std::cerr << "Size of block header: " << sizeof( block_header ) << " " << fc::raw::pack_size( block_header() ) << "\n"; } catch ( const fc::exception& e ){ edump((e.to_detail_string())); } idump((sizeof(signed_block))); diff --git a/tests/intense/block_tests.cpp b/tests/intense/block_tests.cpp index fd77132e..7e975537 100644 --- a/tests/intense/block_tests.cpp +++ b/tests/intense/block_tests.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index 8b92ec4e..e016571b 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -166,7 +165,6 @@ BOOST_AUTO_TEST_CASE( price_test ) BOOST_CHECK(dummy == dummy2); } - BOOST_AUTO_TEST_CASE( memo_test ) { try { memo_data m; @@ -186,134 +184,6 @@ BOOST_AUTO_TEST_CASE( memo_test ) BOOST_CHECK_EQUAL(m.get_message(receiver, sender.get_public_key()), "Hello, world!"); } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE( witness_rng_test_bits ) -{ - try - { - const uint64_t COUNT = 131072; - const uint64_t HASH_SIZE = 32; - string ref_bits = ""; - ref_bits.reserve( COUNT * HASH_SIZE ); - static const char seed_data[] = "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55"; - - for( uint64_t i=0; i> 0x08) & 0xFF) ); - enc.put( char((i >> 0x10) & 0xFF) ); - enc.put( char((i >> 0x18) & 0xFF) ); - enc.put( char((i >> 0x20) & 0xFF) ); - enc.put( char((i >> 0x28) & 0xFF) ); - enc.put( char((i >> 0x30) & 0xFF) ); - enc.put( char((i >> 0x38) & 0xFF) ); - - fc::sha256 result = enc.result(); - auto result_data = result.data(); - std::copy( result_data, result_data+HASH_SIZE, std::back_inserter( ref_bits ) ); - } - - fc::sha256 seed = fc::sha256::hash( string("") ); - // seed = sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - BOOST_CHECK( memcmp( seed.data(), seed_data, HASH_SIZE ) == 0 ); - - hash_ctr_rng< fc::sha256, 32 > test_rng(seed.data(), 0); - // python2 -c 'import hashlib; import struct; h = lambda x : hashlib.sha256(x).digest(); i = lambda x : struct.pack(" uint64_t - { - uint64_t result = 0; - uint64_t i = ref_get_bits_offset; - uint64_t mask = 1; - while( count > 0 ) - { - if( ref_bits[ i >> 3 ] & (1 << (i & 7)) ) - result |= mask; - mask += mask; - i++; - count--; - } - ref_get_bits_offset = i; - return result; - }; - - // use PRNG to decide between 0-64 bits - std::minstd_rand rng; - rng.seed( 9999 ); - std::uniform_int_distribution< uint16_t > bit_dist( 0, 64 ); - for( int i=0; i<10000; i++ ) - { - uint8_t bit_count = bit_dist( rng ); - uint64_t ref_bits = ref_get_bits( bit_count ); - uint64_t test_bits = test_rng.get_bits( bit_count ); - //std::cout << i << ": get(" << int(bit_count) << ") -> " << test_bits << " (expect " << ref_bits << ")\n"; - if( bit_count < 64 ) - { - BOOST_CHECK( ref_bits < (uint64_t( 1 ) << bit_count ) ); - BOOST_CHECK( test_bits < (uint64_t( 1 ) << bit_count ) ); - } - BOOST_CHECK( ref_bits == test_bits ); - if( ref_bits != test_bits ) - break; - } - - std::uniform_int_distribution< uint64_t > whole_dist( - 0, std::numeric_limits::max() ); - for( int i=0; i<10000; i++ ) - { - uint8_t bit_count = bit_dist( rng ); - uint64_t bound = whole_dist( rng ) & ((uint64_t(1) << bit_count) - 1); - //std::cout << "bound:" << bound << "\n"; - uint64_t rnum = test_rng( bound ); - //std::cout << "rnum:" << rnum << "\n"; - if( bound > 1 ) - { - BOOST_CHECK( rnum < bound ); - } - else - { - BOOST_CHECK( rnum == 0 ); - } - } - - } FC_LOG_AND_RETHROW() -} - BOOST_AUTO_TEST_CASE( exceptions ) { GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(balance_claim_invalid_claim_amount, "Etc"), balance_claim_invalid_claim_amount); diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index d8301856..e6677213 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include @@ -644,7 +643,6 @@ BOOST_FIXTURE_TEST_CASE( maintenance_interval, database_fixture ) initial_properties.parameters.maximum_transaction_size); BOOST_CHECK_EQUAL(db.get_dynamic_global_properties().next_maintenance_time.sec_since_epoch(), db.head_block_time().sec_since_epoch() + db.get_global_properties().parameters.block_interval); - // shuffling is now handled by the witness_schedule_object. BOOST_CHECK(db.get_global_properties().active_witnesses == initial_properties.active_witnesses); BOOST_CHECK(db.get_global_properties().active_committee_members == initial_properties.active_committee_members); @@ -870,32 +868,6 @@ BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) } } -BOOST_FIXTURE_TEST_CASE( witness_scheduler_missed_blocks, database_fixture ) -{ try { - db.get_near_witness_schedule(); - generate_block(); - auto near_schedule = db.get_near_witness_schedule(); - - std::for_each(near_schedule.begin(), near_schedule.end(), [&](witness_id_type id) { - generate_block(0); - BOOST_CHECK(db.get_dynamic_global_properties().current_witness == id); - }); - - near_schedule = db.get_near_witness_schedule(); - generate_block(0, init_account_priv_key, 2); - BOOST_CHECK(db.get_dynamic_global_properties().current_witness == near_schedule[2]); - - near_schedule.erase(near_schedule.begin(), near_schedule.begin() + 3); - auto new_schedule = db.get_near_witness_schedule(); - new_schedule.erase(new_schedule.end() - 3, new_schedule.end()); - BOOST_CHECK(new_schedule == near_schedule); - - std::for_each(near_schedule.begin(), near_schedule.end(), [&](witness_id_type id) { - generate_block(0); - BOOST_CHECK(db.get_dynamic_global_properties().current_witness == id); - }); -} FC_LOG_AND_RETHROW() } - BOOST_FIXTURE_TEST_CASE( rsf_missed_blocks, database_fixture ) { try @@ -904,7 +876,7 @@ BOOST_FIXTURE_TEST_CASE( rsf_missed_blocks, database_fixture ) auto rsf = [&]() -> string { - fc::uint128 rsf = db.get( witness_schedule_id_type() ).recent_slots_filled; + fc::uint128 rsf = db.get_dynamic_global_properties().recent_slots_filled; string result = ""; result.reserve(128); for( int i=0; i<128; i++ ) diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 59c34c92..925c8a8d 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -443,34 +443,15 @@ BOOST_AUTO_TEST_CASE( witness_create ) auto itr = std::find(witnesses.begin(), witnesses.end(), nathan_witness_id); BOOST_CHECK(itr != witnesses.end()); - generate_blocks(witnesses.size()); - - // make sure we're scheduled to produce - vector near_witnesses = db.get_near_witness_schedule(); - BOOST_CHECK( std::find( near_witnesses.begin(), near_witnesses.end(), nathan_witness_id ) - != near_witnesses.end() ); - - struct generator_helper { - database_fixture& f; - witness_id_type nathan_id; - fc::ecc::private_key nathan_key; - bool nathan_generated_block; - - void operator()(witness_id_type id) { - if( id == nathan_id ) - { - nathan_generated_block = true; - f.generate_block(0, nathan_key); - } else - f.generate_block(0); - BOOST_CHECK_EQUAL(f.db.get_dynamic_global_properties().current_witness.instance.value, id.instance.value); - f.db.get_near_witness_schedule(); - } - }; - - generator_helper h = std::for_each(near_witnesses.begin(), near_witnesses.end(), - generator_helper{*this, nathan_witness_id, nathan_private_key, false}); - BOOST_CHECK(h.nathan_generated_block); + int produced = 0; + // Make sure we get scheduled exactly once in witnesses.size() blocks + // TODO: intense_test that repeats this loop many times + for( size_t i=0; i