Skip to main content

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}