Line data Source code
1 : #include "fd_notar.h"
2 : #include "../../util/bits/fd_bits.h"
3 :
4 : void *
5 : fd_notar_new( void * shmem,
6 0 : ulong slot_max ) {
7 :
8 0 : if( FD_UNLIKELY( !shmem ) ) {
9 0 : FD_LOG_WARNING(( "NULL mem" ));
10 0 : return NULL;
11 0 : }
12 :
13 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_notar_align() ) ) ) {
14 0 : FD_LOG_WARNING(( "misaligned mem" ));
15 0 : return NULL;
16 0 : }
17 :
18 0 : ulong footprint = fd_notar_footprint( slot_max );
19 0 : if( FD_UNLIKELY( !footprint ) ) {
20 0 : FD_LOG_WARNING(( "bad slot_max (%lu)", slot_max ));
21 0 : return NULL;
22 0 : }
23 :
24 0 : fd_memset( shmem, 0, footprint );
25 :
26 0 : int lg_slot_max = fd_ulong_find_msb( fd_ulong_pow2_up( slot_max ) ) + 1;
27 0 : int lg_blk_max = fd_ulong_find_msb( fd_ulong_pow2_up( slot_max * FD_VOTER_MAX ) ) + 1;
28 0 : int lg_vtr_max = fd_ulong_find_msb( fd_ulong_pow2_up( FD_VOTER_MAX ) ) + 1;
29 :
30 0 : FD_SCRATCH_ALLOC_INIT( l, shmem );
31 0 : fd_notar_t * notar = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_align(), sizeof(fd_notar_t) );
32 0 : void * slot_map = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_slot_align(), fd_notar_slot_footprint( lg_slot_max ) );
33 0 : void * blk_map = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_blk_align(), fd_notar_blk_footprint( lg_blk_max ) );
34 0 : void * vtr_map = FD_SCRATCH_ALLOC_APPEND( l, fd_notar_vtr_align(), fd_notar_vtr_footprint( lg_vtr_max ) );
35 0 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_notar_align() ) == (ulong)shmem + footprint );
36 :
37 0 : notar->root = ULONG_MAX;
38 0 : notar->slot_max = slot_max;
39 0 : notar->slot_map = fd_notar_slot_new( slot_map, lg_slot_max, 0UL );
40 0 : notar->blk_map = fd_notar_blk_new( blk_map, lg_blk_max, 0UL );
41 0 : notar->vtr_map = fd_notar_vtr_new( vtr_map, lg_vtr_max, 0UL );
42 :
43 0 : return shmem;
44 0 : }
45 :
46 : fd_notar_t *
47 0 : fd_notar_join( void * shnotar ) {
48 0 : fd_notar_t * notar = (fd_notar_t *)shnotar;
49 :
50 0 : if( FD_UNLIKELY( !notar ) ) {
51 0 : FD_LOG_WARNING(( "NULL notar" ));
52 0 : return NULL;
53 0 : }
54 :
55 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)notar, fd_notar_align() ) ) ) {
56 0 : FD_LOG_WARNING(( "misaligned notar" ));
57 0 : return NULL;
58 0 : }
59 :
60 0 : notar->slot_map = fd_notar_slot_join( notar->slot_map );
61 0 : notar->blk_map = fd_notar_blk_join( notar->blk_map );
62 0 : notar->vtr_map = fd_notar_vtr_join( notar->vtr_map );
63 :
64 0 : return notar;
65 0 : }
66 :
67 : void *
68 0 : fd_notar_leave( fd_notar_t const * notar ) {
69 :
70 0 : if( FD_UNLIKELY( !notar ) ) {
71 0 : FD_LOG_WARNING(( "NULL notar" ));
72 0 : return NULL;
73 0 : }
74 :
75 0 : return (void *)notar;
76 0 : }
77 :
78 : void *
79 0 : fd_notar_delete( void * notar ) {
80 :
81 0 : if( FD_UNLIKELY( !notar ) ) {
82 0 : FD_LOG_WARNING(( "NULL notar" ));
83 0 : return NULL;
84 0 : }
85 :
86 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)notar, fd_notar_align() ) ) ) {
87 0 : FD_LOG_WARNING(( "misaligned notar" ));
88 0 : return NULL;
89 0 : }
90 :
91 0 : return notar;
92 0 : }
93 :
94 : fd_notar_blk_t *
95 : fd_notar_count_vote( fd_notar_t * notar,
96 : fd_pubkey_t const * addr,
97 : ulong vote_slot,
98 0 : fd_hash_t const * vote_block_id ) {
99 :
100 0 : if( FD_UNLIKELY( notar->root==ULONG_MAX ) ) return NULL; /* uninitialized root */
101 0 : if( FD_UNLIKELY( vote_slot < notar->root ) ) return NULL; /* vote too far behind */
102 0 : if( FD_UNLIKELY( vote_slot > notar->root + notar->slot_max ) ) return NULL; /* vote too far ahead */
103 :
104 0 : fd_notar_vtr_t const * vtr = fd_notar_vtr_query( notar->vtr_map, *addr, NULL );
105 0 : if( FD_UNLIKELY( !vtr ) ) return NULL; /* voter not found */
106 :
107 : /* Check we haven't already counted the voter's stake for this slot.
108 : If a voter votes for multiple block ids for the same slot, we only
109 : count their first one. Honest voters never vote more than once for
110 : the same slot so the percentage of stake doing this should be small
111 : as only malicious voters would equivocate votes this way. */
112 :
113 0 : fd_notar_slot_t * notar_slot = fd_notar_slot_query( notar->slot_map, vote_slot, NULL );
114 0 : if( FD_UNLIKELY( !notar_slot ) ) {
115 0 : FD_TEST( fd_notar_slot_key_cnt( notar->slot_map ) < fd_notar_slot_slot_cnt( notar->slot_map ) );
116 0 : notar_slot = fd_notar_slot_insert( notar->slot_map, vote_slot );
117 0 : notar_slot->parent_slot = ULONG_MAX;
118 0 : notar_slot->prev_leader_slot = ULONG_MAX;
119 0 : notar_slot->stake = 0;
120 0 : notar_slot->is_leader = 0;
121 0 : notar_slot->is_propagated = 0;
122 0 : notar_slot->block_ids_cnt = 0;
123 0 : fd_notar_slot_vtrs_null( notar_slot->vtrs );
124 0 : }
125 0 : if( FD_UNLIKELY( vtr->bit==ULONG_MAX ) ) return NULL;
126 0 : if( FD_UNLIKELY( fd_notar_slot_vtrs_test( notar_slot->vtrs, vtr->bit ) ) ) return NULL;
127 0 : fd_notar_slot_vtrs_insert( notar_slot->vtrs, vtr->bit );
128 0 : notar_slot->stake += vtr->stake;
129 :
130 : /* Get the actual block with the block_id. */
131 :
132 0 : fd_notar_blk_t * notar_blk = fd_notar_blk_query( notar->blk_map, *vote_block_id, NULL );
133 0 : if( FD_UNLIKELY( !notar_blk ) ) {
134 0 : FD_TEST( notar_slot->block_ids_cnt < FD_VOTER_MAX ); /* at most one unique block id per voter in a slot */
135 0 : notar_blk = fd_notar_blk_insert( notar->blk_map, *vote_block_id );
136 0 : notar_blk->slot = vote_slot;
137 0 : notar_blk->stake = 0;
138 0 : notar_blk->level = -1;
139 0 : notar_blk->fwd_level = -1;
140 0 : notar_slot->block_ids[notar_slot->block_ids_cnt++] = *vote_block_id;
141 0 : }
142 0 : notar_blk->stake += vtr->stake;
143 0 : return notar_blk;
144 0 : }
145 :
146 : void
147 : fd_notar_publish( fd_notar_t * notar,
148 0 : ulong root ) {
149 0 : for(ulong slot = notar->root; slot < root; slot++ ) {
150 0 : fd_notar_slot_t * notar_slot = fd_notar_slot_query( notar->slot_map, slot, NULL );
151 0 : if( FD_LIKELY( notar_slot ) ) {
152 0 : for( ulong i=0; i<notar_slot->block_ids_cnt; i++ ) {
153 0 : fd_hash_t const * block_id = ¬ar_slot->block_ids[i];
154 0 : fd_notar_blk_t * notar_blk = fd_notar_blk_query( notar->blk_map, *block_id, NULL );
155 0 : if( FD_UNLIKELY( !notar_blk ) ) { FD_BASE58_ENCODE_32_BYTES( block_id->uc, crit ); FD_LOG_CRIT(( "missing %lu %s %lu %lu", slot, crit, i, notar_slot->block_ids_cnt )); };
156 0 : fd_notar_blk_remove( notar->blk_map, notar_blk );
157 0 : }
158 0 : fd_notar_slot_remove( notar->slot_map, notar_slot );
159 0 : }
160 0 : }
161 0 : notar->root = root;
162 0 : }
|