pub fn execute_till_block_end(&mut self, job_type: BootloaderJobType) -> VmBlockResult {
        let timestamp_initial = Timestamp(self.state.local_state.timestamp);
        let cycles_initial = self.state.local_state.monotonic_cycle_counter;
        let gas_before = self.gas_remaining();

        let mut tx_result_tracer = TransactionResultTracer::default();
        let stop_reason = self.execute_with_custom_tracer(&mut tx_result_tracer);
        match stop_reason {
            VmExecutionStopReason::VmFinished => {
                let mut full_result = vm_may_have_ended(self, gas_before).unwrap();

                if job_type == BootloaderJobType::TransactionExecution
                    && tx_has_failed(&self.state, 0)
                    && full_result.revert_reason.is_none()
                {
                    let revert_reason = tx_result_tracer
                        .revert_reason
                        .map(|reason| {
                            let vm_revert_reason = VmRevertReason::try_from(reason.as_slice())
                                .unwrap_or_else(|_| VmRevertReason::Unknown {
                                    function_selector: vec![],
                                    data: reason.clone(),
                                });

                            VmRevertReasonParsingResult {
                                revert_reason: TxRevertReason::TxReverted(vm_revert_reason),
                                original_data: reason,
                            }
                        })
                        .unwrap_or_else(|| VmRevertReasonParsingResult {
                            revert_reason: TxRevertReason::TxReverted(VmRevertReason::General {
                                msg: "Transaction reverted with empty reason. Possibly out of gas"
                                    .to_string(),
                            }),
                            original_data: vec![],
                        });

                    full_result.revert_reason = Some(revert_reason);
                }

                let block_tip_result = VmPartialExecutionResult {
                    logs: self.collect_execution_logs_after_timestamp(timestamp_initial),
                    revert_reason: full_result.revert_reason.clone().map(|r| r.revert_reason),
                    contracts_used: self
                        .state
                        .decommittment_processor
                        .get_decommitted_bytes_after_timestamp(timestamp_initial),
                    cycles_used: self.state.local_state.monotonic_cycle_counter - cycles_initial,
                    gas_remaining: self.gas_remaining(),
                };

                // Collecting `block_tip_result` needs logs with timestamp, so we drain events for the `full_result`
                // after because draining will drop timestamps.
                let (raw_events, l1_messages) = self.state.event_sink.flatten();
                full_result.events = merge_events(raw_events)
                    .into_iter()
                    .map(|e| {
                        e.into_vm_event(L1BatchNumber(self.block_context.context.block_number))
                    })
                    .collect();
                full_result.l2_to_l1_logs =
                    l1_messages.into_iter().map(GlueInto::glue_into).collect();
                VmBlockResult {
                    full_result,
                    block_tip_result,
                }
            }
            VmExecutionStopReason::TracerRequestedStop => {
                unreachable!("NoopMemoryTracer will never stop execution until the block ends")
            }
        }
    }
Returns full VM result and partial result produced within the current execution.
core/lib/multivm/src/versions/vm_m5/vm_instance.rs