Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h 2 : #define HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h 3 : 4 : /* fd_acc_mgr provides APIs for the Solana account database. */ 5 : 6 : #include "../fd_flamenco_base.h" 7 : #include "../../ballet/txn/fd_txn.h" 8 : #include "fd_txn_account.h" 9 : 10 : #if FD_HAS_AVX 11 : #include "../../util/simd/fd_avx.h" 12 : #endif 13 : 14 : /* FD_ACC_MGR_{SUCCESS,ERR{...}} are account management specific error codes. 15 : To be stored in an int. */ 16 : 17 6162 : #define FD_ACC_MGR_SUCCESS (0) 18 7806 : #define FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT (-1) 19 0 : #define FD_ACC_MGR_ERR_WRITE_FAILED (-2) 20 0 : #define FD_ACC_MGR_ERR_READ_FAILED (-3) 21 : 22 0 : #define FD_ACC_NONCE_SZ_MAX (80UL) /* 80 bytes */ 23 : 24 : /* FD_ACC_TOT_SZ_MAX is the size limit of a Solana account in the firedancer 25 : client. This means that it includes the max size of the account (10MiB) 26 : and the associated metadata. */ 27 : 28 0 : #define FD_ACC_TOT_SZ_MAX (FD_RUNTIME_ACC_SZ_MAX + sizeof(fd_account_meta_t)) 29 : 30 0 : #define FD_ACC_NONCE_TOT_SZ_MAX (FD_ACC_NONCE_SZ_MAX + sizeof(fd_account_meta_t)) 31 : 32 : FD_PROTOTYPES_BEGIN 33 : 34 : /* Account Management APIs **************************************************/ 35 : 36 : /* The following account management APIs are helpers for fd_account_meta_t creation, 37 : existence, and retrieval from funk */ 38 : 39 : static inline void 40 42 : fd_account_meta_init( fd_account_meta_t * m ) { 41 42 : fd_memset( m, 0, sizeof(fd_account_meta_t) ); 42 42 : } 43 : 44 : /* fd_account_meta_exists checks if the account in a funk record exists or was 45 : deleted. Handles NULL input safely. Returns 0 if the account was 46 : deleted (zero lamports, empty data, zero owner). Otherwise, returns 47 : 1. */ 48 : 49 : static inline int 50 0 : fd_account_meta_exists( fd_account_meta_t const * m ) { 51 : 52 0 : if( !m ) return 0; 53 : 54 0 : # if FD_HAS_AVX 55 0 : wl_t o = wl_ldu( m->owner ); 56 0 : int has_owner = !_mm256_testz_si256( o, o ); 57 : # else 58 : int has_owner = 0; 59 : for( ulong i=0UL; i<32UL; i++ ) 60 : has_owner |= m->owner[i]; 61 : has_owner = !!has_owner; 62 : # endif 63 : 64 0 : return ((m->lamports > 0UL) | 65 0 : (m->dlen > 0UL) | 66 0 : (has_owner ) ); 67 : 68 0 : } 69 : 70 : /* Account meta helpers */ 71 : static inline void * 72 3 : fd_account_meta_get_data( fd_account_meta_t * m ) { 73 3 : return ((uchar *) m) + sizeof(fd_account_meta_t); 74 3 : } 75 : 76 : static inline void const * 77 0 : fd_account_meta_get_data_const( fd_account_meta_t const * m ) { 78 0 : return ((uchar const *) m) + sizeof(fd_account_meta_t); 79 0 : } 80 : 81 : static inline ulong 82 0 : fd_account_meta_get_record_sz( fd_account_meta_t const * m ) { 83 0 : return sizeof(fd_account_meta_t) + m->dlen; 84 0 : } 85 : 86 : /* Funk key handling **************************************************/ 87 : 88 : /* fd_acc_funk_key returns a fd_funk database key given an account 89 : address. */ 90 : 91 : FD_FN_PURE static inline fd_funk_rec_key_t 92 5184 : fd_funk_acc_key( fd_pubkey_t const * pubkey ) { 93 5184 : fd_funk_rec_key_t key = {0}; 94 5184 : memcpy( key.uc, pubkey, sizeof(fd_pubkey_t) ); 95 5184 : key.uc[ FD_FUNK_REC_KEY_FOOTPRINT - 1 ] = FD_FUNK_KEY_TYPE_ACC; 96 5184 : return key; 97 5184 : } 98 : 99 : /* fd_funk_key_is_acc returns 1 if given fd_funk key is an account 100 : and 0 otherwise. */ 101 : 102 : FD_FN_PURE static inline int 103 0 : fd_funk_key_is_acc( fd_funk_rec_key_t const * id ) { 104 0 : return id->uc[ FD_FUNK_REC_KEY_FOOTPRINT - 1 ] == FD_FUNK_KEY_TYPE_ACC; 105 0 : } 106 : 107 : /* Account Access from Funk APIs *************************************************/ 108 : 109 : /* The following fd_funk_acc_mgr APIs translate between the runtime account DB abstraction 110 : and the actual funk database. 111 : 112 : ### Translation 113 : 114 : Each runtime account is backed by a funk record. However, not all 115 : funk records contain an account. Funk records may temporarily hold 116 : "deleted accounts". 117 : 118 : The memory layout of the account funk record data is 119 : (fd_account_meta_t, padding, account data). */ 120 : 121 : /* fd_funk_get_acc_meta_readonly requests a read-only handle to account data. 122 : funk is the database handle. txn is the database 123 : transaction to query. pubkey is the account key to query. 124 : 125 : On success: 126 : - loads the account data into in-memory cache 127 : - returns a pointer to it in the caller's local address space 128 : - if out_rec!=NULL, sets *out_rec to a pointer to the funk rec. 129 : This handle is suitable as opt_con_rec for fd_funk_get_acc_meta_readonly. 130 : - notably, leaves *opt_err untouched, even if opt_err!=NULL 131 : 132 : First byte of returned pointer is first byte of fd_account_meta_t. 133 : To find data region of account, add sizeof(fd_account_meta_t). 134 : 135 : Lifetime of returned fd_funk_rec_t and account record pointers ends 136 : when user calls modify_data for same account, or tranasction ends. 137 : 138 : On failure, returns NULL, and sets *opt_err if opt_err!=NULL. 139 : Reasons for error include 140 : - account not found 141 : - internal database or user error (out of memory, attempting to view 142 : record which has an active modify_data handle, etc.) 143 : 144 : It is always wrong to cast return value to a non-const pointer. 145 : Instead, use fd_funk_get_acc_meta_mutable to acquire a mutable handle. 146 : 147 : if txn_out is supplied (non-null), the txn the key was found in 148 : is returned. If *txn_out == NULL, the key was found in the root 149 : context. 150 : 151 : IMPORTANT: fd_funk_get_acc_meta_readonly is only safe if it 152 : is guaranteed there are no other modifying accesses to the account. */ 153 : 154 : fd_account_meta_t const * 155 : fd_funk_get_acc_meta_readonly( fd_funk_t const * funk, 156 : fd_funk_txn_t const * txn, 157 : fd_pubkey_t const * pubkey, 158 : fd_funk_rec_t const ** opt_out_rec, 159 : int * opt_err, 160 : fd_funk_txn_t const ** txn_out ); 161 : 162 : /* fd_funk_get_acc_meta_mutable requests a writable handle to an account. 163 : Follows interface of fd_funk_get_account_meta_readonly with the following 164 : changes: 165 : 166 : - do_create controls behavior if account does not exist. If set to 167 : 0, returns error. If set to 1, creates account with given size 168 : and zero-initializes metadata. Caller must initialize metadata of 169 : returned handle in this case. 170 : - min_data_sz is the minimum writable data size that the caller will 171 : accept. This parameter will never shrink an existing account. If 172 : do_create, specifies the new account's size. Otherwise, increases 173 : record size if necessary. 174 : - When resizing or creating an account, the caller should also always 175 : set the account meta's size field. This is not done automatically. 176 : - If caller already has a read-only handle to the requested account, 177 : opt_con_rec can be used to skip query by pubkey. 178 : - In most cases, account is copied to "dirty cache". 179 : 180 : On success: 181 : - If opt_out_rec!=NULL, sets *opt_out_rec to a pointer to writable 182 : funk rec. 183 : - If a record was cloned from an ancestor funk txn or created, 184 : out_prepare is populated with the prepared record object. 185 : - Returns pointer to mutable account metadata and data analogous to 186 : fd_funk_get_acc_meta_readonly. 187 : - IMPORTANT: Return value may point to the same memory region as a 188 : previous calls to fd_funk_get_acc_meta_readonly or fd_funk_get_acc_meta_mutable do, 189 : for the same funk rec (account/txn pair). fd_funk_acc_mgr APIs only promises 190 : that account handles requested for different funk txns will not 191 : alias. Generally, for each funk txn, the user should only ever 192 : access the latest handle returned by view/modify. 193 : 194 : IMPORTANT: fd_funk_get_acc_meta_mutable can only be called if 195 : it is guaranteed that there are no other modifying accesses to 196 : that account. */ 197 : 198 : fd_account_meta_t * 199 : fd_funk_get_acc_meta_mutable( fd_funk_t * funk, 200 : fd_funk_txn_t * txn, 201 : fd_pubkey_t const * pubkey, 202 : int do_create, 203 : ulong min_data_sz, 204 : fd_funk_rec_t ** opt_out_rec, 205 : fd_funk_rec_prepare_t * out_prepare, 206 : int * opt_err ); 207 : 208 : /* fd_acc_mgr_strerror converts an fd_acc_mgr error code into a human 209 : readable cstr. The lifetime of the returned pointer is infinite and 210 : the call itself is thread safe. The returned pointer is always to a 211 : non-NULL cstr. */ 212 : 213 : FD_FN_CONST char const * 214 : fd_acc_mgr_strerror( int err ); 215 : 216 : FD_PROTOTYPES_END 217 : 218 : #endif /* HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h */