Line data Source code
1 : #include "fd_features.h"
2 : #include "../runtime/fd_system_ids.h"
3 : #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h"
4 :
5 : FD_STATIC_ASSERT( sizeof ( fd_feature_t )==9UL, layout );
6 : FD_STATIC_ASSERT( offsetof( fd_feature_t, is_active )==0UL, layout );
7 : FD_STATIC_ASSERT( offsetof( fd_feature_t, activation_slot )==1UL, layout );
8 :
9 : fd_feature_t *
10 : fd_feature_decode( fd_feature_t * feature,
11 : uchar const * data,
12 438 : ulong data_sz ) {
13 438 : if( FD_UNLIKELY( data_sz < sizeof(fd_feature_t) ) ) return NULL;
14 435 : *feature = FD_LOAD( fd_feature_t, data );
15 435 : if( FD_UNLIKELY( feature->is_active>1 ) ) return NULL;
16 435 : return feature;
17 435 : }
18 :
19 : void
20 21 : fd_features_enable_all( fd_features_t * f ) {
21 21 : for( fd_feature_id_t const * id = fd_feature_iter_init();
22 6216 : !fd_feature_iter_done( id );
23 6195 : id = fd_feature_iter_next( id ) ) {
24 6195 : fd_features_set( f, id, 0UL );
25 6195 : }
26 21 : }
27 :
28 : void
29 7281 : fd_features_disable_all( fd_features_t * f ) {
30 7281 : for( fd_feature_id_t const * id = fd_feature_iter_init();
31 2155176 : !fd_feature_iter_done( id );
32 2147895 : id = fd_feature_iter_next( id ) ) {
33 2147895 : fd_features_set( f, id, FD_FEATURE_DISABLED );
34 2147895 : }
35 7281 : }
36 :
37 : void
38 4224 : fd_features_enable_cleaned_up( fd_features_t * f ) {
39 4224 : for( fd_feature_id_t const * id = fd_feature_iter_init();
40 1250304 : !fd_feature_iter_done( id );
41 1246080 : id = fd_feature_iter_next( id ) ) {
42 1246080 : if( FD_LIKELY( id->cleaned_up ) ) {
43 916608 : fd_features_set( f, id, 0UL );
44 916608 : } else {
45 329472 : fd_features_set( f, id, FD_FEATURE_DISABLED );
46 329472 : }
47 1246080 : }
48 4224 : }
49 :
50 : static uchar one_off_forced[ FD_FEATURE_ID_CNT ];
51 :
52 : void
53 18 : fd_features_enable_one_offs( fd_features_t * f, char const * * one_offs, uint one_offs_cnt, ulong slot ) {
54 18 : uchar pubkey[32];
55 72 : for( uint i=0U; i<one_offs_cnt; i++ ) {
56 54 : fd_base58_decode_32( one_offs[i], pubkey );
57 54 : for( fd_feature_id_t const * id = fd_feature_iter_init();
58 13230 : !fd_feature_iter_done( id );
59 13230 : id = fd_feature_iter_next( id ) ) {
60 13230 : if( !memcmp( &id->id, pubkey, sizeof(fd_pubkey_t) ) ) {
61 54 : fd_features_set( f, id, slot );
62 54 : one_off_forced[ id->index ] = (uchar)( slot!=FD_FEATURE_DISABLED );
63 54 : break;
64 54 : }
65 13230 : }
66 54 : }
67 18 : }
68 :
69 : static void
70 : fd_feature_restore( fd_bank_t * bank,
71 : fd_accdb_t * accdb,
72 : fd_feature_id_t const * id,
73 101775 : fd_pubkey_t const * addr ) {
74 :
75 101775 : fd_features_t * features = &bank->f.features;
76 101775 : fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
77 101775 : ulong slot = bank->f.slot;
78 :
79 101775 : if( FD_UNLIKELY( id->cleaned_up ) ) {
80 74865 : fd_features_set( features, id, 0UL );
81 74865 : return;
82 74865 : }
83 :
84 26910 : fd_features_set( features, id, FD_FEATURE_DISABLED );
85 :
86 : /* Skip reverted features */
87 26910 : if( FD_UNLIKELY( id->reverted ) ) return;
88 :
89 21045 : fd_acc_t acc = fd_accdb_read_one( accdb, bank->accdb_fork_id, addr->uc );
90 21045 : if( FD_UNLIKELY( !acc.lamports ) ) {
91 20766 : fd_accdb_unread_one( accdb, &acc );
92 20766 : return;
93 20766 : }
94 :
95 : /* Skip accounts that are not owned by the feature program
96 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L42-L44 */
97 279 : if( FD_UNLIKELY( memcmp( acc.owner, fd_solana_feature_program_id.uc, 32UL ) ) ) {
98 6 : fd_accdb_unread_one( accdb, &acc );
99 6 : return;
100 6 : }
101 :
102 : /* Account data size must be >= FD_FEATURE_SIZEOF (9 bytes)
103 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L45-L47 */
104 273 : if( FD_UNLIKELY( acc.data_len<sizeof(fd_feature_t) ) ) {
105 6 : fd_accdb_unread_one( accdb, &acc );
106 6 : return;
107 6 : }
108 :
109 : /* Deserialize the feature account data
110 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L48-L50 */
111 267 : fd_feature_t feature[1];
112 267 : if( FD_UNLIKELY( !fd_feature_decode( feature, acc.data, acc.data_len ) ) ) {
113 0 : fd_accdb_unread_one( accdb, &acc );
114 0 : return;
115 0 : }
116 267 : fd_accdb_unread_one( accdb, &acc );
117 :
118 267 : FD_BASE58_ENCODE_32_BYTES( addr->uc, addr_b58 );
119 267 : if( feature->is_active ) {
120 228 : FD_LOG_DEBUG(( "feature %s activated at slot %lu", addr_b58, feature->activation_slot ));
121 228 : fd_features_set( features, id, feature->activation_slot );
122 228 : } else if( fd_slot_to_epoch( epoch_schedule, slot, NULL )!=fd_slot_to_epoch( epoch_schedule, slot+1UL, NULL ) ) {
123 39 : ulong activation_slot = slot+1UL;
124 39 : FD_LOG_DEBUG(( "feature %s pending, pre-populating activation at slot %lu", addr_b58, activation_slot ));
125 39 : fd_features_set( features, id, activation_slot );
126 39 : } else {
127 0 : FD_LOG_DEBUG(( "feature %s not activated at slot %lu", addr_b58, feature->activation_slot ));
128 0 : }
129 267 : }
130 :
131 : void
132 : fd_features_restore( fd_bank_t * bank,
133 345 : fd_accdb_t * accdb ) {
134 345 : for( fd_feature_id_t const * id = fd_feature_iter_init();
135 102120 : !fd_feature_iter_done( id );
136 101775 : id = fd_feature_iter_next( id ) ) {
137 101775 : fd_feature_restore( bank, accdb, id, &id->id );
138 101775 : if( FD_UNLIKELY( one_off_forced[ id->index ] ) ) fd_features_set( &bank->f.features, id, 0UL );
139 101775 : }
140 345 : }
|