Line data Source code
1 : #include "fd_slot_params.h"
2 : #include "fd_bank.h"
3 : #include "fd_runtime_const.h"
4 : #include "../genesis/fd_genesis_parse.h"
5 : #include "../features/fd_features.h"
6 : #include "sysvar/fd_sysvar_epoch_schedule.h"
7 : #include "../../util/bits/fd_sat.h"
8 : #include <stddef.h>
9 :
10 : /* The reduce_slot_time feature gates take effect an epoch after they
11 : have been activated, because they affect the turbine shred filtering
12 : rules. */
13 : static ulong
14 : feature_effective_slot( fd_epoch_schedule_t const * epoch_schedule,
15 775 : ulong activation_slot ) {
16 775 : ulong activation_epoch = fd_slot_to_epoch( epoch_schedule, activation_slot, NULL );
17 775 : return fd_epoch_slot0( epoch_schedule, fd_ulong_sat_add( activation_epoch, 1UL ) );
18 775 : }
19 :
20 1470 : #define FD_SLOT_TIME_GATE_CNT (4UL)
21 : struct fd_slot_time_gate {
22 : ulong feature_off;
23 : fd_slot_params_t const * params;
24 : };
25 :
26 : typedef struct fd_slot_time_gate fd_slot_time_gate_t;
27 :
28 : static fd_slot_time_gate_t const fd_slot_time_gates[ FD_SLOT_TIME_GATE_CNT ] = {
29 : { .feature_off = offsetof( fd_features_t, reduce_slot_time_to_350ms ), .params = &FD_SLOT_PARAMS_350MS },
30 : { .feature_off = offsetof( fd_features_t, reduce_slot_time_to_300ms ), .params = &FD_SLOT_PARAMS_300MS },
31 : { .feature_off = offsetof( fd_features_t, reduce_slot_time_to_250ms ), .params = &FD_SLOT_PARAMS_250MS },
32 : { .feature_off = offsetof( fd_features_t, reduce_slot_time_to_200ms ), .params = &FD_SLOT_PARAMS_200MS },
33 : };
34 :
35 : static ulong
36 : fd_slot_params_feature_effective_slot( fd_features_t const * features,
37 : fd_epoch_schedule_t const * epoch_schedule,
38 1101 : fd_slot_time_gate_t const * gate ) {
39 1101 : ulong activation_slot = fd_features_get_activation_slot_from_offset( features, gate->feature_off );
40 1101 : if( activation_slot==FD_FEATURE_DISABLED ) return ULONG_MAX;
41 775 : return feature_effective_slot( epoch_schedule, activation_slot );
42 1101 : }
43 :
44 : fd_slot_params_t
45 0 : fd_slot_params_from_genesis( fd_genesis_t const * genesis ) {
46 0 : uint128 tick_ns = (uint128)genesis->poh.tick_duration_secs*1000000000UL + (uint128)genesis->poh.tick_duration_ns;
47 0 : fd_slot_params_t params = FD_SLOT_PARAMS_400MS;
48 0 : params.ns_per_slot = (ulong)( tick_ns * genesis->poh.ticks_per_slot );
49 0 : params.ns_per_slot_adjusted = fd_ulong_sat_sub( params.ns_per_slot, FD_TARGET_SLOT_ADJUSTMENT_NS );
50 0 : params.slots_per_year = SECONDS_PER_YEAR * (1000000000.0 / (double)tick_ns) / (double)genesis->poh.ticks_per_slot;
51 0 : params.hashes_per_tick = genesis->poh.hashes_per_tick;
52 0 : return params;
53 0 : }
54 :
55 : int
56 : fd_slot_params_any_reduction_effective( fd_features_t const * features,
57 : fd_epoch_schedule_t const * epoch_schedule,
58 : ulong slot,
59 0 : ulong ns_per_slot ) {
60 0 : for( ulong i=0UL; i<FD_SLOT_TIME_GATE_CNT; i++ ) {
61 0 : fd_slot_time_gate_t const * gate = &fd_slot_time_gates[ i ];
62 0 : if( gate->params->ns_per_slot > ns_per_slot ) continue;
63 0 : ulong eff = fd_slot_params_feature_effective_slot( features, epoch_schedule, gate );
64 0 : if( eff!=ULONG_MAX && eff<=slot ) return 1;
65 0 : }
66 0 : return 0;
67 0 : }
68 :
69 : fd_slot_params_t
70 : fd_slot_params_at_slot( fd_bank_t const * bank,
71 190 : ulong slot ) {
72 190 : return fd_slot_params_lookup( &bank->f.slot_params_default,
73 190 : &bank->f.features,
74 190 : &bank->f.epoch_schedule,
75 190 : slot );
76 190 : }
77 :
78 : fd_slot_params_t
79 : fd_slot_params_lookup( fd_slot_params_t const * default_params,
80 : fd_features_t const * features,
81 : fd_epoch_schedule_t const * epoch_schedule,
82 242 : ulong slot ) {
83 242 : fd_slot_params_t result = *default_params;
84 1210 : for( ulong i=0UL; i<FD_SLOT_TIME_GATE_CNT; i++ ) {
85 968 : fd_slot_time_gate_t const * gate = &fd_slot_time_gates[ i ];
86 968 : ulong eff = fd_slot_params_feature_effective_slot( features, epoch_schedule, gate );
87 968 : if( gate->params->ns_per_slot <= result.ns_per_slot && eff!=ULONG_MAX && eff<=slot ) {
88 601 : result = *gate->params;
89 601 : }
90 968 : }
91 242 : return result;
92 242 : }
93 :
94 : ulong
95 : fd_slot_params_effective_slot( fd_slot_params_t const * params,
96 : fd_features_t const * features,
97 0 : fd_epoch_schedule_t const * epoch_schedule ) {
98 0 : for( ulong i=0UL; i<FD_SLOT_TIME_GATE_CNT; i++ ) {
99 0 : fd_slot_time_gate_t const * gate = &fd_slot_time_gates[ i ];
100 0 : if( gate->params->ns_per_slot==params->ns_per_slot )
101 0 : return fd_slot_params_feature_effective_slot( features, epoch_schedule, gate );
102 0 : }
103 0 : return 0UL;
104 0 : }
105 :
106 : ulong
107 : fd_slot_params_next_transition( fd_features_t const * features,
108 : fd_epoch_schedule_t const * epoch_schedule,
109 : ulong slot,
110 52 : ulong current_ns_per_slot ) {
111 52 : ulong next = ULONG_MAX;
112 260 : for( ulong i=0UL; i<FD_SLOT_TIME_GATE_CNT; i++ ) {
113 208 : fd_slot_time_gate_t const * gate = &fd_slot_time_gates[ i ];
114 208 : if( gate->params->ns_per_slot > current_ns_per_slot ) continue;
115 133 : ulong eff = fd_slot_params_feature_effective_slot( features, epoch_schedule, gate );
116 133 : if( eff>slot && eff<next ) next = eff;
117 133 : }
118 52 : return next;
119 52 : }
120 :
121 : ulong
122 : fd_slot_params_next_effective_slot( fd_slot_params_t const * params,
123 : fd_features_t const * features,
124 0 : fd_epoch_schedule_t const * epoch_schedule ) {
125 0 : ulong next = ULONG_MAX;
126 0 : for( ulong i=0UL; i<FD_SLOT_TIME_GATE_CNT; i++ ) {
127 0 : fd_slot_time_gate_t const * gate = &fd_slot_time_gates[ i ];
128 0 : if( gate->params->ns_per_slot >= params->ns_per_slot ) continue;
129 0 : ulong eff = fd_slot_params_feature_effective_slot( features, epoch_schedule, gate );
130 0 : if( eff<next ) next = eff;
131 0 : }
132 0 : return next;
133 0 : }
134 :
135 : FD_FN_PURE ulong
136 : fd_slot_params_slot_range_duration_ns( fd_bank_t const * bank,
137 : ulong start_slot,
138 0 : ulong end_slot ) {
139 0 : fd_slot_params_t const * default_params = &bank->f.slot_params_default;
140 0 : fd_features_t const * features = &bank->f.features;
141 0 : fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
142 0 : ulong curr_slot = start_slot;
143 0 : uint128 ns = 0;
144 0 : while( curr_slot<end_slot ) {
145 0 : fd_slot_params_t params = fd_slot_params_lookup( default_params, features, epoch_schedule, curr_slot );
146 0 : ulong next = fd_slot_params_next_transition( features, epoch_schedule, curr_slot, params.ns_per_slot );
147 0 : ulong seg_end = next<end_slot ? next : end_slot;
148 0 : ns = fd_uint128_sat_add( ns, fd_uint128_sat_mul( (uint128)( seg_end-curr_slot ), (uint128)params.ns_per_slot ) );
149 0 : curr_slot = seg_end;
150 0 : }
151 : /* We saturate here because all the Agave callers do as well. In
152 : practice, the callers all limit the inputs such that this range
153 : will never overflow ULONG_MAX, but we saturate for defense in
154 : depth.
155 : https://github.com/anza-xyz/agave/blob/v4.2/runtime/src/bank.rs#L2985-L2987 */
156 0 : return ns>(uint128)ULONG_MAX ? ULONG_MAX : (ulong)ns;
157 0 : }
158 :
159 : FD_FN_PURE double
160 : fd_slot_params_slot_range_duration_years( fd_bank_t const * bank,
161 : ulong start_slot,
162 28 : ulong end_slot ) {
163 28 : fd_slot_params_t const * default_params = &bank->f.slot_params_default;
164 28 : fd_features_t const * features = &bank->f.features;
165 28 : fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
166 28 : ulong curr_slot = start_slot;
167 28 : double years = 0.0;
168 80 : while( curr_slot<end_slot ) {
169 52 : fd_slot_params_t p = fd_slot_params_lookup( default_params, features, epoch_schedule, curr_slot );
170 52 : ulong next = fd_slot_params_next_transition( features, epoch_schedule, curr_slot, p.ns_per_slot );
171 52 : ulong seg_end = next<end_slot ? next : end_slot;
172 52 : years += (double)( seg_end-curr_slot ) / p.slots_per_year;
173 52 : curr_slot = seg_end;
174 52 : }
175 28 : return years;
176 28 : }
|