miclockwork_thread_program/state/
versioned_thread.rs1use anchor_lang::{prelude::*, AccountDeserialize};
2use miclockwork_thread_program_v1::{
3 state::Thread as ThreadV1,
4 typedefs::{Trigger as TriggerV1, TriggerContext as TriggerContextV1},
5};
6use miclockwork_utils::thread::SerializableAccount;
7
8use crate::{
9 ClockData, ExecContext, SerializableInstruction, Thread as ThreadV2, Trigger, TriggerContext,
10};
11
12#[derive(Clone, Debug, PartialEq)]
13pub enum VersionedThread {
14 V1(ThreadV1),
15 V2(ThreadV2),
16}
17
18impl VersionedThread {
19 pub fn authority(&self) -> Pubkey {
20 match self {
21 Self::V1(t) => t.authority,
22 Self::V2(t) => t.authority,
23 }
24 }
25
26 pub fn created_at(&self) -> ClockData {
27 match self {
28 Self::V1(t) => ClockData {
29 slot: t.created_at.slot,
30 epoch: t.created_at.epoch,
31 unix_timestamp: t.created_at.unix_timestamp,
32 },
33 Self::V2(t) => t.created_at.clone(),
34 }
35 }
36
37 pub fn exec_context(&self) -> Option<ExecContext> {
38 match self {
39 Self::V1(t) => t.exec_context.map(|e| ExecContext {
40 exec_index: 0,
41 execs_since_reimbursement: e.execs_since_reimbursement,
42 execs_since_slot: e.execs_since_slot,
43 last_exec_at: e.last_exec_at,
44 trigger_context: unsafe {
45 std::mem::transmute::<TriggerContextV1, TriggerContext>(e.trigger_context)
46 },
47 }),
48 Self::V2(t) => t.exec_context,
49 }
50 }
51
52 pub fn id(&self) -> Vec<u8> {
53 match self {
54 Self::V1(t) => t.id.as_bytes().to_vec(),
55 Self::V2(t) => t.id.clone(),
56 }
57 }
58
59 pub fn next_instruction(&self) -> Option<SerializableInstruction> {
60 match self {
61 Self::V1(t) => match &t.next_instruction {
62 None => None,
63 Some(ix) => Some(SerializableInstruction {
64 program_id: ix.program_id,
65 accounts: ix
66 .accounts
67 .iter()
68 .map(|a| unsafe {
69 std::mem::transmute_copy::<
70 miclockwork_thread_program_v1::typedefs::AccountMetaData,
71 SerializableAccount,
72 >(a)
73 })
74 .collect::<Vec<SerializableAccount>>(),
75 data: ix.data.clone(),
76 }),
77 },
78 Self::V2(t) => t.next_instruction.clone(),
79 }
80 }
81
82 pub fn paused(&self) -> bool {
83 match self {
84 Self::V1(t) => t.paused,
85 Self::V2(t) => t.paused,
86 }
87 }
88
89 pub fn program_id(&self) -> Pubkey {
90 match self {
91 Self::V1(_) => miclockwork_thread_program_v1::ID,
92 Self::V2(_) => crate::ID,
93 }
94 }
95
96 pub fn pubkey(&self) -> Pubkey {
97 match self {
98 Self::V1(_) => {
99 ThreadV1::pubkey(self.authority(), String::from_utf8(self.id()).unwrap())
100 }
101 Self::V2(_) => ThreadV2::pubkey(self.authority(), self.id()),
102 }
103 }
104
105 pub fn rate_limit(&self) -> u64 {
106 match self {
107 Self::V1(t) => t.rate_limit,
108 Self::V2(t) => t.rate_limit,
109 }
110 }
111
112 pub fn trigger(&self) -> Trigger {
113 match self {
114 Self::V1(t) => match &t.trigger {
115 TriggerV1::Account {
116 address,
117 offset,
118 size,
119 } => Trigger::Account {
120 address: *address,
121 offset: *offset as u64,
122 size: *size as u64,
123 },
124 TriggerV1::Cron {
125 schedule,
126 skippable,
127 } => Trigger::Cron {
128 schedule: schedule.clone(),
129 skippable: *skippable,
130 },
131 TriggerV1::Immediate => Trigger::Now,
132 },
133 Self::V2(t) => t.trigger.clone(),
134 }
135 }
136}
137
138impl AccountDeserialize for VersionedThread {
139 fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
140 Self::try_deserialize_unchecked(buf)
141 }
142
143 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
144 match ThreadV2::try_deserialize(buf) {
147 Err(_err) => Ok(VersionedThread::V1(ThreadV1::try_deserialize(buf)?)),
148 Ok(t) => Ok(VersionedThread::V2(t)),
149 }
150 }
151}
152
153impl TryFrom<Vec<u8>> for VersionedThread {
154 type Error = Error;
155 fn try_from(data: Vec<u8>) -> std::result::Result<Self, Self::Error> {
156 VersionedThread::try_deserialize(&mut data.as_slice())
157 }
158}