pinocchio 0.11.1

Create Solana programs with no external dependencies attached
Documentation
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
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]

//! A library for creating Solana programs in Rust with no external
//! dependencies. The only dependencies are types from the Solana SDK
//! specifically designed for on-chain programs. This mitigates dependency
//! issues and offers an efficient zero-copy library for writing programs,
//! optimized in terms of both compute unit consumption and binary size.
//!
//! ## Defining the program entrypoint
//!
//! A Solana program needs to define an entrypoint, which will be called by the
//! runtime to begin the program execution. The `entrypoint!` macro emits the
//! common boilerplate to set up the program entrypoint. The macro will also set
//! up [global allocator](https://doc.rust-lang.org/stable/core/alloc/trait.GlobalAlloc.html)
//! and [panic handler](https://doc.rust-lang.org/nomicon/panic-handler.html) using
//! the [`default_allocator!`] and [`default_panic_handler!`] macros.
//!
//! The [`entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.entrypoint.html)
//! is a convenience macro that invokes three other macros to set all components
//! required for a program execution:
//!
//! * [`program_entrypoint!`]: declares the program entrypoint
//! * [`default_allocator!`]: declares the default (bump) global allocator
//! * [`default_panic_handler!`]: declares the default panic "hook" that works
//!   in combination with the `std` panic handler
//!
//! When all dependencies are `no_std`, you should use [`nostd_panic_handler!`](https://docs.rs/pinocchio/latest/pinocchio/macro.nostd_panic_handler.html)
//! instead of `default_panic_handler!` to declare a rust runtime panic handler.
//! There's no need to do this when any dependency is `std` since rust compiler
//! will emit a panic handler.
//!
//! To use the `entrypoint!` macro, use the following in your entrypoint
//! definition:
//! ```ignore
//! use pinocchio::{
//!   AccountView,
//!   Address,
//!   entrypoint,
//!   ProgramResult
//! };
//! use solana_program_log::log;
//!
//! entrypoint!(process_instruction);
//!
//! pub fn process_instruction(
//!   program_id: &Address,
//!   accounts: &mut [AccountView],
//!   instruction_data: &[u8],
//! ) -> ProgramResult {
//!   log!("Hello from my pinocchio program!");
//!   Ok(())
//! }
//! ```
//!
//! The input is parsed into the following components:
//!
//! * `program_id`: the `ID` of the program being called
//! * `accounts`: the accounts received
//! * `instruction_data`: data for the instruction
//!
//! `pinocchio` also offers variations of the program entrypoint
//! (`lazy_program_entrypoint`) and global allocator (`no_allocator`). In order
//! to use these, the program needs to specify the program entrypoint, global
//! allocator and panic handler individually. The `entrypoint!` macro is
//! equivalent to writing:
//! ```ignore
//! program_entrypoint!(process_instruction);
//! default_allocator!();
//! default_panic_handler!();
//! ```
//! Any of these macros can be replaced by alternative implementations.
//!
//! ### Custom entrypoints with [`crate::entrypoint::process_entrypoint`]
//!
//! For programs that need maximum control over the entrypoint, `pinocchio`
//! exposes the [`crate::entrypoint::process_entrypoint`] function. This
//! function is the same deserialization logic used internally by the
//! [`program_entrypoint!`] macro, exposed as a public API and can be called
//! directly from a custom entrypoint, allowing you to implement fast-path
//! optimizations or custom pre-processing logic before falling back to standard
//! input parsing.
//!
//! To use [`crate::entrypoint::process_entrypoint`] in a custom entrypoint:
//!
//! ```ignore
//! use pinocchio::{
//!   AccountView,
//!   Address,
//!   default_panic_handler,
//!   entrypoint::process_entrypoint,
//!   MAX_TX_ACCOUNTS,
//!   no_allocator,
//!   ProgramResult,
//! };
//! use solana_program_log::log;
//!
//! no_allocator!();
//! default_panic_handler!();
//!
//! #[no_mangle]
//! pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
//!   // Fast path: check the number of accounts
//!   let num_accounts = unsafe { *(input as *const u64) };
//!   if num_accounts == 0 {
//!     log("Fast path - no accounts!");
//!     return 0;
//!   }
//!
//!   // Standard path: delegate to `process_entrypoint`
//!   unsafe { process_entrypoint::<MAX_TX_ACCOUNTS>(input, process_instruction) }
//! }
//!
//! pub fn process_instruction(
//!   program_id: &Address,
//!   accounts: &mut [AccountView],
//!   instruction_data: &[u8],
//! ) -> ProgramResult {
//!   log("Standard path");
//!   Ok(())
//! }
//! ```
//!
//! ### [`lazy_program_entrypoint!`]
//!
//! The [`entrypoint!`] macro looks similar to the "standard" one found in
//! [`solana-program-entrypoint`](https://docs.rs/solana-program-entrypoint/latest/solana_program_entrypoint/macro.entrypoint.html).
//! It parses the whole input and provides the `program_id`, `accounts` and
//! `instruction_data` separately. This consumes compute units before the
//! program begins its execution. In some cases, it is beneficial for a program
//! to have more control over when input parsing happens, including whether
//! parsing is needed at all - this is the purpose of the
//! [`lazy_program_entrypoint!`] macro. This macro only wraps the program input
//! and provides methods to parse the input on-demand.
//!
//! The [`lazy_program_entrypoint`] is suitable for programs that have a single
//! or very few instructions, since it requires the program to handle the
//! parsing, which can become complex as the number of instructions increases.
//! For *larger* programs, the [`program_entrypoint!`] will likely be easier and
//! more efficient to use.
//!
//! To use the [`lazy_program_entrypoint!`] macro, use the following in your
//! entrypoint definition:
//! ```ignore
//! use pinocchio::{
//!   default_allocator,
//!   default_panic_handler,
//!   entrypoint::InstructionContext,
//!   lazy_program_entrypoint,
//!   ProgramResult
//! };
//!
//! lazy_program_entrypoint!(process_instruction);
//! default_allocator!();
//! default_panic_handler!();
//!
//! pub fn process_instruction(
//!   mut context: InstructionContext
//! ) -> ProgramResult {
//!   Ok(())
//! }
//! ```
//!
//! The [`InstructionContext`](entrypoint::InstructionContext) provides
//! on-demand access to the information of the input:
//!
//! * [`remaining()`](entrypoint::InstructionContext::remaining): number of
//!   available accounts to parse; this number is decremented as the program
//!   parses accounts.
//! * [`next_account()`](entrypoint::InstructionContext::next_account): parses
//!   the next available account (can be used as many times as accounts
//!   available).
//! * [`instruction_data()`](entrypoint::InstructionContext::instruction_data):
//!   parses the instruction data.
//! * [`program_id()`](entrypoint::InstructionContext::program_id): parses the
//!   program id.
//!
//!
//! 💡 The [`lazy_program_entrypoint!`] does not set up a global allocator nor a
//! panic handler. A program should explicitly use one of the provided macros to
//! set them up or include its own implementation.
//!
//! ### [`no_allocator!`]
//!
//! When writing programs, it can be useful to make sure the program does not
//! attempt to make any allocations. In these cases, Pinocchio includes a
//! [`no_allocator!`] macro that sets a global allocator that panics on any
//! attempt to allocate memory.
//!
//! To use the [`no_allocator!`] macro, use the following in your entrypoint
//! definition:
//! ```ignore
//! use pinocchio::{
//!   AccountView,
//!   Address,
//!   default_panic_handler,
//!   no_allocator,
//!   program_entrypoint,
//!   ProgramResult
//! };
//!
//! program_entrypoint!(process_instruction);
//! default_panic_handler!();
//! no_allocator!();
//!
//! pub fn process_instruction(
//!   program_id: &Address,
//!   accounts: &mut [AccountView],
//!   instruction_data: &[u8],
//! ) -> ProgramResult {
//!   Ok(())
//! }
//! ```
//!
//! 💡 The [`no_allocator!`] macro can also be used in combination with the
//! [`lazy_program_entrypoint!`].
//!
//! Since the `no_allocator!` macro does not allocate memory, the `32kb` memory
//! region reserved for the heap remains unused. To take advantage of this, the
//! `no_allocator!` macro emits an `allocate_unchecked` helper function that
//! allows you to manually reserve memory for a type at compile time.
//! ```ignore
//! // static allocation:
//! //    - 0 is the offset when the type will be allocated
//! //    - `allocate_unchecked` returns a mutable reference to the allocated
//! type let lamports = allocate_unchecked::<u64>(0);
//! *lamports = 1_000_000_000;
//! ```
//!
//! Note that it is the developer's responsibility to ensure that types do not
//! overlap in memory - the `offset + <size of type>` of different types must
//! not overlap.
//!
//! ### [`nostd_panic_handler!`]
//!
//! When writing `no_std` programs, it is necessary to declare a panic handler
//! using the [`nostd_panic_handler!`] macro. This macro sets up a default panic
//! handler that logs the location (file, line and column) where the panic
//! occurred and then calls the `abort()` syscall.
//!
//! 💡 The `default_panic_handler!` macro only works in an `std` context.
//!
//! ## Crate features
//!
//! ### `alloc`
//!
//! The `alloc` feature is enabled by default and it uses the [`alloc`](https://doc.rust-lang.org/alloc/)
//! crate. This provides access to dynamic memory allocation in combination with
//! the [`default_allocator!`], e.g., required to use `String` and `Vec` in a
//! program. Helpers that need to allocate memory, such as fetching
//! [`crate::sysvars::slot_hashes::SlotHashes::fetch`] sysvar data, are also
//! available.
//!
//! When no allocation is needed or desired, the feature can be disabled:
//! ```ignore
//! pinocchio = { version = "0.11", default-features = false }
//! ```
//!
//! ### `copy`
//!
//! The `copy` feature enables the derivation of the `Copy` trait for types. It
//! also enables the `copy` feature on the `solana-account-view` and
//! `solana-address` re-exports.
//!
//! ### `cpi`
//!
//! The `cpi` feature enables the cross-program invocation helpers, as well as
//! types to define instructions and signer information.
//! ```ignore
//! pinocchio = { version = "0.11", features = ["cpi"] }
//! ```
//!
//! ### `account-resize`
//!
//! The `account-resize` feature allows a program to grow or shrink an
//! `AccountView`'s data at runtime. At the start of execution, the entrypoint
//! stores the original data length so it can verify that the resize stays
//! within the permitted bounds. This operation consumes `2` CUs per account.
//!
//! ### `unsafe-account-resize`
//!
//! The `unsafe-account-resize` feature, like `account-resize`, allows a program
//! to grow or shrink an `AccountView`'s data at runtime. Unlike
//! `account-resize`, it does not validate the new size, so it adds no
//! entrypoint overhead. The program must ensure that the account remains within
//! the permitted bounds.
//!
//! ## Advanced entrypoint configuration
//!
//! The symbols emitted by the entrypoint macros - program entrypoint, global
//! allocator and default panic handler - can only be defined once globally. If
//! the program crate is also intended to be used as a library, it is common
//! practice to define a Cargo [feature](https://doc.rust-lang.org/cargo/reference/features.html)
//! in your program crate to conditionally enable the module that includes the
//! [`entrypoint!`] macro invocation. The convention is to name the feature
//! `bpf-entrypoint`.
//! ```ignore
//! #[cfg(feature = "bpf-entrypoint")]
//! mod entrypoint {
//!   use pinocchio::{
//!     AccountView,
//!     Address,
//!     entrypoint,
//!     ProgramResult
//!   };
//!
//!   entrypoint!(process_instruction);
//!
//!   pub fn process_instruction(
//!     program_id: &Address,
//!     accounts: &mut [AccountView],
//!     instruction_data: &[u8],
//!   ) -> ProgramResult {
//!     Ok(())
//!   }
//! }
//! ```
//!
//! When building the program binary, you must enable the `bpf-entrypoint`
//! feature:
//! ```ignore
//! cargo build-sbf --features bpf-entrypoint
//! ```
//!
//! ## Upstream BPF compatibility
//!
//! Pinocchio is compatible with the upstream BPF target (`target_arch = bpf`).
//! When using syscalls (e.g., cross-program invocations), it is necessary to
//! explicitly enable static syscalls in your program's `Cargo.toml`:
//! ```toml
//! [dependencies]
//! # Enable static syscalls for BPF target
//! solana-define-syscall = { version = "5.0", features = ["unstable-static-syscalls"] }
//! ```
//!
//! When compiling your program with the upstream BPF target, the `std` library
//! is not available. Therefore, the program crate must include the `#![no_std]`
//! crate-level attribute and use the [`nostd_panic_handler!`] macro. An
//! allocator may be used as long as `alloc` is used.

