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 372 : ulong data_sz ) {
13 372 : if( FD_UNLIKELY( data_sz < sizeof(fd_feature_t) ) ) return NULL;
14 369 : *feature = FD_LOAD( fd_feature_t, data );
15 369 : if( FD_UNLIKELY( feature->is_active>1 ) ) return NULL;
16 369 : return feature;
17 369 : }
18 :
19 : void
20 15 : fd_features_enable_all( fd_features_t * f ) {
21 15 : for( fd_feature_id_t const * id = fd_feature_iter_init();
22 4170 : !fd_feature_iter_done( id );
23 4155 : id = fd_feature_iter_next( id ) ) {
24 4155 : fd_features_set( f, id, 0UL );
25 4155 : }
26 15 : }
27 :
28 : void
29 6924 : fd_features_disable_all( fd_features_t * f ) {
30 6924 : for( fd_feature_id_t const * id = fd_feature_iter_init();
31 1924872 : !fd_feature_iter_done( id );
32 1917948 : id = fd_feature_iter_next( id ) ) {
33 1917948 : fd_features_set( f, id, FD_FEATURE_DISABLED );
34 1917948 : }
35 6924 : }
36 :
37 : void
38 3747 : fd_features_enable_cleaned_up( fd_features_t * f ) {
39 3747 : for( fd_feature_id_t const * id = fd_feature_iter_init();
40 1041666 : !fd_feature_iter_done( id );
41 1037919 : id = fd_feature_iter_next( id ) ) {
42 1037919 : if( FD_LIKELY( id->cleaned_up ) ) {
43 771882 : fd_features_set( f, id, 0UL );
44 771882 : } else {
45 266037 : fd_features_set( f, id, FD_FEATURE_DISABLED );
46 266037 : }
47 1037919 : }
48 3747 : }
49 :
50 : void
51 18 : fd_features_enable_one_offs( fd_features_t * f, char const * * one_offs, uint one_offs_cnt, ulong slot ) {
52 18 : uchar pubkey[32];
53 72 : for( uint i=0U; i<one_offs_cnt; i++ ) {
54 54 : fd_base58_decode_32( one_offs[i], pubkey );
55 54 : for( fd_feature_id_t const * id = fd_feature_iter_init();
56 13230 : !fd_feature_iter_done( id );
57 13230 : id = fd_feature_iter_next( id ) ) {
58 13230 : if( !memcmp( &id->id, pubkey, sizeof(fd_pubkey_t) ) ) {
59 54 : fd_features_set( f, id, slot );
60 54 : break;
61 54 : }
62 13230 : }
63 54 : }
64 18 : }
65 :
66 : static void
67 : fd_feature_restore( fd_bank_t * bank,
68 : fd_accdb_t * accdb,
69 : fd_feature_id_t const * id,
70 69804 : fd_pubkey_t const * addr ) {
71 :
72 69804 : fd_features_t * features = &bank->f.features;
73 69804 : fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
74 69804 : ulong slot = bank->f.slot;
75 :
76 69804 : if( FD_UNLIKELY( id->cleaned_up ) ) {
77 51912 : fd_features_set( features, id, 0UL );
78 51912 : return;
79 51912 : }
80 :
81 17892 : fd_features_set( features, id, FD_FEATURE_DISABLED );
82 :
83 : /* Skip reverted features */
84 17892 : if( FD_UNLIKELY( id->reverted ) ) return;
85 :
86 13860 : fd_acc_t acc = fd_accdb_read_one( accdb, bank->accdb_fork_id, addr->uc );
87 13860 : if( FD_UNLIKELY( !acc.lamports ) ) {
88 13602 : fd_accdb_unread_one( accdb, &acc );
89 13602 : return;
90 13602 : }
91 :
92 : /* Skip accounts that are not owned by the feature program
93 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L42-L44 */
94 258 : if( FD_UNLIKELY( memcmp( acc.owner, fd_solana_feature_program_id.uc, 32UL ) ) ) {
95 6 : fd_accdb_unread_one( accdb, &acc );
96 6 : return;
97 6 : }
98 :
99 : /* Account data size must be >= FD_FEATURE_SIZEOF (9 bytes)
100 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L45-L47 */
101 252 : if( FD_UNLIKELY( acc.data_len<sizeof(fd_feature_t) ) ) {
102 6 : fd_accdb_unread_one( accdb, &acc );
103 6 : return;
104 6 : }
105 :
106 : /* Deserialize the feature account data
107 : https://github.com/anza-xyz/solana-sdk/blob/6512aca61167088ce10f2b545c35c9bcb1400e70/feature-gate-interface/src/lib.rs#L48-L50 */
108 246 : fd_feature_t feature[1];
109 246 : if( FD_UNLIKELY( !fd_feature_decode( feature, acc.data, acc.data_len ) ) ) {
110 0 : fd_accdb_unread_one( accdb, &acc );
111 0 : return;
112 0 : }
113 246 : fd_accdb_unread_one( accdb, &acc );
114 :
115 246 : FD_BASE58_ENCODE_32_BYTES( addr->uc, addr_b58 );
116 246 : if( feature->is_active ) {
117 243 : FD_LOG_DEBUG(( "feature %s activated at slot %lu", addr_b58, feature->activation_slot ));
118 243 : fd_features_set( features, id, feature->activation_slot );
119 243 : } 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 246 : }
127 :
128 : void
129 : fd_features_restore( fd_bank_t * bank,
130 252 : fd_accdb_t * accdb ) {
131 252 : for( fd_feature_id_t const * id = fd_feature_iter_init();
132 70056 : !fd_feature_iter_done( id );
133 69804 : id = fd_feature_iter_next( id ) ) {
134 69804 : fd_feature_restore( bank, accdb, id, &id->id );
135 69804 : }
136 252 : }
|