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