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