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 0 : ulong data_sz ) {
15 0 : if( FD_UNLIKELY( data_sz < sizeof(fd_feature_t) ) ) return NULL;
16 0 : *feature = FD_LOAD( fd_feature_t, data );
17 0 : if( FD_UNLIKELY( feature->is_active>1 ) ) return NULL;
18 0 : return feature;
19 0 : }
20 :
21 : void
22 0 : fd_features_enable_all( fd_features_t * f ) {
23 0 : for( fd_feature_id_t const * id = fd_feature_iter_init();
24 0 : !fd_feature_iter_done( id );
25 0 : id = fd_feature_iter_next( id ) ) {
26 0 : fd_features_set( f, id, 0UL );
27 0 : }
28 0 : }
29 :
30 : void
31 31056 : fd_features_disable_all( fd_features_t * f ) {
32 31056 : for( fd_feature_id_t const * id = fd_feature_iter_init();
33 8246580 : !fd_feature_iter_done( id );
34 8215524 : id = fd_feature_iter_next( id ) ) {
35 8215524 : fd_features_set( f, id, FD_FEATURE_DISABLED );
36 8215524 : }
37 31056 : }
38 :
39 : void
40 0 : fd_features_enable_cleaned_up( fd_features_t * f ) {
41 0 : for( fd_feature_id_t const * id = fd_feature_iter_init();
42 0 : !fd_feature_iter_done( id );
43 0 : id = fd_feature_iter_next( id ) ) {
44 0 : if( FD_LIKELY( id->cleaned_up ) ) {
45 0 : fd_features_set( f, id, 0UL );
46 0 : } else {
47 0 : fd_features_set( f, id, FD_FEATURE_DISABLED );
48 0 : }
49 0 : }
50 0 : }
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 : break;
63 0 : }
64 0 : }
65 0 : }
66 0 : }
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 1060 : fd_pubkey_t const * addr ) {
74 :
75 1060 : fd_features_t * features = fd_bank_features_modify( bank );
76 1060 : fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( bank );
77 1060 : ulong slot = fd_bank_slot_get( bank );
78 :
79 : /* Skip reverted features */
80 1060 : if( FD_UNLIKELY( id->reverted ) ) return;
81 :
82 1016 : fd_accdb_ro_t ro[1];
83 1016 : if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, ro, xid, addr ) ) ) {
84 1016 : return;
85 1016 : }
86 :
87 : /* Skip accounts that are not owned by the feature program
88 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L42-L44 */
89 0 : if( FD_UNLIKELY( memcmp( fd_accdb_ref_owner( ro ), fd_solana_feature_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
90 0 : fd_accdb_close_ro( accdb, ro );
91 0 : return;
92 0 : }
93 :
94 : /* Account data size must be >= FD_FEATURE_SIZEOF (9 bytes)
95 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L45-L47 */
96 0 : if( FD_UNLIKELY( fd_accdb_ref_data_sz( ro ) < sizeof(fd_feature_t) ) ) {
97 0 : fd_accdb_close_ro( accdb, ro );
98 0 : return;
99 0 : }
100 :
101 : /* Deserialize the feature account data
102 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L48-L50 */
103 0 : fd_feature_t feature[1];
104 0 : if( FD_UNLIKELY( !fd_feature_decode(
105 0 : feature,
106 0 : fd_accdb_ref_data_const( ro ),
107 0 : fd_accdb_ref_data_sz ( ro ) ) ) ) {
108 0 : fd_accdb_close_ro( accdb, ro );
109 0 : return;
110 0 : }
111 0 : fd_accdb_close_ro( accdb, ro );
112 :
113 0 : FD_BASE58_ENCODE_32_BYTES( addr->uc, addr_b58 );
114 0 : if( feature->is_active ) {
115 0 : FD_LOG_DEBUG(( "feature %s activated at slot %lu", addr_b58, feature->activation_slot ));
116 0 : fd_features_set( features, id, feature->activation_slot );
117 0 : } else if( fd_slot_to_epoch( epoch_schedule, slot, NULL )!=fd_slot_to_epoch( epoch_schedule, slot+1UL, NULL ) ) {
118 0 : ulong activation_slot = slot+1UL;
119 0 : FD_LOG_DEBUG(( "feature %s pending, pre-populating activation at slot %lu", addr_b58, activation_slot ));
120 0 : fd_features_set( features, id, activation_slot );
121 0 : } else {
122 0 : FD_LOG_DEBUG(( "feature %s not activated at slot %lu", addr_b58, feature->activation_slot ));
123 0 : }
124 0 : }
125 :
126 : void
127 : fd_features_restore( fd_bank_t * bank,
128 : fd_accdb_user_t * accdb,
129 4 : fd_funk_txn_xid_t const * xid ) {
130 :
131 4 : for( fd_feature_id_t const * id = fd_feature_iter_init();
132 1064 : !fd_feature_iter_done( id );
133 1060 : id = fd_feature_iter_next( id ) ) {
134 1060 : fd_feature_restore( bank, accdb, xid, id, &id->id );
135 1060 : }
136 4 : }
|