Line data Source code
1 : #include "fd_sysvar_instructions.h" 2 : #include "../fd_runtime.h" 3 : #include "../fd_system_ids.h" 4 : 5 : static ulong 6 : instructions_serialized_size( fd_instr_info_t const * instrs, 7 0 : ushort instrs_cnt ) { 8 0 : ulong serialized_size = 0; 9 : 10 0 : serialized_size += sizeof(ushort) // num_instructions 11 0 : + (sizeof(ushort) * instrs_cnt); // instruction offsets 12 : 13 0 : for ( ushort i = 0; i < instrs_cnt; ++i ) { 14 0 : fd_instr_info_t const * instr = &instrs[i]; 15 : 16 0 : serialized_size += sizeof(ushort); // num_accounts; 17 : 18 0 : serialized_size += instr->acct_cnt * ( 19 0 : sizeof(uchar) // flags (is_signer, is_writeable) 20 0 : + sizeof(fd_pubkey_t) // pubkey 21 0 : ); 22 : 23 0 : serialized_size += sizeof(fd_pubkey_t) // program_id pubkey 24 0 : + sizeof(ushort) // instr_data_len; 25 0 : + instr->data_sz; // instr_data; 26 : 27 0 : } 28 : 29 0 : serialized_size += sizeof(ushort); // current_instr_idx 30 : 31 0 : return serialized_size; 32 0 : } 33 : 34 : /* https://github.com/anza-xyz/agave/blob/v2.1.1/svm/src/account_loader.rs#L547-L576 */ 35 : void 36 : fd_sysvar_instructions_serialize_account( fd_txn_in_t const * txn_in, 37 : fd_txn_out_t * txn_out, 38 : fd_instr_info_t const * instrs, 39 : ushort instrs_cnt, 40 0 : ulong txn_idx ) { 41 0 : ulong serialized_sz = instructions_serialized_size( instrs, instrs_cnt ); 42 : 43 0 : fd_txn_account_t * rec = NULL; 44 0 : int err = fd_runtime_get_account_with_key( txn_in, 45 0 : txn_out, 46 0 : &fd_sysvar_instructions_id, 47 0 : &rec, 48 0 : fd_runtime_account_check_exists ); 49 0 : if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS && rec==NULL ) ) { 50 : /* The way we use this, this should NEVER hit since the borrowed accounts should be set up 51 : before this is called, and this is only called if the sysvar instructions account is in 52 : the borrowed accounts list. */ 53 0 : FD_LOG_ERR(( "Failed to view sysvar instructions borrowed account. It may not be included in the txn account keys." )); 54 0 : } 55 : 56 : /* This stays within the FD spad allocation bounds because... 57 : 1. Case 1: rec->meta!=NULL 58 : - rec->meta was set up in `fd_executor_setup_accounts_for_txn()` and data was allocated from the spad 59 : - No need to allocate meta and data here 60 : 2. Case 2: rec->meta==NULL 61 : - `fd_executor_setup_accounts_for_txn()` did not make an spad allocation for this account 62 : - spad memory is sized out for allocations for 128 (max number) accounts 63 : - sizeof(fd_account_meta_t) + serialized_sz will always be less than FD_ACC_TOT_SZ_MAX 64 : - at most 127 accounts could be using spad memory right now, so this allocation is safe */ 65 0 : if( !fd_txn_account_is_mutable( rec ) ) { 66 0 : uchar const * mem = txn_in->exec_accounts->accounts_mem[ txn_idx ]; 67 0 : fd_account_meta_t * meta = (fd_account_meta_t *)mem; 68 0 : fd_txn_account_t * acc = fd_txn_account_join( fd_txn_account_new( rec, &fd_sysvar_instructions_id, meta, 1 ) ); 69 0 : if( FD_UNLIKELY( !acc ) ) { 70 0 : FD_LOG_CRIT(( "Failed to join txn account" )); 71 0 : } 72 0 : } 73 : 74 : /* Agave sets up the borrowed account for the instructions sysvar to contain 75 : default values except for the data which is serialized into the account. */ 76 : 77 0 : fd_txn_account_set_owner( rec, &fd_sysvar_owner_id ); 78 0 : fd_txn_account_set_lamports( rec, 0UL ); 79 0 : fd_txn_account_set_executable( rec, 0 ); 80 0 : fd_txn_account_set_data_len( rec, serialized_sz ); 81 0 : rec->starting_lamports = 0UL; 82 : 83 0 : uchar * serialized_instructions = fd_txn_account_get_data_mut( rec ); 84 0 : ulong offset = 0; 85 : 86 : // TODO: do we needs bounds checking? 87 : // num_instructions 88 0 : FD_STORE( ushort, serialized_instructions + offset, instrs_cnt); 89 0 : offset += sizeof(ushort); 90 : 91 : // instruction offsets 92 0 : uchar * serialized_instruction_offsets = serialized_instructions + offset; 93 0 : offset += (ushort)(sizeof(ushort) * instrs_cnt); 94 : 95 : // serialize instructions 96 0 : for( ushort i = 0; i < instrs_cnt; ++i ) { 97 : // set the instruction offset 98 0 : FD_STORE( ushort, serialized_instruction_offsets, (ushort) offset ); 99 0 : serialized_instruction_offsets += sizeof(ushort); 100 : 101 0 : fd_instr_info_t const * instr = &instrs[i]; 102 : 103 : // num_accounts 104 0 : FD_STORE( ushort, serialized_instructions + offset, instr->acct_cnt ); 105 0 : offset += sizeof(ushort); 106 : 107 0 : for ( ushort j = 0; j < instr->acct_cnt; j++ ) { 108 : // flags 109 0 : FD_STORE( uchar, serialized_instructions + offset, fd_instr_get_acc_flags( instr, j ) ); 110 0 : offset += sizeof(uchar); 111 : 112 : // pubkey 113 0 : ushort idx_in_txn = instr->accounts[j].index_in_transaction; 114 0 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, txn_out->accounts.account_keys[ idx_in_txn ] ); 115 0 : offset += sizeof(fd_pubkey_t); 116 0 : } 117 : 118 : // program_id_pubkey 119 0 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, txn_out->accounts.account_keys[ instr->program_id ] ); 120 0 : offset += sizeof(fd_pubkey_t); 121 : 122 : // instr_data_len 123 0 : FD_STORE( ushort, serialized_instructions + offset, instr->data_sz ); 124 0 : offset += sizeof(ushort); 125 : 126 : // instr_data 127 0 : fd_memcpy( serialized_instructions + offset, instr->data, instr->data_sz ); 128 0 : offset += instr->data_sz; 129 0 : } 130 : 131 : // 132 0 : FD_STORE( ushort, serialized_instructions + offset, 0 ); 133 0 : offset += sizeof(ushort); 134 0 : } 135 : 136 : /* Stores the current instruction index in the instructions sysvar account. 137 : https://github.com/anza-xyz/solana-sdk/blob/instructions-sysvar%40v2.2.1/instructions-sysvar/src/lib.rs#L164-L167 */ 138 : void 139 : fd_sysvar_instructions_update_current_instr_idx( fd_txn_account_t * rec, 140 0 : ushort current_instr_idx ) { 141 : /* Extra safety checks */ 142 0 : if( FD_UNLIKELY( fd_txn_account_get_data_len( rec )<sizeof(ushort) ) ) { 143 0 : return; 144 0 : } 145 : 146 0 : uchar * serialized_current_instr_idx = fd_txn_account_get_data_mut( rec ) + (fd_txn_account_get_data_len( rec ) - sizeof(ushort)); 147 0 : FD_STORE( ushort, serialized_current_instr_idx, current_instr_idx ); 148 0 : }