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