@@ -14,235 +14,196 @@ use alloy::{
14
14
} ,
15
15
} ;
16
16
use eyre:: Result ;
17
+ use init4_bin_base:: utils:: { calc:: SlotCalculator , from_env:: FromEnv } ;
17
18
use oauth2:: url;
18
19
use signet_types:: config:: { HostConfig , PredeployTokens , RollupConfig , SignetSystemConstants } ;
19
20
use signet_zenith:: Zenith ;
20
- use std:: { borrow:: Cow , env , num , str :: FromStr } ;
21
+ use std:: borrow:: Cow ;
21
22
22
- // Keys for .env variables that need to be set to configure the builder.
23
- const HOST_CHAIN_ID : & str = "HOST_CHAIN_ID" ;
24
- const RU_CHAIN_ID : & str = "RU_CHAIN_ID" ;
25
- const HOST_RPC_URL : & str = "HOST_RPC_URL" ;
26
- const ROLLUP_RPC_URL : & str = "ROLLUP_RPC_URL" ;
27
- const TX_BROADCAST_URLS : & str = "TX_BROADCAST_URLS" ;
28
- const ZENITH_ADDRESS : & str = "ZENITH_ADDRESS" ;
29
- const BUILDER_HELPER_ADDRESS : & str = "BUILDER_HELPER_ADDRESS" ;
30
- const QUINCEY_URL : & str = "QUINCEY_URL" ;
31
- const BUILDER_PORT : & str = "BUILDER_PORT" ;
32
- const SEQUENCER_KEY : & str = "SEQUENCER_KEY" ; // empty (to use Quincey) OR AWS key ID (to use AWS signer) OR raw private key (to use local signer)
33
- const BUILDER_KEY : & str = "BUILDER_KEY" ; // AWS key ID (to use AWS signer) OR raw private key (to use local signer)
34
- const BLOCK_CONFIRMATION_BUFFER : & str = "BLOCK_CONFIRMATION_BUFFER" ;
35
- const CHAIN_OFFSET : & str = "CHAIN_OFFSET" ;
36
- const TARGET_SLOT_TIME : & str = "TARGET_SLOT_TIME" ;
37
- const BUILDER_REWARDS_ADDRESS : & str = "BUILDER_REWARDS_ADDRESS" ;
38
- const ROLLUP_BLOCK_GAS_LIMIT : & str = "ROLLUP_BLOCK_GAS_LIMIT" ;
39
- const TX_POOL_URL : & str = "TX_POOL_URL" ;
40
- const AUTH_TOKEN_REFRESH_INTERVAL : & str = "AUTH_TOKEN_REFRESH_INTERVAL" ;
41
- const TX_POOL_CACHE_DURATION : & str = "TX_POOL_CACHE_DURATION" ;
42
- const OAUTH_CLIENT_ID : & str = "OAUTH_CLIENT_ID" ;
43
- const OAUTH_CLIENT_SECRET : & str = "OAUTH_CLIENT_SECRET" ;
44
- const OAUTH_AUTHENTICATE_URL : & str = "OAUTH_AUTHENTICATE_URL" ;
45
- const OAUTH_TOKEN_URL : & str = "OAUTH_TOKEN_URL" ;
46
- const CONCURRENCY_LIMIT : & str = "CONCURRENCY_LIMIT" ;
47
- const START_TIMESTAMP : & str = "START_TIMESTAMP" ;
23
+ /// Type alias for the provider used to build and submit blocks to the host.
24
+ pub type HostProvider = FillProvider <
25
+ JoinFill <
26
+ JoinFill <
27
+ Identity ,
28
+ JoinFill < GasFiller , JoinFill < BlobGasFiller , JoinFill < NonceFiller , ChainIdFiller > > > ,
29
+ > ,
30
+ WalletFiller < EthereumWallet > ,
31
+ > ,
32
+ RootProvider ,
33
+ Ethereum ,
34
+ > ;
48
35
49
36
/// Configuration for a builder running a specific rollup on a specific host
50
37
/// chain.
51
- #[ derive( serde:: Serialize , serde :: Deserialize , Debug , Clone ) ]
38
+ #[ derive( serde:: Deserialize , Debug , Clone , FromEnv ) ]
52
39
pub struct BuilderConfig {
53
40
/// The chain ID of the host chain
41
+ #[ from_env( var = "HOST_CHAIN_ID" , desc = "The chain ID of the host chain" ) ]
54
42
pub host_chain_id : u64 ,
55
- /// The chain ID of the host chain
43
+ /// The chain ID of the rollup chain
44
+ #[ from_env( var = "RU_CHAIN_ID" , desc = "The chain ID of the rollup chain" ) ]
56
45
pub ru_chain_id : u64 ,
57
46
/// URL for Host RPC node.
47
+ #[ from_env( var = "HOST_RPC_URL" , desc = "URL for Host RPC node" , infallible) ]
58
48
pub host_rpc_url : Cow < ' static , str > ,
59
49
/// URL for the Rollup RPC node.
50
+ #[ from_env( var = "ROLLUP_RPC_URL" , desc = "URL for Rollup RPC node" , infallible) ]
60
51
pub ru_rpc_url : Cow < ' static , str > ,
61
52
/// Additional RPC URLs to which to broadcast transactions.
62
53
/// NOTE: should not include the host_rpc_url value
54
+ #[ from_env(
55
+ var = "TX_BROADCAST_URLS" ,
56
+ desc = "Additional RPC URLs to which to broadcast transactions" ,
57
+ infallible
58
+ ) ]
63
59
pub tx_broadcast_urls : Vec < Cow < ' static , str > > ,
64
60
/// address of the Zenith contract on Host.
61
+ #[ from_env( var = "ZENITH_ADDRESS" , desc = "address of the Zenith contract on Host" ) ]
65
62
pub zenith_address : Address ,
66
63
/// address of the Builder Helper contract on Host.
64
+ #[ from_env(
65
+ var = "BUILDER_HELPER_ADDRESS" ,
66
+ desc = "address of the Builder Helper contract on Host"
67
+ ) ]
67
68
pub builder_helper_address : Address ,
68
69
/// URL for remote Quincey Sequencer server to sign blocks.
69
70
/// Disregarded if a sequencer_signer is configured.
71
+ #[ from_env(
72
+ var = "QUINCEY_URL" ,
73
+ desc = "URL for remote Quincey Sequencer server to sign blocks" ,
74
+ infallible
75
+ ) ]
70
76
pub quincey_url : Cow < ' static , str > ,
71
77
/// Port for the Builder server.
78
+ #[ from_env( var = "BUILDER_PORT" , desc = "Port for the Builder server" ) ]
72
79
pub builder_port : u16 ,
73
80
/// Key to access Sequencer Wallet - AWS Key ID _OR_ local private key.
74
81
/// Set IFF using local Sequencer signing instead of remote Quincey signing.
82
+ #[ from_env(
83
+ var = "SEQUENCER_KEY" ,
84
+ desc = "Key to access Sequencer Wallet - AWS Key ID _OR_ local private key, set IFF using local Sequencer signing instead of remote Quincey signing" ,
85
+ infallible,
86
+ optional
87
+ ) ]
75
88
pub sequencer_key : Option < String > ,
76
89
/// Key to access Builder transaction submission wallet - AWS Key ID _OR_ local private key.
90
+ #[ from_env(
91
+ var = "BUILDER_KEY" ,
92
+ desc = "Key to access Builder transaction submission wallet - AWS Key ID _OR_ local private key" ,
93
+ infallible
94
+ ) ]
77
95
pub builder_key : String ,
78
96
/// Buffer in seconds in which the `submitBlock` transaction must confirm on the Host chain.
97
+ #[ from_env(
98
+ var = "BLOCK_CONFIRMATION_BUFFER" ,
99
+ desc = "Buffer in seconds in which the `submitBlock` transaction must confirm on the Host chain"
100
+ ) ]
79
101
pub block_confirmation_buffer : u64 ,
80
- /// The offset between Unix time and the chain's block times. For Holesky, this is 0; for Ethereum, 11.
81
- pub chain_offset : u64 ,
82
- /// The slot time at which the Builder should begin building a block. 0 to begin at the very start of the slot; 6 to begin in the middle; etc.
83
- pub target_slot_time : u64 ,
102
+
84
103
/// Address on Rollup to which Builder will receive user transaction fees.
104
+ #[ from_env(
105
+ var = "BUILDER_REWARDS_ADDRESS" ,
106
+ desc = "Address on Rollup to which Builder will receive user transaction fees"
107
+ ) ]
85
108
pub builder_rewards_address : Address ,
86
109
/// Gas limit for RU block.
87
110
/// NOTE: a "smart" builder would determine this programmatically by simulating the block.
111
+ #[ from_env( var = "ROLLUP_BLOCK_GAS_LIMIT" , desc = "Gas limit for RU block" ) ]
88
112
pub rollup_block_gas_limit : u64 ,
89
113
/// URL of the tx pool to poll for incoming transactions.
114
+ #[ from_env(
115
+ var = "TX_POOL_URL" ,
116
+ desc = "URL of the tx pool to poll for incoming transactions" ,
117
+ infallible
118
+ ) ]
90
119
pub tx_pool_url : Cow < ' static , str > ,
91
120
/// Duration in seconds transactions can live in the tx-pool cache.
121
+ #[ from_env(
122
+ var = "AUTH_TOKEN_REFRESH_INTERVAL" ,
123
+ desc = "Duration in seconds transactions can live in the tx-pool cache"
124
+ ) ]
92
125
pub tx_pool_cache_duration : u64 ,
93
126
/// OAuth client ID for the builder.
127
+ #[ from_env( var = "TX_POOL_CACHE_DURATION" , desc = "OAuth client ID for the builder" ) ]
94
128
pub oauth_client_id : String ,
95
129
/// OAuth client secret for the builder.
130
+ #[ from_env( var = "OAUTH_CLIENT_ID" , desc = "OAuth client secret for the builder" ) ]
96
131
pub oauth_client_secret : String ,
97
132
/// OAuth authenticate URL for the builder for performing OAuth logins.
133
+ #[ from_env(
134
+ var = "OAUTH_CLIENT_SECRET" ,
135
+ desc = "OAuth authenticate URL for the builder for performing OAuth logins"
136
+ ) ]
98
137
pub oauth_authenticate_url : String ,
99
138
/// OAuth token URL for the builder to get an OAuth2 access token
139
+ #[ from_env(
140
+ var = "OAUTH_AUTHENTICATE_URL" ,
141
+ desc = "OAuth token URL for the builder to get an OAuth2 access token"
142
+ ) ]
100
143
pub oauth_token_url : String ,
101
144
/// The oauth token refresh interval in seconds.
145
+ #[ from_env( var = "OAUTH_TOKEN_URL" , desc = "The oauth token refresh interval in seconds" ) ]
102
146
pub oauth_token_refresh_interval : u64 ,
103
147
/// The max number of simultaneous block simulations to run.
148
+ #[ from_env(
149
+ var = "CONCURRENCY_LIMIT" ,
150
+ desc = "The max number of simultaneous block simulations to run"
151
+ ) ]
104
152
pub concurrency_limit : usize ,
105
- /// The anchor for slot time and number calculations before adjusting for chain offset.
106
- pub start_timestamp : u64 ,
107
- }
108
-
109
- /// Error loading the configuration.
110
- #[ derive( Debug , thiserror:: Error ) ]
111
- pub enum ConfigError {
112
- /// Error loading from environment variable
113
- #[ error( "missing or non-unicode environment variable: {0}" ) ]
114
- Var ( String ) ,
115
- /// Error parsing environment variable
116
- #[ error( "failed to parse environment variable: {0}" ) ]
117
- Parse ( #[ from] num:: ParseIntError ) ,
118
- /// Error parsing boolean environment variable
119
- #[ error( "failed to parse boolean environment variable" ) ]
120
- ParseBool ,
121
- /// Error parsing hex from environment variable
122
- #[ error( "failed to parse hex: {0}" ) ]
123
- Hex ( #[ from] hex:: FromHexError ) ,
124
- /// Error connecting to the provider
125
- #[ error( "failed to connect to provider: {0}" ) ]
126
- Provider ( #[ from] alloy:: transports:: TransportError ) ,
127
- /// Error connecting to the signer
128
- #[ error( "failed to connect to signer: {0}" ) ]
129
- Signer ( #[ from] SignerError ) ,
130
- /// I/O error
131
- #[ error( "I/O error: {0}" ) ]
132
- Io ( #[ from] std:: io:: Error ) ,
133
- }
134
153
135
- impl ConfigError {
136
- /// Missing or non-unicode env var.
137
- pub fn missing ( s : & str ) -> Self {
138
- ConfigError :: Var ( s. to_string ( ) )
139
- }
154
+ /// The slot calculator for the builder.
155
+ pub slot_calculator : SlotCalculator ,
140
156
}
141
157
142
- /// Type alias for the provider used to build and submit blocks to the host.
143
- pub type HostProvider = FillProvider <
144
- JoinFill <
145
- JoinFill <
146
- Identity ,
147
- JoinFill < GasFiller , JoinFill < BlobGasFiller , JoinFill < NonceFiller , ChainIdFiller > > > ,
148
- > ,
149
- WalletFiller < EthereumWallet > ,
150
- > ,
151
- RootProvider ,
152
- Ethereum ,
153
- > ;
154
-
155
158
/// Type alias for the provider used to simulate against rollup state.
156
159
pub type RuProvider = RootProvider < Ethereum > ;
157
160
158
161
/// A [`Zenith`] contract instance using [`Provider`] as the provider.
159
162
pub type ZenithInstance < P = HostProvider > = Zenith :: ZenithInstance < ( ) , P , alloy:: network:: Ethereum > ;
160
163
161
164
impl BuilderConfig {
162
- /// Load the builder configuration from environment variables.
163
- pub fn load_from_env ( ) -> Result < BuilderConfig , ConfigError > {
164
- Ok ( BuilderConfig {
165
- host_chain_id : load_u64 ( HOST_CHAIN_ID ) ?,
166
- ru_chain_id : load_u64 ( RU_CHAIN_ID ) ?,
167
- host_rpc_url : load_url ( HOST_RPC_URL ) ?,
168
- ru_rpc_url : load_url ( ROLLUP_RPC_URL ) ?,
169
- tx_broadcast_urls : env:: var ( TX_BROADCAST_URLS )
170
- . unwrap_or_default ( )
171
- . split ( ',' )
172
- . map ( str:: trim)
173
- . filter ( |url| !url. is_empty ( ) )
174
- . map ( ToOwned :: to_owned)
175
- . map ( Into :: into)
176
- . collect ( ) ,
177
- zenith_address : load_address ( ZENITH_ADDRESS ) ?,
178
- builder_helper_address : load_address ( BUILDER_HELPER_ADDRESS ) ?,
179
- quincey_url : load_url ( QUINCEY_URL ) ?,
180
- builder_port : load_u16 ( BUILDER_PORT ) ?,
181
- sequencer_key : load_string_option ( SEQUENCER_KEY ) ,
182
- builder_key : load_string ( BUILDER_KEY ) ?,
183
- block_confirmation_buffer : load_u64 ( BLOCK_CONFIRMATION_BUFFER ) ?,
184
- chain_offset : load_u64 ( CHAIN_OFFSET ) ?,
185
- target_slot_time : load_u64 ( TARGET_SLOT_TIME ) ?,
186
- builder_rewards_address : load_address ( BUILDER_REWARDS_ADDRESS ) ?,
187
- rollup_block_gas_limit : load_u64 ( ROLLUP_BLOCK_GAS_LIMIT ) ?,
188
- tx_pool_url : load_url ( TX_POOL_URL ) ?,
189
- tx_pool_cache_duration : load_u64 ( TX_POOL_CACHE_DURATION ) ?,
190
- oauth_client_id : load_string ( OAUTH_CLIENT_ID ) ?,
191
- oauth_client_secret : load_string ( OAUTH_CLIENT_SECRET ) ?,
192
- oauth_authenticate_url : load_string ( OAUTH_AUTHENTICATE_URL ) ?,
193
- oauth_token_url : load_string ( OAUTH_TOKEN_URL ) ?,
194
- oauth_token_refresh_interval : load_u64 ( AUTH_TOKEN_REFRESH_INTERVAL ) ?,
195
- concurrency_limit : load_concurrency_limit ( ) ?,
196
- start_timestamp : load_u64 ( START_TIMESTAMP ) ?,
197
- } )
198
- }
199
-
200
165
/// Connect to the Builder signer.
201
- pub async fn connect_builder_signer ( & self ) -> Result < LocalOrAws , ConfigError > {
202
- LocalOrAws :: load ( & self . builder_key , Some ( self . host_chain_id ) ) . await . map_err ( Into :: into )
166
+ pub async fn connect_builder_signer ( & self ) -> Result < LocalOrAws , SignerError > {
167
+ LocalOrAws :: load ( & self . builder_key , Some ( self . host_chain_id ) ) . await
203
168
}
204
169
205
170
/// Connect to the Sequencer signer.
206
- pub async fn connect_sequencer_signer ( & self ) -> Result < Option < LocalOrAws > , ConfigError > {
207
- match & self . sequencer_key {
208
- Some ( sequencer_key ) => LocalOrAws :: load ( sequencer_key, Some ( self . host_chain_id ) )
171
+ pub async fn connect_sequencer_signer ( & self ) -> eyre :: Result < Option < LocalOrAws > > {
172
+ if let Some ( sequencer_key ) = & self . sequencer_key {
173
+ LocalOrAws :: load ( sequencer_key, Some ( self . host_chain_id ) )
209
174
. await
210
175
. map_err ( Into :: into)
211
- . map ( Some ) ,
212
- None => Ok ( None ) ,
176
+ . map ( Some )
177
+ } else {
178
+ Ok ( None )
213
179
}
214
180
}
215
181
216
182
/// Connect to the Rollup rpc provider.
217
- pub async fn connect_ru_provider ( & self ) -> Result < RootProvider < Ethereum > , ConfigError > {
183
+ pub fn connect_ru_provider ( & self ) -> RootProvider < Ethereum > {
218
184
let url = url:: Url :: parse ( & self . ru_rpc_url ) . expect ( "failed to parse URL" ) ;
219
- let provider = RootProvider :: < Ethereum > :: new_http ( url) ;
220
- Ok ( provider)
185
+ RootProvider :: < Ethereum > :: new_http ( url)
221
186
}
222
187
223
188
/// Connect to the Host rpc provider.
224
- pub async fn connect_host_provider ( & self ) -> Result < HostProvider , ConfigError > {
189
+ pub async fn connect_host_provider ( & self ) -> eyre :: Result < HostProvider > {
225
190
let builder_signer = self . connect_builder_signer ( ) . await ?;
226
- let provider = ProviderBuilder :: new ( )
191
+ ProviderBuilder :: new ( )
227
192
. wallet ( EthereumWallet :: from ( builder_signer) )
228
193
. connect ( & self . host_rpc_url )
229
194
. await
230
- . map_err ( ConfigError :: Provider ) ?;
231
-
232
- Ok ( provider)
195
+ . map_err ( Into :: into)
233
196
}
234
197
235
198
/// Connect additional broadcast providers.
236
- pub async fn connect_additional_broadcast ( & self ) -> Result < Vec < RootProvider > , ConfigError > {
237
- let mut providers: Vec < RootProvider > = Vec :: with_capacity ( self . tx_broadcast_urls . len ( ) ) ;
238
-
239
- for url_str in self . tx_broadcast_urls . iter ( ) {
240
- let url = url:: Url :: parse ( url_str) . expect ( "failed to parse URL" ) ;
241
- let provider = RootProvider :: new_http ( url) ;
242
- providers. push ( provider) ;
243
- }
244
-
245
- Ok ( providers)
199
+ pub fn connect_additional_broadcast ( & self ) -> Vec < RootProvider > {
200
+ self . tx_broadcast_urls
201
+ . iter ( )
202
+ . map ( |url_str| {
203
+ let url = url:: Url :: parse ( url_str) . expect ( "failed to parse URL" ) ;
204
+ RootProvider :: new_http ( url)
205
+ } )
206
+ . collect :: < Vec < _ > > ( )
246
207
}
247
208
248
209
/// Connect to the Zenith instance, using the specified provider.
@@ -276,50 +237,3 @@ impl BuilderConfig {
276
237
SignetSystemConstants :: new ( host, rollup)
277
238
}
278
239
}
279
-
280
- /// Load a string from an environment variable.
281
- pub fn load_string ( key : & str ) -> Result < String , ConfigError > {
282
- env:: var ( key) . map_err ( |_| ConfigError :: missing ( key) )
283
- }
284
-
285
- /// Load a string from an environment variable, returning None if the variable
286
- /// is not set.
287
- fn load_string_option ( key : & str ) -> Option < String > {
288
- load_string ( key) . ok ( )
289
- }
290
-
291
- /// Load a boolean from an environment variable.
292
- pub fn load_u64 ( key : & str ) -> Result < u64 , ConfigError > {
293
- let val = load_string ( key) ?;
294
- val. parse :: < u64 > ( ) . map_err ( Into :: into)
295
- }
296
-
297
- /// Load a u16 from an environment variable.
298
- fn load_u16 ( key : & str ) -> Result < u16 , ConfigError > {
299
- let val = load_string ( key) ?;
300
- val. parse :: < u16 > ( ) . map_err ( Into :: into)
301
- }
302
-
303
- /// Load a URL from an environment variable.
304
- pub fn load_url ( key : & str ) -> Result < Cow < ' static , str > , ConfigError > {
305
- load_string ( key) . map ( Into :: into)
306
- }
307
-
308
- /// Load an address from an environment variable.
309
- pub fn load_address ( key : & str ) -> Result < Address , ConfigError > {
310
- let address = load_string ( key) ?;
311
- Address :: from_str ( & address)
312
- . map_err ( |_| ConfigError :: Var ( format ! ( "Invalid address format for {}" , key) ) )
313
- }
314
-
315
- /// Checks the configured concurrency parameter and, if none is set, checks the available
316
- /// system concurrency with `std::thread::available_parallelism` and returns that.
317
- pub fn load_concurrency_limit ( ) -> Result < usize , ConfigError > {
318
- match load_u16 ( CONCURRENCY_LIMIT ) {
319
- Ok ( env) => Ok ( env as usize ) ,
320
- Err ( _) => {
321
- let limit = std:: thread:: available_parallelism ( ) ?. get ( ) ;
322
- Ok ( limit)
323
- }
324
- }
325
- }
0 commit comments