Line data Source code
1 : #include "fd_borrowed_account.h" 2 : #include "fd_runtime.h" 3 : 4 : #if FD_HAS_AVX512 5 : #include "../../util/simd/fd_avx512.h" 6 : #elif FD_HAS_AVX 7 : #include "../../util/simd/fd_avx.h" 8 : #endif 9 : 10 : FD_FN_PURE int 11 1316 : fd_borrowed_account_is_zeroed( fd_borrowed_account_t const * borrowed_acct ) { 12 1316 : uchar const * data = borrowed_acct->acc->data; 13 1316 : ulong data_sz = borrowed_acct->acc->data_len; 14 : 15 : /* Peel the loop to avoid unaligned accesses. */ 16 3332 : while( data_sz && ( (ulong)data & 0x3fUL ) ) { 17 2016 : if( FD_UNLIKELY( *data ) ) return 0; 18 2016 : data++; 19 2016 : data_sz--; 20 2016 : } 21 : 22 1316 : #if FD_HAS_AVX512 23 1187679 : while( data_sz>=512UL ) { 24 1186369 : wwv_t x0 = wwv_or( wwv_ldu( data ), wwv_ldu( data+ 64UL ) ); 25 1186369 : wwv_t x1 = wwv_or( wwv_ldu( data+128UL ), wwv_ldu( data+192UL ) ); 26 1186369 : wwv_t x2 = wwv_or( wwv_ldu( data+256UL ), wwv_ldu( data+320UL ) ); 27 1186369 : wwv_t x3 = wwv_or( wwv_ldu( data+384UL ), wwv_ldu( data+448UL ) ); 28 1186369 : wwv_t x = wwv_or( wwv_or( x0, x1 ), wwv_or( x2, x3 ) ); 29 1186369 : if( FD_UNLIKELY( _mm512_test_epi64_mask( x, x ) ) ) return 0; 30 1186363 : data += 512UL; 31 1186363 : data_sz -= 512UL; 32 1186363 : } 33 : #elif FD_HAS_AVX 34 : while( data_sz>=256UL ) { 35 : wv_t x0 = wv_or( wv_ldu( data ), wv_ldu( data+ 32UL ) ); 36 : wv_t x1 = wv_or( wv_ldu( data+ 64UL ), wv_ldu( data+ 96UL ) ); 37 : wv_t x2 = wv_or( wv_ldu( data+128UL ), wv_ldu( data+160UL ) ); 38 : wv_t x3 = wv_or( wv_ldu( data+192UL ), wv_ldu( data+224UL ) ); 39 : wv_t x = wv_or( wv_or( x0, x1 ), wv_or( x2, x3 ) ); 40 : if( FD_UNLIKELY( !_mm256_testz_si256( x, x ) ) ) return 0; 41 : data += 256UL; 42 : data_sz -= 256UL; 43 : } 44 : #endif 45 : 46 132517 : for( ulong i=0UL; i<data_sz; i++ ) 47 131215 : if( FD_UNLIKELY( data[i] ) ) return 0; 48 : 49 1302 : return 1; 50 1310 : } 51 : 52 : int 53 : fd_borrowed_account_get_data_mut( fd_borrowed_account_t * borrowed_acct, 54 : uchar * * data_out, 55 4464 : ulong * dlen_out ) { 56 : 57 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L824 */ 58 4464 : int err; 59 4464 : fd_borrowed_account_can_data_be_changed( borrowed_acct, &err ); 60 4464 : if( FD_UNLIKELY( err ) ) { 61 11 : return err; 62 11 : } 63 : 64 4453 : *borrowed_acct->touched = 1; 65 : 66 4453 : if ( data_out != NULL ) 67 4453 : *data_out = borrowed_acct->acc->data; 68 4453 : if ( dlen_out != NULL ) 69 4453 : *dlen_out = borrowed_acct->acc->data_len; 70 : 71 4453 : return FD_EXECUTOR_INSTR_SUCCESS; 72 4464 : } 73 : 74 : int 75 : fd_borrowed_account_set_owner( fd_borrowed_account_t * borrowed_acct, 76 1407 : fd_pubkey_t const * owner ) { 77 : 78 : /* Only the owner can assign a new owner 79 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L741 */ 80 1407 : if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) { 81 79 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 82 79 : } 83 : 84 : /* And only if the account is writable 85 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L745 */ 86 1328 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 87 12 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 88 12 : } 89 : 90 : /* And only if the data is zero-initialized or empty 91 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L753 */ 92 1316 : if( FD_UNLIKELY( !fd_borrowed_account_is_zeroed( borrowed_acct ) ) ) { 93 14 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 94 14 : } 95 : 96 : /* Don't copy the account if the owner does not change 97 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L757 */ 98 1302 : if( !memcmp( borrowed_acct->acc->owner, owner, sizeof(fd_pubkey_t) ) ) { 99 0 : return FD_EXECUTOR_INSTR_SUCCESS; 100 0 : } 101 : 102 1302 : *borrowed_acct->touched = 1; 103 : 104 : /* Copy into owner 105 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L761 */ 106 1302 : fd_memcpy( borrowed_acct->acc->owner, owner, sizeof(fd_pubkey_t) ); 107 1302 : return FD_EXECUTOR_INSTR_SUCCESS; 108 1302 : } 109 : 110 : /* Overwrites the number of lamports of this account (transaction wide) 111 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L773 */ 112 : int 113 : fd_borrowed_account_set_lamports( fd_borrowed_account_t * borrowed_acct, 114 4551 : ulong lamports ) { 115 : 116 : /* An account not owned by the program cannot have its balance decrease 117 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L775 */ 118 4551 : if( FD_UNLIKELY( (!fd_borrowed_account_is_owned_by_current_program( borrowed_acct )) && 119 4551 : (lamports<borrowed_acct->acc->lamports) ) ) { 120 10 : return FD_EXECUTOR_INSTR_ERR_EXTERNAL_ACCOUNT_LAMPORT_SPEND; 121 10 : } 122 : 123 : /* The balance of read-only may not change 124 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L779 */ 125 4541 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 126 154 : return FD_EXECUTOR_INSTR_ERR_READONLY_LAMPORT_CHANGE; 127 154 : } 128 : 129 : /* Don't copy the account if the lamports do not change 130 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L787 */ 131 4387 : if( borrowed_acct->acc->lamports==lamports ) { 132 94 : return FD_EXECUTOR_INSTR_SUCCESS; 133 94 : } 134 : 135 4293 : *borrowed_acct->touched = 1; 136 : 137 4293 : borrowed_acct->acc->lamports = lamports; 138 4293 : return FD_EXECUTOR_INSTR_SUCCESS; 139 4387 : } 140 : 141 : int 142 : fd_borrowed_account_set_data_from_slice( fd_borrowed_account_t * borrowed_acct, 143 : uchar const * data, 144 315 : ulong data_sz ) { 145 : 146 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L181-L184 */ 147 315 : int err; 148 315 : if ( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, data_sz, &err ) ) ) { 149 63 : return err; 150 63 : } 151 : 152 252 : *borrowed_acct->touched = 1; 153 : 154 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L868 */ 155 252 : if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, data_sz, &err ) ) ) { 156 0 : return err; 157 0 : } 158 : 159 : /* AccountSharedData::set_data_from_slice() */ 160 252 : borrowed_acct->acc->data_len = (uint)data_sz; 161 252 : fd_memcpy( borrowed_acct->acc->data, data, data_sz ); 162 : 163 252 : return FD_EXECUTOR_INSTR_SUCCESS; 164 252 : } 165 : 166 : int 167 : fd_borrowed_account_set_data_length( fd_borrowed_account_t * borrowed_acct, 168 1122 : ulong new_len ) { 169 1122 : int err = FD_EXECUTOR_INSTR_SUCCESS; 170 : 171 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L197-L204 */ 172 1122 : if( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, new_len, &err ) ) ) { 173 23 : return err; 174 23 : } 175 : 176 1099 : ulong old_len = borrowed_acct->acc->data_len; 177 : 178 : /* Don't copy the account if the length does not change 179 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L886 */ 180 1099 : if( old_len==new_len ) { 181 96 : return FD_EXECUTOR_INSTR_SUCCESS; 182 96 : } 183 : 184 1003 : *borrowed_acct->touched = 1; 185 : 186 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L890 */ 187 1003 : if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, new_len, &err ) ) ) { 188 0 : return err; 189 0 : } 190 : 191 : /* Resize the account 192 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L891 */ 193 1003 : ulong memset_sz = fd_ulong_sat_sub( new_len, borrowed_acct->acc->data_len ); 194 1003 : fd_memset( borrowed_acct->acc->data+borrowed_acct->acc->data_len, 0, memset_sz ); 195 1003 : borrowed_acct->acc->data_len = (uint)new_len; 196 : 197 1003 : return FD_EXECUTOR_INSTR_SUCCESS; 198 1003 : } 199 : 200 : int 201 : fd_borrowed_account_set_executable( fd_borrowed_account_t * borrowed_acct, 202 174 : int is_executable ) { 203 : /* To become executable an account must be rent exempt 204 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1003-L1006 */ 205 174 : fd_rent_t const * rent = &borrowed_acct->instr_ctx->bank->f.rent; 206 174 : if( FD_UNLIKELY( borrowed_acct->acc->lamports<fd_rent_exempt_minimum_balance( rent, borrowed_acct->acc->data_len ) ) ) { 207 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT; 208 0 : } 209 : 210 : /* Only the owner can set the executable flag 211 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1011 */ 212 174 : if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) { 213 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED; 214 0 : } 215 : 216 : /* And only if the account is writable 217 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1015 */ 218 174 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 219 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED; 220 0 : } 221 : 222 : /* Don't copy the account if the executable flag does not change 223 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1023 */ 224 174 : if( fd_borrowed_account_is_executable( borrowed_acct ) == is_executable ) { 225 0 : return FD_EXECUTOR_INSTR_SUCCESS; 226 0 : } 227 : 228 174 : *borrowed_acct->touched = 1; 229 : 230 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1027 */ 231 174 : borrowed_acct->acc->executable = !!is_executable; 232 : 233 174 : return FD_EXECUTOR_INSTR_SUCCESS; 234 174 : } 235 : 236 : int 237 : fd_borrowed_account_update_accounts_resize_delta( fd_borrowed_account_t * borrowed_acct, 238 : ulong new_len, 239 1255 : int * err ) { 240 1255 : fd_exec_instr_ctx_t const * instr_ctx = borrowed_acct->instr_ctx; 241 1255 : long size_delta = fd_long_sat_sub( (long)new_len, (long)borrowed_acct->acc->data_len ); 242 : 243 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/transaction-context/src/transaction_accounts.rs#L303-L313 */ 244 1255 : instr_ctx->txn_out->details.accounts_resize_delta = fd_long_sat_add( instr_ctx->txn_out->details.accounts_resize_delta, size_delta ); 245 1255 : *err = FD_EXECUTOR_INSTR_SUCCESS; 246 1255 : return 1; 247 1255 : } 248 : 249 : int 250 : fd_borrowed_account_can_data_be_resized( fd_borrowed_account_t const * borrowed_acct, 251 : ulong new_length, 252 25629 : int * err ) { 253 : /* The new length can not exceed the maximum permitted length 254 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/transaction_accounts.rs#L319-L322 */ 255 25629 : if( FD_UNLIKELY( new_length>MAX_PERMITTED_DATA_LENGTH ) ) { 256 0 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC; 257 0 : return 0; 258 0 : } 259 : 260 : /* The resize can not exceed the per-transaction maximum 261 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/transaction_accounts.rs#L323-L329 */ 262 25629 : long length_delta = fd_long_sat_sub( (long)new_length, (long)borrowed_acct->acc->data_len ); 263 25629 : long new_accounts_resize_delta = fd_long_sat_add( borrowed_acct->instr_ctx->txn_out->details.accounts_resize_delta, length_delta ); 264 25629 : if( FD_UNLIKELY( new_accounts_resize_delta>MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN ) ) { 265 0 : *err = FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED; 266 0 : return 0; 267 0 : } 268 : 269 : /* The account data can only be resized if it can be changed 270 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L351-L357 */ 271 25629 : return fd_borrowed_account_can_data_be_changed( borrowed_acct, err ); 272 25629 : }