#[cfg(feature = "alloc")]
extern crate alloc;

pub mod entrypoint;
pub mod sysvars;

// Re-export the `solana_define_syscall` for downstream use.
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
pub use solana_define_syscall::definitions as syscalls;
#[cfg(feature = "account-resize")]
use {
    core::ptr::write_bytes,
    solana_account_view::{RuntimeAccount, MAX_PERMITTED_DATA_INCREASE},
    solana_program_error::ProgramError,
};
// Re-export for downstream use:
//   - `solana_account_view`
//   - `solana_address`
//   - `solana_program_error`
pub use {
    solana_account_view::{self as account, AccountView},
    solana_address::{self as address, Address},
    solana_program_error::{self as error, ProgramResult},
};
// Re-export the `solana_instruction_view` for downstream use.
#[cfg(feature = "cpi")]
pub use {solana_instruction_view as instruction, solana_instruction_view::cpi};

/// Maximum number of accounts that a transaction may process.
///
/// This value is set to `u8::MAX`, which is the theoretical maximum
/// number of accounts that a transaction can process given that indices
/// of accounts are represented by an `u8` value and the last
/// value (`255`) is reserved to indicate non-duplicated accounts.
///
/// The `MAX_TX_ACCOUNTS` is used to statically initialize the array of
/// `AccountView`s when parsing accounts in an instruction.
pub const MAX_TX_ACCOUNTS: usize = u8::MAX as usize;

