Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_fd_borrowed_account_h 2 : #define HEADER_fd_src_flamenco_runtime_fd_borrowed_account_h 3 : 4 : #include "../../ballet/txn/fd_txn.h" 5 : #include "../types/fd_types.h" 6 : #include "../../funk/fd_funk_rec.h" 7 : 8 : 9 : /* TODO This should be called fd_txn_acct. */ 10 : 11 : struct __attribute__((aligned(8UL))) fd_borrowed_account { 12 : ulong magic; 13 : 14 : fd_pubkey_t pubkey[1]; 15 : 16 : fd_account_meta_t const * const_meta; 17 : uchar const * const_data; 18 : fd_funk_rec_t const * const_rec; 19 : 20 : fd_account_meta_t * meta; 21 : uchar * data; 22 : fd_funk_rec_t * rec; 23 : 24 : fd_account_meta_t const * orig_meta; 25 : uchar const * orig_data; 26 : fd_funk_rec_t const * orig_rec; 27 : 28 : ulong starting_dlen; 29 : ulong starting_lamports; 30 : 31 : ulong starting_owner_dlen; 32 : 33 : /* Provide read/write mutual exclusion semantics. 34 : Used for single-threaded logic only, thus not comparable to a 35 : data synchronization lock. */ 36 : 37 : ushort refcnt_excl; 38 : ushort refcnt_shared; 39 : 40 : uchar account_found; 41 : }; 42 : typedef struct fd_borrowed_account fd_borrowed_account_t; 43 6573885 : #define FD_BORROWED_ACCOUNT_FOOTPRINT (sizeof(fd_borrowed_account_t)) 44 : #define FD_BORROWED_ACCOUNT_ALIGN (8UL) 45 6573885 : #define FD_BORROWED_ACCOUNT_MAGIC (0xF15EDF1C51F51AA1UL) 46 : 47 5880906 : #define FD_BORROWED_ACCOUNT_DECL(_x) fd_borrowed_account_t _x[1]; fd_borrowed_account_init(_x); 48 : 49 : /* This macro provides the same scoping guarantees as the Agave client's 50 : borrowed account semantics. It allows for implict/explicit dropping of 51 : borrowed accounts' write locks. It's usage mirrors the use of 52 : FD_SCRATCH_SCOPE_{BEGIN,END}. It is also safe to use the original 53 : acquire/release api within the scoped macro in case you don't want 54 : variables to go out of scope. An example of this is in the extend 55 : instruction within the bpf loader. 56 : Equivalent to Agave's instruction_context::try_borrow_instruction_account() 57 : https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L647 */ 58 : 59 40638 : #define FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( _ctx, _idx, _account ) do { \ 60 40638 : if( FD_UNLIKELY( _idx>=(_ctx)->instr->acct_cnt ) ) { \ 61 9 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; \ 62 9 : } \ 63 40638 : fd_borrowed_account_t * _account = NULL; \ 64 40629 : int _err = fd_instr_borrowed_account_view_idx( _ctx, _idx, &_account ); \ 65 40629 : if( FD_UNLIKELY( _err != FD_ACC_MGR_SUCCESS ) ) { \ 66 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; \ 67 0 : } \ 68 40629 : int _acquire_result = fd_borrowed_account_acquire_write(_account); \ 69 40629 : if( FD_UNLIKELY( !_acquire_result ) ) { \ 70 237 : return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED; \ 71 237 : } \ 72 40629 : fd_borrowed_account_t * __fd_borrowed_lock_guard_ ## __LINE__ \ 73 40392 : __attribute__((cleanup(fd_borrowed_account_release_write_private))) \ 74 40392 : __attribute__((unused)) = _account; \ 75 40392 : do 76 40392 : #define FD_BORROWED_ACCOUNT_DROP( _account_check ) while(0); (void)_account_check; } while(0) 77 : 78 : FD_PROTOTYPES_BEGIN 79 : 80 : fd_borrowed_account_t * 81 : fd_borrowed_account_init( void * ptr ); 82 : 83 : void 84 : fd_borrowed_account_resize( fd_borrowed_account_t * borrowed_account, 85 : ulong dlen ); 86 : 87 : FD_FN_PURE static inline ulong 88 0 : fd_borrowed_account_raw_size( fd_borrowed_account_t const * borrowed_account ) { 89 0 : ulong dlen = ( borrowed_account->const_meta != NULL ) ? borrowed_account->const_meta->dlen : 0; 90 0 : return sizeof(fd_account_meta_t) + dlen; 91 0 : } 92 : 93 : fd_borrowed_account_t * 94 : fd_borrowed_account_make_modifiable( fd_borrowed_account_t * borrowed_account, 95 : void * buf ); 96 : 97 : /* In Agave, dummy accounts are sometimes created that contain metadata 98 : that differs from what's in the accounts DB. For example, see 99 : handling of the executable bit in 100 : fd_executor_load_transaction_accounts(). 101 : This allows us to emulate that by modifying metadata of read-only 102 : borrowed accounts without those modification writing through to 103 : funk. 104 : */ 105 : fd_borrowed_account_t * 106 : fd_borrowed_account_make_readonly_copy( fd_borrowed_account_t * borrowed_account, 107 : void * buf ); 108 : 109 : void * 110 : fd_borrowed_account_restore( fd_borrowed_account_t * borrowed_account ); 111 : 112 : void * 113 : fd_borrowed_account_destroy( fd_borrowed_account_t * borrowed_account ); 114 : 115 : /* fd_borrowed_account_acquire_{read,write}_is_safe returns 1 if 116 : fd_borrowed_account_acquire_{read,write} will be successful for the 117 : given borrowed account. If a lock is already held, returns 0. */ 118 : 119 : FD_FN_PURE static inline int 120 94281 : fd_borrowed_account_acquire_write_is_safe( fd_borrowed_account_t const * rw ) { 121 94281 : return (!rw->refcnt_excl) & (!rw->refcnt_shared); 122 94281 : } 123 : 124 : FD_FN_PURE static inline int 125 0 : fd_borrowed_account_acquire_read_is_safe( fd_borrowed_account_t const * rw ) { 126 0 : return (!rw->refcnt_excl); 127 0 : } 128 : 129 : /* fd_borrowed_account_acquire_write acquires write/exclusive access. 130 : Causes all other write or read acquire attempts will fail. Returns 1 131 : on success, 0 on failure. */ 132 : 133 : static inline int 134 53889 : fd_borrowed_account_acquire_write( fd_borrowed_account_t * rw ) { 135 53889 : if( FD_UNLIKELY( !fd_borrowed_account_acquire_write_is_safe( rw ) ) ) { 136 237 : return 0; 137 237 : } 138 53652 : rw->refcnt_excl = (ushort)1; 139 53652 : return 1; 140 53889 : } 141 : 142 : /* fd_borrowed_account_release_write{_private} releases a write/exclusive 143 : access handle. The private version should only be used by the try borrow 144 : scoping macro. */ 145 : 146 : static inline void 147 51114 : fd_borrowed_account_release_write( fd_borrowed_account_t * rw ) { 148 51114 : FD_TEST( rw->refcnt_excl==1U ); 149 51114 : rw->refcnt_excl = (ushort)0; 150 51114 : } 151 : 152 : static inline void 153 40392 : fd_borrowed_account_release_write_private(fd_borrowed_account_t ** rw ) { 154 : /* Only release if it is not yet released */ 155 40392 : if( !fd_borrowed_account_acquire_write_is_safe( *rw ) ) { 156 40332 : fd_borrowed_account_release_write( *rw ); 157 40332 : } 158 40392 : rw = NULL; 159 40392 : } 160 : 161 : /* fd_borrowed_account_acquire_read acquires read/shared access. Causes 162 : write attempts to fail. Further attempts to read will succeed. */ 163 : 164 : static inline int 165 0 : fd_borrowed_account_acquire_read( fd_borrowed_account_t * rw ) { 166 0 : if( FD_UNLIKELY( !fd_borrowed_account_acquire_read_is_safe( rw ) ) ) 167 0 : return 0; 168 0 : rw->refcnt_shared = (ushort)( rw->refcnt_shared + 1U ); 169 0 : return 1; 170 0 : } 171 : 172 : /* fd_borrowed_account_release_read releases a read/shared access 173 : handle. */ 174 : 175 : static inline void 176 0 : fd_borrowed_account_release_read( fd_borrowed_account_t * rw ) { 177 0 : FD_TEST( rw->refcnt_shared>0U ); 178 0 : rw->refcnt_shared--; 179 0 : } 180 : 181 : FD_PROTOTYPES_END 182 : 183 : #endif /* HEADER_fd_src_flamenco_runtime_fd_borrowed_account_h */