miclockwork_thread_program/state/
thread.rs

1use std::mem::size_of;
2
3use anchor_lang::{prelude::*, AnchorDeserialize, AnchorSerialize};
4use miclockwork_utils::thread::{ClockData, SerializableInstruction, Trigger};
5
6pub use miclockwork_utils::thread::Equality;
7
8pub const SEED_THREAD: &[u8] = b"thread";
9
10/// Static space for next_instruction field.
11pub const NEXT_INSTRUCTION_SIZE: usize = 1232;
12
13/// Tracks the current state of a transaction thread on Solana.
14#[account]
15#[derive(Debug)]
16pub struct Thread {
17    /// The owner of this thread.
18    pub authority: Pubkey,
19    /// The bump, used for PDA validation.
20    pub bump: u8,
21    /// The cluster clock at the moment the thread was created.
22    pub created_at: ClockData,
23    /// The context of the thread's current execution state.
24    pub exec_context: Option<ExecContext>,
25    /// The number of lamports to payout to workers per execution.
26    pub fee: u64,
27    /// The id of the thread, given by the authority.
28    pub id: Vec<u8>,
29    /// The instructions to be executed.
30    pub instructions: Vec<SerializableInstruction>,
31    /// The name of the thread.
32    pub name: String,
33    /// The next instruction to be executed.
34    pub next_instruction: Option<SerializableInstruction>,
35    /// Whether or not the thread is currently paused.
36    pub paused: bool,
37    /// The maximum number of execs allowed per slot.
38    pub rate_limit: u64,
39    /// The triggering event to kickoff a thread.
40    pub trigger: Trigger,
41}
42
43impl Thread {
44    /// Derive the pubkey of a thread account.
45    pub fn pubkey(authority: Pubkey, id: Vec<u8>) -> Pubkey {
46        Pubkey::find_program_address(
47            &[SEED_THREAD, authority.as_ref(), id.as_slice()],
48            &crate::ID,
49        )
50        .0
51    }
52}
53
54impl PartialEq for Thread {
55    fn eq(&self, other: &Self) -> bool {
56        self.authority.eq(&other.authority) && self.id.eq(&other.id)
57    }
58}
59
60impl Eq for Thread {}
61
62/// Trait for reading and writing to a thread account.
63pub trait ThreadAccount {
64    /// Get the pubkey of the thread account.
65    fn pubkey(&self) -> Pubkey;
66
67    /// Allocate more memory for the account.
68    fn realloc(&mut self) -> Result<()>;
69}
70
71impl ThreadAccount for Account<'_, Thread> {
72    fn pubkey(&self) -> Pubkey {
73        Thread::pubkey(self.authority, self.id.clone())
74    }
75
76    fn realloc(&mut self) -> Result<()> {
77        // Realloc memory for the thread account
78        let data_len = vec![
79            8,
80            size_of::<Thread>(),
81            self.id.len(),
82            self.instructions.try_to_vec()?.len(),
83            self.trigger.try_to_vec()?.len(),
84            NEXT_INSTRUCTION_SIZE,
85        ]
86        .iter()
87        .sum();
88        self.to_account_info().realloc(data_len, false)?;
89        Ok(())
90    }
91}
92
93/// The execution context of a particular transaction thread.
94#[derive(AnchorDeserialize, AnchorSerialize, Clone, Copy, Debug, PartialEq, Eq)]
95pub struct ExecContext {
96    /// Index of the next instruction to be executed.
97    pub exec_index: u64,
98
99    /// Number of execs since the last tx reimbursement.
100    /// To be deprecated in v3 since we now reimburse for every transaction.
101    pub execs_since_reimbursement: u64,
102
103    /// Number of execs in this slot.
104    pub execs_since_slot: u64,
105
106    /// Slot of the last exec
107    pub last_exec_at: u64,
108
109    /// Context for the triggering condition
110    pub trigger_context: TriggerContext,
111}
112
113/// The event which allowed a particular transaction thread to be triggered.
114#[derive(AnchorDeserialize, AnchorSerialize, Clone, Copy, Debug, PartialEq, Eq)]
115pub enum TriggerContext {
116    /// A running hash of the observed account data.
117    Account {
118        /// The account's data hash.
119        data_hash: u64,
120    },
121
122    /// A cron execution context.
123    Cron {
124        /// The threshold moment the schedule was waiting for.
125        started_at: i64,
126    },
127
128    /// The trigger context for threads with a "now" trigger.
129    Now,
130
131    /// The trigger context for threads with a "slot" trigger.
132    Slot {
133        /// The threshold slot the schedule was waiting for.
134        started_at: u64,
135    },
136
137    /// The trigger context for threads with an "epoch" trigger.
138    Epoch {
139        /// The threshold epoch the schedule was waiting for.
140        started_at: u64,
141    },
142
143    /// The trigger context for threads with an "timestamp" trigger.
144    Timestamp {
145        /// The threshold moment the schedule was waiting for.
146        started_at: i64,
147    },
148
149    /// The trigger context for threads with a "pyth" trigger.
150    Pyth { price: i64 },
151}
152
153/// The properties of threads which are updatable.
154#[derive(AnchorSerialize, AnchorDeserialize)]
155pub struct ThreadSettings {
156    pub fee: Option<u64>,
157    pub instructions: Option<Vec<SerializableInstruction>>,
158    pub name: Option<String>,
159    pub rate_limit: Option<u64>,
160    pub trigger: Option<Trigger>,
161}