/// `assert_eq(core::mem::align_of::<u128>(), 8)` is true for BPF but not
/// for some host machines.
const BPF_ALIGN_OF_U128: usize = 8;

/// Return value for a successful program execution.
pub const SUCCESS: u64 = 0;

#[cfg(feature = "account-resize")]
/// Trait to indicate that an account can be resized.
pub trait Resize: sealed::Sealed {
    /// Resize (either truncating or zero extending) the account's data.
    ///
    /// The account data can be increased by up to
    /// [`MAX_PERMITTED_DATA_INCREASE`] bytes within an instruction.
    ///
    /// # Important
    ///
    /// This method makes assumptions about the layout and location of memory
    /// referenced by `RuntimeAccount` fields. It should only be called for
    /// instances of `AccountView` that were created by the runtime and received
    /// in the `process_instruction` entrypoint of a program.
    fn resize(&mut self, new_len: usize) -> Result<(), ProgramError>;

    /// Resize (either truncating or zero extending) the account's data.
    ///
    /// The account data can be increased by up to
    /// [`MAX_PERMITTED_DATA_INCREASE`] bytes within an instruction.
    ///
    /// # Important
    ///
    /// This method makes assumptions about the layout and location of memory
    /// referenced by `RuntimeAccount` fields. It should only be called for
    /// instances of `AccountView` that were created by the runtime and received
    /// in the `process_instruction` entrypoint of a program.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it does not check if the account data is
    /// already borrowed. The caller must guarantee that there are no active
    /// borrows to the account data.
    unsafe fn resize_unchecked(&mut self, new_len: usize) -> Result<(), ProgramError>;
}

