Line data Source code
1 : #include "fd_types_custom.h" 2 : #include "fd_bincode.h" 3 : #include "fd_types.h" 4 : #ifndef SOURCE_fd_src_flamenco_types_fd_types_c 5 : #error "fd_types_custom.c is part of the fd_types.c compile uint" 6 : #endif /* !SOURCE_fd_src_flamenco_types_fd_types_c */ 7 : 8 : #include <stdio.h> 9 : 10 0 : int fd_tower_sync_encode( fd_tower_sync_t const * self, fd_bincode_encode_ctx_t * ctx ) { 11 0 : FD_LOG_ERR(( "todo")); 12 0 : } 13 : 14 : static void fd_hash_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ); 15 : static int fd_hash_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); 16 : static void fd_lockout_offset_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ); 17 : static int fd_lockout_offset_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); 18 : 19 0 : int fd_tower_sync_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { 20 : /* This is a modified version of fd_compact_tower_sync_decode_footprint_inner() */ 21 0 : int err = 0; 22 0 : if( FD_UNLIKELY( ctx->data>ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 23 0 : err = fd_bincode_uint64_decode_footprint( ctx ); 24 : 25 : /* The first modification is that we want to grab the value fo the root. */ 26 0 : ulong root = 0UL; 27 0 : fd_bincode_decode_ctx_t root_ctx = { .data = (uchar*)ctx->data - sizeof(ulong), .dataend = ctx->data }; 28 0 : if( FD_UNLIKELY( ((ulong)ctx->data)+sizeof(ulong)>(ulong)ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 29 0 : fd_bincode_uint64_decode_unsafe( &root, &root_ctx ); 30 0 : root = root != ULONG_MAX ? root : 0UL; 31 : /* Done with first modification */ 32 : 33 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; 34 0 : ushort lockout_offsets_len; 35 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 36 0 : err = fd_bincode_compact_u16_decode( &lockout_offsets_len, ctx ); 37 : 38 0 : if( FD_UNLIKELY( err ) ) return err; 39 0 : ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 ); 40 0 : *total_sz += deq_fd_lockout_offset_t_align() + deq_fd_lockout_offset_t_footprint( lockout_offsets_max ); 41 : 42 0 : for( ulong i = 0; i < lockout_offsets_len; ++i ) { 43 : 44 0 : uchar const * start_data = ctx->data; 45 0 : err = fd_lockout_offset_decode_footprint_inner( ctx, total_sz ); 46 0 : if( FD_UNLIKELY( err ) ) return err; 47 : 48 : /* The second modification is that we want to grab the lockout offset from 49 : the deque to make sure that we can do a checked add successfully. */ 50 0 : fd_lockout_offset_t lockout_offset = {0}; 51 0 : fd_bincode_decode_ctx_t lockout_ctx = { .data = start_data, .dataend = start_data+sizeof(fd_lockout_offset_t) }; 52 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 53 0 : fd_lockout_offset_decode_inner( &lockout_offset, NULL, &lockout_ctx ); 54 0 : err = __builtin_uaddl_overflow( root, lockout_offset.offset, &root ); 55 0 : if( FD_UNLIKELY( err ) ) { 56 0 : return err; 57 0 : } 58 : /* Done with second modification. */ 59 0 : } 60 : 61 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 62 0 : err = fd_hash_decode_footprint_inner( ctx, total_sz ); 63 0 : if( FD_UNLIKELY( err ) ) return err; 64 0 : { 65 0 : uchar o; 66 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 67 0 : err = fd_bincode_bool_decode( &o, ctx ); 68 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; 69 0 : if( o ) { 70 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 71 0 : err = fd_bincode_int64_decode_footprint( ctx ); 72 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; 73 0 : } 74 0 : } 75 0 : if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; } 76 0 : err = fd_hash_decode_footprint_inner( ctx, total_sz ); 77 0 : if( FD_UNLIKELY( err ) ) return err; 78 0 : return 0; 79 0 : } 80 : 81 0 : int fd_tower_sync_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { 82 0 : *total_sz += sizeof(fd_tower_sync_t); 83 0 : void const * start_data = ctx->data; 84 0 : int err = fd_tower_sync_decode_footprint_inner( ctx, total_sz ); 85 0 : ctx->data = start_data; 86 0 : return err; 87 0 : } 88 : 89 0 : void fd_tower_sync_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { 90 0 : fd_tower_sync_t * self = (fd_tower_sync_t *)struct_mem; 91 0 : self->has_root = 1; 92 0 : fd_bincode_uint64_decode_unsafe( &self->root, ctx ); 93 0 : self->has_root = self->root != ULONG_MAX; 94 : 95 0 : ushort lockout_offsets_len; 96 0 : fd_bincode_compact_u16_decode_unsafe( &lockout_offsets_len, ctx ); 97 0 : ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 ); 98 0 : self->lockouts = deq_fd_vote_lockout_t_join_new( alloc_mem, lockout_offsets_max ); 99 : 100 : /* NOTE: Agave does a a checked add on the sum of the root with all of the 101 : lockout offsets in their custom deserializer for tower sync votes. If the 102 : checked add is violated (this should never happen), the deocder will 103 : return NULL. */ 104 : 105 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L1062-L1077 106 0 : ulong last_slot = ((self->root == ULONG_MAX) ? 0 : self->root); 107 0 : for( ulong i=0; i < lockout_offsets_len; i++ ) { 108 0 : fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( self->lockouts ); 109 : 110 0 : fd_lockout_offset_t o; 111 0 : fd_lockout_offset_decode_inner( &o, alloc_mem, ctx ); 112 : 113 0 : elem->slot = last_slot + o.offset; 114 0 : elem->confirmation_count = o.confirmation_count; 115 0 : last_slot = elem->slot; 116 0 : } 117 : 118 0 : fd_hash_decode_inner( &self->hash, alloc_mem, ctx ); 119 0 : { 120 0 : uchar o; 121 0 : fd_bincode_bool_decode_unsafe( &o, ctx ); 122 0 : self->has_timestamp = !!o; 123 0 : if( o ) { 124 0 : fd_bincode_int64_decode_unsafe( &self->timestamp, ctx ); 125 0 : } 126 0 : } 127 0 : fd_hash_decode_inner( &self->block_id, alloc_mem, ctx ); 128 0 : } 129 : 130 0 : void * fd_tower_sync_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) { 131 0 : fd_tower_sync_t * self = (fd_tower_sync_t *)mem; 132 0 : fd_tower_sync_new( self ); 133 0 : void * alloc_region = (uchar *)mem + sizeof(fd_tower_sync_t); 134 0 : void * * alloc_mem = &alloc_region; 135 0 : fd_tower_sync_decode_inner( mem, alloc_mem, ctx ); 136 0 : return self; 137 0 : } 138 : 139 : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2374 140 : // 141 : // During the call to Duration::new(...), it normalizes the seconds and nanoseconds automatically. We need to 142 : // match this behavior correctly 143 : // 144 : void 145 0 : fd_rust_duration_normalize ( fd_rust_duration_t * self ) { 146 0 : if( self->nanoseconds < 1000000000U ) 147 0 : return; 148 0 : uint secs = self->nanoseconds/1000000000U; 149 0 : self->seconds += secs; 150 0 : self->nanoseconds -= secs * 1000000000U; 151 0 : } 152 : 153 : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2203 154 : // 155 : // There is an overflow check at line 2373 that turns an overflow into an encoding error 156 : // 157 : int 158 0 : fd_rust_duration_footprint_validator ( fd_bincode_decode_ctx_t * ctx ) { 159 0 : if( (ulong)ctx->data + ( sizeof(ulong) + sizeof(uint) ) > (ulong)ctx->dataend ) 160 0 : return FD_BINCODE_ERR_OVERFLOW; 161 : 162 0 : ulong seconds = FD_LOAD( ulong, ctx->data ); 163 0 : uint nanoseconds = FD_LOAD( uint, (uchar*)ctx->data + sizeof(ulong) ); 164 : 165 0 : if( nanoseconds < 1000000000U ) 166 0 : return FD_BINCODE_SUCCESS; 167 0 : ulong out; 168 0 : if( __builtin_uaddl_overflow( seconds, nanoseconds/1000000000U, &out ) ) 169 0 : return FD_BINCODE_ERR_ENCODING; 170 0 : return FD_BINCODE_SUCCESS; 171 0 : }