1#[cfg(feature = "dev-context-only-utils")]
2use qualifier_attr::qualifiers;
3use {
4 crate::{
5 IndexOfAccount, MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION, MAX_ACCOUNT_DATA_LEN,
6 vm_addresses::{GUEST_ACCOUNT_PAYLOAD_BASE_ADDRESS, GUEST_REGION_SIZE},
7 vm_slice::VmSlice,
8 },
9 solana_account::{AccountSharedData, ReadableAccount, WritableAccount},
10 solana_instruction::error::InstructionError,
11 solana_pubkey::Pubkey,
12 std::{
13 cell::{Cell, UnsafeCell},
14 ops::{Deref, DerefMut},
15 ptr,
16 sync::Arc,
17 },
18};
19
20#[repr(C)]
22#[derive(Debug, PartialEq)]
23struct AccountSharedFields {
24 key: Pubkey,
25 owner: Pubkey,
26 lamports: u64,
27 payload: VmSlice<u8>,
30}
31
32#[derive(Debug, PartialEq)]
33#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
34struct AccountPrivateFields {
35 rent_epoch: u64,
36 executable: bool,
37 payload: Arc<Vec<u8>>,
38}
39
40#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
41impl AccountPrivateFields {
42 fn payload_len(&self) -> usize {
43 self.payload.len()
44 }
45}
46
47#[derive(Debug, PartialEq)]
48#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
49pub struct TransactionAccountView<'a> {
50 abi_account: &'a AccountSharedFields,
51 private_fields: &'a AccountPrivateFields,
52}
53
54#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
55impl ReadableAccount for TransactionAccountView<'_> {
56 fn lamports(&self) -> u64 {
57 self.abi_account.lamports
58 }
59
60 fn data(&self) -> &[u8] {
61 self.private_fields.payload.as_slice()
62 }
63
64 fn owner(&self) -> &Pubkey {
65 &self.abi_account.owner
66 }
67
68 fn executable(&self) -> bool {
69 self.private_fields.executable
70 }
71
72 fn rent_epoch(&self) -> u64 {
73 self.private_fields.rent_epoch
74 }
75}
76
77#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
78impl PartialEq<AccountSharedData> for TransactionAccountView<'_> {
79 fn eq(&self, other: &AccountSharedData) -> bool {
80 other.lamports() == self.lamports()
81 && other.data() == self.data()
82 && other.owner() == self.owner()
83 && other.executable() == self.executable()
84 && other.rent_epoch() == self.rent_epoch()
85 }
86}
87
88#[derive(Debug)]
89#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
90pub struct TransactionAccountViewMut<'a> {
91 abi_account: &'a mut AccountSharedFields,
92 private_fields: &'a mut AccountPrivateFields,
93}
94
95#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
96impl TransactionAccountViewMut<'_> {
97 fn data_mut(&mut self) -> &mut Vec<u8> {
98 Arc::make_mut(&mut self.private_fields.payload)
99 }
100
101 pub(crate) fn raw_mut_data_slice(&mut self) -> *mut [u8] {
102 &raw mut self.data_mut()[..]
103 }
104
105 pub(crate) fn resize(&mut self, new_len: usize, value: u8) {
106 self.data_mut().resize(new_len, value);
107 self.abi_account.payload.set_len(new_len as u64);
108 }
109
110 #[cfg_attr(feature = "dev-context-only-utils", qualifiers(pub))]
111 pub(crate) fn set_data_from_slice(&mut self, new_data: &[u8]) {
112 let Some(data) = Arc::get_mut(&mut self.private_fields.payload) else {
114 self.private_fields.payload = Arc::new(new_data.to_vec());
117 self.abi_account.payload.set_len(new_data.len() as u64);
118 return;
119 };
120
121 let new_len = new_data.len();
122
123 data.reserve(new_len.saturating_sub(data.len()));
138
139 unsafe {
144 data.set_len(0);
145 ptr::copy_nonoverlapping(new_data.as_ptr(), data.as_mut_ptr(), new_len);
146 data.set_len(new_len);
147 self.abi_account.payload.set_len(new_len as u64);
148 };
149 }
150
151 pub(crate) fn extend_from_slice(&mut self, data: &[u8]) {
152 self.data_mut().extend_from_slice(data);
153 self.abi_account
154 .payload
155 .set_len(self.private_fields.payload_len() as u64);
156 }
157
158 pub(crate) fn reserve(&mut self, additional: usize) {
159 if let Some(data) = Arc::get_mut(&mut self.private_fields.payload) {
160 data.reserve(additional)
161 } else {
162 let mut data =
163 Vec::with_capacity(self.private_fields.payload_len().saturating_add(additional));
164 data.extend_from_slice(self.private_fields.payload.as_slice());
165 self.private_fields.payload = Arc::new(data);
166 }
167 }
168
169 #[cfg_attr(feature = "dev-context-only-utils", qualifiers(pub))]
170 pub(crate) fn is_shared(&self) -> bool {
171 Arc::strong_count(&self.private_fields.payload) > 1
172 }
173}
174
175#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
176impl ReadableAccount for TransactionAccountViewMut<'_> {
177 fn lamports(&self) -> u64 {
178 self.abi_account.lamports
179 }
180
181 fn data(&self) -> &[u8] {
182 self.private_fields.payload.as_slice()
183 }
184
185 fn owner(&self) -> &Pubkey {
186 &self.abi_account.owner
187 }
188
189 fn executable(&self) -> bool {
190 self.private_fields.executable
191 }
192
193 fn rent_epoch(&self) -> u64 {
194 self.private_fields.rent_epoch
195 }
196}
197
198#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
199impl WritableAccount for TransactionAccountViewMut<'_> {
200 fn set_lamports(&mut self, lamports: u64) {
201 self.abi_account.lamports = lamports;
202 }
203
204 fn data_as_mut_slice(&mut self) -> &mut [u8] {
205 Arc::make_mut(&mut self.private_fields.payload).as_mut_slice()
206 }
207
208 fn set_owner(&mut self, owner: Pubkey) {
209 self.abi_account.owner = owner;
210 }
211
212 fn copy_into_owner_from_slice(&mut self, source: &[u8]) {
213 self.abi_account.owner.as_mut().copy_from_slice(source);
214 }
215
216 fn set_executable(&mut self, executable: bool) {
217 self.private_fields.executable = executable;
218 }
219
220 fn set_rent_epoch(&mut self, epoch: u64) {
221 self.private_fields.rent_epoch = epoch;
222 }
223}
224
225#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
227pub type KeyedAccountSharedData = (Pubkey, AccountSharedData);
228#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
229pub(crate) type DeconstructedTransactionAccounts =
230 (Vec<KeyedAccountSharedData>, Box<[Cell<bool>]>, Cell<i64>);
231
232#[derive(Debug)]
233#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
234pub struct TransactionAccounts {
235 shared_account_fields: Box<[UnsafeCell<AccountSharedFields>]>,
236 private_account_fields: Box<[UnsafeCell<AccountPrivateFields>]>,
237 borrow_counters: Box<[BorrowCounter]>,
238 touched_flags: Box<[Cell<bool>]>,
239 resize_delta: Cell<i64>,
240 lamports_delta: Cell<i128>,
241}
242
243#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
244impl TransactionAccounts {
245 pub(crate) fn new(accounts: Vec<KeyedAccountSharedData>) -> TransactionAccounts {
246 let touched_flags = vec![Cell::new(false); accounts.len()].into_boxed_slice();
247 let borrow_counters = vec![BorrowCounter::default(); accounts.len()].into_boxed_slice();
248 let (shared_accounts, private_fields) = accounts
249 .into_iter()
250 .enumerate()
251 .map(|(idx, item)| {
252 (
253 UnsafeCell::new(AccountSharedFields {
254 key: item.0,
255 owner: *item.1.owner(),
256 lamports: item.1.lamports(),
257 payload: VmSlice::new(
258 GUEST_ACCOUNT_PAYLOAD_BASE_ADDRESS
259 .saturating_add(GUEST_REGION_SIZE.saturating_mul(idx as u64)),
260 item.1.data().len() as u64,
261 ),
262 }),
263 UnsafeCell::new(AccountPrivateFields {
264 rent_epoch: item.1.rent_epoch(),
265 executable: item.1.executable(),
266 payload: item.1.data_clone(),
267 }),
268 )
269 })
270 .collect::<(
271 Vec<UnsafeCell<AccountSharedFields>>,
272 Vec<UnsafeCell<AccountPrivateFields>>,
273 )>();
274
275 TransactionAccounts {
276 shared_account_fields: shared_accounts.into_boxed_slice(),
277 private_account_fields: private_fields.into_boxed_slice(),
278 borrow_counters,
279 touched_flags,
280 resize_delta: Cell::new(0),
281 lamports_delta: Cell::new(0),
282 }
283 }
284
285 pub(crate) fn len(&self) -> usize {
286 self.shared_account_fields.len()
287 }
288
289 pub fn touch(&self, index: IndexOfAccount) -> Result<(), InstructionError> {
290 self.touched_flags
291 .get(index as usize)
292 .ok_or(InstructionError::MissingAccount)?
293 .set(true);
294 Ok(())
295 }
296
297 pub(crate) fn update_accounts_resize_delta(
298 &self,
299 old_len: usize,
300 new_len: usize,
301 ) -> Result<(), InstructionError> {
302 let accounts_resize_delta = self.resize_delta.get();
303 self.resize_delta.set(
304 accounts_resize_delta.saturating_add((new_len as i64).saturating_sub(old_len as i64)),
305 );
306 Ok(())
307 }
308
309 pub(crate) fn can_data_be_resized(
310 &self,
311 old_len: usize,
312 new_len: usize,
313 ) -> Result<(), InstructionError> {
314 if new_len > MAX_ACCOUNT_DATA_LEN as usize {
316 return Err(InstructionError::InvalidRealloc);
317 }
318 let length_delta = (new_len as i64).saturating_sub(old_len as i64);
320 if self.resize_delta.get().saturating_add(length_delta)
321 > MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION
322 {
323 return Err(InstructionError::MaxAccountsDataAllocationsExceeded);
324 }
325 Ok(())
326 }
327
328 #[cfg_attr(feature = "dev-context-only-utils", qualifiers(pub))]
329 pub(crate) fn try_borrow_mut(
330 &self,
331 index: IndexOfAccount,
332 ) -> Result<AccountRefMut<'_>, InstructionError> {
333 let borrow_counter = self
334 .borrow_counters
335 .get(index as usize)
336 .ok_or(InstructionError::MissingAccount)?;
337 borrow_counter.try_borrow_mut()?;
338
339 let svm_account = unsafe {
343 &mut *self
344 .shared_account_fields
345 .get(index as usize)
346 .unwrap()
347 .get()
348 };
349
350 let private_fields = unsafe {
351 &mut *self
352 .private_account_fields
353 .get(index as usize)
354 .unwrap()
355 .get()
356 };
357
358 let account = TransactionAccountViewMut {
359 abi_account: svm_account,
360 private_fields,
361 };
362
363 Ok(AccountRefMut {
364 account,
365 borrow_counter,
366 })
367 }
368
369 pub fn try_borrow(&self, index: IndexOfAccount) -> Result<AccountRef<'_>, InstructionError> {
370 let borrow_counter = self
371 .borrow_counters
372 .get(index as usize)
373 .ok_or(InstructionError::MissingAccount)?;
374 borrow_counter.try_borrow()?;
375
376 let svm_account = unsafe {
380 &*self
381 .shared_account_fields
382 .get(index as usize)
383 .unwrap()
384 .get()
385 };
386
387 let private_fields = unsafe {
388 &*self
389 .private_account_fields
390 .get(index as usize)
391 .unwrap()
392 .get()
393 };
394
395 let account = TransactionAccountView {
396 abi_account: svm_account,
397 private_fields,
398 };
399
400 Ok(AccountRef {
401 account,
402 borrow_counter,
403 })
404 }
405
406 pub(crate) fn add_lamports_delta(&self, balance: i128) -> Result<(), InstructionError> {
407 let delta = self.lamports_delta.get();
408 self.lamports_delta.set(
409 delta
410 .checked_add(balance)
411 .ok_or(InstructionError::ArithmeticOverflow)?,
412 );
413 Ok(())
414 }
415
416 pub(crate) fn get_lamports_delta(&self) -> i128 {
417 self.lamports_delta.get()
418 }
419
420 fn deconstruct_into_keyed_account_shared_data(&mut self) -> Vec<KeyedAccountSharedData> {
421 let shared_account_fields = std::mem::take(&mut self.shared_account_fields);
422 let private_account_fields = std::mem::take(&mut self.private_account_fields);
423 shared_account_fields
424 .into_iter()
425 .zip(private_account_fields)
426 .map(|(shared_fields_cell, private_fields_cell)| {
427 let shared_fields = shared_fields_cell.into_inner();
428 let private_fields = private_fields_cell.into_inner();
429 (
430 shared_fields.key,
431 AccountSharedData::create_from_existing_shared_data(
432 shared_fields.lamports,
433 private_fields.payload.clone(),
434 shared_fields.owner,
435 private_fields.executable,
436 private_fields.rent_epoch,
437 ),
438 )
439 })
440 .collect()
441 }
442
443 pub(crate) fn deconstruct_into_account_shared_data(&mut self) -> Vec<AccountSharedData> {
444 let shared_account_fields = std::mem::take(&mut self.shared_account_fields);
445 let private_account_fields = std::mem::take(&mut self.private_account_fields);
446 shared_account_fields
447 .into_iter()
448 .zip(private_account_fields)
449 .map(|(shared_fields_cell, private_fields_cell)| {
450 let shared_fields = shared_fields_cell.into_inner();
451 let private_fields = private_fields_cell.into_inner();
452 AccountSharedData::create_from_existing_shared_data(
453 shared_fields.lamports,
454 private_fields.payload.clone(),
455 shared_fields.owner,
456 private_fields.executable,
457 private_fields.rent_epoch,
458 )
459 })
460 .collect()
461 }
462
463 pub(crate) fn take(mut self) -> DeconstructedTransactionAccounts {
464 let shared_data = self.deconstruct_into_keyed_account_shared_data();
465 (shared_data, self.touched_flags, self.resize_delta)
466 }
467
468 pub fn resize_delta(&self) -> i64 {
469 self.resize_delta.get()
470 }
471
472 pub(crate) fn account_key(&self, index: IndexOfAccount) -> Option<&Pubkey> {
473 unsafe {
475 self.shared_account_fields
476 .get(index as usize)
477 .map(|acc| &(*acc.get()).key)
478 }
479 }
480
481 pub(crate) fn account_keys_iter(&self) -> impl Iterator<Item = &Pubkey> {
482 unsafe {
484 self.shared_account_fields
485 .iter()
486 .map(|item| &(*item.get()).key)
487 }
488 }
489}
490
491#[derive(Default, Debug, Clone)]
492#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
493struct BorrowCounter {
494 counter: Cell<i8>,
495}
496
497#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
498impl BorrowCounter {
499 #[inline]
500 fn is_writing(&self) -> bool {
501 self.counter.get() < 0
502 }
503
504 #[inline]
505 fn is_reading(&self) -> bool {
506 self.counter.get() > 0
507 }
508
509 #[inline]
510 fn try_borrow(&self) -> Result<(), InstructionError> {
511 if self.is_writing() {
512 return Err(InstructionError::AccountBorrowFailed);
513 }
514
515 if let Some(counter) = self.counter.get().checked_add(1) {
516 self.counter.set(counter);
517 return Ok(());
518 }
519
520 Err(InstructionError::AccountBorrowFailed)
521 }
522
523 #[inline]
524 fn try_borrow_mut(&self) -> Result<(), InstructionError> {
525 if self.is_writing() || self.is_reading() {
526 return Err(InstructionError::AccountBorrowFailed);
527 }
528
529 self.counter.set(self.counter.get().saturating_sub(1));
530
531 Ok(())
532 }
533
534 #[inline]
535 fn release_borrow(&self) {
536 self.counter.set(self.counter.get().saturating_sub(1));
537 }
538
539 #[inline]
540 fn release_borrow_mut(&self) {
541 self.counter.set(self.counter.get().saturating_add(1));
542 }
543}
544
545#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
546pub struct AccountRef<'a> {
547 account: TransactionAccountView<'a>,
548 borrow_counter: &'a BorrowCounter,
549}
550
551#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
552impl Drop for AccountRef<'_> {
553 fn drop(&mut self) {
554 self.borrow_counter.release_borrow();
555 }
556}
557
558#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
559impl<'a> Deref for AccountRef<'a> {
560 type Target = TransactionAccountView<'a>;
561 fn deref(&self) -> &Self::Target {
562 &self.account
563 }
564}
565
566#[derive(Debug)]
567#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
568pub struct AccountRefMut<'a> {
569 account: TransactionAccountViewMut<'a>,
570 borrow_counter: &'a BorrowCounter,
571}
572
573#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
574impl Drop for AccountRefMut<'_> {
575 fn drop(&mut self) {
576 self.account
577 .abi_account
578 .payload
579 .set_len(self.account.private_fields.payload_len() as u64);
580 self.borrow_counter.release_borrow_mut();
581 }
582}
583
584#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
585impl<'a> Deref for AccountRefMut<'a> {
586 type Target = TransactionAccountViewMut<'a>;
587 fn deref(&self) -> &Self::Target {
588 &self.account
589 }
590}
591
592#[cfg(not(any(target_arch = "bpf", target_arch = "sbf")))]
593impl DerefMut for AccountRefMut<'_> {
594 fn deref_mut(&mut self) -> &mut Self::Target {
595 &mut self.account
596 }
597}
598
599#[cfg(all(test, not(target_arch = "sbf"), not(target_arch = "bpf")))]
600mod tests {
601 use {
602 crate::transaction_accounts::TransactionAccounts, solana_account::AccountSharedData,
603 solana_instruction::error::InstructionError, solana_pubkey::Pubkey,
604 };
605
606 #[test]
607 fn test_missing_account() {
608 let accounts = vec![
609 (
610 Pubkey::new_unique(),
611 AccountSharedData::new(2, 1, &Pubkey::new_unique()),
612 ),
613 (
614 Pubkey::new_unique(),
615 AccountSharedData::new(2, 1, &Pubkey::new_unique()),
616 ),
617 ];
618
619 let tx_accounts = TransactionAccounts::new(accounts);
620
621 let res = tx_accounts.try_borrow(3);
622 assert_eq!(res.err(), Some(InstructionError::MissingAccount));
623
624 let res = tx_accounts.try_borrow_mut(3);
625 assert_eq!(res.err(), Some(InstructionError::MissingAccount));
626 }
627
628 #[test]
629 fn test_invalid_borrow() {
630 let accounts = vec![
631 (
632 Pubkey::new_unique(),
633 AccountSharedData::new(2, 1, &Pubkey::new_unique()),
634 ),
635 (
636 Pubkey::new_unique(),
637 AccountSharedData::new(2, 1, &Pubkey::new_unique()),
638 ),
639 ];
640
641 let tx_accounts = TransactionAccounts::new(accounts);
642
643 {
645 let acc_1 = tx_accounts.try_borrow(0);
646 assert!(acc_1.is_ok());
647
648 let acc_2 = tx_accounts.try_borrow(1);
649 assert!(acc_2.is_ok());
650
651 let acc_1_new = tx_accounts.try_borrow(0);
652 assert!(acc_1_new.is_ok());
653
654 assert_eq!(acc_1.unwrap().account, acc_1_new.unwrap().account);
655 }
656
657 {
659 let acc_1 = tx_accounts.try_borrow_mut(0);
660 assert!(acc_1.is_ok());
661
662 let acc_2 = tx_accounts.try_borrow_mut(1);
663 assert!(acc_2.is_ok());
664
665 let acc_1_new = tx_accounts.try_borrow_mut(0);
666 assert_eq!(acc_1_new.err(), Some(InstructionError::AccountBorrowFailed));
667 }
668
669 {
671 let acc_1 = tx_accounts.try_borrow(0);
672 assert!(acc_1.is_ok());
673
674 let acc_2 = tx_accounts.try_borrow(1);
675 assert!(acc_2.is_ok());
676
677 let acc_1_new = tx_accounts.try_borrow_mut(0);
678 assert_eq!(acc_1_new.err(), Some(InstructionError::AccountBorrowFailed));
679 }
680
681 {
683 let acc_1 = tx_accounts.try_borrow_mut(0);
684 assert!(acc_1.is_ok());
685
686 let acc_2 = tx_accounts.try_borrow_mut(1);
687 assert!(acc_2.is_ok());
688
689 let acc_1_new = tx_accounts.try_borrow(0);
690 assert_eq!(acc_1_new.err(), Some(InstructionError::AccountBorrowFailed));
691 }
692
693 {
695 let acc_1 = tx_accounts.try_borrow_mut(0);
696 assert!(acc_1.is_ok());
697 }
698
699 {
700 let acc_1 = tx_accounts.try_borrow_mut(0);
701 assert!(acc_1.is_ok());
702 }
703 }
704
705 #[test]
706 fn too_many_borrows() {
707 let accounts = vec![
708 (
709 Pubkey::new_unique(),
710 AccountSharedData::new(2, 1, &Pubkey::new_unique()),
711 ),
712 (
713 Pubkey::new_unique(),
714 AccountSharedData::new(2, 1, &Pubkey::new_unique()),
715 ),
716 ];
717
718 let tx_accounts = TransactionAccounts::new(accounts);
719 let mut borrows = Vec::new();
720 for i in 0..129 {
721 let acc = tx_accounts.try_borrow(1);
722 if i < 127 {
723 assert!(acc.is_ok());
724 borrows.push(acc.unwrap());
725 } else {
726 assert_eq!(acc.err(), Some(InstructionError::AccountBorrowFailed));
727 }
728 }
729 }
730}