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 9001 : ulong data_sz ) {
13 9001 : if( FD_UNLIKELY( data_sz < sizeof(fd_feature_t) ) ) return NULL;
14 9001 : *feature = FD_LOAD( fd_feature_t, data );
15 9001 : if( FD_UNLIKELY( feature->is_active>1 ) ) return NULL;
16 9001 : return feature;
17 9001 : }
18 :
19 : void
20 0 : fd_features_enable_all( fd_features_t * f ) {
21 0 : for( fd_feature_id_t const * id = fd_feature_iter_init();
22 0 : !fd_feature_iter_done( id );
23 0 : id = fd_feature_iter_next( id ) ) {
24 0 : fd_features_set( f, id, 0UL );
25 0 : }
26 0 : }
27 :
28 : void
29 67017 : fd_features_disable_all( fd_features_t * f ) {
30 67017 : for( fd_feature_id_t const * id = fd_feature_iter_init();
31 19869873 : !fd_feature_iter_done( id );
32 19802856 : id = fd_feature_iter_next( id ) ) {
33 19802856 : fd_features_set( f, id, FD_FEATURE_DISABLED );
34 19802856 : }
35 67017 : }
36 :
37 : void
38 0 : fd_features_enable_cleaned_up( fd_features_t * f ) {
39 0 : for( fd_feature_id_t const * id = fd_feature_iter_init();
40 0 : !fd_feature_iter_done( id );
41 0 : id = fd_feature_iter_next( id ) ) {
42 0 : if( FD_LIKELY( id->cleaned_up ) ) {
43 0 : fd_features_set( f, id, 0UL );
44 0 : } else {
45 0 : fd_features_set( f, id, FD_FEATURE_DISABLED );
46 0 : }
47 0 : }
48 0 : }
49 :
50 : static uchar one_off_forced[ FD_FEATURE_ID_CNT ];
51 :
52 : void
53 0 : fd_features_enable_one_offs( fd_features_t * f, char const * * one_offs, uint one_offs_cnt, ulong slot ) {
54 0 : uchar pubkey[32];
55 0 : for( uint i=0U; i<one_offs_cnt; i++ ) {
56 0 : fd_base58_decode_32( one_offs[i], pubkey );
57 0 : for( fd_feature_id_t const * id = fd_feature_iter_init();
58 0 : !fd_feature_iter_done( id );
59 0 : id = fd_feature_iter_next( id ) ) {
60 0 : if( !memcmp( &id->id, pubkey, sizeof(fd_pubkey_t) ) ) {
61 0 : fd_features_set( f, id, slot );
62 0 : one_off_forced[ id->index ] = (uchar)( slot!=FD_FEATURE_DISABLED );
63 0 : break;
64 0 : }
65 0 : }
66 0 : }
67 0 : }
68 :
69 : static void
70 : fd_feature_restore( fd_features_t * features,
71 : fd_accdb_t * accdb,
72 : fd_accdb_fork_id_t fork_id,
73 : ulong slot,
74 : fd_epoch_schedule_t const * epoch_schedule,
75 10234 : fd_feature_id_t const * id ) {
76 :
77 10234 : if( FD_UNLIKELY( id->cleaned_up ) ) {
78 7378 : fd_features_set( features, id, 0UL );
79 7378 : return;
80 7378 : }
81 :
82 2856 : fd_features_set( features, id, FD_FEATURE_DISABLED );
83 :
84 : /* Skip reverted features */
85 2856 : if( FD_UNLIKELY( id->reverted ) ) return;
86 :
87 2244 : fd_acc_t acc = fd_accdb_read_one( accdb, fork_id, id->id.uc );
88 2244 : if( FD_UNLIKELY( !acc.lamports ) ) {
89 1190 : fd_accdb_unread_one( accdb, &acc );
90 1190 : return;
91 1190 : }
92 :
93 : /* Skip accounts that are not owned by the feature program
94 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L42-L44 */
95 1054 : if( FD_UNLIKELY( memcmp( acc.owner, fd_solana_feature_program_id.uc, 32UL ) ) ) {
96 0 : fd_accdb_unread_one( accdb, &acc );
97 0 : return;
98 0 : }
99 :
100 : /* Account data size must be >= FD_FEATURE_SIZEOF (9 bytes)
101 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L45-L47 */
102 1054 : if( FD_UNLIKELY( acc.data_len<sizeof(fd_feature_t) ) ) {
103 0 : fd_accdb_unread_one( accdb, &acc );
104 0 : return;
105 0 : }
106 :
107 : /* Deserialize the feature account data
108 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L48-L50 */
109 1054 : fd_feature_t feature[1];
110 1054 : if( FD_UNLIKELY( !fd_feature_decode( feature, acc.data, acc.data_len ) ) ) {
111 0 : fd_accdb_unread_one( accdb, &acc );
112 0 : return;
113 0 : }
114 1054 : fd_accdb_unread_one( accdb, &acc );
115 :
116 1054 : FD_BASE58_ENCODE_32_BYTES( id->id.uc, addr_b58 );
117 1054 : if( feature->is_active ) {
118 1054 : FD_LOG_DEBUG(( "feature %s activated at slot %lu", addr_b58, feature->activation_slot ));
119 1054 : fd_features_set( features, id, feature->activation_slot );
120 1054 : } else if( fd_slot_to_epoch( epoch_schedule, slot, NULL )!=fd_slot_to_epoch( epoch_schedule, slot+1UL, NULL ) ) {
121 0 : ulong activation_slot = slot+1UL;
122 0 : FD_LOG_DEBUG(( "feature %s pending, pre-populating activation at slot %lu", addr_b58, activation_slot ));
123 0 : fd_features_set( features, id, activation_slot );
124 0 : } else {
125 0 : FD_LOG_DEBUG(( "feature %s not activated at slot %lu", addr_b58, feature->activation_slot ));
126 0 : }
127 1054 : }
128 :
129 : void
130 : fd_features_restore_chunk( fd_features_t * features,
131 : fd_accdb_t * accdb,
132 : fd_accdb_fork_id_t fork_id,
133 : ulong slot,
134 : fd_epoch_schedule_t const * epoch_schedule,
135 : ulong chunk_idx,
136 34 : ulong chunk_cnt ) {
137 34 : FD_TEST( chunk_cnt>0UL );
138 34 : FD_TEST( chunk_idx<chunk_cnt );
139 :
140 34 : ulong begin = chunk_idx * FD_FEATURE_ID_CNT / chunk_cnt;
141 34 : ulong end = (chunk_idx+1) * FD_FEATURE_ID_CNT / chunk_cnt;
142 :
143 10268 : for( fd_feature_id_t const * id=ids+begin; id<ids+end; id++ ) {
144 10234 : fd_feature_restore( features, accdb, fork_id, slot, epoch_schedule, id );
145 10234 : if( FD_UNLIKELY( one_off_forced[ id->index ] ) ) fd_features_set( features, id, 0UL );
146 10234 : }
147 34 : }
148 :
149 : void
150 : fd_features_restore( fd_features_t * features,
151 : fd_accdb_t * accdb,
152 : fd_accdb_fork_id_t fork_id,
153 : ulong slot,
154 34 : fd_epoch_schedule_t const * epoch_schedule ) {
155 34 : fd_features_restore_chunk( features, accdb, fork_id, slot, epoch_schedule, 0UL, 1UL );
156 34 : }
|