magicblock_magic_program_api/instruction.rs
1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use solana_program::pubkey::Pubkey;
5
6use crate::args::{
7 MagicBaseIntentArgs, MagicIntentBundleArgs, ScheduleTaskArgs,
8};
9
10#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
11pub enum MagicBlockInstruction {
12 /// Modify one or more accounts
13 ///
14 /// # Account references
15 /// - **0.** `[WRITE, SIGNER]` Validator Authority
16 /// - **1..n.** `[WRITE]` Accounts to modify
17 /// - **n+1** `[SIGNER]` (Implicit NativeLoader)
18 ModifyAccounts {
19 accounts: HashMap<Pubkey, AccountModificationForInstruction>,
20 message: Option<String>,
21 },
22
23 /// Schedules the accounts provided at end of accounts Vec to be committed.
24 /// It should be invoked from the program whose PDA accounts are to be
25 /// committed.
26 ///
27 /// This is the first part of scheduling a commit.
28 /// A second transaction [MagicBlockInstruction::AcceptScheduleCommits] has to run in order
29 /// to finish scheduling the commit.
30 ///
31 /// # Account references
32 /// - **0.** `[WRITE, SIGNER]` Payer requesting the commit to be scheduled
33 /// - **1.** `[WRITE]` Magic Context Account containing to which we store
34 /// the scheduled commits
35 /// - **2..n** `[]` Accounts to be committed
36 ScheduleCommit,
37
38 /// This is the exact same instruction as [MagicBlockInstruction::ScheduleCommit] except
39 /// that the [ScheduledCommit] is flagged such that when accounts are committed, a request
40 /// to undelegate them is included with the same transaction.
41 /// Additionally the validator will refuse anymore transactions for the specific account
42 /// since they are no longer considered delegated to it.
43 ///
44 /// This is the first part of scheduling a commit.
45 /// A second transaction [MagicBlockInstruction::AcceptScheduleCommits] has to run in order
46 /// to finish scheduling the commit.
47 ///
48 /// # Account references
49 /// - **0.** `[WRITE, SIGNER]` Payer requesting the commit to be scheduled
50 /// - **1.** `[WRITE]` Magic Context Account containing to which we store
51 /// the scheduled commits
52 /// - **2..n** `[]` Accounts to be committed and undelegated
53 ScheduleCommitAndUndelegate,
54
55 /// Moves the scheduled commit from the MagicContext to the global scheduled commits
56 /// map. This is the second part of scheduling a commit.
57 ///
58 /// It is run at the start of the slot to update the global scheduled commits map just
59 /// in time for the validator to realize the commits right after.
60 ///
61 /// # Account references
62 /// - **0.** `[SIGNER]` Validator Authority
63 /// - **1.** `[WRITE]` Magic Context Account containing the initially scheduled commits
64 AcceptScheduleCommits,
65
66 /// Records the attempt to realize a scheduled commit on chain.
67 ///
68 /// The signature of this transaction can be pre-calculated since we pass the
69 /// ID of the scheduled commit and retrieve the signature from a globally
70 /// stored hashmap.
71 ///
72 /// We implement it this way so we can log the signature of this transaction
73 /// as part of the [MagicBlockInstruction::ScheduleCommit] instruction.
74 /// Args: (intent_id, bump) - bump is needed in order to guarantee unique transactions
75 ScheduledCommitSent((u64, u64)),
76
77 /// Schedules execution of a single *base intent*.
78 ///
79 /// A "base intent" is an atomic unit of work executed by the validator on the Base layer,
80 /// such as:
81 /// - executing standalone base actions (`BaseActions`)
82 /// - committing a set of accounts (`Commit`)
83 /// - committing and undelegating accounts, optionally with post-actions (`CommitAndUndelegate`)
84 ///
85 /// This instruction is the legacy/single-intent variant of scheduling. For batching multiple
86 /// independent intents into a single instruction, see [`MagicBlockInstruction::ScheduleIntentBundle`].
87 ///
88 /// # Account references
89 /// - **0.** `[WRITE, SIGNER]` Payer requesting the intent to be scheduled
90 /// - **1.** `[WRITE]` Magic Context account
91 /// - **2..n** `[]` Accounts referenced by the intent (including action accounts)
92 ///
93 /// # Data
94 /// The embedded [`MagicBaseIntentArgs`] encodes account references by indices into the
95 /// accounts array (compact representation).
96 ScheduleBaseIntent(MagicBaseIntentArgs),
97
98 /// Schedule a new task for execution
99 ///
100 /// # Account references
101 /// - **0.** `[WRITE, SIGNER]` Payer (payer)
102 /// - **1.** `[WRITE]` Task context account
103 /// - **2..n** `[]` Accounts included in the task
104 ScheduleTask(ScheduleTaskArgs),
105
106 /// Cancel a task
107 ///
108 /// # Account references
109 /// - **0.** `[WRITE, SIGNER]` Task authority
110 /// - **1.** `[WRITE]` Task context account
111 CancelTask { task_id: i64 },
112
113 /// Disables the executable check, needed to modify the data of a program
114 /// in preparation to deploying it via LoaderV4 and to modify its authority.
115 ///
116 /// # Account references
117 /// - **0.** `[SIGNER]` Validator authority
118 DisableExecutableCheck,
119
120 /// Enables the executable check, and should run after
121 /// a program is deployed with the LoaderV4 and we modified its authority
122 ///
123 /// # Account references
124 /// - **0.** `[SIGNER]` Validator authority
125 EnableExecutableCheck,
126
127 /// Noop instruction
128 Noop(u64),
129
130 /// Schedules execution of a *bundle* of intents in a single instruction.
131 ///
132 /// A "intent bundle" is an atomic unit of work executed by the validator on the Base layer,
133 /// such as:
134 /// - standalone base actions
135 /// - an optional `Commit`
136 /// - an optional `CommitAndUndelegate`
137 ///
138 /// This is the recommended scheduling path when the caller wants to submit multiple
139 /// independent intents while paying account overhead only once.
140 ///
141 /// # Account references
142 /// - **0.** `[WRITE, SIGNER]` Payer requesting the bundle to be scheduled
143 /// - **1.** `[WRITE]` Magic Context account
144 /// - **2..n** `[]` All accounts referenced by any intent in the bundle
145 ///
146 /// # Data
147 /// The embedded [`MagicIntentBundleArgs`] encodes account references by indices into the
148 /// accounts array.
149 ScheduleIntentBundle(MagicIntentBundleArgs),
150
151 /// Creates a new ephemeral account with rent paid by a sponsor.
152 /// The account is automatically owned by the calling program (CPI caller).
153 ///
154 /// # Account references
155 /// - **0.** `[WRITE]` Sponsor account (pays rent, can be PDA or oncurve)
156 /// - **1.** `[WRITE]` Ephemeral account to create (must have 0 lamports)
157 /// - **2.** `[WRITE]` Vault account (receives rent payment)
158 CreateEphemeralAccount {
159 /// Initial data length in bytes
160 data_len: u32,
161 },
162
163 /// Resizes an existing ephemeral account, adjusting rent accordingly.
164 ///
165 /// # Account references
166 /// - **0.** `[WRITE]` Sponsor account (pays/receives rent difference)
167 /// - **1.** `[WRITE]` Ephemeral account to resize
168 /// - **2.** `[WRITE]` Vault account (holds/receives lamports for rent transfer)
169 ResizeEphemeralAccount {
170 /// New data length in bytes
171 new_data_len: u32,
172 },
173
174 /// Closes an ephemeral account, refunding rent to the sponsor.
175 ///
176 /// # Account references
177 /// - **0.** `[WRITE]` Sponsor account (receives rent refund)
178 /// - **1.** `[WRITE]` Ephemeral account to close
179 /// - **2.** `[WRITE]` Vault account (source of rent refund)
180 CloseEphemeralAccount,
181
182 /// Schedules the accounts provided at end of accounts Vec to be committed and finalized in a
183 /// single DLP instruction.
184 /// It should be invoked from the program whose PDA accounts are to be
185 /// committed.
186 ///
187 /// This is the first part of scheduling a commit.
188 /// A second transaction [MagicBlockInstruction::AcceptScheduleCommits] has to run in order
189 /// to finish scheduling the commit.
190 ///
191 /// # Account references
192 /// - **0.** `[WRITE, SIGNER]` Payer requesting the commit to be scheduled
193 /// - **1.** `[WRITE]` Magic Context Account containing to which we store
194 /// the scheduled commits
195 /// - **2..n** `[]` Accounts to be committed
196 ScheduleCommitFinalize { request_undelegation: bool },
197 /// Clone a single account that fits in one transaction (<63KB data).
198 ///
199 /// # Account references
200 /// - **0.** `[WRITE, SIGNER]` Validator Authority
201 /// - **1.** `[WRITE]` Account to clone
202 CloneAccount {
203 pubkey: Pubkey,
204 data: Vec<u8>,
205 fields: AccountCloneFields,
206 },
207
208 /// Initialize a multi-transaction clone for a large account.
209 /// Adds the pubkey to PENDING_CLONES. Must be followed by CloneAccountContinue
210 /// with is_last=true to complete.
211 ///
212 /// # Account references
213 /// - **0.** `[WRITE, SIGNER]` Validator Authority
214 /// - **1.** `[WRITE]` Account to clone
215 CloneAccountInit {
216 pubkey: Pubkey,
217 total_data_len: u32,
218 initial_data: Vec<u8>,
219 fields: AccountCloneFields,
220 },
221
222 /// Continue a multi-transaction clone with the next data chunk.
223 /// If is_last=true, removes the pubkey from PENDING_CLONES.
224 ///
225 /// # Account references
226 /// - **0.** `[WRITE, SIGNER]` Validator Authority
227 /// - **1.** `[WRITE]` Account being cloned
228 CloneAccountContinue {
229 pubkey: Pubkey,
230 offset: u32,
231 data: Vec<u8>,
232 is_last: bool,
233 },
234
235 /// Cleanup a partial clone on failure. Removes from PENDING_CLONES
236 /// and deletes the account.
237 ///
238 /// # Account references
239 /// - **0.** `[WRITE, SIGNER]` Validator Authority
240 /// - **1.** `[WRITE]` Account to cleanup
241 CleanupPartialClone { pubkey: Pubkey },
242
243 /// Finalize program deployment from a buffer account.
244 /// Does the following:
245 /// 1. Copies data from buffer account to program account
246 /// 2. Sets loader header with Retracted status and validator authority
247 /// 3. Closes buffer account
248 ///
249 /// After this, LoaderV4::Deploy must be called, then SetProgramAuthority.
250 ///
251 /// # Account references
252 /// - **0.** `[SIGNER]` Validator Authority
253 /// - **1.** `[WRITE]` Program account
254 /// - **2.** `[WRITE]` Buffer account (closed after)
255 FinalizeProgramFromBuffer { remote_slot: u64 },
256
257 /// Finalize V1 program deployment from a buffer account.
258 /// V1 programs are converted to V3 (upgradeable loader) format.
259 /// Does the following:
260 /// 1. Creates program_data account with V3 ProgramData header + ELF
261 /// 2. Creates program account with V3 Program header
262 /// 3. Closes buffer account
263 ///
264 /// # Account references
265 /// - **0.** `[SIGNER]` Validator Authority
266 /// - **1.** `[WRITE]` Program account
267 /// - **2.** `[WRITE]` Program data account
268 /// - **3.** `[WRITE]` Buffer account (closed after)
269 FinalizeV1ProgramFromBuffer { remote_slot: u64, authority: Pubkey },
270
271 /// Update the authority in a LoaderV4 program header.
272 /// Used after Deploy to set the final chain authority.
273 ///
274 /// # Account references
275 /// - **0.** `[SIGNER]` Validator Authority
276 /// - **1.** `[WRITE]` Program account
277 SetProgramAuthority { authority: Pubkey },
278}
279
280impl MagicBlockInstruction {
281 pub fn try_to_vec(&self) -> Result<Vec<u8>, bincode::Error> {
282 bincode::serialize(self)
283 }
284}
285
286#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
287pub struct AccountModification {
288 pub pubkey: Pubkey,
289 pub lamports: Option<u64>,
290 pub owner: Option<Pubkey>,
291 pub executable: Option<bool>,
292 pub data: Option<Vec<u8>>,
293 pub delegated: Option<bool>,
294 pub confined: Option<bool>,
295 pub remote_slot: Option<u64>,
296}
297
298#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
299pub struct AccountModificationForInstruction {
300 pub lamports: Option<u64>,
301 pub owner: Option<Pubkey>,
302 pub executable: Option<bool>,
303 pub data: Option<Vec<u8>>,
304 pub delegated: Option<bool>,
305 pub confined: Option<bool>,
306 pub remote_slot: Option<u64>,
307}
308
309/// Common fields for cloning an account.
310#[derive(
311 Default, Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq,
312)]
313pub struct AccountCloneFields {
314 pub lamports: u64,
315 pub owner: Pubkey,
316 pub executable: bool,
317 pub delegated: bool,
318 pub confined: bool,
319 pub remote_slot: u64,
320}