#[cfg(all(feature = "unsafe-account-resize", not(feature = "account-resize")))]
pub trait UnsafeResize: sealed::Sealed {
    /// Resize (either truncating or zero extending) the account's data.
    ///
    /// The account data can be increased by up to
    /// [`MAX_PERMITTED_DATA_INCREASE`] bytes within an instruction.
    ///
    /// # Important
    ///
    /// This method makes assumptions about the layout and location of memory
    /// referenced by `RuntimeAccount` fields. It should only be called for
    /// instances of `AccountView` that were created by the runtime and received
    /// in the `process_instruction` entrypoint of a program.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it does not check if the account data is
    /// already borrowed nor validate the `new_len` against the maximum
    /// permitted data increase.
    ///
    /// The caller must guarantee that there are no active borrows to the
    /// account data and that the `new_len` is valid. Resizing an account
    /// beyond [`MAX_PERMITTED_DATA_INCREASE`] leads to out-of-bounds memory
    /// accesses and undefined behavior. Particular care must be taken when
    /// resizing an account after a cross-program invocation, since the
    /// account data may have been resized by the invoked program.
    unsafe fn resize(&mut self, new_len: usize);
}

// Only AccountView is "sealed", so only it can implement `Resize`.
#[cfg(any(feature = "account-resize", feature = "unsafe-account-resize"))]
impl sealed::Sealed for AccountView {}

#[cfg(feature = "account-resize")]
impl Resize for AccountView {
    fn resize(&mut self, new_len: usize) -> Result<(), ProgramError> {
        // Check whether the account data is already borrowed.
        self.check_borrow_mut()?;

        unsafe { self.resize_unchecked(new_len) }
    }

