Line data Source code
1 : #include "fd_borrowed_account.h" 2 : #include "fd_runtime.h" 3 : int 4 : fd_borrowed_account_get_data_mut( fd_borrowed_account_t * borrowed_acct, 5 : uchar * * data_out, 6 0 : ulong * dlen_out ) { 7 0 : fd_txn_account_t * acct = borrowed_acct->acct; 8 : 9 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L824 */ 10 0 : int err; 11 0 : fd_borrowed_account_can_data_be_changed( borrowed_acct, &err ); 12 0 : if( FD_UNLIKELY( err ) ) { 13 0 : return err; 14 0 : } 15 : 16 0 : if ( data_out != NULL ) 17 0 : *data_out = fd_txn_account_get_data_mut( acct ); 18 0 : if ( dlen_out != NULL ) 19 0 : *dlen_out = fd_txn_account_get_data_len( acct ); 20 : 21 0 : return FD_EXECUTOR_INSTR_SUCCESS; 22 0 : } 23 : 24 : int 25 : fd_borrowed_account_set_owner( fd_borrowed_account_t * borrowed_acct, 26 0 : fd_pubkey_t const * owner ) { 27 0 : fd_txn_account_t * acct = borrowed_acct->acct; 28 : 29 : /* Only the owner can assign a new owner 30 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L741 */ 31 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) { 32 0 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 33 0 : } 34 : 35 : /* And only if the account is writable 36 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L745 */ 37 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 38 0 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 39 0 : } 40 : 41 : /* And only if the data is zero-initialized or empty 42 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L753 */ 43 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_zeroed( borrowed_acct ) ) ) { 44 0 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 45 0 : } 46 : 47 : /* Don't copy the account if the owner does not change 48 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L757 */ 49 0 : if( !memcmp( fd_txn_account_get_owner( acct ), owner, sizeof( fd_pubkey_t ) ) ) { 50 0 : return FD_EXECUTOR_INSTR_SUCCESS; 51 0 : } 52 : 53 : /* Agave self.touch() is a no-op */ 54 : 55 : /* Copy into owner 56 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L761 */ 57 0 : fd_txn_account_set_owner( acct, owner ); 58 0 : return FD_EXECUTOR_INSTR_SUCCESS; 59 0 : } 60 : 61 : /* Overwrites the number of lamports of this account (transaction wide) 62 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L773 */ 63 : int 64 : fd_borrowed_account_set_lamports( fd_borrowed_account_t * borrowed_acct, 65 0 : ulong lamports ) { 66 0 : fd_txn_account_t * acct = borrowed_acct->acct; 67 : 68 : /* An account not owned by the program cannot have its blanace decrease 69 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L775 */ 70 0 : if( FD_UNLIKELY( (!fd_borrowed_account_is_owned_by_current_program( borrowed_acct )) && 71 0 : (lamports<fd_txn_account_get_lamports( acct )) ) ) { 72 0 : return FD_EXECUTOR_INSTR_ERR_EXTERNAL_ACCOUNT_LAMPORT_SPEND; 73 0 : } 74 : 75 : /* The balance of read-only may not change 76 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L779 */ 77 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 78 0 : return FD_EXECUTOR_INSTR_ERR_READONLY_LAMPORT_CHANGE; 79 0 : } 80 : 81 : /* Don't copy the account if the lamports do not change 82 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L787 */ 83 0 : if( fd_txn_account_get_lamports( acct )==lamports ) { 84 0 : return FD_EXECUTOR_INSTR_SUCCESS; 85 0 : } 86 : 87 : /* Agave self.touch() is a no-op */ 88 : 89 0 : fd_txn_account_set_lamports( acct, lamports ); 90 0 : return FD_EXECUTOR_INSTR_SUCCESS; 91 0 : } 92 : 93 : int 94 : fd_borrowed_account_set_data_from_slice( fd_borrowed_account_t * borrowed_acct, 95 : uchar const * data, 96 0 : ulong data_sz ) { 97 0 : fd_txn_account_t * acct = borrowed_acct->acct; 98 : 99 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L865 */ 100 0 : int err; 101 0 : if ( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, data_sz, &err ) ) ) { 102 0 : return err; 103 0 : } 104 : 105 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L866 */ 106 0 : if( FD_UNLIKELY( !fd_borrowed_account_can_data_be_changed( borrowed_acct, &err ) ) ) { 107 0 : return err; 108 0 : } 109 : 110 : /* Agave self.touch() is a no-op */ 111 : 112 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L868 */ 113 0 : if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, data_sz, &err ) ) ) { 114 0 : return err; 115 0 : } 116 : 117 : /* AccountSharedData::set_data_from_slice() */ 118 0 : fd_txn_account_set_data( acct, data, data_sz ); 119 : 120 0 : return FD_EXECUTOR_INSTR_SUCCESS; 121 0 : } 122 : 123 : int 124 : fd_borrowed_account_set_data_length( fd_borrowed_account_t * borrowed_acct, 125 0 : ulong new_len ) { 126 0 : fd_txn_account_t * acct = borrowed_acct->acct; 127 0 : int err = FD_EXECUTOR_INSTR_SUCCESS; 128 : 129 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L883 */ 130 0 : if( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, new_len, &err ) ) ) { 131 0 : return err; 132 0 : } 133 : 134 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L884 */ 135 0 : if( FD_UNLIKELY( !fd_borrowed_account_can_data_be_changed( borrowed_acct, &err ) ) ) { 136 0 : return err; 137 0 : } 138 : 139 0 : ulong old_len = fd_txn_account_get_data_len( acct ); 140 : 141 : /* Don't copy the account if the length does not change 142 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L886 */ 143 0 : if( old_len==new_len ) { 144 0 : return FD_EXECUTOR_INSTR_SUCCESS; 145 0 : } 146 : 147 : /* Agave self.touch() is a no-op */ 148 : 149 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L890 */ 150 0 : if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, new_len, &err ) ) ) { 151 0 : return err; 152 0 : } 153 : 154 : /* Resize the account 155 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L891 */ 156 0 : fd_txn_account_resize( acct, new_len ); 157 0 : return FD_EXECUTOR_INSTR_SUCCESS; 158 0 : } 159 : 160 : int 161 : fd_borrowed_account_set_executable( fd_borrowed_account_t * borrowed_acct, 162 0 : int is_executable ) { 163 0 : fd_txn_account_t * acct = borrowed_acct->acct; 164 : 165 : /* To become executable an account must be rent exempt 166 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1003-L1006 */ 167 0 : fd_rent_t const * rent = fd_bank_rent_query( borrowed_acct->instr_ctx->bank ); 168 0 : if( FD_UNLIKELY( fd_txn_account_get_lamports( acct )<fd_rent_exempt_minimum_balance( rent, fd_txn_account_get_data_len( acct ) ) ) ) { 169 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT; 170 0 : } 171 : 172 : /* Only the owner can set the exectuable flag 173 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1011 */ 174 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) { 175 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED; 176 0 : } 177 : 178 : /* And only if the account is writable 179 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1015 */ 180 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 181 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED; 182 0 : } 183 : 184 : /* Don't copy the account if the exectuable flag does not change 185 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1023 */ 186 0 : if( fd_borrowed_account_is_executable( borrowed_acct ) == is_executable ) { 187 0 : return FD_EXECUTOR_INSTR_SUCCESS; 188 0 : } 189 : 190 : /* Agave self.touch() is a no-op */ 191 : 192 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1027 */ 193 0 : fd_txn_account_set_executable( acct, is_executable ); 194 : 195 0 : return FD_EXECUTOR_INSTR_SUCCESS; 196 0 : } 197 : 198 : int 199 : fd_borrowed_account_update_accounts_resize_delta( fd_borrowed_account_t * borrowed_acct, 200 : ulong new_len, 201 0 : int * err ) { 202 0 : fd_exec_instr_ctx_t const * instr_ctx = borrowed_acct->instr_ctx; 203 0 : fd_txn_account_t * acct = borrowed_acct->acct; 204 0 : ulong size_delta = fd_ulong_sat_sub( new_len, fd_txn_account_get_data_len( acct ) ); 205 : 206 : /* TODO: The size delta should never exceed the value of ULONG_MAX so this 207 : could be replaced with a normal addition. However to match execution with 208 : the agave client, this is being left as a sat add */ 209 0 : instr_ctx->txn_out->details.accounts_resize_delta = fd_ulong_sat_add( instr_ctx->txn_out->details.accounts_resize_delta, size_delta ); 210 0 : *err = FD_EXECUTOR_INSTR_SUCCESS; 211 0 : return 1; 212 0 : } 213 : 214 : int 215 : fd_borrowed_account_can_data_be_resized( fd_borrowed_account_t const * borrowed_acct, 216 : ulong new_length, 217 0 : int * err ) { 218 0 : fd_txn_account_t * acct = borrowed_acct->acct; 219 : 220 : /* Only the owner can change the length of the data 221 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1095 */ 222 0 : if( FD_UNLIKELY( (fd_txn_account_get_data_len( acct )!=new_length) & 223 0 : (!fd_borrowed_account_is_owned_by_current_program( borrowed_acct )) ) ) { 224 0 : *err = FD_EXECUTOR_INSTR_ERR_ACC_DATA_SIZE_CHANGED; 225 0 : return 0; 226 0 : } 227 : 228 : /* The new length can not exceed the maximum permitted length 229 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1099 */ 230 0 : if( FD_UNLIKELY( new_length>MAX_PERMITTED_DATA_LENGTH ) ) { 231 0 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC; 232 0 : return 0; 233 0 : } 234 : 235 : /* The resize can not exceed the per-transaction maximum 236 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1104-L1108 */ 237 0 : ulong length_delta = fd_ulong_sat_sub( new_length, fd_txn_account_get_data_len( acct ) ); 238 0 : ulong new_accounts_resize_delta = fd_ulong_sat_add( borrowed_acct->instr_ctx->txn_out->details.accounts_resize_delta, length_delta ); 239 0 : if( FD_UNLIKELY( new_accounts_resize_delta > MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN ) ) { 240 0 : *err = FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED; 241 0 : return 0; 242 0 : } 243 : 244 0 : *err = FD_EXECUTOR_INSTR_SUCCESS; 245 0 : return 1; 246 0 : }