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