@@ -57,7 +57,8 @@ test_funk_txn_cancel( void ) {
5757
5858/* Helper to create a test account */
5959static void
60- create_test_account ( fd_pubkey_t const * pubkey ,
60+ create_test_account ( fd_funk_txn_xid_t const * xid ,
61+ fd_pubkey_t const * pubkey ,
6162 fd_pubkey_t const * owner ,
6263 uchar const * data ,
6364 ulong data_len ,
@@ -67,7 +68,7 @@ create_test_account( fd_pubkey_t const * pubkey,
6768 int err = fd_txn_account_init_from_funk_mutable ( /* acc */ acc ,
6869 /* pubkey */ pubkey ,
6970 /* funk */ test_accdb ,
70- /* xid */ & test_xid ,
71+ /* xid */ xid ,
7172 /* do_create */ 1 ,
7273 /* min_data_sz */ data_len ,
7374 /* prepare */ & prepare );
@@ -133,7 +134,8 @@ test_account_not_bpf_loader_owner( void ) {
133134 test_xid = test_funk_txn_create ();
134135
135136 /* Create an account owned by a non-BPF loader */
136- create_test_account ( & test_program_pubkey ,
137+ create_test_account ( & test_xid ,
138+ & test_program_pubkey ,
137139 & fd_solana_system_program_id ,
138140 invalid_program_data ,
139141 invalid_program_data_sz ,
@@ -156,7 +158,8 @@ test_invalid_program_not_in_cache_first_time( void ) {
156158 test_xid = test_funk_txn_create ();
157159
158160 /* Create a BPF loader account */
159- create_test_account ( & test_program_pubkey ,
161+ create_test_account ( & test_xid ,
162+ & test_program_pubkey ,
160163 & fd_solana_bpf_loader_program_id ,
161164 invalid_program_data ,
162165 invalid_program_data_sz ,
@@ -182,7 +185,8 @@ test_valid_program_not_in_cache_first_time( void ) {
182185 test_xid = test_funk_txn_create ();
183186
184187 /* Create a BPF loader account */
185- create_test_account ( & test_program_pubkey ,
188+ create_test_account ( & test_xid ,
189+ & test_program_pubkey ,
186190 & fd_solana_bpf_loader_program_id ,
187191 valid_program_data ,
188192 valid_program_data_sz ,
@@ -209,7 +213,8 @@ test_program_in_cache_needs_reverification( void ) {
209213 test_xid = test_funk_txn_create ();
210214
211215 /* Create a BPF loader account */
212- create_test_account ( & test_program_pubkey ,
216+ create_test_account ( & test_xid ,
217+ & test_program_pubkey ,
213218 & fd_solana_bpf_loader_program_id ,
214219 valid_program_data ,
215220 valid_program_data_sz ,
@@ -250,7 +255,8 @@ test_program_in_cache_queued_for_reverification( void ) {
250255 test_xid = test_funk_txn_create ();
251256
252257 /* Create a BPF loader account */
253- create_test_account ( & test_program_pubkey ,
258+ create_test_account ( & test_xid ,
259+ & test_program_pubkey ,
254260 & fd_solana_bpf_loader_program_id ,
255261 valid_program_data ,
256262 valid_program_data_sz ,
@@ -309,7 +315,8 @@ test_program_queued_for_reverification_account_does_not_exist( void ) {
309315 test_xid = test_funk_txn_create ();
310316
311317 /* Create a BPF loader account but don't add it to the cache */
312- create_test_account ( & test_program_pubkey ,
318+ create_test_account ( & test_xid ,
319+ & test_program_pubkey ,
313320 & fd_solana_bpf_loader_program_id ,
314321 valid_program_data ,
315322 valid_program_data_sz ,
@@ -345,7 +352,8 @@ test_program_in_cache_queued_for_reverification_and_processed( void ) {
345352 test_xid = test_funk_txn_create ();
346353
347354 /* Create a BPF loader account */
348- create_test_account ( & test_program_pubkey ,
355+ create_test_account ( & test_xid ,
356+ & test_program_pubkey ,
349357 & fd_solana_bpf_loader_program_id ,
350358 valid_program_data ,
351359 valid_program_data_sz ,
@@ -409,7 +417,8 @@ test_invalid_genesis_program_reverified_after_genesis( void ) {
409417 fd_bank_slot_set ( test_bank , 0UL );
410418
411419 /* Create a BPF loader account */
412- create_test_account ( & test_program_pubkey ,
420+ create_test_account ( & test_xid ,
421+ & test_program_pubkey ,
413422 & fd_solana_bpf_loader_program_id ,
414423 invalid_program_data ,
415424 invalid_program_data_sz ,
@@ -454,7 +463,8 @@ test_valid_genesis_program_reverified_after_genesis( void ) {
454463 fd_bank_slot_set ( test_bank , 0UL );
455464
456465 /* Create a BPF loader account */
457- create_test_account ( & test_program_pubkey ,
466+ create_test_account ( & test_xid ,
467+ & test_program_pubkey ,
458468 & fd_solana_bpf_loader_program_id ,
459469 valid_program_data ,
460470 valid_program_data_sz ,
@@ -498,7 +508,8 @@ test_program_upgraded_with_larger_programdata( void ) {
498508 fd_bank_slot_set ( test_bank , 0UL );
499509
500510 /* Create a BPF loader account */
501- create_test_account ( & test_program_pubkey ,
511+ create_test_account ( & test_xid ,
512+ & test_program_pubkey ,
502513 & fd_solana_bpf_loader_program_id ,
503514 valid_program_data ,
504515 valid_program_data_sz ,
@@ -572,7 +583,8 @@ test_program_rooted( void ) {
572583 fd_bank_slot_set ( test_bank , 0UL );
573584
574585 /* Create a BPF loader account */
575- create_test_account ( & test_program_pubkey ,
586+ create_test_account ( & test_xid ,
587+ & test_program_pubkey ,
576588 & fd_solana_bpf_loader_program_id ,
577589 valid_program_data ,
578590 valid_program_data_sz ,
@@ -603,6 +615,122 @@ test_program_rooted( void ) {
603615 FD_TEST ( fd_progcache_peek ( test_cache , fd_funk_last_publish ( test_cache -> funk ), & test_program_pubkey )== NULL );
604616}
605617
618+ /* Test 13: Epoch boundary */
619+
620+ static int
621+ find_rec ( fd_progcache_t * cache ,
622+ fd_funk_txn_xid_t const * xid ,
623+ fd_pubkey_t const * pubkey ,
624+ fd_progcache_rec_t const * expected ) {
625+ fd_funk_rec_key_t id ; memcpy ( & id , pubkey , 32UL );
626+ fd_funk_rec_query_t query [1 ];
627+ fd_funk_rec_t const * rec = fd_funk_rec_query_try_global ( cache -> funk , xid , & id , NULL , query );
628+ if ( !rec ) return 0 ;
629+ if ( fd_funk_rec_query_test ( query ) ) return 0 ;
630+ return fd_funk_txn_xid_eq ( rec -> pair .xid , xid ) && fd_wksp_laddr_fast ( cache -> funk -> wksp , rec -> val_gaddr )== expected ;
631+ }
632+
633+ static void
634+ bank_slot_set ( fd_bank_t * bank , ulong slot ) {
635+ fd_bank_slot_set ( bank , slot );
636+ fd_bank_epoch_set ( bank , slot / 432000UL );
637+ }
638+
639+ static void
640+ test_epoch_boundary ( void ) {
641+ FD_LOG_INFO (( "Testing: Epoch boundary" ));
642+
643+ /* Fork graph:
644+ A -> B -> C # -> D -> G
645+ # -> H
646+ -> E # -> F
647+
648+ '#' marks an epoch boundary
649+ 'A' is the last published (root)
650+ Program is created at 'B'
651+ Feature activations at 'C' and 'E' respectively */
652+
653+ fd_funk_txn_xid_t const fork_a = { .ul = { 863997UL , 1UL } };
654+ fd_funk_txn_xid_t const fork_b = { .ul = { 863998UL , 2UL } };
655+ fd_funk_txn_xid_t const fork_c = { .ul = { 863999UL , 3UL } };
656+ fd_funk_txn_xid_t const fork_d = { .ul = { 864000UL , 4UL } };
657+ fd_funk_txn_xid_t const fork_e = { .ul = { 863999UL , 5UL } };
658+ fd_funk_txn_xid_t const fork_f = { .ul = { 864001UL , 6UL } };
659+ fd_funk_txn_xid_t const fork_g = { .ul = { 864002UL , 7UL } };
660+ fd_funk_txn_xid_t const fork_h = { .ul = { 864003UL , 8UL } };
661+
662+ fd_funk_txn_prepare ( test_accdb , fd_funk_last_publish ( test_accdb ), & fork_a );
663+ fd_funk_txn_prepare ( test_cache -> funk , fd_funk_last_publish ( test_cache -> funk ), & fork_a );
664+ fd_funk_txn_publish ( test_accdb , & fork_a );
665+ fd_funk_txn_publish ( test_cache -> funk , & fork_a );
666+
667+ fd_funk_txn_prepare ( test_accdb , & fork_a , & fork_b );
668+ fd_funk_txn_prepare ( test_cache -> funk , & fork_a , & fork_b );
669+ create_test_account ( & fork_b ,
670+ & test_program_pubkey ,
671+ & fd_solana_bpf_loader_program_id ,
672+ valid_program_data ,
673+ valid_program_data_sz ,
674+ 1 );
675+
676+ fd_funk_txn_prepare ( test_accdb , & fork_b , & fork_c );
677+ fd_funk_txn_prepare ( test_cache -> funk , & fork_b , & fork_c );
678+ fd_funk_txn_prepare ( test_accdb , & fork_b , & fork_e );
679+ fd_funk_txn_prepare ( test_cache -> funk , & fork_b , & fork_e );
680+ fd_funk_txn_prepare ( test_accdb , & fork_c , & fork_d );
681+ fd_funk_txn_prepare ( test_cache -> funk , & fork_c , & fork_d );
682+ fd_funk_txn_prepare ( test_accdb , & fork_e , & fork_f );
683+ fd_funk_txn_prepare ( test_cache -> funk , & fork_e , & fork_f );
684+ fd_funk_txn_prepare ( test_accdb , & fork_d , & fork_g );
685+ fd_funk_txn_prepare ( test_cache -> funk , & fork_d , & fork_g );
686+ fd_funk_txn_prepare ( test_accdb , & fork_d , & fork_h );
687+ fd_funk_txn_prepare ( test_cache -> funk , & fork_d , & fork_h );
688+
689+ /* Pull program from fork G, should create cache entry at D */
690+ FD_TEST ( !fd_progcache_peek ( test_cache , & fork_d , & test_program_pubkey ) );
691+ bank_slot_set ( test_bank , fork_g .ul [0 ] );
692+ FD_TEST ( fd_bank_epoch_get ( test_bank )== 2UL );
693+ fd_progcache_rec_t const * rec_d = fd_progcache_pull ( test_cache , test_accdb , & fork_g , & test_program_pubkey , 1UL , test_bank );
694+ FD_TEST ( find_rec ( test_cache , & fork_d , & test_program_pubkey , rec_d ) );
695+ FD_TEST ( fd_progcache_peek ( test_cache , & fork_d , & test_program_pubkey )== rec_d );
696+
697+ /* Pull program from fork H, should reuse existing cache entry */
698+ FD_TEST ( fd_progcache_peek ( test_cache , & fork_h , & test_program_pubkey )== rec_d );
699+
700+ /* Pull program from fork F, should create cache entry at F */
701+ FD_TEST ( !fd_progcache_peek ( test_cache , & fork_f , & test_program_pubkey ) );
702+ bank_slot_set ( test_bank , fork_f .ul [0 ] );
703+ FD_TEST ( fd_bank_epoch_get ( test_bank )== 2UL );
704+ fd_progcache_rec_t const * rec_f = fd_progcache_pull ( test_cache , test_accdb , & fork_f , & test_program_pubkey , 1UL , test_bank );
705+ FD_TEST ( find_rec ( test_cache , & fork_f , & test_program_pubkey , rec_f ) );
706+ FD_TEST ( fd_progcache_peek ( test_cache , & fork_f , & test_program_pubkey )== rec_f );
707+
708+ /* Pull program from fork D, should reuse existing cache entry */
709+ FD_TEST ( fd_progcache_peek ( test_cache , & fork_d , & test_program_pubkey )== rec_d );
710+
711+ /* Pull program from fork E, should create cache entry at B */
712+ FD_TEST ( !fd_progcache_peek ( test_cache , & fork_e , & test_program_pubkey ) );
713+ bank_slot_set ( test_bank , fork_e .ul [0 ] );
714+ FD_TEST ( fd_bank_epoch_get ( test_bank )== 1UL );
715+ fd_progcache_rec_t const * rec_b = fd_progcache_pull ( test_cache , test_accdb , & fork_e , & test_program_pubkey , 1UL , test_bank );
716+ FD_TEST ( find_rec ( test_cache , & fork_b , & test_program_pubkey , rec_b ) );
717+ FD_TEST ( fd_progcache_peek ( test_cache , & fork_e , & test_program_pubkey )== rec_b );
718+
719+ /* Root fork B */
720+ fd_funk_txn_publish ( test_accdb , & fork_b );
721+ fd_funk_txn_publish ( test_cache -> funk , & fork_b );
722+
723+ /* Pull program from fork C, should reuse existing cache entry */
724+ FD_TEST ( fd_progcache_peek ( test_cache , & fork_c , & test_program_pubkey )== rec_b );
725+
726+ /* Root fork D */
727+ fd_funk_txn_publish ( test_accdb , & fork_d );
728+ fd_funk_txn_publish ( test_cache -> funk , & fork_d );
729+
730+ /* Pull program from fork G, should reuse existing cache entry */
731+ FD_TEST ( fd_progcache_peek ( test_cache , & fork_g , & test_program_pubkey )== rec_d );
732+ }
733+
606734int
607735main ( int argc ,
608736 char * * argv ) {
@@ -674,6 +802,7 @@ main( int argc,
674802 test_valid_genesis_program_reverified_after_genesis ();
675803 test_program_upgraded_with_larger_programdata ();
676804 test_program_rooted ();
805+ test_epoch_boundary ();
677806
678807 test_teardown ();
679808
0 commit comments