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 3 : instructions_serialized_size( fd_txn_t const * txn ) { 7 3 : ushort instr_cnt = txn->instr_cnt; 8 3 : ulong serialized_size = sizeof(ushort) // num_instructions 9 3 : + (sizeof(ushort)*instr_cnt); // instruction offsets 10 : 11 9 : for( ushort i=0; i<instr_cnt; i++ ) { 12 6 : ushort data_sz = txn->instr[i].data_sz; 13 6 : ushort acct_cnt = txn->instr[i].acct_cnt; 14 : 15 6 : serialized_size += sizeof(ushort); // num_accounts; 16 : 17 6 : serialized_size += acct_cnt * ( 18 6 : sizeof(uchar) // flags (is_signer, is_writeable) 19 6 : + sizeof(fd_pubkey_t) // pubkey 20 6 : ); 21 : 22 6 : serialized_size += sizeof(fd_pubkey_t) // program_id pubkey 23 6 : + sizeof(ushort) // instr_data_len; 24 6 : + data_sz; // instr_data; 25 : 26 6 : } 27 : 28 3 : serialized_size += sizeof(ushort); // current_instr_idx 29 : 30 3 : return serialized_size; 31 3 : } 32 : 33 : /* https://github.com/anza-xyz/agave/blob/v2.1.1/svm/src/account_loader.rs#L547-L576 */ 34 : int 35 : fd_sysvar_instructions_serialize_account( fd_txn_in_t const * txn_in, 36 : fd_txn_out_t * txn_out, 37 3 : ulong txn_idx ) { 38 3 : fd_txn_t const * txn = TXN( txn_in->txn ); 39 3 : ulong serialized_sz = instructions_serialized_size( txn ); 40 : 41 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/svm/src/account_loader.rs#L660-L665 */ 42 3 : if( FD_UNLIKELY( fd_sysvar_instructions_offsets_overflow( txn ) ) ) { 43 3 : return FD_RUNTIME_TXN_ERR_MAX_LOADED_ACCOUNTS_DATA_SIZE_EXCEEDED; 44 3 : } 45 0 : FD_TEST( serialized_sz<=FD_SYSVAR_INSTRUCTIONS_FOOTPRINT ); 46 : 47 0 : fd_acc_t * acc = txn_out->accounts.account[ txn_idx ]; 48 : /* Agave sets up the borrowed account for the instructions sysvar to contain 49 : default values except for the data which is serialized into the account. 50 : The accdb returns data=NULL for the sysvar instructions account because 51 : it is constructed on the fly and never persisted; point it at the 52 : dedicated scratch buffer in txn_out. */ 53 : 54 0 : fd_memcpy( acc->owner, &fd_sysvar_owner_id, sizeof(fd_pubkey_t) ); 55 0 : acc->lamports = 0UL; 56 0 : acc->executable = 0; 57 0 : acc->data = txn_out->accounts.sysvar_instructions_data; 58 0 : acc->data_len = serialized_sz; 59 : 60 0 : uchar * serialized_instructions = acc->data; 61 0 : ulong offset = 0; 62 : 63 : // num_instructions 64 0 : ushort instr_cnt = txn->instr_cnt; 65 0 : FD_STORE( ushort, serialized_instructions + offset, instr_cnt); 66 0 : offset += sizeof(ushort); 67 : 68 : // instruction offsets 69 0 : uchar * serialized_instruction_offsets = serialized_instructions + offset; 70 0 : offset += (ushort)(sizeof(ushort) * instr_cnt); 71 : 72 : // serialize instructions 73 0 : for( ushort i=0; i<instr_cnt; ++i ) { 74 : // set the instruction offset 75 0 : FD_STORE( ushort, serialized_instruction_offsets, (ushort)offset ); 76 0 : serialized_instruction_offsets += sizeof(ushort); 77 : 78 0 : fd_txn_instr_t const * instr = &txn->instr[i]; 79 : 80 : // num_accounts 81 0 : FD_STORE( ushort, serialized_instructions + offset, instr->acct_cnt ); 82 0 : offset += sizeof(ushort); 83 : 84 0 : uchar const * instr_accts = fd_txn_get_instr_accts( instr, txn_in->txn->payload ); 85 0 : for( ushort j=0; j<instr->acct_cnt; j++ ) { 86 0 : uchar idx_in_txn = instr_accts[j]; 87 0 : uchar is_writable = (uchar)fd_runtime_account_is_writable_idx( txn_in, txn_out, idx_in_txn ); 88 0 : uchar is_signer = (uchar)fd_txn_is_signer( txn, idx_in_txn ); 89 0 : uchar flags = (uchar)( ((!!is_signer)*FD_INSTR_ACCT_FLAGS_IS_SIGNER) | ((!!is_writable)*FD_INSTR_ACCT_FLAGS_IS_WRITABLE) ); 90 : 91 : // flags 92 0 : FD_STORE( uchar, serialized_instructions + offset, flags ); 93 0 : offset += sizeof(uchar); 94 : 95 : // pubkey 96 0 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, txn_out->accounts.keys[ idx_in_txn ] ); 97 0 : offset += sizeof(fd_pubkey_t); 98 0 : } 99 : 100 : // program_id_pubkey 101 0 : FD_STORE( fd_pubkey_t, serialized_instructions + offset, txn_out->accounts.keys[ instr->program_id ] ); 102 0 : offset += sizeof(fd_pubkey_t); 103 : 104 : // instr_data_len 105 0 : FD_STORE( ushort, serialized_instructions + offset, instr->data_sz ); 106 0 : offset += sizeof(ushort); 107 : 108 : // instr_data 109 0 : uchar const * instr_data = fd_txn_get_instr_data( instr, txn_in->txn->payload ); 110 0 : fd_memcpy( serialized_instructions + offset, instr_data, instr->data_sz ); 111 0 : offset += instr->data_sz; 112 0 : } 113 : 114 0 : FD_STORE( ushort, serialized_instructions + offset, 0 ); 115 0 : offset += sizeof(ushort); 116 : 117 0 : return FD_RUNTIME_EXECUTE_SUCCESS; 118 0 : } 119 : 120 : /* Stores the current instruction index in the instructions sysvar account. 121 : https://github.com/anza-xyz/solana-sdk/blob/instructions-sysvar%40v2.2.1/instructions-sysvar/src/lib.rs#L164-L167 */ 122 : void 123 : fd_sysvar_instructions_update_current_instr_idx( fd_acc_t * acc, 124 0 : ushort current_instr_idx ) { 125 : /* Extra safety checks */ 126 0 : if( FD_UNLIKELY( acc->data_len<sizeof(ushort) ) ) { 127 0 : return; 128 0 : } 129 : 130 0 : uchar * serialized_current_instr_idx = acc->data + (acc->data_len - sizeof(ushort)); 131 0 : FD_STORE( ushort, serialized_current_instr_idx, current_instr_idx ); 132 0 : }