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 ); }
void database::update_signing_witness(const witness_object& signing_witness, const signed_block& new_block) { 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 ); modify( dpo, [&]( dynamic_global_property_object& _dpo ) { _dpo.witness_budget -= witness_pay; } ); deposit_witness_pay( signing_witness, witness_pay ); modify( signing_witness, [&]( witness_object& _wit ) { _wit.last_aslot = new_block_aslot; } ); }
const witness_object& database::validate_block_header( uint32_t skip, const signed_block& next_block )const { FC_ASSERT( head_block_id() == next_block.previous, "", ("head_block_id",head_block_id())("next.prev",next_block.previous) ); FC_ASSERT( head_block_time() < next_block.timestamp, "", ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()) ); const witness_object& witness = next_block.witness(*this); if( !(skip&skip_witness_signature) ) FC_ASSERT( next_block.validate_signee( witness.signing_key ) ); if( !(skip&skip_witness_schedule_check) ) { uint32_t slot_num = get_slot_at_time( next_block.timestamp ); FC_ASSERT( slot_num > 0 ); witness_id_type scheduled_witness = get_scheduled_witness( slot_num ); FC_ASSERT( next_block.witness == scheduled_witness, "Witness produced block at wrong time", ("block witness",next_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) ); } return witness; }
signed_block database::_generate_block( fc::time_point_sec when, witness_id_type witness_id, const fc::ecc::private_key& block_signing_private_key ) { try { uint32_t skip = get_node_properties().skip_flags; uint32_t slot_num = get_slot_at_time( when ); FC_ASSERT( slot_num > 0 ); witness_id_type scheduled_witness = get_scheduled_witness( slot_num ); FC_ASSERT( scheduled_witness == witness_id ); const auto& witness_obj = witness_id(*this); if( !(skip & skip_witness_signature) ) FC_ASSERT( witness_obj.signing_key == block_signing_private_key.get_public_key() ); static const size_t max_block_header_size = fc::raw::pack_size( signed_block_header() ) + 4; auto maximum_block_size = get_global_properties().parameters.maximum_block_size; size_t total_block_size = max_block_header_size; signed_block pending_block; // // The following code throws away existing pending_tx_session and // rebuilds it by re-applying pending transactions. // // This rebuild is necessary because pending transactions' validity // and semantics may have changed since they were received, because // time-based semantics are evaluated based on the current block // time. These changes can only be reflected in the database when // the value of the "when" variable is known, which means we need to // re-apply pending transactions in this method. // _pending_tx_session.reset(); _pending_tx_session = _undo_db.start_undo_session(); uint64_t postponed_tx_count = 0; // pop pending state (reset to head block state) for( const processed_transaction& tx : _pending_tx ) { size_t new_total_size = total_block_size + fc::raw::pack_size( tx ); // postpone transaction if it would make block too big if( new_total_size >= maximum_block_size ) { postponed_tx_count++; continue; } try { auto temp_session = _undo_db.start_undo_session(); processed_transaction ptx = _apply_transaction( tx ); temp_session.merge(); // We have to recompute pack_size(ptx) because it may be different // than pack_size(tx) (i.e. if one or more results increased // their size) total_block_size += fc::raw::pack_size( ptx ); pending_block.transactions.push_back( ptx ); } catch ( const fc::exception& e ) { // Do nothing, transaction will not be re-applied wlog( "Transaction was not processed while generating block due to ${e}", ("e", e) ); wlog( "The transaction was ${t}", ("t", tx) ); } } if( postponed_tx_count > 0 ) { wlog( "Postponed ${n} transactions due to block size limit", ("n", postponed_tx_count) ); } _pending_tx_session.reset(); // We have temporarily broken the invariant that // _pending_tx_session is the result of applying _pending_tx, as // _pending_tx now consists of the set of postponed transactions. // However, the push_block() call below will re-create the // _pending_tx_session. pending_block.previous = head_block_id(); pending_block.timestamp = when; pending_block.transaction_merkle_root = pending_block.calculate_merkle_root(); pending_block.witness = witness_id; if( !(skip & skip_witness_signature) ) pending_block.sign( block_signing_private_key ); // TODO: Move this to _push_block() so session is restored. if( !(skip & skip_block_size_check) ) { FC_ASSERT( fc::raw::pack_size(pending_block) <= get_global_properties().parameters.maximum_block_size ); } push_block( pending_block, skip ); return pending_block; } FC_CAPTURE_AND_RETHROW( (witness_id) ) }