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 7841 : ulong data_sz ) {
13 7841 : if( FD_UNLIKELY( data_sz < sizeof(fd_feature_t) ) ) return NULL;
14 7841 : *feature = FD_LOAD( fd_feature_t, data );
15 7841 : if( FD_UNLIKELY( feature->is_active>1 ) ) return NULL;
16 7841 : return feature;
17 7841 : }
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 66906 : fd_features_disable_all( fd_features_t * f ) {
30 66906 : for( fd_feature_id_t const * id = fd_feature_iter_init();
31 20212296 : !fd_feature_iter_done( id );
32 20145390 : id = fd_feature_iter_next( id ) ) {
33 20145390 : fd_features_set( f, id, FD_FEATURE_DISABLED );
34 20145390 : }
35 66906 : }
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 : if( FD_UNLIKELY( !fd_base58_decode_32( one_offs[i], pubkey ) ) )
57 0 : FD_LOG_ERR(( "Invalid feature key \"%s\" in [tiles.replay].enable_features", one_offs[i] ));
58 0 : fd_feature_id_t const * id = fd_feature_iter_init();
59 0 : for( ; !fd_feature_iter_done( id );
60 0 : id = fd_feature_iter_next( id ) ) {
61 0 : if( !memcmp( &id->id, pubkey, sizeof(fd_pubkey_t) ) ) {
62 0 : fd_features_set( f, id, slot );
63 0 : one_off_forced[ id->index ] = (uchar)( slot!=FD_FEATURE_DISABLED );
64 0 : break;
65 0 : }
66 0 : }
67 0 : if( FD_UNLIKELY( fd_feature_iter_done( id ) ) )
68 0 : FD_LOG_ERR(( "Unknown feature key \"%s\" in [tiles.replay].enable_features", one_offs[i] ));
69 0 : }
70 0 : }
71 :
72 : static void
73 : fd_feature_restore( fd_features_t * features,
74 : fd_accdb_t * accdb,
75 : fd_accdb_fork_id_t fork_id,
76 : ulong slot,
77 : fd_epoch_schedule_t const * epoch_schedule,
78 9300 : fd_feature_id_t const * id ) {
79 :
80 9300 : if( FD_UNLIKELY( id->cleaned_up ) ) {
81 6630 : fd_features_set( features, id, 0UL );
82 6630 : return;
83 6630 : }
84 :
85 2670 : fd_features_set( features, id, FD_FEATURE_DISABLED );
86 :
87 : /* Skip reverted features */
88 2670 : if( FD_UNLIKELY( id->reverted ) ) return;
89 :
90 2130 : fd_acc_t acc = fd_accdb_read_one( accdb, fork_id, id->id.uc );
91 2130 : if( FD_UNLIKELY( !acc.lamports ) ) {
92 1266 : fd_accdb_unread_one( accdb, &acc );
93 1266 : return;
94 1266 : }
95 :
96 : /* Skip accounts that are not owned by the feature program
97 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L42-L44 */
98 864 : if( FD_UNLIKELY( memcmp( acc.owner, fd_solana_feature_program_id.uc, 32UL ) ) ) {
99 0 : fd_accdb_unread_one( accdb, &acc );
100 0 : return;
101 0 : }
102 :
103 : /* Account data size must be >= FD_FEATURE_SIZEOF (9 bytes)
104 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L45-L47 */
105 864 : if( FD_UNLIKELY( acc.data_len<sizeof(fd_feature_t) ) ) {
106 0 : fd_accdb_unread_one( accdb, &acc );
107 0 : return;
108 0 : }
109 :
110 : /* Deserialize the feature account data
111 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L48-L50 */
112 864 : fd_feature_t feature[1];
113 864 : if( FD_UNLIKELY( !fd_feature_decode( feature, acc.data, acc.data_len ) ) ) {
114 0 : fd_accdb_unread_one( accdb, &acc );
115 0 : return;
116 0 : }
117 864 : fd_accdb_unread_one( accdb, &acc );
118 :
119 864 : FD_BASE58_ENCODE_32_BYTES( id->id.uc, addr_b58 );
120 864 : if( feature->is_active ) {
121 864 : FD_LOG_DEBUG(( "feature %s activated at slot %lu", addr_b58, feature->activation_slot ));
122 864 : fd_features_set( features, id, feature->activation_slot );
123 864 : } else if( fd_slot_to_epoch( epoch_schedule, slot, NULL )!=fd_slot_to_epoch( epoch_schedule, slot+1UL, NULL ) ) {
124 0 : ulong activation_slot = slot+1UL;
125 0 : FD_LOG_DEBUG(( "feature %s pending, pre-populating activation at slot %lu", addr_b58, activation_slot ));
126 0 : fd_features_set( features, id, activation_slot );
127 0 : } else {
128 0 : FD_LOG_DEBUG(( "feature %s not activated at slot %lu", addr_b58, feature->activation_slot ));
129 0 : }
130 864 : }
131 :
132 : void
133 : fd_features_restore_chunk( fd_features_t * features,
134 : fd_accdb_t * accdb,
135 : fd_accdb_fork_id_t fork_id,
136 : ulong slot,
137 : fd_epoch_schedule_t const * epoch_schedule,
138 : ulong chunk_idx,
139 30 : ulong chunk_cnt ) {
140 30 : FD_TEST( chunk_cnt>0UL );
141 30 : FD_TEST( chunk_idx<chunk_cnt );
142 :
143 30 : ulong begin = chunk_idx * FD_FEATURE_ID_CNT / chunk_cnt;
144 30 : ulong end = (chunk_idx+1) * FD_FEATURE_ID_CNT / chunk_cnt;
145 :
146 9330 : for( fd_feature_id_t const * id=ids+begin; id<ids+end; id++ ) {
147 9300 : fd_feature_restore( features, accdb, fork_id, slot, epoch_schedule, id );
148 9300 : if( FD_UNLIKELY( one_off_forced[ id->index ] ) ) fd_features_set( features, id, 0UL );
149 9300 : }
150 30 : }
151 :
152 : void
153 : fd_features_restore( fd_features_t * features,
154 : fd_accdb_t * accdb,
155 : fd_accdb_fork_id_t fork_id,
156 : ulong slot,
157 30 : fd_epoch_schedule_t const * epoch_schedule ) {
158 30 : fd_features_restore_chunk( features, accdb, fork_id, slot, epoch_schedule, 0UL, 1UL );
159 30 : }
|