Skip to content

Commit 7e384a0

Browse files
committed
fix(hfork): removal bug with multiple bank hashes (hard forks)
1 parent a73f5ae commit 7e384a0

File tree

2 files changed

+118
-23
lines changed

2 files changed

+118
-23
lines changed

src/choreo/hfork/fd_hfork.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,25 @@ fd_hfork_delete( void * hfork ) {
170170
return hfork;
171171
}
172172

173+
void
174+
remove( blk_t * blk, fd_hash_t * bank_hash, bank_hash_t * pool ) {
175+
bank_hash_t * prev = NULL;
176+
bank_hash_t * curr = blk->bank_hashes;
177+
while( FD_LIKELY( curr ) ) {
178+
if( FD_LIKELY( 0==memcmp( &curr->bank_hash, bank_hash, 32UL ) ) ) break;
179+
prev = curr;
180+
curr = bank_hash_pool_ele( pool, curr->next );
181+
}
182+
FD_TEST( curr ); /* assumes bank_hash in blk->bank_hashes */
183+
184+
/* In most cases, there is only one bank_hash per blk, so it will be
185+
the first element in blk->bank_hashes and prev will be NULL. */
186+
187+
if( FD_LIKELY( !prev ) ) blk->bank_hashes = bank_hash_pool_ele( pool, curr->next );
188+
else prev->next = curr->next;
189+
bank_hash_pool_ele_release( pool, curr );
190+
}
191+
173192
void
174193
fd_hfork_count_vote( fd_hfork_t * hfork,
175194
fd_hash_t const * vote_acc,
@@ -205,11 +224,9 @@ fd_hfork_count_vote( fd_hfork_t * hfork,
205224
candidate->cnt--;
206225
if( FD_UNLIKELY( candidate->cnt==0 ) ) {
207226
candidate_map_remove( hfork->candidate_map, candidate );
208-
blk_t * blk = blk_map_query( hfork->blk_map, vote.block_id, NULL );
209-
bank_hash_t * remove = blk->bank_hashes;
210-
blk->bank_hashes = bank_hash_pool_ele( hfork->bank_hash_pool, remove->next );
211-
bank_hash_pool_ele_release( hfork->bank_hash_pool, remove );
212-
227+
blk_t * blk = blk_map_query( hfork->blk_map, vote.block_id, NULL );
228+
FD_TEST( blk );
229+
remove( blk, &vote.bank_hash, hfork->bank_hash_pool );
213230
if( FD_UNLIKELY( !blk->bank_hashes ) ) {
214231
blk_map_remove( hfork->blk_map, blk );
215232
if( FD_UNLIKELY( blk->forked ) ) {

src/choreo/hfork/test_hfork.c

Lines changed: 96 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
#include "fd_hfork.h"
22
#include "fd_hfork_private.h"
33

4+
ulong
5+
cnt( fd_hfork_t * hfork, fd_hash_t * block_id ) {
6+
ulong cnt = 0;
7+
blk_t * blk = blk_map_query( hfork->blk_map, *block_id, NULL );
8+
bank_hash_t * curr = blk->bank_hashes;
9+
while( FD_LIKELY( curr ) ) {
10+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
11+
cnt++;
12+
}
13+
return cnt;
14+
}
15+
416
void
517
test_hfork_simple( fd_wksp_t * wksp ) {
618
ulong max_live_slots = 2;
@@ -10,22 +22,30 @@ test_hfork_simple( fd_wksp_t * wksp ) {
1022
fd_hfork_t * hfork = fd_hfork_join( fd_hfork_new( mem, max_live_slots, max_vote_accounts, 42, 0 ) );
1123
FD_TEST( hfork );
1224

13-
ulong slot = 368778153;
25+
ulong slot = 368778150;
1426
fd_hash_t block_id = { .ul = { slot } };
1527
fd_hash_t bank_hash = { .ul = { slot } };
1628

17-
ulong slot1 = 368778154;
29+
ulong slot1 = 368778151;
1830
fd_hash_t block_id1 = { .ul = { slot1 } };
1931
fd_hash_t bank_hash1 = { .ul = { slot1 } };
2032

21-
ulong slot2 = 368778155;
33+
ulong slot2 = 368778152;
2234
fd_hash_t block_id2 = { .ul = { slot2 } };
2335
fd_hash_t bank_hash2 = { .ul = { slot2 } };
2436

25-
ulong slot3 = 368778156;
26-
// fd_hash_t block_id3 = { .ul = { slot3 } };
37+
ulong slot3 = 368778153;
38+
fd_hash_t block_id3 = { .ul = { slot3 } };
2739
fd_hash_t bank_hash3 = { .ul = { slot3 } };
2840

41+
ulong slot4 = 368778154;
42+
fd_hash_t block_id4 = { .ul = { slot4 } };
43+
fd_hash_t bank_hash4 = { .ul = { slot4 } };
44+
45+
ulong slot5 = 368778155;
46+
fd_hash_t block_id5 = { .ul = { slot5 } };
47+
fd_hash_t bank_hash5 = { .ul = { slot5 } };
48+
2949
fd_hash_t voters[4] = {
3050
(fd_hash_t){ .ul = { 1 } },
3151
(fd_hash_t){ .ul = { 2 } },
@@ -66,19 +86,77 @@ test_hfork_simple( fd_wksp_t * wksp ) {
6686

6787
/* max bank hashes for a given block_id */
6888

69-
fd_hfork_count_vote( hfork, &voters[0], &block_id, &bank_hash, slot3, 1, 100, &metrics );
70-
fd_hfork_count_vote( hfork, &voters[1], &block_id, &bank_hash1, slot3, 51, 100, &metrics );
71-
fd_hfork_count_vote( hfork, &voters[2], &block_id, &bank_hash2, slot3, 2, 100, &metrics );
72-
fd_hfork_count_vote( hfork, &voters[3], &block_id, &bank_hash3, slot3, 3, 100, &metrics );
73-
74-
blk_t * blk = blk_map_query( hfork->blk_map, block_id, NULL );
75-
bank_hash_t * curr = blk->bank_hashes;
76-
ulong cnt = 0;
77-
while( FD_LIKELY( curr ) ) {
78-
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
79-
cnt++;
80-
}
81-
FD_TEST( cnt==4 );
89+
fd_hfork_count_vote( hfork, &voters[0], &block_id3, &bank_hash, slot3, 1, 100, &metrics );
90+
fd_hfork_count_vote( hfork, &voters[1], &block_id3, &bank_hash1, slot3, 51, 100, &metrics );
91+
fd_hfork_count_vote( hfork, &voters[2], &block_id3, &bank_hash2, slot3, 2, 100, &metrics );
92+
fd_hfork_count_vote( hfork, &voters[3], &block_id3, &bank_hash3, slot3, 3, 100, &metrics );
93+
94+
FD_TEST( cnt( hfork, &block_id3 )==4 );
95+
blk_t * blk3 = blk_map_query( hfork->blk_map, block_id3, NULL );
96+
bank_hash_t * curr = blk3->bank_hashes;
97+
FD_TEST( curr->bank_hash.ul[0] == bank_hash.ul[0] );
98+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
99+
FD_TEST( curr->bank_hash.ul[0] == bank_hash1.ul[0] );
100+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
101+
FD_TEST( curr->bank_hash.ul[0] == bank_hash2.ul[0] );
102+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
103+
FD_TEST( curr->bank_hash.ul[0] == bank_hash3.ul[0] );
104+
105+
/* evict front (bank_hash) from block_id */
106+
107+
fd_hfork_count_vote( hfork, &voters[0], &block_id4, &bank_hash4, slot4, 1, 100, &metrics );
108+
fd_hfork_count_vote( hfork, &voters[0], &block_id5, &bank_hash5, slot5, 1, 100, &metrics );
109+
110+
FD_TEST( !candidate_map_query( hfork->candidate_map, (candidate_key_t){ .block_id = block_id3, .bank_hash = bank_hash }, NULL ) );
111+
FD_TEST( cnt( hfork, &block_id3 )==3 );
112+
blk3 = blk_map_query( hfork->blk_map, block_id3, NULL );
113+
114+
curr = blk3->bank_hashes;
115+
FD_TEST( curr->bank_hash.ul[0] == bank_hash1.ul[0] );
116+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
117+
FD_TEST( curr->bank_hash.ul[0] == bank_hash2.ul[0] );
118+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
119+
FD_TEST( curr->bank_hash.ul[0] == bank_hash3.ul[0] );
120+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
121+
FD_TEST( !curr );
122+
123+
/* evict middle (bank_hash2) from block_id */
124+
125+
fd_hfork_count_vote( hfork, &voters[2], &block_id4, &bank_hash4, slot4, 1, 100, &metrics );
126+
fd_hfork_count_vote( hfork, &voters[2], &block_id5, &bank_hash5, slot5, 1, 100, &metrics );
127+
128+
FD_TEST( !candidate_map_query( hfork->candidate_map, (candidate_key_t){ .block_id = block_id3, .bank_hash = bank_hash2 }, NULL ) );
129+
FD_TEST( cnt( hfork, &block_id3 )==2 );
130+
blk3 = blk_map_query( hfork->blk_map, block_id3, NULL );
131+
132+
curr = blk3->bank_hashes;
133+
FD_TEST( curr->bank_hash.ul[0] == bank_hash1.ul[0] );
134+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
135+
FD_TEST( curr->bank_hash.ul[0] == bank_hash3.ul[0] );
136+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
137+
FD_TEST( !curr );
138+
139+
/* evict back (bank_hash3) from block_id */
140+
141+
fd_hfork_count_vote( hfork, &voters[3], &block_id4, &bank_hash4, slot4, 1, 100, &metrics );
142+
fd_hfork_count_vote( hfork, &voters[3], &block_id5, &bank_hash5, slot5, 1, 100, &metrics );
143+
144+
FD_TEST( !candidate_map_query( hfork->candidate_map, (candidate_key_t){ .block_id = block_id3, .bank_hash = bank_hash3 }, NULL ) );
145+
FD_TEST( cnt( hfork, &block_id3 )==1 );
146+
blk3 = blk_map_query( hfork->blk_map, block_id3, NULL );
147+
148+
curr = blk3->bank_hashes;
149+
FD_TEST( curr->bank_hash.ul[0] == bank_hash1.ul[0] );
150+
curr = bank_hash_pool_ele( hfork->bank_hash_pool, curr->next );
151+
FD_TEST( !curr );
152+
153+
/* evict singleton (bank_hash1) from block_id */
154+
155+
fd_hfork_count_vote( hfork, &voters[1], &block_id4, &bank_hash4, slot4, 1, 100, &metrics );
156+
fd_hfork_count_vote( hfork, &voters[1], &block_id5, &bank_hash5, slot5, 1, 100, &metrics );
157+
158+
FD_TEST( !candidate_map_query( hfork->candidate_map, (candidate_key_t){ .block_id = block_id3, .bank_hash = bank_hash1 }, NULL ) );
159+
FD_TEST( !blk_map_query( hfork->blk_map, block_id3, NULL ) );
82160

83161
fd_wksp_free_laddr( fd_hfork_delete( fd_hfork_leave( hfork ) ) );
84162
}

0 commit comments

Comments
 (0)