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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
//! Like [`Account`](crate::Account), but deserializes on-demand.
use ;
/// Deserialize account data lazily (on-demand).
///
/// Anchor uses [`borsh`] deserialization by default, which can be expensive for both memory and
/// compute units usage.
///
/// With the regular [`Account`] type, all account data gets deserialized, even the fields not used
/// by your instruction. On contrast, [`LazyAccount`] allows you to deserialize individual fields,
/// saving both memory and compute units.
///
/// # Table of contents
///
/// - [When to use](#when-to-use)
/// - [Features](#features)
/// - [Example](#example)
/// - [Safety](#safety)
/// - [Performance](#performance)
/// - [Memory](#memory)
/// - [Compute units](#compute-units)
///
/// # When to use
///
/// This is currently an experimental account type, and therefore should only be used when you're
/// running into performance issues.
///
/// It's best to use [`LazyAccount`] when you only need to deserialize some of the fields,
/// especially if the account is read-only.
///
/// Replacing [`Account`] (including `Box`ed) with [`LazyAccount`] *can* improve both stack memory
/// and compute unit usage. However, this is not guaranteed. For example, if you need to
/// deserialize the account fully, using [`LazyAccount`] will have additional overhead and
/// therefore use slightly more compute units.
///
/// Currently, using the `mut` constraint eventually results in the whole account getting
/// deserialized, meaning it won't use fewer compute units compared to [`Account`]. This might get
/// optimized in the future.
///
/// # Features
///
/// - Can be used as a replacement for [`Account`].
/// - Checks the account owner and its discriminator.
/// - Does **not** check the type layout matches the defined layout.
/// - All account data can be deserialized with `load` and `load_mut` methods. These methods are
/// non-inlined, meaning that they're less likely to cause stack violation errors.
/// - Each individual field can be deserialized with the generated `load_<field>` and
/// `load_mut_<field>` methods.
///
/// # Example
///
/// ```ignore
/// use anchor_lang::prelude::*;
///
/// declare_id!("LazyAccount11111111111111111111111111111111");
///
/// #[program]
/// pub mod lazy_account {
/// use super::*;
///
/// pub fn init(ctx: Context<Init>) -> Result<()> {
/// let mut my_account = ctx.accounts.my_account.load_mut()?;
/// my_account.authority = ctx.accounts.authority.key();
///
/// // Fill the dynamic data
/// for _ in 0..MAX_DATA_LEN {
/// my_account.dynamic.push(ctx.accounts.authority.key());
/// }
///
/// Ok(())
/// }
///
/// pub fn read(ctx: Context<Read>) -> Result<()> {
/// // Cached load due to the `has_one` constraint
/// let authority = ctx.accounts.my_account.load_authority()?;
/// msg!("Authority: {}", authority);
/// Ok(())
/// }
///
/// pub fn write(ctx: Context<Write>, new_authority: Pubkey) -> Result<()> {
/// // Cached load due to the `has_one` constraint
/// *ctx.accounts.my_account.load_mut_authority()? = new_authority;
/// Ok(())
/// }
/// }
///
/// #[derive(Accounts)]
/// pub struct Init<'info> {
/// #[account(mut)]
/// pub authority: Signer<'info>,
/// #[account(
/// init,
/// payer = authority,
/// space = MyAccount::DISCRIMINATOR.len() + MyAccount::INIT_SPACE
/// )]
/// pub my_account: LazyAccount<'info, MyAccount>,
/// pub system_program: Program<'info, System>,
/// }
///
/// #[derive(Accounts)]
/// pub struct Read<'info> {
/// pub authority: Signer<'info>,
/// #[account(has_one = authority)]
/// pub my_account: LazyAccount<'info, MyAccount>,
/// }
///
/// #[derive(Accounts)]
/// pub struct Write<'info> {
/// pub authority: Signer<'info>,
/// #[account(mut, has_one = authority)]
/// pub my_account: LazyAccount<'info, MyAccount>,
/// }
///
/// const MAX_DATA_LEN: usize = 256;
///
/// #[account]
/// #[derive(InitSpace)]
/// pub struct MyAccount {
/// pub authority: Pubkey,
/// pub fixed: [Pubkey; 8],
/// // Dynamic sized data also works, unlike `AccountLoader`
/// #[max_len(MAX_DATA_LEN)]
/// pub dynamic: Vec<Pubkey>,
/// }
/// ```
///
/// # Safety
///
/// The safety checks are done using the account's discriminator and the account's owner (similar
/// to [`Account`]). However, you should be extra careful when deserializing individual fields if,
/// for example, the account needs to be migrated. Make sure the previously serialized data always
/// matches the account's type identically.
///
/// # Performance
///
/// ## Memory
///
/// All fields (including the inner account type) are heap allocated. It only uses 24 bytes (3x
/// pointer size) of stack memory in total.
///
/// It's worth noting that where the account is being deserialized matters. For example, the main
/// place where Anchor programs are likely to hit stack violation errors is a generated function
/// called `try_accounts` (you might be familiar with it from the mangled build logs). This is
/// where the instruction is deserialized and constraints are run. Although having everything at the
/// same place is convenient for using constraints, this also makes it very easy to use the fixed
/// amount of stack space (4096 bytes) SVM allocates just by increasing the number of accounts the
/// instruction has. In SVM, each function has its own stack frame, meaning that it's possible to
/// deserialize more accounts simply by deserializing them inside other functions (rather than in
/// `try_accounts` which is already quite heavy).
///
/// The mentioned stack limitation can be solved using dynamic stack frames, see [SIMD-0166].
///
/// ## Compute units
///
/// Compute is harder to formulate, as it varies based on the inner account's type. That being said,
/// there are a few things you can do to optimize compute units usage when using [`LazyAccount`]:
///
/// - Order account fields from fixed-size data (e.g. `u8`, `Pubkey`) to dynamic data (e.g. `Vec`).
/// - Order account fields based on how frequently the field is accessed (starting with the most
/// frequent).
/// - Reduce or limit dynamic fields.
///
/// [`borsh`]: crate::prelude::borsh
/// [`Account`]: crate::prelude::Account
/// [SIMD-0166]: https://github.com/solana-foundation/solana-improvement-documents/pull/166