Line data Source code
1 : #include "fd_feature_snoop.h" 2 : #include "../runtime/fd_system_ids.h" 3 : #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h" 4 : 5 : void 6 : fd_feature_snoop_account( fd_feature_snoop_t * snoop, 7 : fd_pubkey_t const * pubkey, 8 : ulong lamports, 9 : uchar const * owner, 10 : uchar const * data, 11 0 : ulong data_len ) { 12 0 : if( FD_LIKELY( !lamports ) ) return; 13 : 14 : /* Only feature-program-owned accounts carry feature activation state. 15 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L42-L44 */ 16 0 : if( FD_LIKELY( memcmp( owner, fd_solana_feature_program_id.uc, 32UL ) ) ) return; 17 : 18 : /* Resolve the account address to a known feature id (by 8-byte prefix, 19 : then confirm the full pubkey). */ 20 0 : fd_feature_id_t const * id = fd_feature_id_query( fd_ulong_load_8( pubkey->uc ) ); 21 0 : if( FD_UNLIKELY( !id || !fd_pubkey_eq( pubkey, &id->id ) ) ) return; 22 : 23 : /* Account data size must be >= FD_FEATURE_SIZEOF (9 bytes). 24 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L45-L47 */ 25 0 : fd_feature_t feature[1]; 26 0 : if( FD_UNLIKELY( data_len<sizeof(fd_feature_t) || !fd_feature_decode( feature, data, data_len ) ) ) return; 27 : 28 0 : snoop->present [ id->index ] = 1; 29 0 : snoop->is_active [ id->index ] = feature->is_active; 30 0 : snoop->activation_slot[ id->index ] = feature->activation_slot; 31 0 : } 32 : 33 : void 34 : fd_feature_snoop_finalize( fd_features_t * features, 35 : ulong slot, 36 : fd_epoch_schedule_t const * epoch_schedule, 37 0 : fd_feature_snoop_t const * snoop ) { 38 : 39 : /* Mirror fd_feature_restore (per id), reading the snooped account state 40 : instead of the accounts database. */ 41 0 : int at_epoch_boundary = fd_slot_to_epoch( epoch_schedule, slot, NULL )!=fd_slot_to_epoch( epoch_schedule, slot+1UL, NULL ); 42 : 43 0 : for( fd_feature_id_t const * id = fd_feature_iter_init(); 44 0 : !fd_feature_iter_done( id ); 45 0 : id = fd_feature_iter_next( id ) ) { 46 0 : if( FD_UNLIKELY( id->cleaned_up ) ) { fd_features_set( features, id, 0UL ); continue; } 47 : 48 0 : fd_features_set( features, id, FD_FEATURE_DISABLED ); 49 : 50 : /* Skip reverted features */ 51 0 : if( FD_UNLIKELY( id->reverted ) ) continue; 52 : 53 : /* No feature account observed in the load stream: stays disabled. */ 54 0 : if( !snoop->present[ id->index ] ) continue; 55 : 56 0 : if( snoop->is_active[ id->index ] ) { 57 0 : fd_features_set( features, id, snoop->activation_slot[ id->index ] ); 58 0 : } else if( at_epoch_boundary ) { 59 : /* Pending feature at the last slot before an epoch boundary: 60 : pre-populate activation at slot+1. */ 61 0 : fd_features_set( features, id, slot+1UL ); 62 0 : } 63 0 : } 64 0 : }