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 : uint level,
95 93 : uint varint ) {
96 93 : (void) varint;
97 :
98 93 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip4_addr", level++, 0 );
99 93 : uchar * octet = (uchar *)self;
100 465 : for( uchar i = 0; i < 4; ++i ) {
101 372 : fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level, 0 );
102 372 : }
103 93 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip4_addr", level--, 0 );
104 : /* TODO: Add support for optional pretty-printing like serde?
105 : Saving this in the meantime */
106 : // char buf[ 16 ];
107 : // sprintf( buf, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( *self ) );
108 : // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip4_addr", level );
109 93 : }
110 :
111 : void
112 : fd_gossip_ip6_addr_walk( void * w,
113 : fd_gossip_ip6_addr_t const * self,
114 : fd_types_walk_fn_t fun,
115 : char const * name,
116 : uint level,
117 0 : uint varint ) {
118 0 : (void) varint;
119 :
120 0 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip6_addr", level++, 0 );
121 0 : uchar * octet = (uchar *)self;
122 0 : for( uchar i = 0; i < 16; ++i ) {
123 0 : fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level, 0 );
124 0 : }
125 0 : fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip6_addr", level--, 0 );
126 : /* Saving this for when we support configurable pretty-printing mode */
127 : // char buf[ 40 ];
128 : // sprintf( buf,
129 : // "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
130 : // FD_LOG_HEX16_FMT_ARGS( self->us ) );
131 : // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip6_addr", level );
132 0 : }
133 :
134 0 : int fd_tower_sync_encode( fd_tower_sync_t const * self, fd_bincode_encode_ctx_t * ctx ) {
135 0 : FD_LOG_ERR(( "todo"));
136 0 : }
137 :
138 : static void fd_hash_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
139 : static int fd_hash_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
140 : static void fd_lockout_offset_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
141 : static int fd_lockout_offset_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
142 :
143 0 : int fd_tower_sync_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
144 : /* This is a modified version of fd_compact_tower_sync_decode_footprint_inner() */
145 0 : int err = 0;
146 0 : if( FD_UNLIKELY( ctx->data>ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
147 0 : err = fd_bincode_uint64_decode_footprint( ctx );
148 :
149 : /* The first modification is that we want to grab the value fo the root. */
150 0 : ulong root = 0UL;
151 0 : fd_bincode_decode_ctx_t root_ctx = { .data = (uchar*)ctx->data - sizeof(ulong), .dataend = ctx->data };
152 0 : if( FD_UNLIKELY( ((ulong)ctx->data)+sizeof(ulong)>(ulong)ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
153 0 : fd_bincode_uint64_decode_unsafe( &root, &root_ctx );
154 0 : root = root != ULONG_MAX ? root : 0UL;
155 : /* Done with first modification */
156 :
157 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
158 0 : ushort lockout_offsets_len;
159 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
160 0 : err = fd_bincode_compact_u16_decode( &lockout_offsets_len, ctx );
161 :
162 0 : if( FD_UNLIKELY( err ) ) return err;
163 0 : ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
164 0 : *total_sz += deq_fd_lockout_offset_t_align() + deq_fd_lockout_offset_t_footprint( lockout_offsets_max );
165 :
166 0 : for( ulong i = 0; i < lockout_offsets_len; ++i ) {
167 :
168 0 : uchar const * start_data = ctx->data;
169 0 : err = fd_lockout_offset_decode_footprint_inner( ctx, total_sz );
170 0 : if( FD_UNLIKELY( err ) ) return err;
171 :
172 : /* The second modification is that we want to grab the lockout offset from
173 : the deque to make sure that we can do a checked add successfully. */
174 0 : fd_lockout_offset_t lockout_offset = {0};
175 0 : fd_bincode_decode_ctx_t lockout_ctx = { .data = start_data, .dataend = start_data+sizeof(fd_lockout_offset_t) };
176 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
177 0 : fd_lockout_offset_decode_inner( &lockout_offset, NULL, &lockout_ctx );
178 0 : err = __builtin_uaddl_overflow( root, lockout_offset.offset, &root );
179 0 : if( FD_UNLIKELY( err ) ) {
180 0 : return err;
181 0 : }
182 : /* Done with second modification. */
183 0 : }
184 :
185 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
186 0 : err = fd_hash_decode_footprint_inner( ctx, total_sz );
187 0 : if( FD_UNLIKELY( err ) ) return err;
188 0 : {
189 0 : uchar o;
190 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
191 0 : err = fd_bincode_bool_decode( &o, ctx );
192 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
193 0 : if( o ) {
194 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
195 0 : err = fd_bincode_int64_decode_footprint( ctx );
196 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
197 0 : }
198 0 : }
199 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
200 0 : err = fd_hash_decode_footprint_inner( ctx, total_sz );
201 0 : if( FD_UNLIKELY( err ) ) return err;
202 0 : return 0;
203 0 : }
204 :
205 0 : int fd_tower_sync_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
206 0 : *total_sz += sizeof(fd_tower_sync_t);
207 0 : void const * start_data = ctx->data;
208 0 : int err = fd_tower_sync_decode_footprint_inner( ctx, total_sz );
209 0 : ctx->data = start_data;
210 0 : return err;
211 0 : }
212 :
213 0 : void fd_tower_sync_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
214 0 : fd_tower_sync_t * self = (fd_tower_sync_t *)struct_mem;
215 0 : self->has_root = 1;
216 0 : fd_bincode_uint64_decode_unsafe( &self->root, ctx );
217 0 : self->has_root = self->root != ULONG_MAX;
218 :
219 0 : ushort lockout_offsets_len;
220 0 : fd_bincode_compact_u16_decode_unsafe( &lockout_offsets_len, ctx );
221 0 : ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
222 0 : self->lockouts = deq_fd_vote_lockout_t_join_new( alloc_mem, lockout_offsets_max );
223 :
224 : /* NOTE: Agave does a a checked add on the sum of the root with all of the
225 : lockout offsets in their custom deserializer for tower sync votes. If the
226 : checked add is violated (this should never happen), the deocder will
227 : return NULL. */
228 :
229 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L1062-L1077
230 0 : ulong last_slot = ((self->root == ULONG_MAX) ? 0 : self->root);
231 0 : for( ulong i=0; i < lockout_offsets_len; i++ ) {
232 0 : fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( self->lockouts );
233 :
234 0 : fd_lockout_offset_t o;
235 0 : fd_lockout_offset_decode_inner( &o, alloc_mem, ctx );
236 :
237 0 : elem->slot = last_slot + o.offset;
238 0 : elem->confirmation_count = o.confirmation_count;
239 0 : last_slot = elem->slot;
240 0 : }
241 :
242 0 : fd_hash_decode_inner( &self->hash, alloc_mem, ctx );
243 0 : {
244 0 : uchar o;
245 0 : fd_bincode_bool_decode_unsafe( &o, ctx );
246 0 : self->has_timestamp = !!o;
247 0 : if( o ) {
248 0 : fd_bincode_int64_decode_unsafe( &self->timestamp, ctx );
249 0 : }
250 0 : }
251 0 : fd_hash_decode_inner( &self->block_id, alloc_mem, ctx );
252 0 : }
253 :
254 0 : void * fd_tower_sync_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) {
255 0 : fd_tower_sync_t * self = (fd_tower_sync_t *)mem;
256 0 : fd_tower_sync_new( self );
257 0 : void * alloc_region = (uchar *)mem + sizeof(fd_tower_sync_t);
258 0 : void * * alloc_mem = &alloc_region;
259 0 : fd_tower_sync_decode_inner( mem, alloc_mem, ctx );
260 0 : return self;
261 0 : }
262 :
263 0 : void fd_tower_sync_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
264 0 : FD_LOG_ERR(("TODO: Implement"));
265 0 : }
266 :
267 : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2374
268 : //
269 : // During the call to Duration::new(...), it normalizes the seconds and nanoseconds automatically. We need to
270 : // match this behavior correctly
271 : //
272 : void
273 0 : fd_rust_duration_normalize ( fd_rust_duration_t * self ) {
274 0 : if( self->nanoseconds < 1000000000U )
275 0 : return;
276 0 : uint secs = self->nanoseconds/1000000000U;
277 0 : self->seconds += secs;
278 0 : self->nanoseconds -= secs * 1000000000U;
279 0 : }
280 :
281 : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2203
282 : //
283 : // There is an overflow check at line 2373 that turns an overflow into an encoding error
284 : //
285 : int
286 0 : fd_rust_duration_footprint_validator ( fd_bincode_decode_ctx_t * ctx ) {
287 0 : fd_rust_duration_t *d = (fd_rust_duration_t *) ctx->data;
288 0 : if( d->nanoseconds < 1000000000U )
289 0 : return FD_BINCODE_SUCCESS;
290 0 : ulong out;
291 0 : if( __builtin_uaddl_overflow( d->seconds, d->nanoseconds/1000000000U, &out ) )
292 0 : return FD_BINCODE_ERR_ENCODING;
293 0 : return FD_BINCODE_SUCCESS;
294 0 : }
295 :
296 0 : void fd_vote_accounts_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
297 0 : fd_vote_accounts_t * self = (fd_vote_accounts_t *)struct_mem;
298 0 : ulong vote_accounts_len;
299 0 : fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
300 0 : self->vote_accounts_pool = fd_vote_accounts_pair_t_map_join_new( alloc_mem, fd_ulong_max( vote_accounts_len, 50000 ) );
301 0 : self->vote_accounts_root = NULL;
302 0 : for( ulong i=0; i < vote_accounts_len; i++ ) {
303 0 : fd_vote_accounts_pair_t_mapnode_t * node = fd_vote_accounts_pair_t_map_acquire( self->vote_accounts_pool );
304 0 : fd_vote_accounts_pair_new( &node->elem );
305 0 : fd_vote_accounts_pair_decode_inner( &node->elem, alloc_mem, ctx );
306 : // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L323
307 : // throws an error and
308 0 : if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
309 : // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L429
310 : // causes the entry to not get added
311 0 : fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, node );
312 0 : } else {
313 0 : fd_vote_accounts_pair_t_mapnode_t * out = NULL;
314 0 : fd_vote_accounts_pair_t_map_insert_or_replace( self->vote_accounts_pool, &self->vote_accounts_root, node, &out );
315 0 : if( !!out ) {
316 0 : fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, out );
317 0 : }
318 0 : }
319 0 : }
320 0 : }
321 :
322 6 : void fd_vote_accounts_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
323 6 : fd_vote_accounts_global_t * self = (fd_vote_accounts_global_t *)struct_mem;
324 6 : ulong vote_accounts_len;
325 6 : fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
326 6 : *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, fd_vote_accounts_pair_global_t_map_align() );
327 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 ) );
328 6 : fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = NULL;
329 6 : for( ulong i=0; i < vote_accounts_len; i++ ) {
330 0 : fd_vote_accounts_pair_global_t_mapnode_t * node = fd_vote_accounts_pair_global_t_map_acquire( vote_accounts_pool );
331 0 : fd_vote_accounts_pair_new( (fd_vote_accounts_pair_t *)fd_type_pun(&node->elem) );
332 0 : fd_vote_accounts_pair_decode_inner_global( &node->elem, alloc_mem, ctx );
333 0 : if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
334 0 : fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, node );
335 0 : } else {
336 0 : fd_vote_accounts_pair_global_t_mapnode_t * out = NULL;
337 0 : fd_vote_accounts_pair_global_t_map_insert_or_replace( vote_accounts_pool, &vote_accounts_root, node, &out );
338 0 : if( !!out ) {
339 0 : fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, out );
340 0 : }
341 0 : }
342 0 : }
343 6 : self->vote_accounts_pool_offset = (ulong)fd_vote_accounts_pair_global_t_map_leave( vote_accounts_pool ) - (ulong)struct_mem;
344 6 : self->vote_accounts_root_offset = (ulong)vote_accounts_root - (ulong)struct_mem;
345 6 : }
|