Skip to main content

tycho_executor/tx/
ticktock.rs

1use anyhow::Context;
2use tycho_types::models::{AccountStatus, ComputePhase, TickTock, TickTockTxInfo};
3
4use crate::error::{TxError, TxResult};
5use crate::phase::{
6    ActionPhaseContext, ComputePhaseContext, ComputePhaseFull, StoragePhaseContext,
7    TransactionInput,
8};
9use crate::{ExecutorInspector, ExecutorState};
10
11impl ExecutorState<'_> {
12    pub fn run_tick_tock_transaction(
13        &mut self,
14        kind: TickTock,
15        mut inspector: Option<&mut ExecutorInspector<'_>>,
16    ) -> TxResult<TickTockTxInfo> {
17        if self.state.status() != AccountStatus::Active {
18            // Skip ticktock transactions for inactive accounts.
19            return Err(TxError::Skipped);
20        }
21
22        // Run storage phase.
23        let storage_phase = self
24            .storage_phase(StoragePhaseContext {
25                adjust_msg_balance: false,
26                received_message: None,
27                inspector: inspector.as_deref_mut(),
28            })
29            .context("storage phase failed")?;
30
31        // Run compute phase.
32        let ComputePhaseFull {
33            compute_phase,
34            original_balance,
35            new_state,
36            actions,
37            ..
38        } = self
39            .compute_phase(ComputePhaseContext {
40                input: TransactionInput::TickTock(kind),
41                storage_fee: storage_phase.storage_fees_collected,
42                force_accept: false,
43                stop_on_accept: false,
44                inspector: inspector.as_deref_mut(),
45            })
46            .context("compute phase failed")?;
47
48        // Run action phase only if compute phase succeeded.
49        let mut aborted = true;
50        let mut destroyed = false;
51        let mut action_phase = None;
52        if let ComputePhase::Executed(compute_phase) = &compute_phase
53            && compute_phase.success
54        {
55            let res = self
56                .action_phase(ActionPhaseContext {
57                    received_message: None,
58                    original_balance,
59                    new_state,
60                    actions,
61                    compute_phase,
62                    inspector,
63                })
64                .context("action phase failed")?;
65
66            aborted = !res.action_phase.success;
67            destroyed = self.end_status == AccountStatus::NotExists;
68            action_phase = Some(res.action_phase);
69        }
70
71        // Build transaction info.
72        Ok(TickTockTxInfo {
73            kind,
74            storage_phase,
75            compute_phase,
76            action_phase,
77            aborted,
78            destroyed,
79        })
80    }
81}