Line data Source code
1 : #include "fd_sysvar_instructions.h" 2 : #include "../fd_account.h" 3 : #include "../fd_system_ids.h" 4 : 5 : static ulong 6 : instructions_serialized_size( fd_instr_info_t const * instrs, 7 93 : ushort instrs_cnt ) { 8 93 : ulong serialized_size = 0; 9 : 10 93 : serialized_size += sizeof(ushort) // num_instructions 11 93 : + (sizeof(ushort) * instrs_cnt); // instruction offsets 12 : 13 204 : for ( ushort i = 0; i < instrs_cnt; ++i ) { 14 111 : fd_instr_info_t const * instr = &instrs[i]; 15 : 16 111 : serialized_size += sizeof(ushort); // num_accounts; 17 : 18 111 : serialized_size += instr->acct_cnt * ( 19 111 : sizeof(uchar) // flags (is_signer, is_writeable) 20 111 : + sizeof(fd_pubkey_t) // pubkey 21 111 : ); 22 : 23 111 : serialized_size += sizeof(fd_pubkey_t) // program_id pubkey 24 111 : + sizeof(ushort) // instr_data_len; 25 111 : + instr->data_sz; // instr_data; 26 : 27 111 : } 28 : 29 93 : serialized_size += sizeof(ushort); // current_instr_idx 30 : 31 93 : return serialized_size; 32 93 : } 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 93 : ushort instrs_cnt ) { 39 93 : ulong serialized_sz = instructions_serialized_size( instrs, instrs_cnt ); 40 : 41 93 : fd_borrowed_account_t * rec = NULL; 42 93 : int err = fd_txn_borrowed_account_view( txn_ctx, &fd_sysvar_instructions_id, &rec ); 43 93 : 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 93 : if( rec->meta==NULL ) { 60 93 : fd_account_meta_t * meta = fd_spad_alloc( txn_ctx->spad, FD_ACCOUNT_REC_ALIGN, sizeof(fd_account_meta_t) + serialized_sz ); 61 93 : void * data = (uchar *)meta + sizeof(fd_account_meta_t); 62 : 63 93 : rec->const_meta = rec->meta = meta; 64 93 : rec->const_data = rec->data = data; 65 93 : } 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 93 : memcpy( rec->meta->info.owner, fd_sysvar_owner_id.key, sizeof(fd_pubkey_t) ); 71 93 : rec->starting_lamports = 0UL; 72 93 : rec->meta->info.lamports = 0UL; // TODO: This cannot be right... well, it gets destroyed almost instantly... 73 93 : rec->meta->info.executable = 0; 74 93 : rec->meta->info.rent_epoch = 0UL; 75 93 : rec->meta->dlen = serialized_sz; 76 : 77 93 : uchar * serialized_instructions = rec->data; 78 93 : ulong offset = 0; 79 : 80 : // TODO: do we needs bounds checking? 81 : // num_instructions 82 93 : FD_STORE( ushort, serialized_instructions + offset, instrs_cnt); 83 93 : offset += sizeof(ushort); 84 : 85 : // instruction offsets 86 93 : uchar * serialized_instruction_offsets = serialized_instructions + offset; 87 93 : offset += (ushort)(sizeof(ushort) * instrs_cnt); 88 : 89 : // serialize instructions 90 204 : for( ushort i = 0; i < instrs_cnt; ++i ) { 91 : // set the instruction offset 92 111 : FD_STORE( ushort, serialized_instruction_offsets, (ushort) offset ); 93 111 : serialized_instruction_offsets += sizeof(ushort); 94 : 95 111 : fd_instr_info_t const * instr = &instrs[i]; 96 : 97 : // num_accounts 98 111 : FD_STORE( ushort, serialized_instructions + offset, instr->acct_cnt ); 99 111 : offset += sizeof(ushort); 100 : 101 402 : for ( ushort j = 0; j < instr->acct_cnt; j++ ) { 102 : // flags 103 291 : FD_STORE( uchar, serialized_instructions + offset, instr->acct_flags[j] ); 104 291 : offset += sizeof(uchar); 105 : 106 : // pubkey 107 291 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, instr->acct_pubkeys[j] ); 108 291 : offset += sizeof(fd_pubkey_t); 109 291 : } 110 : 111 : // program_id_pubkey 112 111 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, instr->program_id_pubkey ); 113 111 : offset += sizeof(fd_pubkey_t); 114 : 115 : // instr_data_len 116 111 : FD_STORE( ushort, serialized_instructions + offset, instr->data_sz ); 117 111 : offset += sizeof(ushort); 118 : 119 : // instr_data 120 111 : fd_memcpy( serialized_instructions + offset, instr->data, instr->data_sz ); 121 111 : offset += instr->data_sz; 122 111 : } 123 : 124 : // 125 93 : FD_STORE( ushort, serialized_instructions + offset, 0 ); 126 93 : offset += sizeof(ushort); 127 93 : } 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_borrowed_account_t * rec = NULL; 133 0 : int err = fd_txn_borrowed_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 : }