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