Line data Source code
1 : #include "fd_bank_hash_cmp.h"
2 : #include <unistd.h>
3 :
4 : void *
5 0 : fd_bank_hash_cmp_new( void * mem ) {
6 :
7 0 : if( FD_UNLIKELY( !mem ) ) {
8 0 : FD_LOG_WARNING( ( "NULL mem" ) );
9 0 : return NULL;
10 0 : }
11 :
12 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_bank_hash_cmp_align() ) ) ) {
13 0 : FD_LOG_WARNING( ( "misaligned mem" ) );
14 0 : return NULL;
15 0 : }
16 :
17 0 : ulong footprint = fd_bank_hash_cmp_footprint();
18 :
19 0 : fd_memset( mem, 0, footprint );
20 :
21 0 : ulong laddr = (ulong)mem;
22 0 : laddr += sizeof( fd_bank_hash_cmp_t );
23 :
24 0 : laddr = fd_ulong_align_up( laddr, fd_bank_hash_cmp_map_align() );
25 0 : fd_bank_hash_cmp_map_new( (void *)laddr );
26 0 : laddr += fd_bank_hash_cmp_map_footprint();
27 :
28 0 : laddr = fd_ulong_align_up( laddr, fd_bank_hash_cmp_align() );
29 0 : FD_TEST( laddr == (ulong)mem + fd_bank_hash_cmp_footprint() );
30 :
31 0 : return mem;
32 0 : }
33 :
34 : fd_bank_hash_cmp_t *
35 0 : fd_bank_hash_cmp_join( void * bank_hash_cmp ) {
36 0 : if( FD_UNLIKELY( !bank_hash_cmp ) ) {
37 0 : FD_LOG_WARNING( ( "NULL bank_hash_cmp" ) );
38 0 : return NULL;
39 0 : }
40 :
41 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)bank_hash_cmp, fd_bank_hash_cmp_align() ) ) ) {
42 0 : FD_LOG_WARNING( ( "misaligned bank_hash_cmp" ) );
43 0 : return NULL;
44 0 : }
45 :
46 0 : ulong laddr = (ulong)bank_hash_cmp;
47 0 : laddr += sizeof( fd_bank_hash_cmp_t );
48 :
49 0 : fd_bank_hash_cmp_t * bank_hash_cmp_ = (fd_bank_hash_cmp_t *)bank_hash_cmp;
50 0 : bank_hash_cmp_->map = fd_bank_hash_cmp_map_join( (void *)laddr );
51 :
52 0 : return bank_hash_cmp;
53 0 : }
54 :
55 : void *
56 0 : fd_bank_hash_cmp_leave( fd_bank_hash_cmp_t const * bank_hash_cmp ) {
57 :
58 0 : if( FD_UNLIKELY( !bank_hash_cmp ) ) {
59 0 : FD_LOG_WARNING( ( "NULL bank_hash_cmp" ) );
60 0 : return NULL;
61 0 : }
62 :
63 0 : return (void *)bank_hash_cmp;
64 0 : }
65 :
66 : void *
67 0 : fd_bank_hash_cmp_delete( void * bank_hash_cmp ) {
68 :
69 0 : if( FD_UNLIKELY( !bank_hash_cmp ) ) {
70 0 : FD_LOG_WARNING( ( "NULL bank_hash_cmp" ) );
71 0 : return NULL;
72 0 : }
73 :
74 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)bank_hash_cmp, fd_bank_hash_cmp_align() ) ) ) {
75 0 : FD_LOG_WARNING( ( "misaligned bank_hash_cmp" ) );
76 0 : return NULL;
77 0 : }
78 :
79 0 : return bank_hash_cmp;
80 0 : }
81 :
82 : void
83 0 : fd_bank_hash_cmp_lock( fd_bank_hash_cmp_t * bank_hash_cmp ) {
84 0 : volatile int * lock = &bank_hash_cmp->lock;
85 0 : # if FD_HAS_THREADS
86 0 : for( ;; ) {
87 0 : if( FD_LIKELY( !FD_ATOMIC_CAS( lock, 0UL, 1UL ) ) ) break;
88 0 : FD_SPIN_PAUSE();
89 0 : }
90 : # else
91 : *lock = 1;
92 : # endif
93 0 : FD_COMPILER_MFENCE();
94 0 : }
95 :
96 : void
97 0 : fd_bank_hash_cmp_unlock( fd_bank_hash_cmp_t * bank_hash_cmp ) {
98 0 : volatile int * lock = &bank_hash_cmp->lock;
99 0 : FD_COMPILER_MFENCE();
100 0 : FD_VOLATILE( *lock ) = 0UL;
101 0 : }
102 :
103 : void
104 : fd_bank_hash_cmp_insert( fd_bank_hash_cmp_t * bank_hash_cmp,
105 : ulong slot,
106 : fd_hash_t const * hash,
107 : int ours,
108 0 : ulong stake ) {
109 0 : if( FD_UNLIKELY( slot <= bank_hash_cmp->watermark ) ) { return; }
110 0 : fd_bank_hash_cmp_entry_t * cmp = fd_bank_hash_cmp_map_query( bank_hash_cmp->map, slot, NULL );
111 :
112 0 : if( !cmp ) {
113 :
114 : /* If full, make room for new bank hashes */
115 :
116 0 : if( FD_UNLIKELY( bank_hash_cmp->cnt == fd_bank_hash_cmp_map_key_max() ) ) {
117 0 : FD_LOG_WARNING( ( "Bank matches unexpectedly full. Clearing. " ) );
118 0 : for( ulong i = 0; i < fd_bank_hash_cmp_map_slot_cnt(); i++ ) {
119 0 : fd_bank_hash_cmp_entry_t * entry = &bank_hash_cmp->map[i];
120 0 : if( FD_LIKELY( !fd_bank_hash_cmp_map_key_inval( entry->slot ) &&
121 0 : entry->slot < bank_hash_cmp->watermark ) ) {
122 0 : fd_bank_hash_cmp_map_remove( bank_hash_cmp->map, entry );
123 0 : bank_hash_cmp->cnt--;
124 0 : }
125 0 : }
126 0 : }
127 :
128 0 : cmp = fd_bank_hash_cmp_map_insert( bank_hash_cmp->map, slot );
129 0 : cmp->cnt = 0;
130 0 : bank_hash_cmp->cnt++;
131 0 : }
132 :
133 0 : if( FD_UNLIKELY( ours ) ) {
134 0 : cmp->ours = *hash;
135 0 : return;
136 0 : }
137 :
138 0 : for( ulong i = 0; i < cmp->cnt; i++ ) {
139 0 : if( FD_LIKELY( 0 == memcmp( &cmp->theirs[i], hash, sizeof( fd_hash_t ) ) ) ) {
140 0 : cmp->stakes[i] += stake;
141 0 : return;
142 0 : }
143 0 : }
144 :
145 0 : ulong max = sizeof( cmp->stakes ) / sizeof( ulong );
146 0 : if( FD_UNLIKELY( cmp->cnt == max ) ) {
147 0 : if( !cmp->overflow ) {
148 0 : FD_LOG_WARNING(( "[Bank Hash Comparison] more than %lu equivocating hashes for slot %lu. "
149 0 : "new hash: %s. ignoring.",
150 0 : max,
151 0 : slot,
152 0 : FD_BASE58_ENC_32_ALLOCA( hash ) ));
153 0 : cmp->overflow = 1;
154 0 : }
155 0 : return;
156 0 : }
157 0 : cmp->cnt++;
158 0 : cmp->theirs[cmp->cnt - 1] = *hash;
159 0 : cmp->stakes[cmp->cnt - 1] = stake;
160 0 : if( FD_UNLIKELY( cmp->cnt > 1 ) ) {
161 0 : for( ulong i = 0; i < cmp->cnt; i++ ) {
162 0 : FD_LOG_WARNING(( "slot: %lu. equivocating hash (#%lu): %s. stake: %lu",
163 0 : cmp->slot,
164 0 : i,
165 0 : FD_BASE58_ENC_32_ALLOCA( cmp->theirs[i].hash ),
166 0 : cmp->stakes[i] ));
167 0 : }
168 0 : }
169 0 : }
170 :
171 : int
172 0 : fd_bank_hash_cmp_check( fd_bank_hash_cmp_t * bank_hash_cmp, ulong slot ) {
173 0 : fd_bank_hash_cmp_entry_t * cmp = fd_bank_hash_cmp_map_query( bank_hash_cmp->map, slot, NULL );
174 :
175 0 : if( FD_UNLIKELY( !cmp ) ) return 0;
176 :
177 0 : fd_hash_t null_hash = { 0 };
178 0 : if( FD_LIKELY( 0 == memcmp( &cmp->ours, &null_hash, sizeof( fd_hash_t ) ) ) ) return 0;
179 :
180 0 : if( FD_UNLIKELY( cmp->cnt == 0 ) ) return 0;
181 :
182 0 : fd_hash_t * theirs = &cmp->theirs[0];
183 0 : ulong stake = cmp->stakes[0];
184 0 : for( ulong i = 1; i < cmp->cnt; i++ ) {
185 0 : if( FD_UNLIKELY( cmp->stakes[i] > stake ) ) {
186 0 : theirs = &cmp->theirs[i];
187 0 : stake = cmp->stakes[i];
188 0 : }
189 0 : }
190 :
191 0 : double pct = (double)stake / (double)bank_hash_cmp->total_stake;
192 0 : if( FD_LIKELY( pct > 0.52 ) ) {
193 0 : if( FD_UNLIKELY( 0 != memcmp( &cmp->ours, theirs, sizeof( fd_hash_t ) ) ) ) {
194 0 : FD_LOG_WARNING(( "\n\n[Bank Hash Comparison]\n"
195 0 : "slot: %lu\n"
196 0 : "ours: %s\n"
197 0 : "theirs: %s\n"
198 0 : "stake: %.0lf%%\n"
199 0 : "result: mismatch!\n",
200 0 : cmp->slot,
201 0 : FD_BASE58_ENC_32_ALLOCA( cmp->ours.hash ),
202 0 : FD_BASE58_ENC_32_ALLOCA( theirs->hash ),
203 0 : pct * 100 ));
204 0 : if( FD_UNLIKELY( cmp->cnt > 1 ) ) {
205 0 : for( ulong i = 0; i < cmp->cnt; i++ ) {
206 0 : FD_LOG_WARNING(( "slot: %lu. hash (#%lu): %s. stake: %lu",
207 0 : cmp->slot,
208 0 : i,
209 0 : FD_BASE58_ENC_32_ALLOCA( cmp->theirs[i].hash ),
210 0 : cmp->stakes[i] ));
211 0 : }
212 0 : }
213 0 : return 1;
214 0 : } else {
215 0 : FD_LOG_NOTICE(( "\n\n[Bank Hash Comparison]\n"
216 0 : "slot: %lu\n"
217 0 : "ours: %s\n"
218 0 : "theirs: %s\n"
219 0 : "stake: %.0lf%%\n"
220 0 : "result: match!\n",
221 0 : cmp->slot,
222 0 : FD_BASE58_ENC_32_ALLOCA( cmp->ours.hash ),
223 0 : FD_BASE58_ENC_32_ALLOCA( theirs->hash ),
224 0 : pct * 100 ));
225 0 : }
226 0 : fd_bank_hash_cmp_map_remove( bank_hash_cmp->map, cmp );
227 0 : bank_hash_cmp->cnt--;
228 0 : return 1;
229 0 : }
230 0 : return 0;
231 0 : }
|