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()) ) }
processed_transaction database::_push_transaction( const signed_transaction& trx ) { // If this is the first transaction pushed after applying a block, start a new undo session. // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives. if( !_pending_tx_session.valid() ) _pending_tx_session = _undo_db.start_undo_session(); // Create a temporary undo session as a child of _pending_tx_session. // The temporary session will be discarded by the destructor if // _apply_transaction fails. If we make it to merge(), we // apply the changes. auto temp_session = _undo_db.start_undo_session(); auto processed_trx = _apply_transaction( trx ); _pending_tx.push_back(processed_trx); notify_changed_objects(); // The transaction applied successfully. Merge its changes into the pending block session. temp_session.merge(); // notify anyone listening to pending transactions on_pending_transaction( trx ); return processed_trx; }