Line data Source code
1 : #include "fd_tower_serdes.h" 2 : #include "fd_tower.h" 3 : 4 : #define SHORTVEC 0 5 : 6 0 : #define DE( T, name ) do { \ 7 0 : if( FD_UNLIKELY( off+sizeof(T)>buf_sz ) ) return -1; \ 8 0 : serde->name = *(T const *)fd_type_pun_const( buf+off ); \ 9 0 : off += sizeof(T); \ 10 0 : } while(0) 11 : 12 0 : #define SER( T, name ) do { \ 13 0 : if( FD_UNLIKELY( off+sizeof(T)>buf_sz ) ) return -1; \ 14 0 : FD_STORE( T, buf+off, serde->name ); \ 15 0 : off += sizeof(T); \ 16 0 : } while(0) 17 : 18 : static ulong 19 0 : de_short_u16( ushort * dst, uchar const * src ) { 20 0 : if ( FD_LIKELY( !(0x80U & src[0]) ) ) { *dst = (ushort)src[0]; return 1; } 21 0 : else if( FD_LIKELY( !(0x80U & src[1]) ) ) { *dst = (ushort)((ulong)(src[0]&0x7FUL) + (((ulong)src[1])<<7)); return 2; } 22 0 : else { *dst = (ushort)((ulong)(src[0]&0x7FUL) + (((ulong)(src[1]&0x7FUL))<<7) + (((ulong)src[2])<<14)); return 3; } 23 0 : } 24 : 25 : static ulong 26 : de_var_int( ulong * dst, 27 : uchar const * src, 28 0 : ulong src_sz ) { 29 0 : *dst = 0; 30 0 : ulong off = 0; 31 0 : ulong bit = 0; 32 0 : while( FD_LIKELY( bit < 64 ) ) { 33 0 : if( FD_UNLIKELY( off >= src_sz ) ) return 0; 34 0 : uchar byte = *(uchar const *)(src+off); 35 0 : off += 1; 36 0 : *dst |= (byte & 0x7FUL) << bit; 37 0 : if( FD_LIKELY( (byte & 0x80U) == 0U ) ) { 38 0 : if( FD_UNLIKELY( (*dst>>bit) != byte ) ) return 0; 39 0 : if( FD_UNLIKELY( byte==0U && (bit!=0U || *dst!=0UL) ) ) return 0; 40 0 : return off; 41 0 : } 42 0 : bit += 7; 43 0 : } 44 0 : return 0; 45 0 : } 46 : 47 : static ulong 48 0 : ser_short_u16( uchar * dst, ushort val ) { 49 0 : if ( FD_LIKELY( val < 0x80U ) ) { 50 0 : dst[0] = (uchar)val; 51 0 : return 1; 52 0 : } 53 0 : else if( FD_LIKELY( val < 0x4000U ) ) { 54 0 : dst[0] = (uchar)((val & 0x7FUL) | 0x80U); 55 0 : dst[1] = (uchar)(val >> 7); 56 0 : return 2; 57 0 : } 58 0 : else { 59 0 : dst[0] = (uchar)((val & 0x7FUL) | 0x80U); 60 0 : dst[1] = (uchar)(((val >> 7) & 0x7FUL) | 0x80U); 61 0 : dst[2] = (uchar)(val >> 14); 62 0 : return 3; 63 0 : } 64 0 : } 65 : 66 : static ulong 67 0 : ser_var_int( uchar * dst, ulong val ) { 68 0 : ulong off = 0; 69 0 : while( FD_LIKELY( val >= 0x80UL ) ) { 70 0 : dst[off] = (uchar)((val & 0x7FUL) | 0x80U); 71 0 : val >>= 7; 72 0 : off += 1; 73 0 : } 74 0 : dst[off] = (uchar)val; 75 0 : return off + 1; 76 0 : } 77 : 78 : int 79 : fd_compact_tower_sync_de( fd_compact_tower_sync_serde_t * serde, 80 : uchar const * buf, 81 0 : ulong buf_sz ) { 82 0 : ulong off = 0; 83 0 : DE( ulong, root ); 84 0 : off += de_short_u16( &serde->lockouts_cnt, buf+off ); 85 0 : if( FD_UNLIKELY( serde->lockouts_cnt > FD_TOWER_VOTE_MAX ) ) return -1; 86 0 : for( ulong i = 0; i < serde->lockouts_cnt; i++ ) { 87 0 : ulong varint_sz = de_var_int( &serde->lockouts[i].offset, buf+off, buf_sz-off ); 88 0 : if( FD_UNLIKELY( !varint_sz ) ) return -1; 89 0 : off += varint_sz; 90 0 : DE( uchar, lockouts[i].confirmation_count ); 91 0 : } 92 0 : DE( fd_hash_t, hash ); 93 0 : DE( uchar, timestamp_option ); 94 0 : if( FD_LIKELY( serde->timestamp_option ) ) { 95 0 : DE( long, timestamp ); 96 0 : } 97 0 : DE( fd_hash_t, block_id ); 98 0 : return 0; 99 0 : } 100 : 101 : int 102 : fd_compact_tower_sync_ser( fd_compact_tower_sync_serde_t const * serde, 103 : uchar * buf, 104 : ulong buf_sz, 105 0 : ulong * out_sz ) { 106 0 : ulong off = 0; 107 0 : SER( ulong, root ); 108 0 : off += ser_short_u16( buf+off, serde->lockouts_cnt ); 109 0 : if( FD_UNLIKELY( serde->lockouts_cnt > FD_TOWER_VOTE_MAX ) ) return -1; 110 0 : for( ulong i = 0; i < serde->lockouts_cnt; i++ ) { 111 0 : off += ser_var_int( buf+off, serde->lockouts[i].offset ); 112 0 : SER( uchar, lockouts[i].confirmation_count ); 113 0 : } 114 0 : SER( fd_hash_t, hash ); 115 0 : SER( uchar, timestamp_option ); 116 0 : if( FD_LIKELY( serde->timestamp_option ) ) { 117 0 : SER( long, timestamp ); 118 0 : } 119 0 : SER( fd_hash_t, block_id ); 120 0 : if( FD_LIKELY( out_sz ) ) *out_sz = off; 121 0 : return 0; 122 0 : } 123 : 124 : static fd_vote_acc_vote_t const * 125 0 : v4_off( fd_vote_acc_t const * voter ) { 126 0 : return (fd_vote_acc_vote_t const *)( voter->v4.bls_pubkey_compressed + voter->v4.has_bls_pubkey_compressed * sizeof(voter->v4.bls_pubkey_compressed) + sizeof(ulong) ); 127 0 : } 128 : 129 : ulong 130 0 : fd_vote_acc_vote_cnt( uchar const * vote_account_data ) { 131 0 : fd_vote_acc_t const * voter = (fd_vote_acc_t const *)fd_type_pun_const( vote_account_data ); 132 0 : switch( voter->kind ) { 133 0 : case FD_VOTE_ACC_V4: return fd_ulong_load_8( voter->v4.bls_pubkey_compressed + voter->v4.has_bls_pubkey_compressed * sizeof(voter->v4.bls_pubkey_compressed) ); 134 0 : case FD_VOTE_ACC_V3: return voter->v3.votes_cnt; 135 0 : case FD_VOTE_ACC_V2: return voter->v2.votes_cnt; 136 0 : default: FD_LOG_HEXDUMP_CRIT(( "bad voter", vote_account_data, 3762 )); 137 0 : } 138 0 : } 139 : 140 : /* fd_vote_acc_vote_slot takes a voter's vote account data and returns the 141 : voter's most recent vote slot in the tower. Returns ULONG_MAX if 142 : they have an empty tower. */ 143 : 144 : ulong 145 0 : fd_vote_acc_vote_slot( uchar const * vote_account_data ) { 146 0 : fd_vote_acc_t const * voter = (fd_vote_acc_t const *)fd_type_pun_const( vote_account_data ); 147 0 : ulong cnt = fd_vote_acc_vote_cnt( vote_account_data ); 148 0 : switch( voter->kind ) { 149 0 : case FD_VOTE_ACC_V4: return cnt ? v4_off( voter )[cnt-1].slot : ULONG_MAX; 150 0 : case FD_VOTE_ACC_V3: return cnt ? voter->v3.votes[cnt-1].slot : ULONG_MAX; 151 0 : case FD_VOTE_ACC_V2: return cnt ? voter->v2.votes[cnt-1].slot : ULONG_MAX; 152 0 : default: FD_LOG_HEXDUMP_CRIT(( "bad voter", vote_account_data, 3762 )); 153 0 : } 154 0 : } 155 : 156 : /* fd_vote_acc_root_slot takes a voter's vote account data and returns the 157 : voter's root slot. Returns ULONG_MAX if they don't have a root. */ 158 : 159 : ulong 160 0 : fd_vote_acc_root_slot( uchar const * vote_account_data ) { 161 0 : fd_vote_acc_t const * voter = (fd_vote_acc_t const *)fd_type_pun_const( vote_account_data ); 162 0 : ulong cnt = fd_vote_acc_vote_cnt( vote_account_data ); 163 0 : switch( voter->kind ) { 164 0 : case FD_VOTE_ACC_V4: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&v4_off( voter )[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&v4_off( voter )[cnt] + 1UL ) : ULONG_MAX; } 165 0 : case FD_VOTE_ACC_V3: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&voter->v3.votes[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&voter->v3.votes[cnt] + 1UL ) : ULONG_MAX; } 166 0 : case FD_VOTE_ACC_V2: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&voter->v2.votes[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&voter->v2.votes[cnt] + 1UL ) : ULONG_MAX; } 167 0 : default: FD_LOG_CRIT(( "unhandled kind %u", voter->kind )); 168 0 : } 169 0 : } 170 : 171 : int 172 : fd_txn_parse_simple_vote( fd_txn_t const * txn, 173 : uchar const * payload, 174 : fd_pubkey_t * opt_identity, 175 : fd_pubkey_t * opt_vote_acct, 176 0 : ulong * opt_vote_slot ) { 177 0 : fd_txn_instr_t const * instr = &txn->instr[ 0 ]; 178 0 : ulong required_accts = txn->signature_cnt==1 ? 2UL : 3UL; 179 0 : if( FD_UNLIKELY( !fd_txn_is_simple_vote_transaction( txn, payload ) || instr->data_sz < sizeof(uint) || txn->acct_addr_cnt < required_accts ) ) return 0; 180 : 181 0 : uchar const * instr_data = payload + instr->data_off; 182 0 : uint kind = fd_uint_load_4_fast( instr_data ); 183 : /* Older vote instruction kinds are deprecated / ignored */ 184 0 : if( FD_UNLIKELY( kind == FD_VOTE_IX_KIND_TOWER_SYNC || kind == FD_VOTE_IX_KIND_TOWER_SYNC_SWITCH ) ) { 185 0 : fd_compact_tower_sync_serde_t compact_tower_sync_serde[ 1 ]; 186 0 : int err = fd_compact_tower_sync_de( compact_tower_sync_serde, instr_data + sizeof(uint), instr->data_sz - sizeof(uint) ); 187 0 : if( FD_LIKELY( !err ) ) { 188 0 : if( !!opt_vote_slot ) { 189 0 : *opt_vote_slot = compact_tower_sync_serde->root; 190 0 : for( ulong i = 0; i < compact_tower_sync_serde->lockouts_cnt; i++ ) *opt_vote_slot += compact_tower_sync_serde->lockouts[ i ].offset; 191 0 : } 192 0 : fd_pubkey_t const * accs = (fd_pubkey_t const *)fd_type_pun_const( payload + txn->acct_addr_off ); 193 0 : if( !!opt_vote_acct ) { 194 0 : if( FD_UNLIKELY( txn->signature_cnt==1 ) ) *opt_vote_acct = *(fd_pubkey_t const *)fd_type_pun_const( &accs[ 1 ] ); /* identity and authority same, account idx 1 is the vote account address */ 195 0 : else *opt_vote_acct = *(fd_pubkey_t const *)fd_type_pun_const( &accs[ 2 ] ); /* identity and authority diff, account idx 2 is the vote account address */ 196 0 : } 197 0 : if( !!opt_identity ) { 198 0 : *opt_identity = *(fd_pubkey_t const *)fd_type_pun_const( &accs[ 0 ] ); 199 0 : } 200 0 : return 1; 201 0 : } 202 0 : } 203 0 : return 0; 204 0 : }