Line data Source code
1 : #ifndef HEADER_fd_src_ballet_txn_fd_compact_u16_h 2 : #define HEADER_fd_src_ballet_txn_fd_compact_u16_h 3 : 4 : /* This file declares some utility methods for decoding compact-u16, a variable 5 : length encoding format for unsigned 16 bit numbers that Solana transactions 6 : use in the wireline format. 7 : The format is documented at 8 : https://docs.solana.com/developing/programming-model/transactions#compact-u16-format 9 : but briefly: 10 : If the 16 bit number has (big endian bits) ponmlkji hgfedcba 11 : [ 0x00, 0x80) (implies [h..p] = 0) -> 0gfedcba (1 byte ) 12 : [ 0x80, 0x4000) (implies [o..p] = 0) -> 1gfedcba 0nmlkjih (2 bytes) 13 : [0x4000, 0x10000) -> 1gfedcba 1nmlkjih 000000po (3 bytes) 14 : Numbers must be encoded with the minimal number of bytes possible. 15 : 16 : This encoding format is filled with sadness, some of which this API 17 : reflects. To limit the sadness, this header is for internal use in fd_txn 18 : and not exported more widely. */ 19 : 20 : #include "../fd_ballet_base.h" 21 : 22 : 23 : FD_PROTOTYPES_BEGIN 24 : /* fd_cu16_dec_fixed: Reads a compact-u16 whose width is known. High 25 : performance API that does no error checking, and as such, it's designed to 26 : be used with fd_cu16_dec_sz, which performs all necessary validation to 27 : ensure this is safe. buf points to the first byte of the encoded value. 28 : sz in {1, 2, 3}. Reads exactly sz bytes. */ 29 : static inline ushort 30 : fd_cu16_dec_fixed( uchar const * buf, 31 10603858062 : ulong sz ) { 32 : /* Branch-free hardware friendly format that is slower on a CPU. If you 33 : switch to this version, be sure to update the documentation to note that 34 : it reads more than sz bytes. */ 35 : /* 36 : ulong w = (ulong)*(uint *)buf; 37 : ulong b0 = (w & 0x00007FUL); 38 : ulong b1 = (w & 0x007F00UL)>>1UL; 39 : ulong b2 = (w & 0xFF0000UL)>>2UL; 40 : ulong m0 = (ulong)(((long)(1UL-sz))>>63); *//* Maps [0,1] to 0; [2,3] to 0xFF..FF */ 41 : /* ulong m01 = (ulong)(((long)(2UL-sz))>>63); *//* Maps [0,2] to 0; [3,3] to 0xFF..FF */ 42 : /* return (ushort)((b0) | (b1 & m0) | (b2 & m01)); */ 43 : 44 : /* This version is actually substantially faster */ 45 : #if FD_TXN_HANDHOLDING 46 : FD_TEST( (1<=sz) & (sz<=3) ) 47 : #endif 48 10603858062 : if( FD_LIKELY( sz==1 ) ) 49 7357358433 : return (ushort)buf[0]; 50 3246499629 : if( FD_LIKELY( sz==2 ) ) 51 3208603425 : return (ushort)((ulong)(buf[0]&0x7F) + (((ulong)buf[1])<<7)); 52 37896204 : return (ushort)((ulong)(buf[0]&0x7F) + (((ulong)buf[1]&0x7F)<<7) + (((ulong)buf[2])<<14)); 53 3246499629 : } 54 : 55 : /*fd_cu16_dec_sz: Returns the number of bytes in the compact-u16. Also 56 : validates that it is a legally-encoded compact-u16 and that it is stored in 57 : no more than bytes_avail bytes. buf points to the first byte of the encoded 58 : value. Result will be in {0, 1, 2, 3}, where 0 indicates validation failed 59 : (not enough bytes avail, illegal encoding, or number is larger than a u16).*/ 60 : static inline ulong 61 : fd_cu16_dec_sz( uchar const * buf, 62 13825094706 : ulong bytes_avail ) { 63 13825094706 : if( FD_LIKELY( bytes_avail>=1 && !(0x80UL & buf[0]) ) ) { 64 7357358433 : return 1UL; 65 7357358433 : } 66 6467736273 : if( FD_LIKELY( bytes_avail>=2 && !(0x80UL & buf[1]) ) ) { 67 3233867946 : if( FD_UNLIKELY( !buf[1] ) ) return 0UL; /* Detect non-minimal encoding */ 68 3208603425 : return 2UL; 69 3233867946 : } 70 3233868327 : if( FD_LIKELY( bytes_avail>=3 && !(0xFCUL & buf[2]) ) ) { 71 50528268 : if( FD_UNLIKELY( !buf[2] ) ) return 0UL; /* Detect non-minimal encoding */ 72 37896204 : return 3UL; 73 50528268 : } 74 3183340059 : return 0UL; 75 3233868327 : } 76 : 77 : /* fd_cu16_dec: Reads a compact-u16. buf points to the first byte of the 78 : encoded value. Validates that the compact-u16 is legally encoded, and 79 : returns 0 to indicate that validation failed. If the compact-u16 is valid, 80 : the decoded value is stored in the location pointed to by result_out. On 81 : success, returns the length of the encoded compact-u16. */ 82 : static inline ulong 83 : fd_cu16_dec( uchar const * buf, 84 : ulong bytes_avail, 85 12935430915 : ushort * result_out ) { 86 12935430915 : ulong sz = fd_cu16_dec_sz( buf, bytes_avail ); 87 12935430915 : if( sz ) *result_out = fd_cu16_dec_fixed( buf, sz ); 88 12935430915 : return sz; 89 12935430915 : } 90 : 91 : static inline uint 92 198147 : fd_cu16_enc( ushort val, uchar * out ) { 93 198147 : ulong v = (ulong)val; 94 198147 : ulong byte0 = (v )&0x7FUL; 95 198147 : ulong byte1 = (v>> 7)&0x7FUL; 96 198147 : ulong byte2 = (v>>14); 97 198147 : int needs_byte1 = (v>0x007FUL); 98 198147 : int needs_byte2 = (v>0x3FFFUL); 99 198147 : fd_uchar_store_if( 1, out + 0, (uchar)(byte0 | ((ulong)needs_byte1<<7)) ); 100 198147 : fd_uchar_store_if( needs_byte1, out + 1, (uchar)(byte1 | ((ulong)needs_byte2<<7)) ); 101 198147 : fd_uchar_store_if( needs_byte2, out + 2, (uchar)(byte2 ) ); 102 198147 : return (uint)(1+needs_byte1+needs_byte2); 103 198147 : } 104 : 105 : FD_PROTOTYPES_END 106 : #endif /* HEADER_fd_src_ballet_txn_fd_compact_u16_h */