99//! For updating the currently permissioned builders,
1010//! Simply update the included `builders.json` file with the new builders.
1111
12- use crate :: utils:: from_env:: { FromEnvErr , FromEnvVar } ;
12+ use crate :: {
13+ perms:: { SlotAuthzConfig , SlotAuthzConfigError , SlotCalculator } ,
14+ utils:: from_env:: { FromEnv , FromEnvErr , FromEnvVar } ,
15+ } ;
1316
14- /// The start timestamp for the permissioned builders, in seconds .
15- const EPOCH_START : u64 = 0 ;
17+ /// The builder list env var .
18+ const BUILDERS : & str = "PERMISSIONED_BUILDERS" ;
1619
1720/// Ethereum's slot time in seconds.
1821pub const ETHEREUM_SLOT_TIME : u64 = 12 ;
@@ -22,7 +25,7 @@ fn now() -> u64 {
2225}
2326
2427/// Possible errors when permissioning a builder.
25- #[ derive( Debug , thiserror:: Error ) ]
28+ #[ derive( Debug , thiserror:: Error , Clone , Copy , PartialEq , Eq ) ]
2629pub enum BuilderPermissionError {
2730 /// Action attempt too early.
2831 #[ error( "action attempt too early" ) ]
@@ -35,7 +38,11 @@ pub enum BuilderPermissionError {
3538 /// Builder not permissioned for this slot.
3639 #[ error( "builder not permissioned for this slot" ) ]
3740 NotPermissioned ,
41+ }
3842
43+ /// Possible errors when loading the builder configuration.
44+ #[ derive( Debug , thiserror:: Error , Clone , PartialEq , Eq ) ]
45+ pub enum BuilderConfigError {
3946 /// Error loading the environment variable.
4047 #[ error(
4148 "failed to parse environment variable. Expected a comma-seperated list of UUIDs. Got: {input}"
@@ -46,6 +53,10 @@ pub enum BuilderPermissionError {
4653 /// The contents of the environment variable.
4754 input : String ,
4855 } ,
56+
57+ /// Error loading the slot authorization configuration.
58+ #[ error( transparent) ]
59+ SlotAutzConfig ( #[ from] SlotAuthzConfigError ) ,
4960}
5061
5162/// An individual builder.
@@ -74,12 +85,20 @@ impl Builder {
7485pub struct Builders {
7586 /// The list of builders.
7687 pub builders : Vec < Builder > ,
88+
89+ /// The slot authorization configuration.
90+ config : SlotAuthzConfig ,
7791}
7892
7993impl Builders {
8094 /// Create a new Builders struct.
81- pub const fn new ( builders : Vec < Builder > ) -> Self {
82- Self { builders }
95+ pub const fn new ( builders : Vec < Builder > , config : SlotAuthzConfig ) -> Self {
96+ Self { builders, config }
97+ }
98+
99+ /// Get the calculator instance.
100+ pub fn calc ( & self ) -> SlotCalculator {
101+ self . config . calc ( )
83102 }
84103
85104 /// Get the builder at a specific index.
@@ -99,7 +118,7 @@ impl Builders {
99118 /// Get the index of the builder that is allowed to sign a block for a
100119 /// particular timestamp.
101120 pub fn index ( & self , timestamp : u64 ) -> u64 {
102- ( ( timestamp - EPOCH_START ) / ETHEREUM_SLOT_TIME ) % self . builders . len ( ) as u64
121+ self . config . calc ( ) . calculate_slot ( timestamp) % self . builders . len ( ) as u64
103122 }
104123
105124 /// Get the index of the builder that is allowed to sign a block at the
@@ -117,23 +136,18 @@ impl Builders {
117136 /// This is based on the current timestamp and the builder's sub. It's a
118137 /// round-robin design, where each builder is allowed to perform an action
119138 /// at a specific slot, and what builder is allowed changes with each slot.
120- pub fn is_builder_permissioned (
121- & self ,
122- config : & crate :: perms:: SlotAuthzConfig ,
123- sub : & str ,
124- ) -> Result < ( ) , BuilderPermissionError > {
139+ pub fn is_builder_permissioned ( & self , sub : & str ) -> Result < ( ) , BuilderPermissionError > {
125140 // Get the current timestamp.
126- let curr_timestamp = now ( ) ;
127141
128142 // Calculate the current slot time, which is a number between 0 and 11.
129- let current_slot_time = ( curr_timestamp - config . chain_offset ( ) ) % ETHEREUM_SLOT_TIME ;
143+ let current_slot_time = self . calc ( ) . current_timepoint_within_slot ( ) ;
130144
131145 // Builders can only perform actions between the configured start and cutoff times, to prevent any timing games.
132- if current_slot_time < config. block_query_start ( ) {
146+ if current_slot_time < self . config . block_query_start ( ) {
133147 tracing:: debug!( "Action attempt too early" ) ;
134148 return Err ( BuilderPermissionError :: ActionAttemptTooEarly ) ;
135149 }
136- if current_slot_time > config. block_query_cutoff ( ) {
150+ if current_slot_time > self . config . block_query_cutoff ( ) {
137151 tracing:: debug!( "Action attempt too late" ) ;
138152 return Err ( BuilderPermissionError :: ActionAttemptTooLate ) ;
139153 }
@@ -151,37 +165,52 @@ impl Builders {
151165 }
152166}
153167
154- impl FromIterator < Builder > for Builders {
155- fn from_iter < T : IntoIterator < Item = Builder > > ( iter : T ) -> Self {
156- Self :: new ( iter. into_iter ( ) . collect ( ) )
157- }
158- }
168+ impl FromEnv for Builders {
169+ type Error = BuilderConfigError ;
159170
160- impl FromEnvVar for Builders {
161- type Error = BuilderPermissionError ;
171+ fn from_env ( ) -> Result < Self , FromEnvErr < Self :: Error > > {
172+ let s = String :: from_env_var ( BUILDERS )
173+ . map_err ( FromEnvErr :: infallible_into :: < BuilderConfigError > ) ?;
174+ let builders = s. split ( ',' ) . map ( Builder :: new) . collect ( ) ;
162175
163- fn from_env_var ( env_var : & str ) -> Result < Self , FromEnvErr < Self :: Error > > {
164- let s = String :: from_env_var ( env_var)
165- . map_err ( FromEnvErr :: infallible_into :: < BuilderPermissionError > ) ?;
176+ let config = SlotAuthzConfig :: from_env ( ) . map_err ( FromEnvErr :: from) ?;
166177
167- Ok ( s . split ( ',' ) . map ( Builder :: new ) . collect ( ) )
178+ Ok ( Self { builders , config } )
168179 }
169180}
170181
171182#[ cfg( test) ]
172183mod test {
184+
173185 use super :: * ;
186+ use crate :: perms;
174187
175188 #[ test]
176189 fn load_builders ( ) {
177- unsafe { std:: env:: set_var ( "TEST" , "0,1,2,3,4,5" ) } ;
190+ unsafe {
191+ std:: env:: set_var ( BUILDERS , "0,1,2,3,4,5" ) ;
192+
193+ std:: env:: set_var ( perms:: calc:: START_TIMESTAMP , "1" ) ;
194+ std:: env:: set_var ( perms:: calc:: SLOT_OFFSET , "0" ) ;
195+ std:: env:: set_var ( perms:: calc:: SLOT_DURATION , "12" ) ;
178196
179- let builders = Builders :: from_env_var ( "TEST" ) . unwrap ( ) ;
197+ std:: env:: set_var ( perms:: config:: BLOCK_QUERY_START , "1" ) ;
198+ std:: env:: set_var ( perms:: config:: BLOCK_QUERY_CUTOFF , "11" ) ;
199+ } ;
200+
201+ let builders = Builders :: from_env ( ) . unwrap ( ) ;
180202 assert_eq ! ( builders. builder_at( 0 ) . sub, "0" ) ;
181203 assert_eq ! ( builders. builder_at( 1 ) . sub, "1" ) ;
182204 assert_eq ! ( builders. builder_at( 2 ) . sub, "2" ) ;
183205 assert_eq ! ( builders. builder_at( 3 ) . sub, "3" ) ;
184206 assert_eq ! ( builders. builder_at( 4 ) . sub, "4" ) ;
185207 assert_eq ! ( builders. builder_at( 5 ) . sub, "5" ) ;
208+
209+ assert_eq ! ( builders. calc( ) . slot_offset( ) , 0 ) ;
210+ assert_eq ! ( builders. calc( ) . slot_duration( ) , 12 ) ;
211+ assert_eq ! ( builders. calc( ) . start_timestamp( ) , 1 ) ;
212+
213+ assert_eq ! ( builders. config. block_query_start( ) , 1 ) ;
214+ assert_eq ! ( builders. config. block_query_cutoff( ) , 11 ) ;
186215 }
187216}
0 commit comments