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 "../../funk/fd_funk.h"
9 : #include "fd_borrowed_account.h"
10 :
11 : /* FD_ACC_MGR_{SUCCESS,ERR{...}} are fd_acc_mgr_t specific error codes.
12 : To be stored in an int. */
13 :
14 10369437 : #define FD_ACC_MGR_SUCCESS (0)
15 3304998 : #define FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT (-1)
16 0 : #define FD_ACC_MGR_ERR_WRITE_FAILED (-2)
17 0 : #define FD_ACC_MGR_ERR_READ_FAILED (-3)
18 0 : #define FD_ACC_MGR_ERR_WRONG_MAGIC (-4)
19 :
20 : /* FD_ACC_SZ_MAX is the hardcoded size limit of a Solana account. */
21 :
22 1192815 : #define FD_ACC_SZ_MAX (10UL<<20) /* 10MiB */
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 1192767 : #define FD_ACC_TOT_SZ_MAX (FD_ACC_SZ_MAX + FD_ACCOUNT_META_FOOTPRINT)
29 :
30 : /* fd_acc_mgr_t translates between the runtime account DB abstraction
31 : and the actual funk database. Also manages rent collection.
32 : fd_acc_mgr_t cannot be relocated to another address space.
33 :
34 : ### Translation
35 :
36 : Each runtime account is backed by a funk record. However, not all
37 : funk records contain an account. Funk records may temporarily hold
38 : "deleted accounts".
39 :
40 : The memory layout of the acc_mgr funk record data is
41 : (fd_account_meta_t, padding, account data). */
42 :
43 : struct __attribute__((aligned(16UL))) fd_acc_mgr {
44 : fd_funk_t * funk;
45 :
46 : ulong slots_per_epoch; /* see epoch schedule. do not update directly */
47 :
48 : /* part_width is the width of rent partition. Each partition is a
49 : contiguous sub-range of [0,2^256) where each element is an
50 : account address. */
51 :
52 : ulong part_width;
53 :
54 : /* skip_rent_rewrites is a feature flag controlling rent collection
55 : behavior during eager rent collection passes. */
56 :
57 : uchar skip_rent_rewrites : 1;
58 :
59 : uint is_locked;
60 : };
61 :
62 : /* FD_ACC_MGR_{ALIGN,FOOTPRINT} specify the parameters for the memory
63 : region backing an fd_acc_mgr_t. */
64 :
65 108789 : #define FD_ACC_MGR_ALIGN (alignof(fd_acc_mgr_t))
66 326367 : #define FD_ACC_MGR_FOOTPRINT ( sizeof(fd_acc_mgr_t))
67 :
68 : FD_PROTOTYPES_BEGIN
69 :
70 : /* Management API *****************************************************/
71 :
72 : /* fd_acc_mgr_new formats a memory region suitable to hold an
73 : fd_acc_mgr_t. Binds newly created object to global and returns
74 : cast. */
75 :
76 : fd_acc_mgr_t *
77 : fd_acc_mgr_new( void * mem,
78 : fd_funk_t * funk );
79 :
80 : /* fd_acc_mgr_delete releases the memory region used by an fd_acc_mgr_t
81 : and returns it to the caller. */
82 :
83 : void *
84 : fd_acc_mgr_delete( fd_acc_mgr_t * acc_mgr );
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 5913021 : fd_acc_funk_key( fd_pubkey_t const * pubkey ) {
93 5913021 : fd_funk_rec_key_t key = {0};
94 5913021 : fd_memcpy( key.c, pubkey, sizeof(fd_pubkey_t) );
95 5913021 : key.c[ FD_FUNK_REC_KEY_FOOTPRINT - 1 ] = FD_FUNK_KEY_TYPE_ACC;
96 5913021 : return key;
97 5913021 : }
98 :
99 : /* fd_funk_key_is_acc returns 1 if given fd_funk key is an account
100 : managed by fd_acc_mgr_t, and 0 otherwise. */
101 :
102 : FD_FN_PURE static inline int
103 1239099 : fd_funk_key_is_acc( fd_funk_rec_key_t const * id ) {
104 1239099 : return id->c[ FD_FUNK_REC_KEY_FOOTPRINT - 1 ] == FD_FUNK_KEY_TYPE_ACC;
105 1239099 : }
106 :
107 : /* fd_funk_key_to_acc reinterprets a funk rec key as an account address.
108 : Safe assuming fd_funk_key_is_acc( id )==1. */
109 :
110 : FD_FN_CONST static inline fd_pubkey_t const *
111 0 : fd_funk_key_to_acc( fd_funk_rec_key_t const * id ) {
112 0 : return (fd_pubkey_t const *)fd_type_pun_const( id->c );
113 0 : }
114 :
115 :
116 : /* Account Access API *************************************************/
117 :
118 : static inline void
119 1310805 : fd_account_meta_init( fd_account_meta_t * m ) {
120 1310805 : fd_memset( m, 0, sizeof(fd_account_meta_t) );
121 1310805 : m->magic = FD_ACCOUNT_META_MAGIC;
122 1310805 : m->hlen = sizeof(fd_account_meta_t);
123 1310805 : }
124 :
125 : /* fd_acc_exists checks if the account in a funk record exists or was
126 : deleted. Handles NULL input safely. Returns 0 if the account was
127 : deleted (zero lamports, empty data, zero owner). Otherwise, returns
128 : 1. */
129 :
130 : static inline int
131 2816976 : fd_acc_exists( fd_account_meta_t const * m ) {
132 :
133 2816976 : if( !m ) return 0;
134 :
135 1778577 : # if FD_HAS_AVX
136 1778577 : wl_t o = wl_ldu( m->info.owner );
137 1778577 : int has_owner = !_mm256_testz_si256( o, o );
138 : # else
139 : int has_owner = 0;
140 : for( ulong i=0UL; i<32UL; i++ )
141 : has_owner |= m->info.owner[i];
142 : has_owner = !!has_owner;
143 : # endif
144 :
145 1778577 : return ( ( m->info.lamports > 0 ) |
146 1778577 : ( m->dlen > 0 ) |
147 1778577 : ( has_owner ) );
148 :
149 2816976 : }
150 :
151 : /* fd_acc_mgr_view_raw requests a read-only handle to account data.
152 : acc_mgr is the global account manager object. txn is the database
153 : transaction to query. pubkey is the account key to query.
154 :
155 : On success:
156 : - loads the account data into in-memory cache
157 : - returns a pointer to it in the caller's local address space
158 : - if out_rec!=NULL, sets *out_rec to a pointer to the funk rec.
159 : This handle is suitable as opt_con_rec for fd_acc_mgr_modify_raw.
160 : - notably, leaves *opt_err untouched, even if opt_err!=NULL
161 :
162 : First byte of returned pointer is first byte of fd_account_meta_t.
163 : To find data region of account, add (fd_account_meta_t)->hlen.
164 :
165 : Lifetime of returned fd_funk_rec_t and account record pointers ends
166 : when user calls modify_data for same account, or tranasction ends.
167 :
168 : On failure, returns NULL, and sets *opt_err if opt_err!=NULL.
169 : Reasons for error include
170 : - account not found
171 : - internal database or user error (out of memory, attempting to view
172 : record which has an active modify_data handle, etc.)
173 :
174 : It is always wrong to cast return value to a non-const pointer.
175 : Instead, use fd_acc_mgr_modify_raw to acquire a mutable handle.
176 :
177 : if txn_out is supplied (non-null), the txn the key was found in
178 : is returned. If *txn_out == NULL, the key was found in the root
179 : context */
180 :
181 : fd_account_meta_t const *
182 : fd_acc_mgr_view_raw( fd_acc_mgr_t * acc_mgr,
183 : fd_funk_txn_t const * txn,
184 : fd_pubkey_t const * pubkey,
185 : fd_funk_rec_t const ** opt_out_rec,
186 : int * opt_err,
187 : fd_funk_txn_t const ** txn_out );
188 :
189 : int
190 : fd_acc_mgr_view( fd_acc_mgr_t * acc_mgr,
191 : fd_funk_txn_t const * txn,
192 : fd_pubkey_t const * pubkey,
193 : fd_borrowed_account_t * account );
194 :
195 : /* fd_acc_mgr_modify_raw requests a writable handle to an account.
196 : Follows interface of fd_acc_mgr_modify_raw with the following
197 : changes:
198 :
199 : - do_create controls behavior if account does not exist. If set to
200 : 0, returns error. If set to 1, creates account with given size
201 : and zero-initializes metadata. Caller must initialize metadata of
202 : returned handle in this case.
203 : - min_data_sz is the minimum writable data size that the caller will
204 : accept. This parameter will never shrink an existing account. If
205 : do_create, specifies the new account's size. Otherwise, increases
206 : record size if necessary.
207 : - When resizing or creating an account, the caller should also always
208 : set the account meta's size field. This is not done automatically.
209 : - If caller already has a read-only handle to the requested account,
210 : opt_con_rec can be used to skip query by pubkey.
211 : - In most cases, account is copied to "dirty cache".
212 :
213 : On success:
214 : - If opt_out_rec!=NULL, sets *opt_out_rec to a pointer to writable
215 : funk rec. Suitable as rec parameter to fd_acc_mgr_commit_raw.
216 : - Returns pointer to mutable account metadata and data analogous to
217 : fd_acc_mgr_view_raw.
218 : - IMPORTANT: Return value may point to the same memory region as a
219 : previous calls to fd_acc_mgr_view_raw or fd_acc_mgr_modify_raw do,
220 : for the same funk rec (account/txn pair). fd_acc_mgr only promises
221 : that account handles requested for different funk txns will not
222 : alias. Generally, for each funk txn, the user should only ever
223 : access the latest handle returned by view/modify.
224 :
225 : Caller must eventually commit funk record. During replay, this is
226 : done automatically by slot freeze. */
227 :
228 : fd_account_meta_t *
229 : fd_acc_mgr_modify_raw( fd_acc_mgr_t * acc_mgr,
230 : fd_funk_txn_t * txn,
231 : fd_pubkey_t const * pubkey,
232 : int do_create,
233 : ulong min_data_sz,
234 : fd_funk_rec_t const * opt_con_rec,
235 : fd_funk_rec_t ** opt_out_rec,
236 : int * opt_err );
237 :
238 : int
239 : fd_acc_mgr_modify( fd_acc_mgr_t * acc_mgr,
240 : fd_funk_txn_t * txn,
241 : fd_pubkey_t const * pubkey,
242 : int do_create,
243 : ulong min_data_sz,
244 : fd_borrowed_account_t * account );
245 :
246 : int
247 : fd_acc_mgr_save( fd_acc_mgr_t * acc_mgr,
248 : fd_borrowed_account_t * account );
249 :
250 : /* This version of save is for old code written before tpool integration */
251 :
252 : int
253 : fd_acc_mgr_save_non_tpool( fd_acc_mgr_t * acc_mgr,
254 : fd_funk_txn_t * txn,
255 : fd_borrowed_account_t * account );
256 :
257 : int
258 : fd_acc_mgr_save_many_tpool( fd_acc_mgr_t * acc_mgr,
259 : fd_funk_txn_t * txn,
260 : fd_borrowed_account_t ** accounts,
261 : ulong accounts_cnt,
262 : fd_tpool_t * tpool );
263 :
264 : void
265 : fd_acc_mgr_lock( fd_acc_mgr_t * acc_mgr );
266 :
267 : void
268 : fd_acc_mgr_unlock( fd_acc_mgr_t * acc_mgr );
269 :
270 : /* fd_acc_mgr_set_slots_per_epoch updates the slots_per_epoch setting
271 : and rebalances rent partitions. No-op unless 'skip_rent_rewrites'
272 : feature is activated or 'slots_per_epoch' changes. */
273 :
274 : void
275 : fd_acc_mgr_set_slots_per_epoch( fd_exec_slot_ctx_t * slot_ctx,
276 : ulong slots_per_epoch );
277 :
278 : /* fd_acc_mgr_strerror converts an fd_acc_mgr error code into a human
279 : readable cstr. The lifetime of the returned pointer is infinite and
280 : the call itself is thread safe. The returned pointer is always to a
281 : non-NULL cstr. */
282 :
283 : FD_FN_CONST char const *
284 : fd_acc_mgr_strerror( int err );
285 :
286 : FD_PROTOTYPES_END
287 :
288 : #endif /* HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h */
|