void database::_apply_block( const signed_block& next_block ) { try { uint32_t next_block_num = next_block.block_num(); uint32_t skip = get_node_properties().skip_flags; _applied_ops.clear(); FC_ASSERT( (skip & skip_merkle_check) || next_block.transaction_merkle_root == next_block.calculate_merkle_root(), "", ("next_block.transaction_merkle_root",next_block.transaction_merkle_root)("calc",next_block.calculate_merkle_root())("next_block",next_block)("id",next_block.id()) ); 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_object>(dynamic_global_property_id_type()); bool maint_needed = (dynamic_global_props.next_maintenance_time <= next_block.timestamp); _current_block_num = next_block_num; _current_trx_in_block = 0; for( const auto& trx : next_block.transactions ) { /* We do not need to push the undo state for each transaction * because they either all apply and are valid or the * entire block fails to apply. We only need an "undo" state * for transactions when validating broadcast transactions or * when building a block. */ apply_transaction( trx, skip ); ++_current_trx_in_block; } update_global_dynamic_data(next_block); update_signing_witness(signing_witness, next_block); update_last_irreversible_block(); // Are we at the maintenance interval? if( maint_needed ) perform_chain_maintenance(next_block, global_props); create_block_summary(next_block); clear_expired_transactions(); clear_expired_proposals(); clear_expired_orders(); 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 ); update_witness_schedule(); if( !_node_property_object.debug_updates.empty() ) apply_debug_updates(); // notify observers that the block has been applied applied_block( next_block ); //emit _applied_ops.clear(); notify_changed_objects(); } FC_CAPTURE_AND_RETHROW( (next_block.block_num()) ) }
void database::update_global_dynamic_data( const signed_block& b ) { const dynamic_global_property_object& _dgp = dynamic_global_property_id_type(0)(*this); 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 ){ if( BOOST_UNLIKELY( b.block_num() == 1 ) ) dgp.recently_missed_count = 0; else if( _checkpoints.size() && _checkpoints.rbegin()->first >= b.block_num() ) dgp.recently_missed_count = 0; else if( missed_blocks ) 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--; dgp.head_block_number = b.block_num(); 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) ) { GRAPHENE_ASSERT( _dgp.recently_missed_count < GRAPHENE_MAX_UNDO_HISTORY, undo_database_exception, "The database does not have enough undo history to support a blockchain with so many missed blocks. " "Please add a checkpoint if you would like to continue applying blocks beyond this point.", ("recently_missed",_dgp.recently_missed_count)("max_undo",GRAPHENE_MAX_UNDO_HISTORY) ); } _undo_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY ); _fork_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY ); }
dynamic_global_property_object database_api::get_dynamic_global_properties()const { return _db.get(dynamic_global_property_id_type()); }
block_id_type database::head_block_id()const { return get( dynamic_global_property_id_type() ).head_block_id; }
uint32_t database::head_block_num()const { return get( dynamic_global_property_id_type() ).head_block_number; }
time_point_sec database::head_block_time()const { return get( dynamic_global_property_id_type() ).time; }
const dynamic_global_property_object&database::get_dynamic_global_properties() const { return get( dynamic_global_property_id_type() ); }