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