Line data Source code
1 : #include "fd_vote_history_serde.h" 2 : 3 : #include "../../ballet/ed25519/fd_ed25519.h" 4 : 5 : void 6 : fd_vote_history_ser( uchar const identity[ static 32 ], 7 : ulong root, 8 0 : uchar buf[ static FD_VOTE_HISTORY_SER_SZ ] ) { 9 0 : FD_STORE( uint, buf, FD_VOTE_HISTORY_SERDE_KIND ); 10 0 : FD_STORE( ulong, buf+FD_VOTE_HISTORY_SERDE_SIG_OFF+64UL, FD_VOTE_HISTORY_SER_SZ-FD_VOTE_HISTORY_SERDE_DATA_OFF ); 11 0 : memcpy( buf+FD_VOTE_HISTORY_SERDE_DATA_OFF, identity, 32UL ); 12 0 : memset( buf+FD_VOTE_HISTORY_SERDE_DATA_OFF+32UL, 0, 9UL*8UL ); 13 0 : FD_STORE( ulong, buf+FD_VOTE_HISTORY_SER_SZ-8UL, root ); 14 0 : } 15 : 16 0 : #define LOAD( T, dst ) do { \ 17 0 : if( FD_UNLIKELY( sizeof(T)>buf_sz-off ) ) return FD_VOTE_HISTORY_DE_ERR_SIZE; \ 18 0 : (dst) = FD_LOAD( T, buf+off ); \ 19 0 : off += sizeof(T); \ 20 0 : } while(0) 21 : 22 : /* LOAD_LEN loads a u64 sequence length of elements at least min_sz 23 : bytes each, rejecting lengths the rest of the buffer cannot hold. */ 24 0 : #define LOAD_LEN( dst, min_sz ) do { \ 25 0 : LOAD( ulong, dst ); \ 26 0 : if( FD_UNLIKELY( (dst)>(buf_sz-off)/(min_sz) ) ) return FD_VOTE_HISTORY_DE_ERR_SIZE; \ 27 0 : } while(0) 28 : 29 0 : #define SKIP( sz ) do { \ 30 0 : if( FD_UNLIKELY( (sz)>buf_sz-off ) ) return FD_VOTE_HISTORY_DE_ERR_SIZE; \ 31 0 : off += (sz); \ 32 0 : } while(0) 33 : 34 : /* LOAD_VOTE loads a slot voted in and folds it into max_vote. */ 35 0 : #define LOAD_VOTE( dst ) do { \ 36 0 : LOAD( ulong, dst ); \ 37 0 : max_vote = fd_ulong_max( max_vote, (dst) ); \ 38 0 : } while(0) 39 : 40 0 : #define LOAD_VOTES() do { \ 41 0 : ulong n_; LOAD_LEN( n_, 8UL ); \ 42 0 : for( ulong i_=0UL; i_<n_; i_++ ) { ulong s_; LOAD_VOTE( s_ ); } \ 43 0 : } while(0) 44 : 45 : int 46 : fd_vote_history_de( uchar const * buf, 47 : ulong buf_sz, 48 : uchar const identity[ static 32 ], 49 0 : ulong * wait_to_vote_slot ) { 50 0 : ulong off = 0UL; 51 : 52 0 : uint kind; LOAD( uint, kind ); 53 0 : if( FD_UNLIKELY( kind!=FD_VOTE_HISTORY_SERDE_KIND ) ) return FD_VOTE_HISTORY_DE_ERR_VERSION; 54 : 55 0 : if( FD_UNLIKELY( buf_sz<FD_VOTE_HISTORY_SERDE_DATA_OFF ) ) return FD_VOTE_HISTORY_DE_ERR_SIZE; 56 0 : uchar const * sig = buf+FD_VOTE_HISTORY_SERDE_SIG_OFF; 57 0 : off = FD_VOTE_HISTORY_SERDE_SIG_OFF+64UL; 58 0 : ulong data_sz; LOAD( ulong, data_sz ); 59 0 : if( FD_UNLIKELY( data_sz>buf_sz-FD_VOTE_HISTORY_SERDE_DATA_OFF ) ) return FD_VOTE_HISTORY_DE_ERR_SIZE; 60 0 : if( FD_UNLIKELY( data_sz>FD_VOTE_HISTORY_DE_MAX-FD_VOTE_HISTORY_SERDE_DATA_OFF ) ) return FD_VOTE_HISTORY_DE_ERR_SIZE; 61 0 : buf_sz = FD_VOTE_HISTORY_SERDE_DATA_OFF+data_sz; /* bytes after the history are ignored, as Agave does */ 62 : 63 0 : fd_sha512_t sha[ 1 ]; 64 0 : if( FD_UNLIKELY( FD_ED25519_SUCCESS!=fd_ed25519_verify( buf+FD_VOTE_HISTORY_SERDE_DATA_OFF, data_sz, sig, identity, sha ) ) ) return FD_VOTE_HISTORY_DE_ERR_SIG; 65 : 66 0 : if( FD_UNLIKELY( 32UL>buf_sz-off ) ) return FD_VOTE_HISTORY_DE_ERR_SIZE; 67 0 : if( FD_UNLIKELY( !fd_memeq( buf+off, identity, 32UL ) ) ) return FD_VOTE_HISTORY_DE_ERR_IDENTITY; 68 0 : off += 32UL; 69 : 70 0 : ulong max_vote = 0UL; 71 : 72 0 : LOAD_VOTES(); /* voted */ 73 : 74 0 : ulong notar_cnt; LOAD_LEN( notar_cnt, 40UL ); 75 0 : for( ulong i=0UL; i<notar_cnt; i++ ) { 76 0 : ulong slot; LOAD_VOTE( slot ); 77 0 : SKIP( 32UL ); 78 0 : } 79 : 80 0 : ulong notar_fallback_cnt; LOAD_LEN( notar_fallback_cnt, 16UL ); 81 0 : for( ulong i=0UL; i<notar_fallback_cnt; i++ ) { 82 0 : ulong slot; LOAD_VOTE( slot ); 83 0 : ulong hash_cnt; LOAD_LEN( hash_cnt, 32UL ); 84 0 : SKIP( hash_cnt*32UL ); 85 0 : } 86 : 87 0 : LOAD_VOTES(); /* voted_skip_fallback */ 88 0 : LOAD_VOTES(); /* skipped */ 89 0 : LOAD_VOTES(); /* its_over */ 90 : 91 0 : ulong votes_slot_cnt; LOAD_LEN( votes_slot_cnt, 16UL ); 92 0 : for( ulong i=0UL; i<votes_slot_cnt; i++ ) { 93 0 : ulong slot; LOAD_VOTE( slot ); 94 0 : ulong vote_cnt; LOAD_LEN( vote_cnt, 11UL ); 95 0 : for( ulong j=0UL; j<vote_cnt; j++ ) { 96 0 : uchar tag; LOAD( uchar, tag ); 97 0 : ulong hash_sz; 98 0 : switch( tag ) { 99 0 : case FD_VOTE_HISTORY_SERDE_TAG_NOTAR: 100 0 : case FD_VOTE_HISTORY_SERDE_TAG_NOTAR_FALLBACK: 101 0 : case FD_VOTE_HISTORY_SERDE_TAG_GENESIS: hash_sz = 32UL; break; 102 0 : case FD_VOTE_HISTORY_SERDE_TAG_FINAL: 103 0 : case FD_VOTE_HISTORY_SERDE_TAG_SKIP: 104 0 : case FD_VOTE_HISTORY_SERDE_TAG_SKIP_FALLBACK: hash_sz = 0UL; break; 105 0 : default: return FD_VOTE_HISTORY_DE_ERR_HISTORY; 106 0 : } 107 0 : ulong vote_slot; LOAD_VOTE( vote_slot ); 108 0 : SKIP( hash_sz+2UL ); /* block hash, shred_version */ 109 0 : } 110 0 : } 111 : 112 0 : ulong notarized_cnt; LOAD_LEN( notarized_cnt, 40UL ); 113 0 : for( ulong i=0UL; i<notarized_cnt; i++ ) { 114 0 : SKIP( 40UL ); /* slot, block hash */ 115 0 : } 116 : 117 0 : ulong parent_ready_slot_cnt; LOAD_LEN( parent_ready_slot_cnt, 16UL ); 118 0 : for( ulong i=0UL; i<parent_ready_slot_cnt; i++ ) { 119 0 : SKIP( 8UL ); /* slot */ 120 0 : ulong block_cnt; LOAD_LEN( block_cnt, 40UL ); 121 0 : SKIP( block_cnt*40UL ); 122 0 : } 123 : 124 0 : ulong root; LOAD( ulong, root ); 125 : 126 0 : *wait_to_vote_slot = fd_ulong_sat_add( fd_first_slot_in_window( fd_ulong_max( max_vote, root ) ), FD_VOTOR_SLOTS_PER_WINDOW ); 127 0 : return FD_VOTE_HISTORY_DE_SUCCESS; 128 0 : } 129 : 130 : #undef LOAD 131 : #undef LOAD_LEN 132 : #undef SKIP 133 : #undef LOAD_VOTE 134 : #undef LOAD_VOTES