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