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