Line data Source code
1 : #include "fd_types_custom.h"
2 : #include "fd_bincode.h"
3 : #include "fd_types.h"
4 : #include "fd_types_meta.h"
5 : #ifndef SOURCE_fd_src_flamenco_types_fd_types_c
6 : #error "fd_types_custom.c is part of the fd_types.c compile uint"
7 : #endif /* !SOURCE_fd_src_flamenco_types_fd_types_c */
8 :
9 : #include "../runtime/fd_system_ids.h"
10 : #include "../runtime/fd_executor_err.h"
11 :
12 : #include <stdio.h>
13 :
14 : int
15 3 : fd_flamenco_txn_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
16 3 : *total_sz += sizeof(fd_flamenco_txn_t);
17 3 : void const * start_data = ctx->data;
18 3 : int err = fd_flamenco_txn_decode_footprint_inner( ctx, total_sz );
19 3 : ctx->data = start_data;
20 3 : return err;
21 3 : }
22 :
23 : int
24 9 : fd_flamenco_txn_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
25 9 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
26 9 : ulong bufsz = (ulong)ctx->dataend - (ulong)ctx->data;
27 9 : fd_flamenco_txn_t self;
28 9 : ulong sz = 0UL;
29 9 : ulong res = fd_txn_parse_core( ctx->data,
30 9 : bufsz,
31 9 : self.txn,
32 9 : NULL,
33 9 : &sz );
34 9 : if( FD_UNLIKELY( !res ) ) {
35 0 : return -1000001;
36 0 : }
37 9 : ctx->data = (void *)( (ulong)ctx->data + sz );
38 9 : *total_sz += sz;
39 9 : return 0;
40 9 : }
41 :
42 : int FD_FN_UNUSED
43 : fd_flamenco_txn_encode_global( fd_flamenco_txn_t const * self,
44 0 : fd_bincode_encode_ctx_t * ctx ) {
45 0 : (void)self;
46 0 : (void)ctx;
47 0 : FD_LOG_ERR(( "only exists for testing" ));
48 0 : }
49 :
50 : void * FD_FN_UNUSED
51 : fd_flamenco_txn_decode_global( void * mem,
52 0 : fd_bincode_decode_ctx_t * ctx ) {
53 0 : (void)mem;
54 0 : (void)ctx;
55 0 : FD_LOG_ERR(( "only exists for testing" ));
56 0 : }
57 :
58 : void *
59 3 : fd_flamenco_txn_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) {
60 3 : fd_flamenco_txn_t * self = (fd_flamenco_txn_t *)mem;
61 3 : fd_flamenco_txn_new( self );
62 3 : void * alloc_region = (uchar *)mem + sizeof(fd_flamenco_txn_t);
63 3 : void * * alloc_mem = &alloc_region;
64 3 : fd_flamenco_txn_decode_inner( mem, alloc_mem, ctx );
65 3 : return self;
66 3 : }
67 :
68 : void
69 9 : fd_flamenco_txn_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
70 9 : fd_flamenco_txn_t * self = (fd_flamenco_txn_t *)struct_mem;
71 9 : static FD_TL fd_txn_parse_counters_t counters[1];
72 9 : ulong bufsz = (ulong)ctx->dataend - (ulong)ctx->data;
73 9 : ulong sz = 0UL;
74 9 : ulong res = fd_txn_parse_core( ctx->data,
75 9 : bufsz,
76 9 : self->txn,
77 9 : counters,
78 9 : &sz );
79 9 : if( FD_UNLIKELY( !res ) ) {
80 0 : FD_LOG_ERR(( "Failed to decode txn (fd_txn.c:%lu)",
81 0 : counters->failure_ring[ counters->failure_cnt % FD_TXN_PARSE_COUNTERS_RING_SZ ] ));
82 0 : return;
83 0 : }
84 9 : fd_memcpy( self->raw, ctx->data, sz );
85 9 : self->raw_sz = sz;
86 9 : ctx->data = (void *)( (ulong)ctx->data + sz );
87 9 : }
88 :
89 : void
90 : fd_gossip_ip4_addr_walk( void * w,
91 : fd_gossip_ip4_addr_t const * self,
92 : fd_types_walk_fn_t fun,
93 : char const * name,
94 93 : uint level ) {
95 :
96 93 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip4_addr", level++ );
97 93 : uchar * octet = (uchar *)self;
98 465 : for( uchar i = 0; i < 4; ++i ) {
99 372 : fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level );
100 372 : }
101 93 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip4_addr", level-- );
102 : /* TODO: Add support for optional pretty-printing like serde?
103 : Saving this in the meantime */
104 : // char buf[ 16 ];
105 : // sprintf( buf, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( *self ) );
106 : // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip4_addr", level );
107 93 : }
108 :
109 : void
110 : fd_gossip_ip6_addr_walk( void * w,
111 : fd_gossip_ip6_addr_t const * self,
112 : fd_types_walk_fn_t fun,
113 : char const * name,
114 0 : uint level ) {
115 0 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip6_addr", level++ );
116 0 : uchar * octet = (uchar *)self;
117 0 : for( uchar i = 0; i < 16; ++i ) {
118 0 : fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level );
119 0 : }
120 0 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip6_addr", level-- );
121 : /* Saving this for when we support configurable pretty-printing mode */
122 : // char buf[ 40 ];
123 : // sprintf( buf,
124 : // "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
125 : // FD_LOG_HEX16_FMT_ARGS( self->us ) );
126 : // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip6_addr", level );
127 0 : }
128 :
129 0 : int fd_tower_sync_encode( fd_tower_sync_t const * self, fd_bincode_encode_ctx_t * ctx ) {
130 0 : FD_LOG_ERR(( "todo"));
131 0 : }
132 :
133 : static void fd_hash_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
134 : static int fd_hash_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
135 : static void fd_lockout_offset_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
136 : static int fd_lockout_offset_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
137 :
138 0 : int fd_tower_sync_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
139 : /* This is a modified version of fd_compact_tower_sync_decode_footprint_inner() */
140 0 : int err = 0;
141 0 : if( FD_UNLIKELY( ctx->data>ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
142 0 : err = fd_bincode_uint64_decode_footprint( ctx );
143 :
144 : /* The first modification is that we want to grab the value fo the root. */
145 0 : ulong root = 0UL;
146 0 : fd_bincode_decode_ctx_t root_ctx = { .data = (uchar*)ctx->data - sizeof(ulong), .dataend = ctx->data };
147 0 : if( FD_UNLIKELY( ((ulong)ctx->data)+sizeof(ulong)>(ulong)ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
148 0 : fd_bincode_uint64_decode_unsafe( &root, &root_ctx );
149 0 : root = root != ULONG_MAX ? root : 0UL;
150 : /* Done with first modification */
151 :
152 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
153 0 : ushort lockout_offsets_len;
154 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
155 0 : err = fd_bincode_compact_u16_decode( &lockout_offsets_len, ctx );
156 :
157 0 : if( FD_UNLIKELY( err ) ) return err;
158 0 : ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
159 0 : *total_sz += deq_fd_lockout_offset_t_align() + deq_fd_lockout_offset_t_footprint( lockout_offsets_max );
160 :
161 0 : for( ulong i = 0; i < lockout_offsets_len; ++i ) {
162 :
163 0 : uchar const * start_data = ctx->data;
164 0 : err = fd_lockout_offset_decode_footprint_inner( ctx, total_sz );
165 0 : if( FD_UNLIKELY( err ) ) return err;
166 :
167 : /* The second modification is that we want to grab the lockout offset from
168 : the deque to make sure that we can do a checked add successfully. */
169 0 : fd_lockout_offset_t lockout_offset = {0};
170 0 : fd_bincode_decode_ctx_t lockout_ctx = { .data = start_data, .dataend = start_data+sizeof(fd_lockout_offset_t) };
171 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
172 0 : fd_lockout_offset_decode_inner( &lockout_offset, NULL, &lockout_ctx );
173 0 : err = __builtin_uaddl_overflow( root, lockout_offset.offset, &root );
174 0 : if( FD_UNLIKELY( err ) ) {
175 0 : return err;
176 0 : }
177 : /* Done with second modification. */
178 0 : }
179 :
180 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
181 0 : err = fd_hash_decode_footprint_inner( ctx, total_sz );
182 0 : if( FD_UNLIKELY( err ) ) return err;
183 0 : {
184 0 : uchar o;
185 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
186 0 : err = fd_bincode_bool_decode( &o, ctx );
187 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
188 0 : if( o ) {
189 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
190 0 : err = fd_bincode_int64_decode_footprint( ctx );
191 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
192 0 : }
193 0 : }
194 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
195 0 : err = fd_hash_decode_footprint_inner( ctx, total_sz );
196 0 : if( FD_UNLIKELY( err ) ) return err;
197 0 : return 0;
198 0 : }
199 :
200 0 : int fd_tower_sync_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
201 0 : *total_sz += sizeof(fd_tower_sync_t);
202 0 : void const * start_data = ctx->data;
203 0 : int err = fd_tower_sync_decode_footprint_inner( ctx, total_sz );
204 0 : ctx->data = start_data;
205 0 : return err;
206 0 : }
207 :
208 0 : void fd_tower_sync_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
209 0 : fd_tower_sync_t * self = (fd_tower_sync_t *)struct_mem;
210 0 : self->has_root = 1;
211 0 : fd_bincode_uint64_decode_unsafe( &self->root, ctx );
212 0 : self->has_root = self->root != ULONG_MAX;
213 :
214 0 : ushort lockout_offsets_len;
215 0 : fd_bincode_compact_u16_decode_unsafe( &lockout_offsets_len, ctx );
216 0 : ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
217 0 : self->lockouts = deq_fd_vote_lockout_t_join_new( alloc_mem, lockout_offsets_max );
218 :
219 : /* NOTE: Agave does a a checked add on the sum of the root with all of the
220 : lockout offsets in their custom deserializer for tower sync votes. If the
221 : checked add is violated (this should never happen), the deocder will
222 : return NULL. */
223 :
224 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L1062-L1077
225 0 : ulong last_slot = ((self->root == ULONG_MAX) ? 0 : self->root);
226 0 : for( ulong i=0; i < lockout_offsets_len; i++ ) {
227 0 : fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( self->lockouts );
228 :
229 0 : fd_lockout_offset_t o;
230 0 : fd_lockout_offset_decode_inner( &o, alloc_mem, ctx );
231 :
232 0 : elem->slot = last_slot + o.offset;
233 0 : elem->confirmation_count = o.confirmation_count;
234 0 : last_slot = elem->slot;
235 0 : }
236 :
237 0 : fd_hash_decode_inner( &self->hash, alloc_mem, ctx );
238 0 : {
239 0 : uchar o;
240 0 : fd_bincode_bool_decode_unsafe( &o, ctx );
241 0 : self->has_timestamp = !!o;
242 0 : if( o ) {
243 0 : fd_bincode_int64_decode_unsafe( &self->timestamp, ctx );
244 0 : }
245 0 : }
246 0 : fd_hash_decode_inner( &self->block_id, alloc_mem, ctx );
247 0 : }
248 :
249 0 : void * fd_tower_sync_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) {
250 0 : fd_tower_sync_t * self = (fd_tower_sync_t *)mem;
251 0 : fd_tower_sync_new( self );
252 0 : void * alloc_region = (uchar *)mem + sizeof(fd_tower_sync_t);
253 0 : void * * alloc_mem = &alloc_region;
254 0 : fd_tower_sync_decode_inner( mem, alloc_mem, ctx );
255 0 : return self;
256 0 : }
257 :
258 0 : void fd_tower_sync_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
259 0 : FD_LOG_ERR(("TODO: Implement"));
260 0 : }
261 :
262 : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2374
263 : //
264 : // During the call to Duration::new(...), it normalizes the seconds and nanoseconds automatically. We need to
265 : // match this behavior correctly
266 : //
267 : void
268 0 : fd_rust_duration_normalize ( fd_rust_duration_t * self ) {
269 0 : if( self->nanoseconds < 1000000000U )
270 0 : return;
271 0 : uint secs = self->nanoseconds/1000000000U;
272 0 : self->seconds += secs;
273 0 : self->nanoseconds -= secs * 1000000000U;
274 0 : }
275 :
276 : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2203
277 : //
278 : // There is an overflow check at line 2373 that turns an overflow into an encoding error
279 : //
280 : int
281 0 : fd_rust_duration_footprint_validator ( fd_bincode_decode_ctx_t * ctx ) {
282 0 : fd_rust_duration_t *d = (fd_rust_duration_t *) ctx->data;
283 0 : if( d->nanoseconds < 1000000000U )
284 0 : return FD_BINCODE_SUCCESS;
285 0 : ulong out;
286 0 : if( __builtin_uaddl_overflow( d->seconds, d->nanoseconds/1000000000U, &out ) )
287 0 : return FD_BINCODE_ERR_ENCODING;
288 0 : return FD_BINCODE_SUCCESS;
289 0 : }
290 :
291 : int
292 0 : fd_gossip_duplicate_shred_validator ( fd_bincode_decode_ctx_t * ctx ) {
293 : // Temporarily disable this till we understand better
294 : #if 0
295 : fd_gossip_duplicate_shred_t *d = (fd_gossip_duplicate_shred_t *) ctx->data;
296 : if( FD_UNLIKELY( (d->_unused_shred_type != 0x5a) || (d->_unused_shred_type != 0xa5) ) )
297 : return FD_BINCODE_ERR_ENCODING;
298 : #else
299 0 : (void) ctx;
300 0 : #endif
301 0 : return FD_BINCODE_SUCCESS;
302 0 : }
303 :
304 0 : void fd_vote_accounts_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
305 0 : fd_vote_accounts_t * self = (fd_vote_accounts_t *)struct_mem;
306 0 : ulong vote_accounts_len;
307 0 : fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
308 0 : self->vote_accounts_pool = fd_vote_accounts_pair_t_map_join_new( alloc_mem, fd_ulong_max( vote_accounts_len, 50000 ) );
309 0 : self->vote_accounts_root = NULL;
310 0 : for( ulong i=0; i < vote_accounts_len; i++ ) {
311 0 : fd_vote_accounts_pair_t_mapnode_t * node = fd_vote_accounts_pair_t_map_acquire( self->vote_accounts_pool );
312 0 : fd_vote_accounts_pair_new( &node->elem );
313 0 : fd_vote_accounts_pair_decode_inner( &node->elem, alloc_mem, ctx );
314 : // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L323
315 : // throws an error and
316 0 : if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
317 : // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L429
318 : // causes the entry to not get added
319 0 : fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, node );
320 0 : } else {
321 0 : fd_vote_accounts_pair_t_mapnode_t * out = NULL;
322 0 : fd_vote_accounts_pair_t_map_insert_or_replace( self->vote_accounts_pool, &self->vote_accounts_root, node, &out );
323 0 : if( !!out ) {
324 0 : fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, out );
325 0 : }
326 0 : }
327 0 : }
328 0 : }
329 :
330 6 : void fd_vote_accounts_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
331 6 : fd_vote_accounts_global_t * self = (fd_vote_accounts_global_t *)struct_mem;
332 6 : ulong vote_accounts_len;
333 6 : fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
334 6 : *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, fd_vote_accounts_pair_global_t_map_align() );
335 6 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_pool = fd_vote_accounts_pair_global_t_map_join_new( alloc_mem, fd_ulong_max( vote_accounts_len, 50000 ) );
336 6 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = NULL;
337 6 : for( ulong i=0; i < vote_accounts_len; i++ ) {
338 0 : fd_vote_accounts_pair_global_t_mapnode_t * node = fd_vote_accounts_pair_global_t_map_acquire( vote_accounts_pool );
339 0 : fd_vote_accounts_pair_new( (fd_vote_accounts_pair_t *)fd_type_pun(&node->elem) );
340 0 : fd_vote_accounts_pair_decode_inner_global( &node->elem, alloc_mem, ctx );
341 0 : if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
342 0 : fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, node );
343 0 : } else {
344 0 : fd_vote_accounts_pair_global_t_mapnode_t * out = NULL;
345 0 : fd_vote_accounts_pair_global_t_map_insert_or_replace( vote_accounts_pool, &vote_accounts_root, node, &out );
346 0 : if( !!out ) {
347 0 : fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, out );
348 0 : }
349 0 : }
350 0 : }
351 6 : self->vote_accounts_pool_offset = (ulong)fd_vote_accounts_pair_global_t_map_leave( vote_accounts_pool ) - (ulong)struct_mem;
352 6 : self->vote_accounts_root_offset = (ulong)vote_accounts_root - (ulong)struct_mem;
353 6 : }
|