Line data Source code
1 : #ifndef HEADER_fd_src_disco_poh_fd_poh_tile_h
2 : #define HEADER_fd_src_disco_poh_fd_poh_tile_h
3 :
4 : #include "../tiles.h"
5 : #include "../shred/fd_stake_ci.h"
6 :
7 : /* Common library functions for the Proof of History tile. */
8 :
9 : /* When we are becoming leader, and we think the prior leader might have
10 : skipped their slot, we give them a grace period to finish. In the
11 : Agave client this is called grace ticks. This is a courtesy to
12 : maintain network health, and is not strictly necessary. It is
13 : actually advantageous to us as new leader to take over right away and
14 : give no grace period, since we could generate more fees.
15 :
16 : Here we define the grace period to be two slots, which is taken from
17 : Agave directly. */
18 : #define GRACE_SLOTS (2UL)
19 :
20 : /* The maximum number of microblocks that pack is allowed to pack into a
21 : single slot. This is not consensus critical, and pack could, if we
22 : let it, produce as many microblocks as it wants, and the slot would
23 : still be valid.
24 :
25 : We have this here instead so that PoH can estimate slot completion,
26 : and keep the hashcnt up to date as pack progresses through packing
27 : the slot. If this upper bound was not enforced, PoH could tick to
28 : the last hash of the slot and have no hashes left to mixin incoming
29 : microblocks from pack, so this upper bound is a coordination
30 : mechanism so that PoH can progress hashcnts while the slot is active,
31 : and know that pack will not need those hashcnts later to do mixins. */
32 0 : #define MAX_MICROBLOCKS_PER_SLOT (16384UL)
33 :
34 : /* When we are hashing in the background in case a prior leader skips
35 : their slot, we need to store the result of each tick hash so we can
36 : publish them when we become leader. The network requires at least
37 : one leader slot to publish in each epoch for the leader schedule to
38 : generate, so in the worst case we might need two full epochs of slots
39 : to store the hashes. (Eg, if epoch T only had a published slot in
40 : position 0 and epoch T+1 only had a published slot right at the end).
41 :
42 : There is a tighter bound: the block data limit of mainnet-beta is
43 : currently FD_PACK_MAX_DATA_PER_BLOCK, or 27,332,342 bytes per slot.
44 : At 48 bytes per tick, it is not possible to publish a slot that skips
45 : 569,424 or more prior slots. */
46 0 : #define MAX_SKIPPED_TICKS (1UL+(FD_PACK_MAX_DATA_PER_BLOCK/48UL))
47 :
48 : struct fd_poh_tile_in_ctx {
49 : fd_wksp_t * mem;
50 : ulong chunk0;
51 : ulong wmark;
52 : };
53 : typedef struct fd_poh_tile_in_ctx fd_poh_tile_in_ctx_t;
54 :
55 : typedef void * (*fd_poh_tile_get_micoblock_buffer_func_t)( void * arg );
56 : typedef void (*fd_poh_tile_publish_microblock_func_t)( void * arg, ulong tspub, ulong sig, ulong sz );
57 : typedef void * (*fd_poh_tile_get_pack_buffer_func_t)( void * arg );
58 : typedef void (*fd_poh_tile_publish_pack_func_t)( void * arg, ulong tspub, ulong sig, ulong sz );
59 : typedef void (*fd_poh_tile_register_tick_func_t)( void * arg, ulong slot, uchar hash[ static 32 ] );
60 : typedef void (*fd_poh_tile_signal_leader_change_func_t)( void * arg );
61 :
62 : struct fd_poh_tile_ctx {
63 : /* Static configuration determined at genesis creation time. See
64 : long comment above for more information. */
65 : double hashcnt_duration_ns;
66 : double slot_duration_ns;
67 : ulong tick_duration_ns;
68 : ulong hashcnt_per_tick;
69 : ulong ticks_per_slot;
70 :
71 : /* Derived from the above configuration, but we precompute it. */
72 : ulong hashcnt_per_slot;
73 :
74 : /* The current slot and hashcnt within that slot of the proof of
75 : history, including hashes we have been producing in the background
76 : while waiting for our next leader slot. */
77 : ulong slot;
78 : ulong hashcnt;
79 :
80 : /* When we send a microblock on to the shred tile, we need to tell
81 : it how many hashes there have been since the last microblock, so
82 : this tracks the hashcnt of the last published microblock.
83 :
84 : As well, the next leader slot that we can transition into will
85 : always be strictly more than the slot this hashcnt is in, otherwise
86 : we could potentially become leader for a slot twice. */
87 : ulong last_slot;
88 : ulong last_hashcnt;
89 :
90 : /* See how this field is used below. If we have sequential leader
91 : slots, we don't reset the expected slot end time between the two,
92 : to prevent clock drift. If we didn't do this, our 2nd slot would
93 : end 400ms + `time_for_replay_to_move_slot_and_reset_poh` after
94 : our 1st, rather than just strictly 400ms. */
95 : ulong expect_sequential_leader_slot;
96 :
97 : /* The PoH tile must never drop microblocks that get committed by the
98 : bank, so it needs to always be able to mixin a microblock hash.
99 : Mixing in requires incrementing the hashcnt, so we need to ensure
100 : at all times that there is enough hascnts left in the slot to
101 : mixin whatever future microblocks pack might produce for it.
102 :
103 : This value tracks that. At any time, max_microblocks_per_slot
104 : - microblocks_lower_bound is an upper bound on the maximum number
105 : of microblocks that might still be received in this slot. */
106 : ulong microblocks_lower_bound;
107 :
108 : /* Constant, fixed at initialization. The maximum number of
109 : microblocks that the pack tile can publish in each slot. */
110 : ulong max_microblocks_per_slot;
111 :
112 : uchar __attribute__((aligned(32UL))) hash[ 32 ];
113 :
114 : /* When we are not leader, we need to save the hashes that were
115 : produced in case the prior leader skips. If they skip, we will
116 : replay these skipped hashes into our next leader bank so that
117 : the slot hashes sysvar can be updated correctly. We only need 150
118 : of these, because that's what's required for consensus in the
119 : sysvar. */
120 : uchar skipped_tick_hashes[ MAX_SKIPPED_TICKS ][ 32 ];
121 :
122 : /* The timestamp in nanoseconds of when the reset slot was received.
123 : This is the timestamp we are building on top of to determine when
124 : our next leader slot starts. */
125 : long reset_slot_start_ns;
126 :
127 : /* The hashcnt corresponding to the start of the current reset slot. */
128 : ulong reset_slot;
129 :
130 : /* The hashcnt at which our next leader slot begins, or ULONG max if
131 : we have no known next leader slot. */
132 : ulong next_leader_slot;
133 :
134 : /* The current slot where we are leader. If it is set to FD_SLOT_NULL, we are
135 : not leader. */
136 : ulong current_leader_slot;
137 :
138 :
139 : /* If we have published a tick or a microblock for a particular slot
140 : to the shred tile, we should never become leader for that slot
141 : again, otherwise we could publish a duplicate block.
142 :
143 : This value tracks the max slot that we have published a tick or
144 : microblock for so we can prevent this. */
145 : ulong highwater_leader_slot;
146 :
147 : fd_sha256_t * sha256;
148 :
149 : fd_stake_ci_t * stake_ci;
150 :
151 : fd_pubkey_t identity_key;
152 :
153 : fd_wksp_t * shred_out_mem;
154 : ulong shred_out_chunk0;
155 : ulong shred_out_wmark;
156 : ulong shred_out_chunk;
157 :
158 : fd_frag_meta_t * pack_out_mcache;
159 : ulong pack_out_depth;
160 : ulong pack_out_seq;
161 : fd_wksp_t * pack_out_mem;
162 : ulong pack_out_chunk0;
163 : ulong pack_out_wmark;
164 : ulong pack_out_chunk;
165 :
166 : fd_histf_t begin_leader_delay[ 1 ];
167 : fd_histf_t first_microblock_delay[ 1 ];
168 : fd_histf_t slot_done_delay[ 1 ];
169 :
170 : /* Callbacks */
171 : void * arg;
172 :
173 : fd_poh_tile_get_micoblock_buffer_func_t get_microblock_buffer_func;
174 : fd_poh_tile_publish_microblock_func_t publish_microblock_func;
175 : fd_poh_tile_get_micoblock_buffer_func_t get_pack_buffer_func;
176 : fd_poh_tile_publish_microblock_func_t publish_pack_func;
177 : fd_poh_tile_register_tick_func_t register_tick_func;
178 : fd_poh_tile_signal_leader_change_func_t signal_leader_change_func;
179 : };
180 : typedef struct fd_poh_tile_ctx fd_poh_tile_ctx_t;
181 :
182 : FD_PROTOTYPES_BEGIN
183 :
184 : ulong
185 : fd_poh_tile_align( void );
186 :
187 : ulong
188 : fd_poh_tile_footprint( void );
189 :
190 : void
191 : fd_poh_tile_publish_microblock( fd_poh_tile_ctx_t * ctx,
192 : ulong sig,
193 : ulong slot,
194 : ulong hashcnt_delta,
195 : fd_txn_p_t * txns,
196 : ulong txn_cnt );
197 :
198 : void
199 : fd_poh_tile_initialize( fd_poh_tile_ctx_t * ctx,
200 : ulong tick_duration_ns, /* See clock comments above, will be 500ns for mainnet-beta. */
201 : ulong hashcnt_per_tick, /* See clock comments above, will be 12,500 for mainnet-beta. */
202 : ulong ticks_per_slot, /* See clock comments above, will almost always be 64. */
203 : ulong tick_height, /* The counter (height) of the tick to start hashing on top of. */
204 : uchar const * last_entry_hash /* Points to start of a 32 byte region of memory, the hash itself at the tick height. */ );
205 :
206 : int
207 : fd_poh_tile_reached_leader_slot( fd_poh_tile_ctx_t * ctx,
208 : ulong * out_leader_slot,
209 : ulong * out_reset_slot );
210 :
211 : void
212 : fd_poh_tile_publish_became_leader( fd_poh_tile_ctx_t * ctx,
213 : void const * current_leader_data,
214 : ulong slot );
215 :
216 : void
217 : fd_poh_tile_no_longer_leader( fd_poh_tile_ctx_t * ctx );
218 :
219 : void
220 : fd_poh_tile_reset( fd_poh_tile_ctx_t * ctx,
221 : ulong completed_bank_slot, /* The slot that successfully produced a block */
222 : uchar const * reset_blockhash, /* The hash of the last tick in the produced block */
223 : ulong hashcnt_per_tick /* The hashcnt per tick of the bank that completed */);
224 : int
225 : fd_poh_tile_get_leader_after_n_slots( fd_poh_tile_ctx_t * ctx,
226 : ulong n,
227 : uchar out_pubkey[ static 32 ] );
228 : int
229 : fd_poh_tile_after_credit( fd_poh_tile_ctx_t * ctx,
230 : int * opt_poll_in );
231 :
232 : void
233 : fd_poh_tile_init_stakes( fd_poh_tile_ctx_t * ctx, uchar const * stakes_msg );
234 :
235 : void
236 : fd_poh_tile_fini_stakes( fd_poh_tile_ctx_t * ctx );
237 :
238 : void
239 : fd_poh_tile_during_housekeeping( fd_poh_tile_ctx_t * ctx );
240 :
241 : void
242 : fd_poh_tile_begin_leader( fd_poh_tile_ctx_t * ctx,
243 : ulong slot,
244 : ulong hashcnt_per_tick );
245 :
246 : void
247 : fd_poh_tile_process_packed_microblock( fd_poh_tile_ctx_t * ctx,
248 : ulong target_slot,
249 : ulong sig,
250 : fd_txn_p_t * txns,
251 : ulong txn_cnt,
252 : uchar mixin_hash[ static 32 ] );
253 :
254 : void
255 : fd_poh_tile_done_packing( fd_poh_tile_ctx_t * ctx,
256 : ulong microblocks_in_slot );
257 :
258 : fd_poh_tile_ctx_t *
259 : fd_poh_tile_new( void * scratch,
260 : void * arg,
261 : fd_poh_tile_get_micoblock_buffer_func_t get_microblock_buffer_func,
262 : fd_poh_tile_publish_microblock_func_t publish_microblock_func,
263 : fd_poh_tile_get_pack_buffer_func_t get_pack_buffer_func,
264 : fd_poh_tile_publish_pack_func_t publish_pack_func,
265 : fd_poh_tile_register_tick_func_t register_tick_func,
266 : fd_poh_tile_signal_leader_change_func_t signal_leader_change_func );
267 :
268 : FD_PROTOTYPES_END
269 :
270 : #endif /* HEADER_fd_src_disco_poh_fd_poh_tile_h */
|