    #[allow(clippy::arithmetic_side_effects)]
    unsafe fn resize_unchecked(&mut self, new_len: usize) -> Result<(), ProgramError> {
        // Return early if length hasn't changed.
        if new_len == self.data_len() {
            return Ok(());
        }

        let account = self.account_ptr() as *mut RuntimeAccount;
        let original_data_len = u32::from_le_bytes(unsafe { (*account).padding }) as usize;
        // Return early if the length increase from the original serialized data
        // length is too large and would result in an out-of-bounds allocation.
        if new_len.saturating_sub(original_data_len) > MAX_PERMITTED_DATA_INCREASE {
            return Err(ProgramError::InvalidRealloc);
        }

        if new_len > self.data_len() {
            unsafe {
                write_bytes(
                    self.data_mut_ptr().add(self.data_len()),
                    0,
                    new_len - self.data_len(),
                );
            }
        }

        unsafe { (*account).data_len = new_len as u64 };

        Ok(())
    }
}

#[cfg(all(feature = "unsafe-account-resize", not(feature = "account-resize")))]
#[allow(clippy::arithmetic_side_effects)]
impl UnsafeResize for AccountView {
    unsafe fn resize(&mut self, new_len: usize) {
        let account = self.account_ptr() as *mut solana_account_view::RuntimeAccount;

        if new_len > self.data_len() {
            unsafe {
                core::ptr::write_bytes(
                    self.data_mut_ptr().add(self.data_len()),
                    0,
                    new_len - self.data_len(),
                );
            }
        }

        unsafe { (*account).data_len = new_len as u64 };
    }
}

// Not `pub`, so other crates cannot name nor implement its trait.
#[cfg(any(feature = "account-resize", feature = "unsafe-account-resize"))]
mod sealed {
    // This is used to "seal" `Resize` and `UnsafeResize` traits, preventing
    // external crates from implementing them for types other than
    // `AccountView`.
    pub trait Sealed {}
}

/// Module with functions to provide hints to the compiler about how code
/// should be optimized.
pub mod hint {
    /// A "dummy" function with a hint to the compiler that it is unlikely to be
    /// called.
    ///
    /// This function is used as a hint to the compiler to optimize other code
    /// paths instead of the one where the function is used.
    #[cold]
    pub const fn cold_path() {}

    /// Return the given `bool` value with a hint to the compiler that `true` is
    /// the likely case.
    #[inline(always)]
    pub const fn likely(b: bool) -> bool {
        if b {
            true
        } else {
            cold_path();
            false
        }
    }

    /// Return a given `bool` value with a hint to the compiler that `false` is
    /// the likely case.
    #[inline(always)]
    pub const fn unlikely(b: bool) -> bool {
        if b {
            cold_path();
            true
        } else {
            false
        }
    }
}

#[cfg(test)]
mod tests {
    use {super::*, solana_account_view::NOT_BORROWED};

    #[test]
    fn test_resize() {
        // 8-bytes aligned account data.
        let mut data = [0u64; 100 * size_of::<u64>()];

        // Set the borrow state.
        data[0] = NOT_BORROWED as u64;
        // Set the initial data length to 100.
        //
        // (dup_marker, signer, writable, executable and padding)
        data[0] = u64::from_le_bytes([255, 0, 0, 0, 100, 0, 0, 0]);
        // `data_len`
        data[10] = 100;

        let runtime_account = data.as_mut_ptr() as *mut RuntimeAccount;
        // SAFETY: `runtime_account` points to a valid in-memory account layout
        // for the duration of this test.
        let mut account = unsafe { AccountView::new_unchecked(runtime_account) };

        assert_eq!(account.data_len(), 100);
        assert_eq!(
            u32::from_le_bytes(unsafe { (*runtime_account).padding }),
            100
        );

        // We should be able to get the data pointer whenever as long as we don't use
        // it while the data is borrowed.
        let data_ptr_before = account.data_ptr();

        // increase the size.

        account.resize(200).unwrap();

        let data_ptr_after = account.data_ptr();
        // The data pointer should point to the same address regardless of the
        // resize.
        assert_eq!(data_ptr_before, data_ptr_after);

        assert_eq!(account.data_len(), 200);

        // decrease the size.

        account.resize(0).unwrap();

        assert_eq!(account.data_len(), 0);

        // Invalid resize.

        let invalid_resize = account.resize(10_000_000_001);
        assert!(invalid_resize.is_err());

        // Reset to its original size.

        account.resize(100).unwrap();

        assert_eq!(account.data_len(), 100);

        // Consecutive resizes.

        account.resize(200).unwrap();
        account.resize(50).unwrap();
        account.resize(500).unwrap();

        assert_eq!(account.data_len(), 500);

        let data = account.try_borrow().unwrap();
        assert_eq!(data.len(), 500);
    }
}