fn execute_with_custom_tracer_and_refunds<
        T: ExecutionEndTracer<H>
            + PendingRefundTracer<H>
            + PubdataSpentTracer<H>
            + StorageInvocationTracer<H>,
    >(
        &mut self,
        tracer: &mut T,
    ) -> (VmExecutionStopReason, u32) {
        let mut operator_refund = None;
        let timestamp_initial = Timestamp(self.state.local_state.timestamp);
        let gas_remaining_before = self.gas_remaining();
        let spent_pubdata_counter_before = self.state.local_state.spent_pubdata_counter;

        loop {
            // Sanity check: we should never reach the maximum value, because then we won't be able to process the next cycle.
            assert_ne!(
                self.state.local_state.monotonic_cycle_counter,
                u32::MAX,
                "VM reached maximum possible amount of cycles. Vm state: {:?}",
                self.state
            );

            let timestamp_before_cycle = self.state.local_state.timestamp;
            self.state
                .cycle(tracer)
                .expect("Failed execution VM cycle.");

            if self.has_ended() {
                return (
                    VmExecutionStopReason::VmFinished,
                    operator_refund.unwrap_or_default(),
                );
            }

            // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas
            // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details).
            if let Some(bootloader_refund) = tracer.requested_refund() {
                assert!(
                    operator_refund.is_none(),
                    "Operator was asked for refund two times"
                );

                let gas_spent_on_pubdata = tracer.gas_spent_on_pubdata(&self.state.local_state)
                    - spent_pubdata_counter_before;
                let tx_body_refund =
                    self.tx_body_refund(timestamp_initial, bootloader_refund, gas_spent_on_pubdata);

                if tx_body_refund < bootloader_refund {
                    tracing::error!(
                        "Suggested tx body refund is less than bootloader refund. Tx body refund: {}, bootloader refund: {}",
                        tx_body_refund,
                        bootloader_refund
                    );
                }

                let refund_to_propose = tx_body_refund
                    + self.block_overhead_refund(
                        timestamp_initial,
                        gas_remaining_before,
                        gas_spent_on_pubdata,
                    );

                let current_tx_index = self.bootloader_state.tx_to_execute() - 1;
                let refund_slot = OPERATOR_REFUNDS_OFFSET + current_tx_index;

                // Writing the refund into memory
                self.state.memory.memory.write_to_memory(
                    BOOTLOADER_HEAP_PAGE as usize,
                    refund_slot,
                    PrimitiveValue {
                        value: refund_to_propose.into(),
                        is_pointer: false,
                    },
                    Timestamp(timestamp_before_cycle),
                );
                operator_refund = Some(refund_to_propose);
                tracer.set_refund_as_done();

                let tx_gas_limit = self.get_tx_gas_limit(current_tx_index);

                if tx_gas_limit < bootloader_refund {
                    tracing::error!(
                        "Tx gas limit is less than bootloader refund. Tx gas limit: {}, bootloader refund: {}",
                        tx_gas_limit,
                        bootloader_refund
                    );
                }
                if tx_gas_limit < refund_to_propose {
                    tracing::error!(
                        "Tx gas limit is less than operator refund. Tx gas limit: {}, operator refund: {}",
                        tx_gas_limit,
                        refund_to_propose
                    );
                }
            }

            tracer.set_missed_storage_invocations(
                self.state
                    .storage
                    .storage
                    .get_ptr()
                    .borrow()
                    .missed_storage_invocations(),
            );

            if tracer.should_stop_execution() {
                return (
                    VmExecutionStopReason::TracerRequestedStop,
                    operator_refund.unwrap_or_default(),
                );
            }
        }
    }
Executes VM until the end or tracer says to stop.
Returns a tuple of `VmExecutionStopReason` and the size of the refund proposed by the operator
core/lib/multivm/src/versions/vm_1_3_2/vm_instance.rs