diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 2afb64e3..dd0e890b 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -395,6 +395,7 @@ void database::_apply_block( const signed_block& next_block ) const witness_object& signing_witness = validate_block_header(skip, next_block); const auto& global_props = get_global_properties(); const auto& dynamic_global_props = get(dynamic_global_property_id_type()); + bool maint_needed = (dynamic_global_props.next_maintenance_time <= next_block.timestamp); _current_block_num = next_block.block_num(); _current_trx_in_block = 0; @@ -418,7 +419,7 @@ void database::_apply_block( const signed_block& next_block ) auto current_block_interval = global_props.parameters.block_interval; // Are we at the maintenance interval? - if( dynamic_global_props.next_maintenance_time <= next_block.timestamp ) + if( maint_needed ) // This will update _pending_block.timestamp if the block interval has changed perform_chain_maintenance(next_block, global_props); @@ -429,6 +430,13 @@ void database::_apply_block( const signed_block& next_block ) update_expired_feeds(); update_withdraw_permissions(); + // n.b., update_maintenance_flag() happens this late + // because get_slot_time() / get_slot_at_time() is needed above + // TODO: figure out if we could collapse this function into + // update_global_dynamic_data() as perhaps these methods only need + // to be called for header validation? + update_maintenance_flag( maint_needed ); + // notify observers that the block has been applied applied_block( next_block ); //emit _applied_ops.clear(); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index f02a7daf..88adb318 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -312,6 +312,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); create([&](dynamic_global_property_object& p) { p.time = genesis_state.initial_timestamp; + p.dynamic_flags = 0; p.witness_budget = 0; }); create([&](block_summary_object&) {}); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index da5f4d7f..4370d81b 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -261,6 +261,18 @@ void database::update_expired_feeds() } } +void database::update_maintenance_flag( bool new_maintenance_flag ) +{ + modify( get_dynamic_global_properties(), [&]( dynamic_global_property_object& dpo ) + { + auto maintenance_flag = dynamic_global_property_object::maintenance_flag; + dpo.dynamic_flags = + (dpo.dynamic_flags & ~maintenance_flag) + | (new_maintenance_flag ? maintenance_flag : 0); + } ); + return; +} + void database::update_withdraw_permissions() { auto& permit_index = get_index_type().indices().get(); diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 657253d2..c2c7cd23 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -447,6 +447,7 @@ namespace graphene { namespace chain { void clear_expired_proposals(); void clear_expired_orders(); void update_expired_feeds(); + void update_maintenance_flag( bool new_maintenance_flag ); void update_withdraw_permissions(); //////////////////// db_witness_schedule.cpp //////////////////// diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index c3d61cc9..addad7f9 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -82,13 +82,25 @@ namespace graphene { namespace chain { */ uint32_t recently_missed_count = 0; - /** if the interval changes then how we calculate witness participation will - * also change. Normally witness participation is defined as % of blocks - * produced in the last round which is calculated by dividing the delta - * time between block N and N-NUM_WITNESSES by the block interval to calculate - * the number of blocks produced. + /** + * dynamic_flags specifies chain state properties that can be + * expressed in one bit. */ - uint32_t first_maintenance_block_with_current_interval = 0; + uint32_t dynamic_flags = 0; + + enum dynamic_flag_bits + { + /** + * If maintenance_flag is set, then the head block is a + * maintenance block. This means + * get_time_slot(1) - head_block_time() will have a gap + * due to maintenance duration. + * + * This flag answers the question, "Was maintenance + * performed in the last call to apply_block()?" + */ + maintenance_flag = 0x01 + }; }; }} @@ -102,7 +114,7 @@ FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene:: (witness_budget) (accounts_registered_this_interval) (recently_missed_count) - (first_maintenance_block_with_current_interval) + (dynamic_flags) ) FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::object),