Line data Source code
1 : #include "fd_borrowed_account.h" 2 : #include "fd_runtime.h" 3 : 4 : int 5 : fd_borrowed_account_get_data_mut( fd_borrowed_account_t * borrowed_acct, 6 : uchar * * data_out, 7 24 : ulong * dlen_out ) { 8 : 9 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L824 */ 10 24 : int err; 11 24 : fd_borrowed_account_can_data_be_changed( borrowed_acct, &err ); 12 24 : if( FD_UNLIKELY( err ) ) { 13 0 : return err; 14 0 : } 15 : 16 24 : if ( data_out != NULL ) 17 24 : *data_out = borrowed_acct->acc->data; 18 24 : if ( dlen_out != NULL ) 19 24 : *dlen_out = borrowed_acct->acc->data_len; 20 : 21 24 : return FD_EXECUTOR_INSTR_SUCCESS; 22 24 : } 23 : 24 : int 25 : fd_borrowed_account_set_owner( fd_borrowed_account_t * borrowed_acct, 26 333 : fd_pubkey_t const * owner ) { 27 : 28 : /* Only the owner can assign a new owner 29 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L741 */ 30 333 : if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) { 31 0 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 32 0 : } 33 : 34 : /* And only if the account is writable 35 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L745 */ 36 333 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 37 0 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 38 0 : } 39 : 40 : /* And only if the data is zero-initialized or empty 41 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L753 */ 42 333 : if( FD_UNLIKELY( !fd_borrowed_account_is_zeroed( borrowed_acct ) ) ) { 43 0 : return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID; 44 0 : } 45 : 46 : /* Don't copy the account if the owner does not change 47 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L757 */ 48 333 : if( !memcmp( borrowed_acct->acc->owner, owner, sizeof(fd_pubkey_t) ) ) { 49 0 : return FD_EXECUTOR_INSTR_SUCCESS; 50 0 : } 51 : 52 : /* Agave self.touch() is a no-op */ 53 : 54 : /* Copy into owner 55 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L761 */ 56 333 : fd_memcpy( borrowed_acct->acc->owner, owner, sizeof(fd_pubkey_t) ); 57 333 : return FD_EXECUTOR_INSTR_SUCCESS; 58 333 : } 59 : 60 : /* Overwrites the number of lamports of this account (transaction wide) 61 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L773 */ 62 : int 63 : fd_borrowed_account_set_lamports( fd_borrowed_account_t * borrowed_acct, 64 357 : ulong lamports ) { 65 : 66 : /* An account not owned by the program cannot have its blanace decrease 67 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L775 */ 68 357 : if( FD_UNLIKELY( (!fd_borrowed_account_is_owned_by_current_program( borrowed_acct )) && 69 357 : (lamports<borrowed_acct->acc->lamports) ) ) { 70 0 : return FD_EXECUTOR_INSTR_ERR_EXTERNAL_ACCOUNT_LAMPORT_SPEND; 71 0 : } 72 : 73 : /* The balance of read-only may not change 74 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L779 */ 75 357 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 76 0 : return FD_EXECUTOR_INSTR_ERR_READONLY_LAMPORT_CHANGE; 77 0 : } 78 : 79 : /* Don't copy the account if the lamports do not change 80 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L787 */ 81 357 : if( borrowed_acct->acc->lamports==lamports ) { 82 0 : return FD_EXECUTOR_INSTR_SUCCESS; 83 0 : } 84 : 85 : /* Agave self.touch() is a no-op */ 86 : 87 357 : borrowed_acct->acc->lamports = lamports; 88 357 : return FD_EXECUTOR_INSTR_SUCCESS; 89 357 : } 90 : 91 : int 92 : fd_borrowed_account_set_data_from_slice( fd_borrowed_account_t * borrowed_acct, 93 : uchar const * data, 94 4632 : ulong data_sz ) { 95 : 96 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L181-L184 */ 97 4632 : int err; 98 4632 : if ( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, data_sz, &err ) ) ) { 99 0 : return err; 100 0 : } 101 : 102 : /* Agave self.touch() is a no-op */ 103 : 104 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L868 */ 105 4632 : if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, data_sz, &err ) ) ) { 106 0 : return err; 107 0 : } 108 : 109 : /* AccountSharedData::set_data_from_slice() */ 110 4632 : borrowed_acct->acc->data_len = (uint)data_sz; 111 4632 : fd_memcpy( borrowed_acct->acc->data, data, data_sz ); 112 : 113 4632 : return FD_EXECUTOR_INSTR_SUCCESS; 114 4632 : } 115 : 116 : int 117 : fd_borrowed_account_set_data_length( fd_borrowed_account_t * borrowed_acct, 118 225 : ulong new_len ) { 119 225 : int err = FD_EXECUTOR_INSTR_SUCCESS; 120 : 121 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L197-L204 */ 122 225 : if( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, new_len, &err ) ) ) { 123 3 : return err; 124 3 : } 125 : 126 222 : ulong old_len = borrowed_acct->acc->data_len; 127 : 128 : /* Don't copy the account if the length does not change 129 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L886 */ 130 222 : if( old_len==new_len ) { 131 3 : return FD_EXECUTOR_INSTR_SUCCESS; 132 3 : } 133 : 134 : /* Agave self.touch() is a no-op */ 135 : 136 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L890 */ 137 219 : if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, new_len, &err ) ) ) { 138 0 : return err; 139 0 : } 140 : 141 : /* Resize the account 142 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L891 */ 143 219 : ulong memset_sz = fd_ulong_sat_sub( new_len, borrowed_acct->acc->data_len ); 144 219 : fd_memset( borrowed_acct->acc->data+borrowed_acct->acc->data_len, 0, memset_sz ); 145 219 : borrowed_acct->acc->data_len = (uint)new_len; 146 : 147 219 : return FD_EXECUTOR_INSTR_SUCCESS; 148 219 : } 149 : 150 : int 151 : fd_borrowed_account_set_executable( fd_borrowed_account_t * borrowed_acct, 152 0 : int is_executable ) { 153 : /* To become executable an account must be rent exempt 154 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1003-L1006 */ 155 0 : fd_rent_t const * rent = &borrowed_acct->instr_ctx->bank->f.rent; 156 0 : if( FD_UNLIKELY( borrowed_acct->acc->lamports<fd_rent_exempt_minimum_balance( rent, borrowed_acct->acc->data_len ) ) ) { 157 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT; 158 0 : } 159 : 160 : /* Only the owner can set the exectuable flag 161 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1011 */ 162 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) { 163 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED; 164 0 : } 165 : 166 : /* And only if the account is writable 167 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1015 */ 168 0 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) { 169 0 : return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED; 170 0 : } 171 : 172 : /* Don't copy the account if the exectuable flag does not change 173 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1023 */ 174 0 : if( fd_borrowed_account_is_executable( borrowed_acct ) == is_executable ) { 175 0 : return FD_EXECUTOR_INSTR_SUCCESS; 176 0 : } 177 : 178 : /* Agave self.touch() is a no-op */ 179 : 180 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1027 */ 181 0 : borrowed_acct->acc->executable = !!is_executable; 182 : 183 0 : return FD_EXECUTOR_INSTR_SUCCESS; 184 0 : } 185 : 186 : int 187 : fd_borrowed_account_update_accounts_resize_delta( fd_borrowed_account_t * borrowed_acct, 188 : ulong new_len, 189 4851 : int * err ) { 190 4851 : fd_exec_instr_ctx_t const * instr_ctx = borrowed_acct->instr_ctx; 191 4851 : long size_delta = fd_long_sat_sub( (long)new_len, (long)borrowed_acct->acc->data_len ); 192 : 193 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/transaction-context/src/transaction_accounts.rs#L303-L313 */ 194 4851 : instr_ctx->txn_out->details.accounts_resize_delta = fd_long_sat_add( instr_ctx->txn_out->details.accounts_resize_delta, size_delta ); 195 4851 : *err = FD_EXECUTOR_INSTR_SUCCESS; 196 4851 : return 1; 197 4851 : } 198 : 199 : int 200 : fd_borrowed_account_can_data_be_resized( fd_borrowed_account_t const * borrowed_acct, 201 : ulong new_length, 202 8511 : int * err ) { 203 : /* The new length can not exceed the maximum permitted length 204 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/transaction_accounts.rs#L319-L322 */ 205 8511 : if( FD_UNLIKELY( new_length>MAX_PERMITTED_DATA_LENGTH ) ) { 206 0 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC; 207 0 : return 0; 208 0 : } 209 : 210 : /* The resize can not exceed the per-transaction maximum 211 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/transaction_accounts.rs#L323-L329 */ 212 8511 : long length_delta = fd_long_sat_sub( (long)new_length, (long)borrowed_acct->acc->data_len ); 213 8511 : long new_accounts_resize_delta = fd_long_sat_add( borrowed_acct->instr_ctx->txn_out->details.accounts_resize_delta, length_delta ); 214 8511 : if( FD_UNLIKELY( new_accounts_resize_delta>MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN ) ) { 215 3 : *err = FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED; 216 3 : return 0; 217 3 : } 218 : 219 : /* The account data can only be resized if it can be changed 220 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L351-L357 */ 221 8508 : return fd_borrowed_account_can_data_be_changed( borrowed_acct, err ); 222 8511 : }