Line data Source code
1 : #include "fd_sysvar_instructions.h" 2 : #include "../fd_borrowed_account.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_exec_txn_ctx_t * txn_ctx, 37 : fd_instr_info_t const * instrs, 38 0 : ushort instrs_cnt ) { 39 0 : ulong serialized_sz = instructions_serialized_size( instrs, instrs_cnt ); 40 : 41 0 : fd_txn_account_t * rec = NULL; 42 0 : int err = fd_exec_txn_ctx_get_account_view( txn_ctx, &fd_sysvar_instructions_id, &rec ); 43 0 : if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS && rec == NULL ) ) { 44 : /* The way we use this, this should NEVER hit since the borrowed accounts should be set up 45 : before this is called, and this is only called if the sysvar instructions account is in 46 : the borrowed accounts list. */ 47 0 : FD_LOG_ERR(( "Failed to view sysvar instructions borrowed account. It may not be included in the txn account keys." )); 48 0 : } 49 : 50 : /* This stays within the FD spad allocation bounds because... 51 : 1. Case 1: rec->meta!=NULL 52 : - rec->meta was set up in `fd_executor_setup_borrowed_accounts_for_txn()` and data was allocated from the spad 53 : - No need to allocate meta and data here 54 : 2. Case 2: rec->meta==NULL 55 : - `fd_executor_setup_borrowed_accounts_for_txn()` did not make an spad allocation for this account 56 : - spad memory is sized out for allocations for 128 (max number) accounts 57 : - sizeof(fd_account_meta_t) + serialized_sz will always be less than FD_ACC_TOT_SZ_MAX 58 : - at most 127 accounts could be using spad memory right now, so this allocation is safe */ 59 0 : if( rec->meta==NULL ) { 60 0 : fd_account_meta_t * meta = fd_spad_alloc( txn_ctx->spad, alignof(fd_account_meta_t), sizeof(fd_account_meta_t) + serialized_sz ); 61 0 : void * data = (uchar *)meta + sizeof(fd_account_meta_t); 62 : 63 0 : rec->const_meta = rec->meta = meta; 64 0 : rec->const_data = rec->data = data; 65 0 : } 66 : 67 : /* Agave sets up the borrowed account for the instructions sysvar to contain 68 : default values except for the data which is serialized into the account. */ 69 : 70 0 : memcpy( rec->meta->info.owner, fd_sysvar_owner_id.key, sizeof(fd_pubkey_t) ); 71 0 : rec->starting_lamports = 0UL; 72 0 : rec->meta->info.lamports = 0UL; // TODO: This cannot be right... well, it gets destroyed almost instantly... 73 0 : rec->meta->info.executable = 0; 74 0 : rec->meta->info.rent_epoch = 0UL; 75 0 : rec->meta->dlen = serialized_sz; 76 : 77 0 : uchar * serialized_instructions = rec->data; 78 0 : ulong offset = 0; 79 : 80 : // TODO: do we needs bounds checking? 81 : // num_instructions 82 0 : FD_STORE( ushort, serialized_instructions + offset, instrs_cnt); 83 0 : offset += sizeof(ushort); 84 : 85 : // instruction offsets 86 0 : uchar * serialized_instruction_offsets = serialized_instructions + offset; 87 0 : offset += (ushort)(sizeof(ushort) * instrs_cnt); 88 : 89 : // serialize instructions 90 0 : for( ushort i = 0; i < instrs_cnt; ++i ) { 91 : // set the instruction offset 92 0 : FD_STORE( ushort, serialized_instruction_offsets, (ushort) offset ); 93 0 : serialized_instruction_offsets += sizeof(ushort); 94 : 95 0 : fd_instr_info_t const * instr = &instrs[i]; 96 : 97 : // num_accounts 98 0 : FD_STORE( ushort, serialized_instructions + offset, instr->acct_cnt ); 99 0 : offset += sizeof(ushort); 100 : 101 0 : for ( ushort j = 0; j < instr->acct_cnt; j++ ) { 102 : // flags 103 0 : FD_STORE( uchar, serialized_instructions + offset, instr->acct_flags[j] ); 104 0 : offset += sizeof(uchar); 105 : 106 : // pubkey 107 0 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, instr->acct_pubkeys[j] ); 108 0 : offset += sizeof(fd_pubkey_t); 109 0 : } 110 : 111 : // program_id_pubkey 112 0 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, instr->program_id_pubkey ); 113 0 : offset += sizeof(fd_pubkey_t); 114 : 115 : // instr_data_len 116 0 : FD_STORE( ushort, serialized_instructions + offset, instr->data_sz ); 117 0 : offset += sizeof(ushort); 118 : 119 : // instr_data 120 0 : fd_memcpy( serialized_instructions + offset, instr->data, instr->data_sz ); 121 0 : offset += instr->data_sz; 122 0 : } 123 : 124 : // 125 0 : FD_STORE( ushort, serialized_instructions + offset, 0 ); 126 0 : offset += sizeof(ushort); 127 0 : } 128 : 129 : int 130 : fd_sysvar_instructions_update_current_instr_idx( fd_exec_txn_ctx_t * txn_ctx, 131 0 : ushort current_instr_idx ) { 132 0 : fd_txn_account_t * rec = NULL; 133 0 : int err = fd_exec_txn_ctx_get_account_modify( txn_ctx, &fd_sysvar_instructions_id, 0, &rec ); 134 0 : if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) 135 0 : return FD_ACC_MGR_ERR_READ_FAILED; 136 : 137 0 : uchar * serialized_current_instr_idx = rec->data + (rec->meta->dlen - sizeof(ushort)); 138 0 : FD_STORE( ushort, serialized_current_instr_idx, current_instr_idx ); 139 : 140 0 : return FD_ACC_MGR_SUCCESS; 141 0 : }