account_info.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. //! Data structures to represent account information.
  2. #![allow(clippy::missing_safety_doc)]
  3. use std::{ptr::NonNull, slice::from_raw_parts_mut};
  4. use crate::{
  5. program_error::ProgramError, pubkey::Pubkey, syscalls::sol_memset_, MAX_PERMITTED_DATA_INCREASE,
  6. };
  7. /// Raw account data.
  8. ///
  9. /// This data is wrapped in an `AccountInfo` struct, which provides safe access
  10. /// to the data.
  11. #[repr(C)]
  12. #[derive(Clone, Copy, Default)]
  13. pub(crate) struct Account {
  14. /// Borrow state of the account data.
  15. ///
  16. /// 0) We reuse the duplicate flag for this. We set it to 0b0000_0000.
  17. /// 1) We use the first four bits to track state of lamport borrow
  18. /// 2) We use the second four bits to track state of data borrow
  19. ///
  20. /// 4 bit state: [1 bit mutable borrow flag | u3 immmutable borrow flag]
  21. /// This gives us up to 7 immutable borrows. Note that does not mean 7
  22. /// duplicate account infos, but rather 7 calls to borrow lamports or
  23. /// borrow data across all duplicate account infos.
  24. pub(crate) borrow_state: u8,
  25. /// Indicates whether the transaction was signed by this account.
  26. is_signer: u8,
  27. /// Indicates whether the account is writable.
  28. is_writable: u8,
  29. /// Indicates whether this account represents a program.
  30. executable: u8,
  31. /// Account's original data length when it was serialized for the
  32. /// current program invocation.
  33. ///
  34. /// The value of this field is lazily initialized to the current data length.
  35. /// On first access, the original data length will be 0. The caller should
  36. /// ensure that the original data length is set to the current data length for
  37. /// subsequence access.
  38. ///
  39. /// The value of this field is currently only used for `realloc`.
  40. original_data_len: [u8; 4],
  41. /// Public key of the account
  42. key: Pubkey,
  43. /// Program that owns this account
  44. owner: Pubkey,
  45. /// The lamports in the account. Modifiable by programs.
  46. lamports: u64,
  47. /// Length of the data.
  48. pub(crate) data_len: u64,
  49. }
  50. // Convenience macro to get the original data length from the account – the value will
  51. // be zero on first access.
  52. macro_rules! get_original_data_len {
  53. ( $self:expr ) => {
  54. unsafe { *(&(*$self).original_data_len as *const _ as *const u32) as usize }
  55. };
  56. }
  57. // Convenience macro to set the original data length in the account.
  58. macro_rules! set_original_data_len {
  59. ( $self:expr, $len:expr ) => {
  60. unsafe {
  61. *(&mut (*$self).original_data_len) = u32::to_le_bytes($len as u32);
  62. }
  63. };
  64. }
  65. /// Wrapper struct for an `Account`.
  66. ///
  67. /// This struct provides safe access to the data in an `Account`. It is also
  68. /// used to track borrows of the account data and lamports, given that an
  69. /// account can be "shared" across multiple `AccountInfo` instances.
  70. #[repr(C)]
  71. #[derive(Clone, PartialEq, Eq)]
  72. pub struct AccountInfo {
  73. /// Raw (pointer to) account data.
  74. ///
  75. /// Note that this is a pointer can be shared across multiple `AccountInfo`.
  76. pub(crate) raw: *mut Account,
  77. }
  78. impl AccountInfo {
  79. /// Public key of the account.
  80. #[inline(always)]
  81. pub fn key(&self) -> &Pubkey {
  82. unsafe { &(*self.raw).key }
  83. }
  84. /// Program that owns this account.
  85. #[inline(always)]
  86. pub fn owner(&self) -> &Pubkey {
  87. unsafe { &(*self.raw).owner }
  88. }
  89. /// Indicates whether the transaction was signed by this account.
  90. #[inline(always)]
  91. pub fn is_signer(&self) -> bool {
  92. unsafe { (*self.raw).is_signer != 0 }
  93. }
  94. /// Indicates whether the account is writable.
  95. #[inline(always)]
  96. pub fn is_writable(&self) -> bool {
  97. unsafe { (*self.raw).is_writable != 0 }
  98. }
  99. /// Indicates whether this account represents a program.
  100. ///
  101. /// Program accounts are always read-only.
  102. #[inline(always)]
  103. pub fn executable(&self) -> bool {
  104. unsafe { (*self.raw).executable != 0 }
  105. }
  106. /// Returns the size of the data in the account.
  107. #[inline(always)]
  108. pub fn data_len(&self) -> usize {
  109. unsafe { (*self.raw).data_len as usize }
  110. }
  111. /// Indicates whether the account data is empty.
  112. ///
  113. /// An account is considered empty if the data length is zero.
  114. #[inline(always)]
  115. pub fn data_is_empty(&self) -> bool {
  116. self.data_len() == 0
  117. }
  118. /// Changes the owner of the account.
  119. #[allow(invalid_reference_casting)]
  120. pub fn assign(&self, new_owner: &Pubkey) {
  121. unsafe {
  122. std::ptr::write_volatile(&(*self.raw).owner as *const _ as *mut Pubkey, *new_owner);
  123. }
  124. }
  125. /// Returns a read-only reference to the lamports in the account.
  126. ///
  127. /// # SAFETY
  128. ///
  129. /// This does not check or modify the 4-bit refcell. Useful when instruction
  130. /// has verified non-duplicate accounts.
  131. pub unsafe fn unchecked_borrow_lamports(&self) -> &u64 {
  132. &(*self.raw).lamports
  133. }
  134. /// Returns a mutable reference to the lamports in the account.
  135. ///
  136. /// # SAFETY
  137. ///
  138. /// This does not check or modify the 4-bit refcell. Useful when instruction
  139. /// has verified non-duplicate accounts.
  140. #[allow(clippy::mut_from_ref)]
  141. pub unsafe fn unchecked_borrow_mut_lamports(&self) -> &mut u64 {
  142. &mut (*self.raw).lamports
  143. }
  144. /// Returns a read-only reference to the data in the account.
  145. ///
  146. /// # SAFETY
  147. ///
  148. /// This does not check or modify the 4-bit refcell. Useful when instruction
  149. /// has verified non-duplicate accounts.
  150. pub unsafe fn unchecked_borrow_data(&self) -> &[u8] {
  151. core::slice::from_raw_parts(self.data_ptr(), self.data_len())
  152. }
  153. /// Returns a mutable reference to the data in the account.
  154. ///
  155. /// # SAFETY
  156. ///
  157. /// This does not check or modify the 4-bit refcell. Useful when instruction
  158. /// has verified non-duplicate accounts.
  159. #[allow(clippy::mut_from_ref)]
  160. pub unsafe fn unchecked_borrow_mut_data(&self) -> &mut [u8] {
  161. core::slice::from_raw_parts_mut(self.data_ptr(), self.data_len())
  162. }
  163. /// Tries to get a read-only reference to the lamport field, failing if the
  164. /// field is already mutable borrowed or if 7 borrows already exist.
  165. pub fn try_borrow_lamports(&self) -> Result<Ref<u64>, ProgramError> {
  166. let borrow_state = unsafe { &mut (*self.raw).borrow_state };
  167. // check if mutable borrow is already taken
  168. if *borrow_state & 0b_1000_0000 != 0 {
  169. return Err(ProgramError::AccountBorrowFailed);
  170. }
  171. // check if we have reached the max immutable borrow count
  172. if *borrow_state & 0b_0111_0000 == 0b_0111_0000 {
  173. return Err(ProgramError::AccountBorrowFailed);
  174. }
  175. // increment the immutable borrow count
  176. *borrow_state += 1 << LAMPORTS_SHIFT;
  177. // return the reference to lamports
  178. Ok(Ref {
  179. value: unsafe { &(*self.raw).lamports },
  180. state: unsafe { NonNull::new_unchecked(&mut (*self.raw).borrow_state) },
  181. borrow_shift: LAMPORTS_SHIFT,
  182. })
  183. }
  184. /// Tries to get a read only reference to the lamport field, failing if the field
  185. /// is already borrowed in any form.
  186. pub fn try_borrow_mut_lamports(&self) -> Result<RefMut<u64>, ProgramError> {
  187. let borrow_state = unsafe { &mut (*self.raw).borrow_state };
  188. // check if any borrow (mutable or immutable) is already taken for lamports
  189. if *borrow_state & 0b_1111_0000 != 0 {
  190. return Err(ProgramError::AccountBorrowFailed);
  191. }
  192. // set the mutable lamport borrow flag
  193. *borrow_state |= 0b_1000_0000;
  194. // return the mutable reference to lamports
  195. Ok(RefMut {
  196. value: unsafe { &mut (*self.raw).lamports },
  197. state: unsafe { NonNull::new_unchecked(&mut (*self.raw).borrow_state) },
  198. borrow_mask: LAMPORTS_MASK,
  199. })
  200. }
  201. /// Tries to get a read only reference to the data field, failing if the field
  202. /// is already mutable borrowed or if 7 borrows already exist.
  203. pub fn try_borrow_data(&self) -> Result<Ref<[u8]>, ProgramError> {
  204. let borrow_state = unsafe { &mut (*self.raw).borrow_state };
  205. // check if mutable data borrow is already taken (most significant bit
  206. // of the data_borrow_state)
  207. if *borrow_state & 0b_0000_1000 != 0 {
  208. return Err(ProgramError::AccountBorrowFailed);
  209. }
  210. // check if we have reached the max immutable data borrow count (7)
  211. if *borrow_state & 0b0111 == 0b0111 {
  212. return Err(ProgramError::AccountBorrowFailed);
  213. }
  214. // increment the immutable data borrow count
  215. *borrow_state += 1;
  216. // return the reference to data
  217. Ok(Ref {
  218. value: unsafe { core::slice::from_raw_parts(self.data_ptr(), self.data_len()) },
  219. state: unsafe { NonNull::new_unchecked(&mut (*self.raw).borrow_state) },
  220. borrow_shift: DATA_SHIFT,
  221. })
  222. }
  223. /// Tries to get a read only reference to the data field, failing if the field
  224. /// is already borrowed in any form.
  225. pub fn try_borrow_mut_data(&self) -> Result<RefMut<[u8]>, ProgramError> {
  226. let borrow_state = unsafe { &mut (*self.raw).borrow_state };
  227. // check if any borrow (mutable or immutable) is already taken for data
  228. if *borrow_state & 0b_0000_1111 != 0 {
  229. return Err(ProgramError::AccountBorrowFailed);
  230. }
  231. // set the mutable data borrow flag
  232. *borrow_state |= 0b0000_1000;
  233. // return the mutable reference to data
  234. Ok(RefMut {
  235. value: unsafe { from_raw_parts_mut(self.data_ptr(), self.data_len()) },
  236. state: unsafe { NonNull::new_unchecked(&mut (*self.raw).borrow_state) },
  237. borrow_mask: DATA_MASK,
  238. })
  239. }
  240. /// Realloc the account's data and optionally zero-initialize the new
  241. /// memory.
  242. ///
  243. /// Note: Account data can be increased within a single call by up to
  244. /// `solana_program::entrypoint::MAX_PERMITTED_DATA_INCREASE` bytes.
  245. ///
  246. /// Note: Memory used to grow is already zero-initialized upon program
  247. /// entrypoint and re-zeroing it wastes compute units. If within the same
  248. /// call a program reallocs from larger to smaller and back to larger again
  249. /// the new space could contain stale data. Pass `true` for `zero_init` in
  250. /// this case, otherwise compute units will be wasted re-zero-initializing.
  251. ///
  252. /// # Safety
  253. ///
  254. /// This method makes assumptions about the layout and location of memory
  255. /// referenced by `AccountInfo` fields. It should only be called for
  256. /// instances of `AccountInfo` that were created by the runtime and received
  257. /// in the `process_instruction` entrypoint of a program.
  258. pub fn realloc(&self, new_len: usize, zero_init: bool) -> Result<(), ProgramError> {
  259. let mut data = self.try_borrow_mut_data()?;
  260. let current_len = data.len();
  261. // return early if length hasn't changed
  262. if new_len == current_len {
  263. return Ok(());
  264. }
  265. let original_len = match get_original_data_len!(self.raw) {
  266. len if len > 0 => len,
  267. _ => {
  268. set_original_data_len!(self.raw, current_len);
  269. current_len
  270. }
  271. };
  272. // return early if the length increase from the original serialized data
  273. // length is too large and would result in an out of bounds allocation
  274. if new_len.saturating_sub(original_len) > MAX_PERMITTED_DATA_INCREASE {
  275. return Err(ProgramError::InvalidRealloc);
  276. }
  277. // realloc
  278. unsafe {
  279. let data_ptr = data.as_mut_ptr();
  280. // set new length in the serialized data
  281. *(data_ptr.offset(-8) as *mut u64) = new_len as u64;
  282. // recreate the local slice with the new length
  283. data.value = from_raw_parts_mut(data_ptr, new_len);
  284. }
  285. if zero_init {
  286. let len_increase = new_len.saturating_sub(current_len);
  287. if len_increase > 0 {
  288. unsafe {
  289. sol_memset_(
  290. &mut data[original_len..] as *mut _ as *mut u8,
  291. 0,
  292. len_increase as u64,
  293. );
  294. }
  295. }
  296. }
  297. Ok(())
  298. }
  299. /// Returns the memory address of the account data.
  300. fn data_ptr(&self) -> *mut u8 {
  301. unsafe { (self.raw as *const _ as *mut u8).add(std::mem::size_of::<Account>()) }
  302. }
  303. }
  304. /// Bytes to shift to get to the borrow state of lamports.
  305. const LAMPORTS_SHIFT: u8 = 4;
  306. /// Bytes to shift to get to the borrow state of data.
  307. const DATA_SHIFT: u8 = 0;
  308. /// Reference to account data or lamports with checked borrow rules.
  309. pub struct Ref<'a, T: ?Sized> {
  310. value: &'a T,
  311. state: NonNull<u8>,
  312. /// Indicates the type of borrow (lamports or data) by representing the
  313. /// shift amount.
  314. borrow_shift: u8,
  315. }
  316. impl<'a, T: ?Sized> core::ops::Deref for Ref<'a, T> {
  317. type Target = T;
  318. fn deref(&self) -> &Self::Target {
  319. self.value
  320. }
  321. }
  322. impl<'a, T: ?Sized> Drop for Ref<'a, T> {
  323. // decrement the immutable borrow count
  324. fn drop(&mut self) {
  325. unsafe { *self.state.as_mut() -= 1 << self.borrow_shift };
  326. }
  327. }
  328. /// Mask representing the mutable borrow flag for lamports.
  329. const LAMPORTS_MASK: u8 = 0b_0111_1111;
  330. /// Mask representing the mutable borrow flag for data.
  331. const DATA_MASK: u8 = 0b_1111_0111;
  332. /// Mutable reference to account data or lamports with checked borrow rules.
  333. pub struct RefMut<'a, T: ?Sized> {
  334. value: &'a mut T,
  335. state: NonNull<u8>,
  336. /// Indicates the type of borrow (lamports or data) by representing the
  337. /// mutable borrow mask.
  338. borrow_mask: u8,
  339. }
  340. impl<'a, T: ?Sized> core::ops::Deref for RefMut<'a, T> {
  341. type Target = T;
  342. fn deref(&self) -> &Self::Target {
  343. self.value
  344. }
  345. }
  346. impl<'a, T: ?Sized> core::ops::DerefMut for RefMut<'a, T> {
  347. fn deref_mut(&mut self) -> &mut <Self as core::ops::Deref>::Target {
  348. self.value
  349. }
  350. }
  351. impl<'a, T: ?Sized> Drop for RefMut<'a, T> {
  352. // unset the mutable borrow flag
  353. fn drop(&mut self) {
  354. unsafe { *self.state.as_mut() &= self.borrow_mask };
  355. }
  356. }