solana_account_view/lib.rs
1//! Data structures to represent account information.
2
3#![no_std]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5#![allow(clippy::arithmetic_side_effects)]
6
7use {
8 core::{
9 marker::PhantomData,
10 mem::{size_of, ManuallyDrop},
11 ops::{Deref, DerefMut},
12 ptr::{addr_of_mut, write, write_bytes, NonNull},
13 slice::{from_raw_parts, from_raw_parts_mut},
14 },
15 solana_address::Address,
16 solana_program_error::{ProgramError, ProgramResult},
17};
18
19/// Maximum number of bytes a program may add to an account during a
20/// single top-level instruction.
21pub const MAX_PERMITTED_DATA_INCREASE: usize = 1_024 * 10;
22
23/// Value to indicate that an account is not borrowed.
24///
25/// This value is the same as `solana_program_entrypoint::NON_DUP_MARKER`.
26pub const NOT_BORROWED: u8 = u8::MAX;
27
28/// Raw account data.
29///
30/// This struct is wrapped by [`AccountView`], which provides safe access
31/// to account information. At runtime, the account's data is serialized
32/// directly after the `Account` struct in memory, with its size specified
33/// by [`RuntimeAccount::data_len`].
34#[repr(C)]
35#[cfg_attr(feature = "copy", derive(Copy))]
36#[derive(Clone, Default)]
37pub struct RuntimeAccount {
38 /// Borrow state for account data.
39 ///
40 /// This reuses the memory reserved for the duplicate flag in the
41 /// account to track data borrows. It represents the numbers of
42 /// borrows available. The value `0` indicates that the account
43 /// data is mutably borrowed, while values between `2` and `255`
44 /// indicate the number of immutable borrows that can still be
45 /// allocated. An account's data can only be mutably borrowed
46 /// when there are no other active borrows, i.e., when this value
47 /// is equal to [`NOT_BORROWED`].
48 pub borrow_state: u8,
49
50 /// Indicates whether the transaction was signed by this account.
51 pub is_signer: u8,
52
53 /// Indicates whether the account is writable.
54 pub is_writable: u8,
55
56 /// Indicates whether this account represents a program.
57 pub executable: u8,
58
59 /// Padding for alignment.
60 ///
61 /// The value of this field is not directly used and always set to `0`.
62 /// Entrypoint implementations may use this space for their own purposes,
63 /// e.g., to track account resizing.
64 pub padding: [u8; 4],
65
66 /// Address of the account.
67 pub address: Address,
68
69 /// Program that owns this account. Modifiable by programs.
70 pub owner: Address,
71
72 /// The lamports in the account. Modifiable by programs.
73 pub lamports: u64,
74
75 /// Length of the data. Modifiable by programs.
76 pub data_len: u64,
77}
78
79/// Wrapper struct for a `RuntimeAccount`.
80///
81/// This struct provides safe access to the data in a `RuntimeAccount`.
82/// It is also used to track borrows of the account data, given that
83/// an account can be "shared" across multiple `AccountView` instances.
84///
85/// # Invariants
86///
87/// - The `raw` pointer must be valid and point to memory containing a
88/// `RuntimeAccount` struct, immediately followed by the account's data
89/// region.
90/// - The length of the account data must exactly match the value stored in
91/// `RuntimeAccount::data_len`.
92///
93/// These conditions must always hold for any `AccountView` created from
94/// a raw pointer.
95#[repr(C)]
96#[cfg_attr(feature = "copy", derive(Copy))]
97#[derive(Clone, PartialEq, Eq, Debug)]
98pub struct AccountView {
99 /// Raw (pointer to) account data.
100 ///
101 /// Note that this is a pointer can be shared across multiple `AccountView`.
102 raw: *mut RuntimeAccount,
103}
104
105impl AccountView {
106 /// Creates a new [`AccountView`] for a given raw account pointer.
107 ///
108 /// # Safety
109 ///
110 /// The caller must ensure that the `raw` pointer is valid and points
111 /// to memory containing a `RuntimeAccount` struct, immediately followed by
112 /// the account's data region.
113 #[inline(always)]
114 pub unsafe fn new_unchecked(raw: *mut RuntimeAccount) -> Self {
115 Self { raw }
116 }
117
118 /// Address of the account.
119 #[inline(always)]
120 pub fn address(&self) -> &Address {
121 // SAFETY: The `raw` pointer is guaranteed to be valid.
122 unsafe { &(*self.raw).address }
123 }
124
125 /// Return a reference to the address of the program that owns this account.
126 ///
127 /// For ownership checks, it is recommended to use the [`Self::owned_by`]
128 /// method instead.
129 ///
130 /// # Important
131 ///
132 /// This method returns a reference to the owner field of the account, which
133 /// can be modified by programs using [`Self::assign`]. It is the caller's
134 /// responsibility to ensure that this reference is not used after the
135 /// account owner has been changed.
136 #[inline(always)]
137 pub fn owner(&self) -> &Address {
138 // SAFETY: The `raw` pointer is guaranteed to be valid.
139 unsafe { &(*self.raw).owner }
140 }
141
142 /// Indicate whether the transaction was signed by this account.
143 #[inline(always)]
144 pub fn is_signer(&self) -> bool {
145 // SAFETY: The `raw` pointer is guaranteed to be valid.
146 unsafe { (*self.raw).is_signer != 0 }
147 }
148
149 /// Indicate whether the account is writable or not.
150 #[inline(always)]
151 pub fn is_writable(&self) -> bool {
152 // SAFETY: The `raw` pointer is guaranteed to be valid.
153 unsafe { (*self.raw).is_writable != 0 }
154 }
155
156 /// Indicate whether this account represents an executable program
157 /// or not.
158 #[inline(always)]
159 pub fn executable(&self) -> bool {
160 // SAFETY: The `raw` pointer is guaranteed to be valid.
161 unsafe { (*self.raw).executable != 0 }
162 }
163
164 /// Return the size of the account data.
165 #[inline(always)]
166 pub fn data_len(&self) -> usize {
167 // SAFETY: The `raw` pointer is guaranteed to be valid.
168 unsafe { (*self.raw).data_len as usize }
169 }
170
171 /// Return the lamports in the account.
172 #[inline(always)]
173 pub fn lamports(&self) -> u64 {
174 // SAFETY: The `raw` pointer is guaranteed to be valid.
175 unsafe { (*self.raw).lamports }
176 }
177
178 /// Set the lamports in the account.
179 #[inline(always)]
180 pub fn set_lamports(&mut self, lamports: u64) {
181 // SAFETY: The `raw` pointer is guaranteed to be valid.
182 unsafe {
183 (*self.raw).lamports = lamports;
184 }
185 }
186
187 /// Indicates whether the account data is empty or not.
188 ///
189 /// An account is considered empty if the data length is zero.
190 #[inline(always)]
191 pub fn is_data_empty(&self) -> bool {
192 // SAFETY: The `raw` pointer is guaranteed to be valid.
193 self.data_len() == 0
194 }
195
196 /// Checks if the account is owned by the given program.
197 #[inline(always)]
198 pub fn owned_by(&self, program: &Address) -> bool {
199 // SAFETY: The `raw` pointer is guaranteed to be valid.
200 unsafe { (*self.raw).owner == *program }
201 }
202
203 /// Changes the owner of the account.
204 ///
205 /// # Safety
206 ///
207 /// It is undefined behavior to use this method while there is an active reference
208 /// to the `owner` returned by [`Self::owner`].
209 #[allow(clippy::clone_on_copy)]
210 #[inline(always)]
211 pub unsafe fn assign(&mut self, new_owner: &Address) {
212 write(addr_of_mut!((*self.raw).owner), new_owner.clone());
213 }
214
215 /// Return `true` if the account data is borrowed in any form.
216 #[inline(always)]
217 pub fn is_borrowed(&self) -> bool {
218 unsafe { (*self.raw).borrow_state != NOT_BORROWED }
219 }
220
221 /// Return `true` if the account data is mutably borrowed.
222 #[inline(always)]
223 pub fn is_borrowed_mut(&self) -> bool {
224 unsafe { (*self.raw).borrow_state == 0 }
225 }
226
227 /// Returns an immutable reference to the data in the account.
228 ///
229 /// # Safety
230 ///
231 /// This method is unsafe because it does not return a `Ref`, thus leaving the borrow
232 /// flag untouched. Useful when an instruction has verified non-duplicate accounts.
233 #[inline(always)]
234 pub unsafe fn borrow_unchecked(&self) -> &[u8] {
235 from_raw_parts(self.data_ptr(), self.data_len())
236 }
237
238 /// Returns a mutable reference to the data in the account.
239 ///
240 /// # Safety
241 ///
242 /// This method is unsafe because it does not return a `RefMut`, thus leaving the borrow
243 /// flag untouched. Useful when an instruction has verified non-duplicate accounts.
244 #[allow(clippy::mut_from_ref)]
245 #[inline(always)]
246 pub unsafe fn borrow_unchecked_mut(&mut self) -> &mut [u8] {
247 from_raw_parts_mut(self.data_mut_ptr(), self.data_len())
248 }
249
250 /// Tries to get an immutable reference to the account data, failing if the account
251 /// is already mutably borrowed.
252 pub fn try_borrow(&self) -> Result<Ref<'_, [u8]>, ProgramError> {
253 // check if the account data can be borrowed
254 self.check_borrow()?;
255
256 let borrow_state = self.raw as *mut u8;
257 // Use one immutable borrow for data by subtracting `1` from the data
258 // borrow counter bits; we are guaranteed that there is at least one
259 // immutable borrow available.
260 //
261 // SAFETY: The `borrow_state` is a mutable pointer to the borrow state
262 // of the account, which is guaranteed to be valid.
263 unsafe { *borrow_state -= 1 };
264
265 // return the reference to data
266 Ok(Ref {
267 value: unsafe { NonNull::from(from_raw_parts(self.data_ptr(), self.data_len())) },
268 state: unsafe { NonNull::new_unchecked(borrow_state) },
269 marker: PhantomData,
270 })
271 }
272
273 /// Tries to get a mutable reference to the account data, failing if the account
274 /// is already borrowed in any form.
275 pub fn try_borrow_mut(&mut self) -> Result<RefMut<'_, [u8]>, ProgramError> {
276 // check if the account data can be mutably borrowed
277 self.check_borrow_mut()?;
278
279 let borrow_state = self.raw as *mut u8;
280 // Set the mutable data borrow bit to `0`; we are guaranteed that account
281 // data is not already borrowed in any form.
282 //
283 // SAFETY: The `borrow_state` is a mutable pointer to the borrow state
284 // of the account, which is guaranteed to be valid.
285 unsafe { *borrow_state = 0 };
286
287 // return the mutable reference to data
288 Ok(RefMut {
289 value: unsafe {
290 NonNull::from(from_raw_parts_mut(self.data_mut_ptr(), self.data_len()))
291 },
292 state: unsafe { NonNull::new_unchecked(borrow_state) },
293 marker: PhantomData,
294 })
295 }
296
297 /// Check if it is possible to get an immutable reference to the account data,
298 /// failing if the account is already mutably borrowed or there are not enough
299 /// immutable borrows available.
300 #[inline(always)]
301 pub fn check_borrow(&self) -> Result<(), ProgramError> {
302 // There must be at least one immutable borrow available.
303 //
304 // SAFETY: The `raw` pointer is guaranteed to be valid.
305 if unsafe { (*self.raw).borrow_state } < 2 {
306 return Err(ProgramError::AccountBorrowFailed);
307 }
308
309 Ok(())
310 }
311
312 /// Checks if it is possible to get a mutable reference to the account data,
313 /// failing if the account is already borrowed in any form.
314 #[inline(always)]
315 pub fn check_borrow_mut(&self) -> Result<(), ProgramError> {
316 // SAFETY: The `raw` pointer is guaranteed to be valid.
317 if unsafe { (*self.raw).borrow_state } != NOT_BORROWED {
318 return Err(ProgramError::AccountBorrowFailed);
319 }
320
321 Ok(())
322 }
323
324 /// Zero out the the account's data length, lamports and owner fields, effectively
325 /// closing the account.
326 ///
327 /// Note: This does not zero the account data. The account data will be zeroed by
328 /// the runtime at the end of the instruction where the account was closed or at the
329 /// next CPI call.
330 ///
331 /// # Important
332 ///
333 /// The lamports must be moved from the account prior to closing it to prevent
334 /// an unbalanced instruction error. Any existing reference to the account owner
335 /// will be invalidated after calling this method.
336 #[inline]
337 pub fn close(&mut self) -> ProgramResult {
338 // Make sure the account is not borrowed since we are about to
339 // resize the data to zero.
340 if self.is_borrowed() {
341 return Err(ProgramError::AccountBorrowFailed);
342 }
343
344 // SAFETY: The are no active borrows on the account data or lamports.
345 unsafe { self.close_unchecked() };
346
347 Ok(())
348 }
349
350 /// Zero out the the account's data length, lamports and owner fields, effectively
351 /// closing the account.
352 ///
353 /// Note: This does not zero the account data. The account data will be zeroed by
354 /// the runtime at the end of the instruction where the account was closed or at the
355 /// next CPI call.
356 ///
357 /// # Important
358 ///
359 /// The lamports must be moved from the account prior to closing it to prevent
360 /// an unbalanced instruction error.
361 ///
362 /// # Safety
363 ///
364 /// This method is unsafe because it does not check if the account data is already
365 /// borrowed. It should only be called when the account is not being used.
366 ///
367 /// It also makes assumptions about the layout and location of memory
368 /// referenced by `RuntimeAccount` fields. It should only be called for
369 /// instances of `AccountView` that were created by the runtime and received
370 /// in the `process_instruction` entrypoint of a program.
371 #[inline(always)]
372 pub unsafe fn close_unchecked(&mut self) {
373 // We take advantage that the 48 bytes before the account data are:
374 // - 32 bytes for the owner
375 // - 8 bytes for the lamports
376 // - 8 bytes for the data_len
377 //
378 // So we can zero out them directly.
379 write_bytes(self.data_mut_ptr().sub(48), 0, 48);
380 }
381
382 /// Returns a raw pointer to the `RuntimeAccount` struct.
383 pub fn account_ptr(&self) -> *const RuntimeAccount {
384 self.raw as *const _
385 }
386
387 /// Returns a mutable raw pointer to the `RuntimeAccount` struct.
388 pub fn account_mut_ptr(&mut self) -> *mut RuntimeAccount {
389 self.raw
390 }
391
392 /// Returns the memory address of the account data.
393 ///
394 /// # Important
395 ///
396 /// Obtaining the raw pointer itself is safe, but de-referencing it requires
397 /// the caller to uphold Rust's aliasing rules. It is undefined behavior to
398 /// de-reference the pointer or write through it while any safe reference
399 /// (e.g., from any of `borrow` or `borrow_mut` methods) to the same data
400 /// is still alive.
401 #[inline(always)]
402 pub const fn data_ptr(&self) -> *const u8 {
403 // SAFETY: The `raw` pointer is guaranteed to be valid.
404 unsafe { (self.raw as *const u8).add(size_of::<RuntimeAccount>()) }
405 }
406
407 /// Returns the memory address of the account data.
408 ///
409 /// # Important
410 ///
411 /// Obtaining the raw pointer itself is safe, but de-referencing it requires
412 /// the caller to uphold Rust's aliasing rules. It is undefined behavior to
413 /// de-reference the pointer or write through it while any safe reference
414 /// (e.g., from any of `borrow` or `borrow_mut` methods) to the same data
415 /// is still alive.
416 #[inline(always)]
417 pub fn data_mut_ptr(&mut self) -> *mut u8 {
418 // SAFETY: The `raw` pointer is guaranteed to be valid.
419 unsafe { (self.raw as *mut u8).add(size_of::<RuntimeAccount>()) }
420 }
421}
422
423/// Allow `AccountView` to be used as a reference to itself
424/// for convenience.
425impl AsRef<AccountView> for AccountView {
426 #[inline(always)]
427 fn as_ref(&self) -> &AccountView {
428 self
429 }
430}
431
432/// Reference to account data with checked borrow rules.
433#[derive(Debug)]
434pub struct Ref<'a, T: ?Sized> {
435 value: NonNull<T>,
436 state: NonNull<u8>,
437 /// The `value` raw pointer is only valid while the `&'a T` lives so we claim
438 /// to hold a reference to it.
439 marker: PhantomData<&'a T>,
440}
441
442impl<'a, T: ?Sized> Ref<'a, T> {
443 /// Maps a reference to a new type.
444 #[inline]
445 pub fn map<U: ?Sized, F>(orig: Ref<'a, T>, f: F) -> Ref<'a, U>
446 where
447 F: FnOnce(&T) -> &U,
448 {
449 // Avoid decrementing the borrow flag on drop.
450 let orig = ManuallyDrop::new(orig);
451 Ref {
452 value: NonNull::from(f(&*orig)),
453 state: orig.state,
454 marker: PhantomData,
455 }
456 }
457
458 /// Tries to makes a new `Ref` for a component of the borrowed data.
459 ///
460 /// On failure, the original guard is returned alongside with the error
461 /// returned by the closure.
462 #[inline]
463 pub fn try_map<U: ?Sized, E>(
464 orig: Ref<'a, T>,
465 f: impl FnOnce(&T) -> Result<&U, E>,
466 ) -> Result<Ref<'a, U>, (Self, E)> {
467 // Avoid decrementing the borrow flag on Drop.
468 let orig = ManuallyDrop::new(orig);
469 match f(&*orig) {
470 Ok(value) => Ok(Ref {
471 value: NonNull::from(value),
472 state: orig.state,
473 marker: PhantomData,
474 }),
475 Err(e) => Err((ManuallyDrop::into_inner(orig), e)),
476 }
477 }
478
479 /// Filters and maps a reference to a new type.
480 ///
481 /// On failure, the original guard is returned.
482 #[inline]
483 pub fn filter_map<U: ?Sized, F>(orig: Ref<'a, T>, f: F) -> Result<Ref<'a, U>, Self>
484 where
485 F: FnOnce(&T) -> Option<&U>,
486 {
487 // Avoid decrementing the borrow flag on drop.
488 let orig = ManuallyDrop::new(orig);
489
490 match f(&*orig) {
491 Some(value) => Ok(Ref {
492 value: NonNull::from(value),
493 state: orig.state,
494 marker: PhantomData,
495 }),
496 None => Err(ManuallyDrop::into_inner(orig)),
497 }
498 }
499}
500
501impl<T: ?Sized> Deref for Ref<'_, T> {
502 type Target = T;
503 fn deref(&self) -> &Self::Target {
504 unsafe { self.value.as_ref() }
505 }
506}
507
508impl<T: ?Sized> Drop for Ref<'_, T> {
509 fn drop(&mut self) {
510 // Increment the available borrow count.
511 unsafe { *self.state.as_mut() += 1 };
512 }
513}
514
515/// Mutable reference to account data with checked borrow rules.
516#[derive(Debug)]
517pub struct RefMut<'a, T: ?Sized> {
518 value: NonNull<T>,
519 state: NonNull<u8>,
520 /// The `value` raw pointer is only valid while the `&'a T` lives so we claim
521 /// to hold a reference to it.
522 marker: PhantomData<&'a mut T>,
523}
524
525impl<'a, T: ?Sized> RefMut<'a, T> {
526 /// Maps a mutable reference to a new type.
527 #[inline]
528 pub fn map<U: ?Sized, F>(orig: RefMut<'a, T>, f: F) -> RefMut<'a, U>
529 where
530 F: FnOnce(&mut T) -> &mut U,
531 {
532 // Avoid decrementing the borrow flag on Drop.
533 let mut orig = ManuallyDrop::new(orig);
534 RefMut {
535 value: NonNull::from(f(&mut *orig)),
536 state: orig.state,
537 marker: PhantomData,
538 }
539 }
540
541 /// Tries to makes a new `RefMut` for a component of the borrowed data.
542 ///
543 /// On failure, the original guard is returned alongside with the error
544 /// returned by the closure.
545 #[inline]
546 pub fn try_map<U: ?Sized, E>(
547 orig: RefMut<'a, T>,
548 f: impl FnOnce(&mut T) -> Result<&mut U, E>,
549 ) -> Result<RefMut<'a, U>, (Self, E)> {
550 // Avoid decrementing the borrow flag on Drop.
551 let mut orig = ManuallyDrop::new(orig);
552 match f(&mut *orig) {
553 Ok(value) => Ok(RefMut {
554 value: NonNull::from(value),
555 state: orig.state,
556 marker: PhantomData,
557 }),
558 Err(e) => Err((ManuallyDrop::into_inner(orig), e)),
559 }
560 }
561
562 /// Filters and maps a mutable reference to a new type.
563 ///
564 /// On failure, the original guard is returned alongside with the error
565 /// returned by the closure.
566 #[inline]
567 pub fn filter_map<U: ?Sized, F>(orig: RefMut<'a, T>, f: F) -> Result<RefMut<'a, U>, Self>
568 where
569 F: FnOnce(&mut T) -> Option<&mut U>,
570 {
571 // Avoid decrementing the mutable borrow flag on Drop.
572 let mut orig = ManuallyDrop::new(orig);
573 match f(&mut *orig) {
574 Some(value) => Ok(RefMut {
575 value: NonNull::from(value),
576 state: orig.state,
577 marker: PhantomData,
578 }),
579 None => Err(ManuallyDrop::into_inner(orig)),
580 }
581 }
582}
583
584impl<T: ?Sized> Deref for RefMut<'_, T> {
585 type Target = T;
586 fn deref(&self) -> &Self::Target {
587 unsafe { self.value.as_ref() }
588 }
589}
590impl<T: ?Sized> DerefMut for RefMut<'_, T> {
591 fn deref_mut(&mut self) -> &mut <Self as core::ops::Deref>::Target {
592 unsafe { self.value.as_mut() }
593 }
594}
595
596impl<T: ?Sized> Drop for RefMut<'_, T> {
597 fn drop(&mut self) {
598 // Reset the borrow state.
599 unsafe { *self.state.as_mut() = NOT_BORROWED };
600 }
601}
602
603#[cfg(test)]
604mod tests {
605 use {
606 super::*,
607 core::mem::{size_of, MaybeUninit},
608 };
609
610 #[test]
611 fn test_ref() {
612 let data: [u8; 4] = [0, 1, 2, 3];
613 let mut state = NOT_BORROWED - 1;
614
615 let ref_data = Ref {
616 value: NonNull::from(&data),
617 // borrow state must be a mutable reference
618 state: NonNull::from(&mut state),
619 marker: PhantomData,
620 };
621
622 let new_ref = Ref::map(ref_data, |data| &data[1]);
623
624 assert_eq!(state, NOT_BORROWED - 1);
625 assert_eq!(*new_ref, 1);
626
627 let Ok(new_ref) = Ref::filter_map(new_ref, |_| Some(&3)) else {
628 unreachable!()
629 };
630
631 assert_eq!(state, NOT_BORROWED - 1);
632 assert_eq!(*new_ref, 3);
633
634 let Ok(new_ref) = Ref::try_map::<_, u8>(new_ref, |_| Ok(&4)) else {
635 unreachable!()
636 };
637
638 assert_eq!(state, NOT_BORROWED - 1);
639 assert_eq!(*new_ref, 4);
640
641 let (new_ref, err) = Ref::try_map::<u8, u8>(new_ref, |_| Err(5)).unwrap_err();
642 assert_eq!(state, NOT_BORROWED - 1);
643 assert_eq!(err, 5);
644 // Unchanged
645 assert_eq!(*new_ref, 4);
646
647 let new_ref = Ref::filter_map(new_ref, |_| Option::<&u8>::None);
648
649 assert_eq!(state, NOT_BORROWED - 1);
650 assert!(new_ref.is_err());
651
652 drop(new_ref);
653
654 assert_eq!(state, NOT_BORROWED);
655 }
656
657 #[test]
658 fn test_ref_mut() {
659 let mut data: [u8; 4] = [0, 1, 2, 3];
660 let mut state = 0;
661
662 let ref_data = RefMut {
663 value: NonNull::from(&mut data),
664 // borrow state must be a mutable reference
665 state: NonNull::from(&mut state),
666 marker: PhantomData,
667 };
668
669 let Ok(mut new_ref) = RefMut::filter_map(ref_data, |data| data.get_mut(0)) else {
670 unreachable!()
671 };
672
673 *new_ref = 4;
674
675 assert_eq!(state, 0);
676 assert_eq!(*new_ref, 4);
677
678 drop(new_ref);
679
680 assert_eq!(data, [4, 1, 2, 3]);
681 assert_eq!(state, NOT_BORROWED);
682 }
683
684 #[test]
685 fn test_borrow() {
686 // 8-bytes aligned account data + 8 bytes of trailing data.
687 let mut data = [0u64; size_of::<RuntimeAccount>() / size_of::<u64>() + 1];
688 data[0] = NOT_BORROWED as u64;
689
690 let account = data.as_mut_ptr() as *mut RuntimeAccount;
691 unsafe { (*account).data_len = 8 };
692
693 let mut account_view = AccountView { raw: account };
694
695 // Check that we can borrow data and lamports.
696 assert!(account_view.check_borrow().is_ok());
697 assert!(account_view.check_borrow_mut().is_ok());
698
699 // It should be sound to mutate the data through the data pointer
700 // while no other borrows exist.
701 let data_ptr = account_view.data_mut_ptr();
702 unsafe {
703 // There are 8 bytes of trailing data.
704 let data = from_raw_parts_mut(data_ptr, 8);
705 data[0] = 1;
706 }
707
708 // Borrow multiple immutable data references (254 immutable borrows
709 // available).
710 const ACCOUNT_REF: MaybeUninit<Ref<[u8]>> = MaybeUninit::<Ref<[u8]>>::uninit();
711 let mut refs = [ACCOUNT_REF; (NOT_BORROWED as usize) - 1];
712
713 refs.iter_mut().for_each(|r| {
714 let Ok(data_ref) = account_view.try_borrow() else {
715 panic!("Failed to borrow data");
716 };
717 // Sanity check: the data pointer should see the change.
718 assert!(data_ref[0] == 1);
719 r.write(data_ref);
720 });
721
722 // Check that we cannot borrow the data anymore.
723 assert!(account_view.check_borrow().is_err());
724 assert!(account_view.try_borrow().is_err());
725 assert!(account_view.check_borrow_mut().is_err());
726
727 // Drop the immutable borrows.
728 refs.iter_mut().for_each(|r| {
729 let r = unsafe { r.assume_init_read() };
730 drop(r);
731 });
732
733 // We should be able to borrow the data again.
734 assert!(account_view.check_borrow().is_ok());
735 assert!(account_view.check_borrow_mut().is_ok());
736
737 // Borrow mutable data.
738 let ref_mut = account_view.try_borrow_mut().unwrap();
739
740 // And drops it.
741 drop(ref_mut);
742
743 // We should be able to borrow the data again.
744 assert!(account_view.check_borrow().is_ok());
745 assert!(account_view.check_borrow_mut().is_ok());
746
747 let borrow_state = unsafe { (*account_view.raw).borrow_state };
748 assert!(borrow_state == NOT_BORROWED);
749 }
750}