Line data Source code
1 : #include "fd_sysvar_clock.h"
2 : #include "fd_sysvar_epoch_schedule.h"
3 : #include "fd_sysvar_rent.h"
4 : #include "fd_sysvar.h"
5 : #include "../fd_executor.h"
6 : #include "../fd_acc_mgr.h"
7 : #include "../fd_system_ids.h"
8 : #include "../context/fd_exec_epoch_ctx.h"
9 : #include "../context/fd_exec_slot_ctx.h"
10 :
11 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/stake_weighted_timestamp.rs#L14 */
12 8634 : #define MAX_ALLOWABLE_DRIFT_FAST ( 25 )
13 :
14 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/stake_weighted_timestamp.rs#L16 */
15 8634 : #define MAX_ALLOWABLE_DRIFT_SLOW ( 150 )
16 :
17 : /* Do all intermediate calculations at nanosecond precision, to mirror Solana's behaviour. */
18 25902 : #define NS_IN_S ( 1000000000 )
19 :
20 : /* The target tick duration, derived from the target tick rate.
21 : https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/src/poh_config.rs#L32
22 : */
23 : #define DEFAULT_TARGET_TICK_DURATION_NS ( NS_IN_S / FD_SYSVAR_CLOCK_DEFAULT_HASHES_PER_TICK )
24 :
25 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/bank.rs#L2200 */
26 : static long
27 17268 : timestamp_from_genesis( fd_exec_slot_ctx_t * slot_ctx ) {
28 17268 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
29 : /* TODO: maybe make types of timestamps the same throughout the runtime codebase. as Solana uses a signed representation */
30 17268 : FD_LOG_INFO(("slot %lu", slot_ctx->slot_bank.slot));
31 17268 : return (long)( epoch_bank->genesis_creation_time + ( ( slot_ctx->slot_bank.slot * epoch_bank->ns_per_slot ) / NS_IN_S ) );
32 17268 : }
33 :
34 : static void
35 : write_clock( fd_exec_slot_ctx_t * slot_ctx,
36 8634 : fd_sol_sysvar_clock_t * clock ) {
37 8634 : ulong sz = fd_sol_sysvar_clock_size( clock );
38 8634 : uchar enc[sz];
39 8634 : memset( enc, 0, sz );
40 8634 : fd_bincode_encode_ctx_t ctx;
41 8634 : ctx.data = enc;
42 8634 : ctx.dataend = enc + sz;
43 8634 : if( fd_sol_sysvar_clock_encode( clock, &ctx ) )
44 0 : FD_LOG_ERR(("fd_sol_sysvar_clock_encode failed"));
45 :
46 8634 : fd_sysvar_set( slot_ctx, fd_sysvar_owner_id.key, (fd_pubkey_t *) &fd_sysvar_clock_id, enc, sz, slot_ctx->slot_bank.slot );
47 8634 : }
48 :
49 :
50 : fd_sol_sysvar_clock_t *
51 : fd_sysvar_clock_read( fd_sol_sysvar_clock_t * result,
52 16116 : fd_exec_slot_ctx_t const * slot_ctx ) {
53 16116 : fd_sol_sysvar_clock_t const * ret = fd_sysvar_cache_clock( slot_ctx->sysvar_cache );
54 16116 : if( NULL != ret ) {
55 2190 : fd_memcpy(result, ret, sizeof(fd_sol_sysvar_clock_t));
56 2190 : return result;
57 2190 : }
58 :
59 13926 : FD_BORROWED_ACCOUNT_DECL(acc);
60 13926 : int rc = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, &fd_sysvar_clock_id, acc );
61 13926 : if( FD_UNLIKELY( rc!=FD_ACC_MGR_SUCCESS ) )
62 0 : return NULL;
63 :
64 13926 : fd_bincode_decode_ctx_t ctx =
65 13926 : { .data = acc->const_data,
66 13926 : .dataend = acc->const_data + acc->const_meta->dlen,
67 13926 : .valloc = {0} /* valloc not required */ };
68 :
69 13926 : if( FD_UNLIKELY( fd_sol_sysvar_clock_decode( result, &ctx )!=FD_BINCODE_SUCCESS ) )
70 0 : return NULL;
71 13926 : return result;
72 13926 : }
73 :
74 : void
75 8634 : fd_sysvar_clock_init( fd_exec_slot_ctx_t * slot_ctx ) {
76 8634 : long timestamp = timestamp_from_genesis( slot_ctx );
77 :
78 8634 : fd_sol_sysvar_clock_t clock = {
79 8634 : .slot = slot_ctx->slot_bank.slot,
80 8634 : .epoch = 0,
81 8634 : .epoch_start_timestamp = timestamp,
82 8634 : .leader_schedule_epoch = 1,
83 8634 : .unix_timestamp = timestamp,
84 8634 : };
85 8634 : write_clock( slot_ctx, &clock );
86 8634 : }
87 :
88 : /* Bounds the timestamp estimate by the max allowable drift from the expected PoH slot duration.
89 :
90 : https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/stake_weighted_timestamp.rs#L67 */
91 : static long
92 : bound_timestamp_estimate( fd_exec_slot_ctx_t * slot_ctx,
93 : long estimate,
94 8634 : long epoch_start_timestamp ) {
95 :
96 : /* Determine offsets from start of epoch */
97 : /* TODO: handle epoch boundary case */
98 8634 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
99 8634 : uint128 poh_estimate_offset = epoch_bank->ns_per_slot * slot_ctx->slot_bank.slot;
100 8634 : uint128 estimate_offset = (uint128)( ( estimate - epoch_start_timestamp ) * NS_IN_S );
101 :
102 8634 : uint128 max_delta_fast = ( poh_estimate_offset * MAX_ALLOWABLE_DRIFT_FAST ) / 100;
103 8634 : uint128 max_delta_slow = ( poh_estimate_offset * MAX_ALLOWABLE_DRIFT_SLOW ) / 100;
104 :
105 8634 : if ( ( estimate_offset > poh_estimate_offset ) && ( ( estimate_offset - poh_estimate_offset ) > max_delta_slow ) ) {
106 0 : return epoch_start_timestamp + (long)( poh_estimate_offset / NS_IN_S ) + (long)( max_delta_slow / NS_IN_S );
107 8634 : } else if ( ( estimate_offset < poh_estimate_offset ) && ( ( poh_estimate_offset - estimate_offset ) > max_delta_fast ) ) {
108 0 : return epoch_start_timestamp + (long)( poh_estimate_offset / NS_IN_S ) + (long)( max_delta_fast / NS_IN_S );
109 0 : }
110 :
111 8634 : return estimate;
112 8634 : }
113 :
114 : /* Estimates the current timestamp, using the stake-weighted median of the latest validator timestamp oracle votes received
115 : from each voting node:
116 : https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/bank.rs#L2927
117 :
118 : Linear interpolation, using the target duration of a slot, is used to calculate the timestamp estimate for the current slot:
119 :
120 : timestamp = (stake-weighted median of vote timestamps) + ((target slot duration) * (slots since median timestamp vote was received))
121 : */
122 : static long
123 8634 : estimate_timestamp( fd_exec_slot_ctx_t * slot_ctx ) {
124 : /* TODO: bound the estimate to ensure it stays within a certain range of the expected PoH clock:
125 : https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/stake_weighted_timestamp.rs#L13 */
126 :
127 8634 : fd_clock_timestamp_vote_t_mapnode_t * votes = slot_ctx->slot_bank.timestamp_votes.votes_root;
128 8634 : if ( NULL == votes ) {
129 8634 : return timestamp_from_genesis( slot_ctx );
130 8634 : }
131 :
132 : /* TODO: actually take the stake-weighted median. For now, just use the root node. */
133 0 : fd_clock_timestamp_vote_t * head = &votes->elem;
134 0 : ulong slots = slot_ctx->slot_bank.slot - head->slot;
135 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
136 0 : uint128 ns_correction = epoch_bank->ns_per_slot * slots;
137 0 : return head->timestamp + (long) (ns_correction / NS_IN_S) ;
138 8634 : }
139 :
140 0 : #define CIDX_T ulong
141 : #define VAL_T long
142 : struct stake_ts_ele {
143 : CIDX_T parent_cidx;
144 : CIDX_T left_cidx;
145 : CIDX_T right_cidx;
146 : CIDX_T prio_cidx;
147 : VAL_T timestamp;
148 : unsigned long stake;
149 : };
150 :
151 : typedef struct stake_ts_ele stake_ts_ele_t;
152 :
153 : #define POOL_NAME stake_ts_pool
154 27852 : #define POOL_T stake_ts_ele_t
155 : #define POOL_IDX_T CIDX_T
156 142602240 : #define POOL_NEXT parent_cidx
157 : #include "../../../util/tmpl/fd_pool.c"
158 :
159 0 : FD_FN_CONST static inline int valcmp (VAL_T a, VAL_T b) {
160 0 : int val = (a < b) ? -1 : 1;
161 0 : return (a == b) ? 0 : val;
162 0 : }
163 :
164 : #define TREAP_NAME stake_ts_treap
165 : #define TREAP_T stake_ts_ele_t
166 : #define TREAP_QUERY_T VAL_T
167 0 : #define TREAP_CMP(q,e) valcmp(q, e->timestamp)
168 0 : #define TREAP_LT(e0,e1) (((VAL_T)((e0)->timestamp)) < ((VAL_T)((e1)->timestamp)))
169 0 : #define TREAP_IDX_T CIDX_T
170 0 : #define TREAP_PARENT parent_cidx
171 0 : #define TREAP_LEFT left_cidx
172 0 : #define TREAP_RIGHT right_cidx
173 0 : #define TREAP_PRIO prio_cidx
174 : #define TREAP_IMPL_STYLE 0
175 : #include "../../../util/tmpl/fd_treap.c"
176 :
177 : /* https://github.com/solana-labs/solana/blob/c091fd3da8014c0ef83b626318018f238f506435/runtime/src/bank.rs#L3600 */
178 : static void
179 : fd_calculate_stake_weighted_timestamp(
180 : fd_exec_slot_ctx_t * slot_ctx,
181 : long * result_timestamp,
182 : uint fix_estimate_into_u64
183 13926 : ) {
184 13926 : FD_SCRATCH_SCOPE_BEGIN {
185 13926 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
186 13926 : ulong slot_duration = (ulong)( epoch_bank->ns_per_slot );
187 13926 : fd_sol_sysvar_clock_t clock;
188 13926 : fd_sysvar_clock_read( &clock, slot_ctx );
189 : // get the unique timestamps
190 : /* stake per timestamp */
191 :
192 : /* Set up a temporary treap, pool, and rng (required for treap prio) */
193 : /* FIXME Hardcoded constant */
194 13926 : stake_ts_treap_t _treap[1];
195 13926 : stake_ts_treap_t * treap = stake_ts_treap_join( stake_ts_treap_new( _treap, 10240UL ) );
196 13926 : uchar * pool_mem = fd_scratch_alloc( stake_ts_pool_align(), stake_ts_pool_footprint( 10240UL ) );
197 13926 : stake_ts_ele_t * pool = stake_ts_pool_join( stake_ts_pool_new( pool_mem, 10240UL ) );
198 13926 : fd_rng_t _rng[1];
199 13926 : fd_rng_t * rng = fd_rng_join( fd_rng_new( _rng, (uint)slot_ctx->slot_bank.transaction_count, 0UL ) );
200 :
201 13926 : ulong total_stake = 0;
202 :
203 13926 : fd_clock_timestamp_vote_t_mapnode_t * timestamp_votes_root = slot_ctx->slot_bank.timestamp_votes.votes_root;
204 13926 : fd_clock_timestamp_vote_t_mapnode_t * timestamp_votes_pool = slot_ctx->slot_bank.timestamp_votes.votes_pool;
205 13926 : fd_vote_accounts_pair_t_mapnode_t * vote_acc_root = slot_ctx->slot_bank.epoch_stakes.vote_accounts_root;
206 13926 : fd_vote_accounts_pair_t_mapnode_t * vote_acc_pool = slot_ctx->slot_bank.epoch_stakes.vote_accounts_pool;
207 13926 : for (
208 13926 : fd_vote_accounts_pair_t_mapnode_t* n = fd_vote_accounts_pair_t_map_minimum(vote_acc_pool, vote_acc_root);
209 13926 : n;
210 13926 : n = fd_vote_accounts_pair_t_map_successor(vote_acc_pool, n)
211 13926 : ) {
212 :
213 : /* get timestamp */
214 0 : fd_pubkey_t const * vote_pubkey = &n->elem.key;
215 :
216 0 : if( timestamp_votes_pool == NULL ) {
217 0 : continue;
218 0 : } else {
219 0 : fd_clock_timestamp_vote_t_mapnode_t query_vote_acc_node;
220 0 : query_vote_acc_node.elem.pubkey = *vote_pubkey;
221 0 : fd_clock_timestamp_vote_t_mapnode_t * vote_acc_node = fd_clock_timestamp_vote_t_map_find(timestamp_votes_pool, timestamp_votes_root, &query_vote_acc_node);
222 0 : ulong vote_timestamp;
223 0 : ulong vote_slot;
224 0 : if( vote_acc_node == NULL ) {
225 0 : vote_timestamp = (ulong)n->elem.value.last_timestamp_ts;
226 0 : vote_slot = n->elem.value.last_timestamp_slot;
227 0 : } else {
228 0 : vote_timestamp = (ulong)vote_acc_node->elem.timestamp;
229 0 : vote_slot = vote_acc_node->elem.slot;
230 0 : }
231 :
232 0 : ulong slot_delta = fd_ulong_sat_sub(slot_ctx->slot_bank.slot, vote_slot);
233 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
234 0 : if (slot_delta > epoch_bank->epoch_schedule.slots_per_epoch) {
235 0 : continue;
236 0 : }
237 :
238 0 : ulong offset = fd_ulong_sat_mul(slot_duration, slot_delta);
239 0 : long estimate = (long)vote_timestamp + (long)(offset / NS_IN_S);
240 : /* get stake */
241 0 : total_stake += n->elem.stake;
242 0 : ulong treap_idx = stake_ts_treap_idx_query( treap, estimate, pool );
243 0 : if ( FD_LIKELY( treap_idx < ULONG_MAX ) ) {
244 0 : pool[ treap_idx ].stake += n->elem.stake;
245 0 : } else {
246 0 : if( 0 == stake_ts_pool_free( pool ) ) {
247 0 : FD_LOG_ERR(( "stake_ts_pool is empty" ));
248 0 : }
249 0 : ulong idx = stake_ts_pool_idx_acquire( pool );
250 0 : pool[ idx ].prio_cidx = fd_rng_ulong( rng );
251 0 : pool[ idx ].timestamp = estimate;
252 0 : pool[ idx ].stake = n->elem.stake;
253 0 : stake_ts_treap_idx_insert( treap, idx, pool );
254 0 : }
255 0 : }
256 0 : }
257 :
258 13926 : *result_timestamp = 0;
259 13926 : if (total_stake == 0) {
260 13926 : return;
261 13926 : }
262 :
263 : // FIXME: this should be a uint128
264 0 : ulong stake_accumulator = 0;
265 0 : for (stake_ts_treap_fwd_iter_t iter = stake_ts_treap_fwd_iter_init ( treap, pool);
266 0 : !stake_ts_treap_fwd_iter_done( iter );
267 0 : iter = stake_ts_treap_fwd_iter_next( iter, pool ) ) {
268 0 : ulong idx = stake_ts_treap_fwd_iter_idx( iter );
269 0 : stake_accumulator = fd_ulong_sat_add(stake_accumulator, pool[ idx ].stake);
270 0 : if (stake_accumulator > (total_stake / 2)) {
271 0 : *result_timestamp = pool[ idx ].timestamp;
272 0 : break;
273 0 : }
274 0 : }
275 :
276 0 : FD_LOG_DEBUG(( "stake weighted timestamp: %ld total stake %lu", *result_timestamp, total_stake ));
277 :
278 : // Bound estimate by `max_allowable_drift` since the start of the epoch
279 0 : fd_epoch_schedule_t schedule = slot_ctx->epoch_ctx->epoch_bank.epoch_schedule;
280 0 : ulong epoch_start_slot = fd_epoch_slot0( &schedule, clock.epoch );
281 0 : FD_LOG_DEBUG(("Epoch start slot %lu", epoch_start_slot));
282 0 : ulong poh_estimate_offset = fd_ulong_sat_mul(slot_duration, fd_ulong_sat_sub(slot_ctx->slot_bank.slot, epoch_start_slot));
283 0 : ulong estimate_offset = fd_ulong_sat_mul(NS_IN_S, (fix_estimate_into_u64) ? fd_ulong_sat_sub((ulong)*result_timestamp, (ulong)clock.epoch_start_timestamp) : (ulong)(*result_timestamp - clock.epoch_start_timestamp));
284 0 : ulong max_delta_fast = fd_ulong_sat_mul(poh_estimate_offset, MAX_ALLOWABLE_DRIFT_FAST) / 100;
285 0 : ulong max_delta_slow = fd_ulong_sat_mul(poh_estimate_offset, MAX_ALLOWABLE_DRIFT_SLOW) / 100;
286 0 : FD_LOG_DEBUG(("poh offset %lu estimate %lu fast %lu slow %lu", poh_estimate_offset, estimate_offset, max_delta_fast, max_delta_slow));
287 0 : if (estimate_offset > poh_estimate_offset && fd_ulong_sat_sub(estimate_offset, poh_estimate_offset) > max_delta_slow) {
288 0 : *result_timestamp = clock.epoch_start_timestamp + (long)poh_estimate_offset / NS_IN_S + (long)max_delta_slow / NS_IN_S;
289 0 : } else if (estimate_offset < poh_estimate_offset && fd_ulong_sat_sub(poh_estimate_offset, estimate_offset) > max_delta_fast) {
290 0 : *result_timestamp = clock.epoch_start_timestamp + (long)poh_estimate_offset / NS_IN_S - (long)max_delta_fast / NS_IN_S;
291 0 : }
292 :
293 0 : FD_LOG_DEBUG(( "corrected stake weighted timestamp: %ld", *result_timestamp ));
294 :
295 0 : if (*result_timestamp < clock.unix_timestamp) {
296 0 : FD_LOG_DEBUG(( "updated timestamp to ancestor" ));
297 0 : *result_timestamp = clock.unix_timestamp;
298 0 : }
299 0 : return;
300 :
301 13926 : }
302 13926 : FD_SCRATCH_SCOPE_END;
303 13926 : }
304 :
305 : int
306 8634 : fd_sysvar_clock_update( fd_exec_slot_ctx_t * slot_ctx ) {
307 :
308 8634 : fd_pubkey_t const * key = &fd_sysvar_clock_id;
309 :
310 8634 : FD_BORROWED_ACCOUNT_DECL(rec);
311 8634 : int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, key, rec);
312 8634 : if (err)
313 0 : FD_LOG_CRIT(( "fd_acc_mgr_view(clock) failed: %d", err ));
314 :
315 8634 : fd_bincode_decode_ctx_t ctx;
316 8634 : ctx.data = rec->const_data;
317 8634 : ctx.dataend = rec->const_data + rec->const_meta->dlen;
318 8634 : ctx.valloc = slot_ctx->valloc;
319 8634 : fd_sol_sysvar_clock_t clock;
320 8634 : if( fd_sol_sysvar_clock_decode( &clock, &ctx ) )
321 0 : FD_LOG_ERR(("fd_sol_sysvar_clock_decode failed"));
322 :
323 8634 : long ancestor_timestamp = clock.unix_timestamp;
324 :
325 8634 : if (slot_ctx->slot_bank.slot != 0) {
326 8634 : fd_calculate_stake_weighted_timestamp(slot_ctx, &clock.unix_timestamp, FD_FEATURE_ACTIVE( slot_ctx, warp_timestamp_again ) );
327 8634 : }
328 :
329 8634 : if (0 == clock.unix_timestamp) {
330 : /* generate timestamp for genesis */
331 8634 : long timestamp_estimate = estimate_timestamp( slot_ctx );
332 8634 : long bounded_timestamp_estimate = bound_timestamp_estimate( slot_ctx, timestamp_estimate, clock.epoch_start_timestamp );
333 8634 : if ( timestamp_estimate != bounded_timestamp_estimate ) {
334 0 : FD_LOG_INFO(( "corrected timestamp_estimate %ld to %ld", timestamp_estimate, bounded_timestamp_estimate ));
335 0 : }
336 : /* if let Some(timestamp_estimate) =
337 : self.get_timestamp_estimate(max_allowable_drift, epoch_start_timestamp)
338 : {
339 : unix_timestamp = timestamp_estimate;
340 : if timestamp_estimate < ancestor_timestamp {
341 : unix_timestamp = ancestor_timestamp;
342 : }
343 : } */
344 8634 : if( bounded_timestamp_estimate < ancestor_timestamp ) {
345 0 : FD_LOG_DEBUG(( "clock rewind detected: %ld -> %ld", ancestor_timestamp, bounded_timestamp_estimate ));
346 0 : bounded_timestamp_estimate = ancestor_timestamp;
347 0 : }
348 8634 : clock.unix_timestamp = bounded_timestamp_estimate;
349 8634 : }
350 :
351 8634 : clock.slot = slot_ctx->slot_bank.slot;
352 :
353 8634 : ulong epoch_old = clock.epoch;
354 8634 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
355 8634 : ulong epoch_new = fd_slot_to_epoch( &epoch_bank->epoch_schedule, clock.slot, NULL );
356 8634 : FD_LOG_DEBUG(("Epoch old %lu new %lu slot %lu", epoch_old, epoch_new, clock.slot));
357 8634 : clock.epoch = epoch_new;
358 8634 : if( epoch_old != epoch_new ) {
359 5292 : long timestamp_estimate = 0L;
360 5292 : fd_calculate_stake_weighted_timestamp( slot_ctx, ×tamp_estimate, FD_FEATURE_ACTIVE( slot_ctx, warp_timestamp_again ) );
361 5292 : clock.unix_timestamp = fd_long_max( timestamp_estimate, ancestor_timestamp );
362 5292 : clock.epoch_start_timestamp = clock.unix_timestamp;
363 5292 : clock.leader_schedule_epoch = fd_slot_to_leader_schedule_epoch( &epoch_bank->epoch_schedule, slot_ctx->slot_bank.slot );
364 5292 : }
365 :
366 8634 : FD_LOG_DEBUG(( "Updated clock at slot %lu", slot_ctx->slot_bank.slot ));
367 8634 : FD_LOG_DEBUG(( "clock.slot: %lu", clock.slot ));
368 8634 : FD_LOG_DEBUG(( "clock.epoch_start_timestamp: %ld", clock.epoch_start_timestamp ));
369 8634 : FD_LOG_DEBUG(( "clock.epoch: %lu", clock.epoch ));
370 8634 : FD_LOG_DEBUG(( "clock.leader_schedule_epoch: %lu", clock.leader_schedule_epoch ));
371 8634 : FD_LOG_DEBUG(( "clock.unix_timestamp: %ld", clock.unix_timestamp ));
372 :
373 8634 : ulong sz = fd_sol_sysvar_clock_size(&clock);
374 8634 : FD_BORROWED_ACCOUNT_DECL(acc);
375 8634 : err = fd_acc_mgr_modify( slot_ctx->acc_mgr, slot_ctx->funk_txn, key, 1, sz, acc);
376 8634 : if (err)
377 0 : FD_LOG_CRIT(( "fd_acc_mgr_modify(clock) failed: %d", err ));
378 :
379 8634 : fd_bincode_encode_ctx_t e_ctx = {
380 8634 : .data = acc->data,
381 8634 : .dataend = acc->data+sz,
382 8634 : };
383 8634 : if( fd_sol_sysvar_clock_encode( &clock, &e_ctx ) )
384 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
385 :
386 8634 : ulong lamps = fd_rent_exempt_minimum_balance( &epoch_bank->rent, sz );
387 8634 : if( acc->meta->info.lamports < lamps )
388 0 : acc->meta->info.lamports = lamps;
389 :
390 8634 : acc->meta->dlen = sz;
391 8634 : fd_memcpy( acc->meta->info.owner, fd_sysvar_owner_id.key, 32 );
392 :
393 8634 : return 0;
394 8634 : }
|