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