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