diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 3e87beae..28e15602 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -73,14 +73,4 @@ node_property_object& database::node_properties() return _node_property_object; } -double database::witness_participation_rate()const -{ - if( head_block_num() < 10 ) return 1; // sample size is too small - uint32_t produced = std::min( head_block_num()-1, 100 ); - auto prior = fetch_block_by_number( head_block_num() - produced ); - auto delta_time = head_block_time() - prior->timestamp; - auto expected_slots = delta_time.to_seconds() / get_global_properties().parameters.block_interval; - return double(produced) / expected_slots; -} - } } diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index bf3e16bf..ffd928a3 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -525,6 +525,8 @@ void database::init_genesis(const genesis_state_type& genesis_state) _wso.scheduler.produce_schedule(rng); _wso.last_scheduling_block = 0; + + _wso.recent_slots_filled = fc::uint128::max_value(); }); assert( wso.id == witness_schedule_id_type() ); diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 4585e605..d233c8bf 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -141,6 +141,16 @@ void database::update_witness_schedule(const signed_block& next_block) 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); }); } + +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; +} + } } diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index bbd001d6..0500f834 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -138,9 +138,9 @@ namespace graphene { namespace chain { /** * Calculate the percent of block production slots that were missed in the - * past 100 blocks. + * past 128 blocks, not including the current block. */ - double witness_participation_rate()const; + uint32_t witness_participation_rate()const; void add_checkpoints( const flat_map& checkpts ); const flat_map get_checkpoints()const { return _checkpoints; } diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 67d7e7b5..4b83b993 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -16,6 +16,8 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once +#include + #include #include #include diff --git a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp index 5661651c..cd11ebca 100644 --- a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp @@ -19,6 +19,7 @@ // needed to serialize witness_scheduler #include +#include #include #include @@ -57,6 +58,12 @@ class witness_schedule_object : public abstract_object 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; }; } } @@ -77,4 +84,5 @@ FC_REFLECT_DERIVED( graphene::chain::witness_schedule_object, (graphene::chain:: (last_scheduling_block) (slots_since_genesis) (rng_seed) + (recent_slots_filled) ) diff --git a/libraries/fc b/libraries/fc index 03916654..5f43c06b 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 0391665471b4dffb7af951853a777565a7ae9a74 +Subproject commit 5f43c06bae6d03e319dd2f230fe7cbd74399a773 diff --git a/libraries/plugins/witness/include/graphene/witness/witness.hpp b/libraries/plugins/witness/include/graphene/witness/witness.hpp index 0f5bbdb2..3d2dc0bc 100644 --- a/libraries/plugins/witness/include/graphene/witness/witness.hpp +++ b/libraries/plugins/witness/include/graphene/witness/witness.hpp @@ -57,7 +57,7 @@ private: boost::program_options::variables_map _options; bool _production_enabled = false; bool _consecutive_production_enabled = false; - int _required_witness_participation = 33; + uint32_t _required_witness_participation = 33 * GRAPHENE_1_PERCENT; std::map _private_keys; std::set _witnesses; diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index bd336c83..c48184da 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -39,7 +39,7 @@ void witness_plugin::plugin_set_program_options( string witness_id_example = fc::json::to_string(chain::witness_id_type()); command_line_options.add_options() ("enable-stale-production", bpo::bool_switch()->notifier([this](bool e){_production_enabled = e;}), "Enable block production, even if the chain is stale.") - ("required-participation", bpo::bool_switch()->notifier([this](int e){_required_witness_participation = e;}), "Percent of witnesses (0-99) that must be participating in order to produce blocks") + ("required-participation", bpo::bool_switch()->notifier([this](int e){_required_witness_participation = uint32_t(e*GRAPHENE_1_PERCENT);}), "Percent of witnesses (0-99) that must be participating in order to produce blocks") ("allow-consecutive", bpo::bool_switch()->notifier([this](bool e){_consecutive_production_enabled = e;}), "Allow block production, even if the last block was produced by the same witness.") ("witness-id,w", bpo::value>()->composing()->multitoken(), ("ID of witness controlled by this node (e.g. " + witness_id_example + ", quotes are required, may specify multiple times)").c_str()) @@ -191,11 +191,11 @@ void witness_plugin::block_production_loop() return false; } - double prate = db.witness_participation_rate(); - if( int(100*prate) < _required_witness_participation ) + uint32_t prate = db.witness_participation_rate(); + if( prate < _required_witness_participation ) { elog("Not producing block because node appers to be on a minority fork with only ${x}% witness participation", - ("x",uint32_t(100*prate) ) ); + ("x",uint32_t(100*uint64_t(prate) / GRAPHENE_1_PERCENT) ) ); return false; }