Skip to content

Commit 07ee54f

Browse files
committed
refactor: update config to use derive
1 parent 421238d commit 07ee54f

File tree

5 files changed

+115
-159
lines changed

5 files changed

+115
-159
lines changed

bin/builder.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ use builder::{
66
tx_poller,
77
},
88
};
9-
use init4_bin_base::deps::tracing;
10-
use init4_bin_base::utils::calc::SlotCalculator;
9+
use init4_bin_base::{deps::tracing, utils::from_env::FromEnv};
1110
use signet_sim::SimCache;
1211
use std::sync::Arc;
1312
use tokio::select;
@@ -20,7 +19,7 @@ async fn main() -> eyre::Result<()> {
2019
let _guard = init4_bin_base::init4();
2120
let init_span_guard = info_span!("builder initialization");
2221

23-
let config = BuilderConfig::load_from_env()?.clone();
22+
let config = BuilderConfig::from_env()?.clone();
2423
let constants = config.load_pecorino_constants();
2524
let authenticator = Authenticator::new(&config)?;
2625

@@ -56,8 +55,7 @@ async fn main() -> eyre::Result<()> {
5655
let (submit_channel, submit_jh) = submit.spawn();
5756

5857
let sim_items = SimCache::new();
59-
let slot_calculator =
60-
SlotCalculator::new(config.start_timestamp, config.chain_offset, config.target_slot_time);
58+
let slot_calculator = config.slot_calculator;
6159

6260
let sim = Arc::new(Simulator::new(&config, ru_provider.clone(), slot_calculator));
6361

bin/submit_transaction.rs

+34-24
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ use alloy::{
55
rpc::types::eth::TransactionRequest,
66
signers::aws::AwsSigner,
77
};
8-
use aws_config::BehaviorVersion;
9-
use builder::config::{HostProvider, load_address, load_string, load_u64, load_url};
8+
use builder::config::HostProvider;
109
use init4_bin_base::{
1110
deps::metrics::{counter, histogram},
1211
init4,
12+
utils::from_env::FromEnv,
1313
};
1414
use std::time::{Duration, Instant};
1515
use tokio::time::timeout;
@@ -19,18 +19,22 @@ async fn main() {
1919
init4();
2020

2121
tracing::trace!("connecting to provider");
22-
let (provider, recipient_address, sleep_time) = connect_from_config().await;
22+
23+
let config = Config::from_env().unwrap();
24+
let provider = config.provider().await;
25+
let recipient_address = config.recipient_address;
26+
let sleep_time = config.sleep_time;
2327

2428
loop {
2529
tracing::debug!("attempting transaction");
26-
send_transaction(provider.clone(), recipient_address).await;
30+
send_transaction(&provider, recipient_address).await;
2731

2832
tracing::debug!(sleep_time, "sleeping");
2933
tokio::time::sleep(tokio::time::Duration::from_secs(sleep_time)).await;
3034
}
3135
}
3236

33-
async fn send_transaction(provider: HostProvider, recipient_address: Address) {
37+
async fn send_transaction(provider: &HostProvider, recipient_address: Address) {
3438
// construct simple transaction to send ETH to a recipient
3539
let tx = TransactionRequest::default()
3640
.with_from(provider.default_signer_address())
@@ -67,25 +71,31 @@ async fn send_transaction(provider: HostProvider, recipient_address: Address) {
6771
histogram!("txn_submitter.tx_mine_time").record(mine_time as f64);
6872
}
6973

70-
async fn connect_from_config() -> (HostProvider, Address, u64) {
71-
// load signer config values from .env
72-
let rpc_url = load_url("RPC_URL").unwrap();
73-
let chain_id = load_u64("CHAIN_ID").unwrap();
74-
let kms_key_id = load_string("AWS_KMS_KEY_ID").unwrap();
75-
// load transaction sending config value from .env
76-
let recipient_address: Address = load_address("RECIPIENT_ADDRESS").unwrap();
77-
let sleep_time = load_u64("SLEEP_TIME").unwrap();
78-
79-
// connect signer & provider
80-
let config = aws_config::load_defaults(BehaviorVersion::latest()).await;
81-
let client = aws_sdk_kms::Client::new(&config);
82-
let signer = AwsSigner::new(client, kms_key_id.to_string(), Some(chain_id)).await.unwrap();
74+
#[derive(Debug, Clone, FromEnv)]
75+
struct Config {
76+
#[from_env(var = "RPC_URL", desc = "Ethereum RPC URL")]
77+
rpc_url: String,
78+
#[from_env(var = "CHAIN_ID", desc = "Ethereum chain ID")]
79+
chain_id: u64,
80+
#[from_env(var = "AWS_KMS_KEY_ID", desc = "AWS KMS key ID")]
81+
kms_key_id: String,
82+
#[from_env(var = "RECIPIENT_ADDRESS", desc = "Recipient address")]
83+
recipient_address: Address,
84+
#[from_env(var = "SLEEP_TIME", desc = "Time to sleep between transactions")]
85+
sleep_time: u64,
86+
}
8387

84-
let provider = ProviderBuilder::new()
85-
.wallet(EthereumWallet::from(signer))
86-
.connect(&rpc_url)
87-
.await
88-
.unwrap();
88+
impl Config {
89+
async fn provider(&self) -> HostProvider {
90+
let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
91+
let client = aws_sdk_kms::Client::new(&config);
92+
let signer =
93+
AwsSigner::new(client, self.kms_key_id.clone(), Some(self.chain_id)).await.unwrap();
8994

90-
(provider, recipient_address, sleep_time)
95+
ProviderBuilder::new()
96+
.wallet(EthereumWallet::from(signer))
97+
.connect(&self.rpc_url)
98+
.await
99+
.unwrap()
100+
}
91101
}

src/config.rs

+71-120
Original file line numberDiff line numberDiff line change
@@ -14,96 +14,132 @@ use alloy::{
1414
},
1515
};
1616
use eyre::Result;
17+
use init4_bin_base::utils::{calc::SlotCalculator, from_env::FromEnv};
1718
use oauth2::url;
1819
use signet_types::config::{HostConfig, PredeployTokens, RollupConfig, SignetSystemConstants};
1920
use signet_zenith::Zenith;
20-
use std::{borrow::Cow, env, num, str::FromStr};
21-
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";
21+
use std::{borrow::Cow, num};
4822

4923
/// Configuration for a builder running a specific rollup on a specific host
5024
/// chain.
51-
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
25+
#[derive(serde::Deserialize, Debug, Clone, FromEnv)]
5226
pub struct BuilderConfig {
5327
/// The chain ID of the host chain
28+
#[from_env(var = "HOST_CHAIN_ID", desc = "The chain ID of the host chain")]
5429
pub host_chain_id: u64,
5530
/// The chain ID of the host chain
31+
#[from_env(var = "RU_CHAIN_ID", desc = "The chain ID of the rollup chain")]
5632
pub ru_chain_id: u64,
5733
/// URL for Host RPC node.
34+
#[from_env(var = "HOST_RPC_URL", desc = "URL for Host RPC node", infallible)]
5835
pub host_rpc_url: Cow<'static, str>,
5936
/// URL for the Rollup RPC node.
37+
#[from_env(var = "ROLLUP_RPC_URL", desc = "URL for Host RPC node", infallible)]
6038
pub ru_rpc_url: Cow<'static, str>,
6139
/// Additional RPC URLs to which to broadcast transactions.
6240
/// NOTE: should not include the host_rpc_url value
41+
#[from_env(
42+
var = "TX_BROADCAST_URLS",
43+
desc = "Additional RPC URLs to which to broadcast transactions",
44+
infallible
45+
)]
6346
pub tx_broadcast_urls: Vec<Cow<'static, str>>,
6447
/// address of the Zenith contract on Host.
48+
#[from_env(var = "ZENITH_ADDRESS", desc = "address of the Zenith contract on Host")]
6549
pub zenith_address: Address,
6650
/// address of the Builder Helper contract on Host.
51+
#[from_env(
52+
var = "BUILDER_HELPER_ADDRESS",
53+
desc = "address of the Builder Helper contract on Host"
54+
)]
6755
pub builder_helper_address: Address,
6856
/// URL for remote Quincey Sequencer server to sign blocks.
6957
/// Disregarded if a sequencer_signer is configured.
58+
#[from_env(
59+
var = "QUINCEY_URL",
60+
desc = "URL for remote Quincey Sequencer server to sign blocks",
61+
infallible
62+
)]
7063
pub quincey_url: Cow<'static, str>,
7164
/// Port for the Builder server.
65+
#[from_env(var = "BUILDER_PORT", desc = "Port for the Builder server")]
7266
pub builder_port: u16,
7367
/// Key to access Sequencer Wallet - AWS Key ID _OR_ local private key.
7468
/// Set IFF using local Sequencer signing instead of remote Quincey signing.
69+
#[from_env(
70+
var = "SEQUENCER_KEY",
71+
desc = "Key to access Sequencer Wallet - AWS Key ID _OR_ local private key, set IFF using local Sequencer signing instead of remote Quincey signing",
72+
infallible,
73+
optional
74+
)]
7575
pub sequencer_key: Option<String>,
7676
/// Key to access Builder transaction submission wallet - AWS Key ID _OR_ local private key.
77+
#[from_env(
78+
var = "BUILDER_KEY",
79+
desc = "Key to access Builder transaction submission wallet - AWS Key ID _OR_ local private key",
80+
infallible
81+
)]
7782
pub builder_key: String,
7883
/// Buffer in seconds in which the `submitBlock` transaction must confirm on the Host chain.
84+
#[from_env(
85+
var = "BLOCK_CONFIRMATION_BUFFER",
86+
desc = "Buffer in seconds in which the `submitBlock` transaction must confirm on the Host chain"
87+
)]
7988
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,
89+
8490
/// Address on Rollup to which Builder will receive user transaction fees.
91+
#[from_env(
92+
var = "BUILDER_REWARDS_ADDRESS",
93+
desc = "Address on Rollup to which Builder will receive user transaction fees"
94+
)]
8595
pub builder_rewards_address: Address,
8696
/// Gas limit for RU block.
8797
/// NOTE: a "smart" builder would determine this programmatically by simulating the block.
98+
#[from_env(var = "ROLLUP_BLOCK_GAS_LIMIT", desc = "Gas limit for RU block")]
8899
pub rollup_block_gas_limit: u64,
89100
/// URL of the tx pool to poll for incoming transactions.
101+
#[from_env(
102+
var = "TX_POOL_URL",
103+
desc = "URL of the tx pool to poll for incoming transactions",
104+
infallible
105+
)]
90106
pub tx_pool_url: Cow<'static, str>,
91107
/// Duration in seconds transactions can live in the tx-pool cache.
108+
#[from_env(
109+
var = "AUTH_TOKEN_REFRESH_INTERVAL",
110+
desc = "Duration in seconds transactions can live in the tx-pool cache"
111+
)]
92112
pub tx_pool_cache_duration: u64,
93113
/// OAuth client ID for the builder.
114+
#[from_env(var = "TX_POOL_CACHE_DURATION", desc = "OAuth client ID for the builder")]
94115
pub oauth_client_id: String,
95116
/// OAuth client secret for the builder.
117+
#[from_env(var = "OAUTH_CLIENT_ID", desc = "OAuth client secret for the builder")]
96118
pub oauth_client_secret: String,
97119
/// OAuth authenticate URL for the builder for performing OAuth logins.
120+
#[from_env(
121+
var = "OAUTH_CLIENT_SECRET",
122+
desc = "OAuth authenticate URL for the builder for performing OAuth logins"
123+
)]
98124
pub oauth_authenticate_url: String,
99125
/// OAuth token URL for the builder to get an OAuth2 access token
126+
#[from_env(
127+
var = "OAUTH_AUTHENTICATE_URL",
128+
desc = "OAuth token URL for the builder to get an OAuth2 access token"
129+
)]
100130
pub oauth_token_url: String,
101131
/// The oauth token refresh interval in seconds.
132+
#[from_env(var = "OAUTH_TOKEN_URL", desc = "The oauth token refresh interval in seconds")]
102133
pub oauth_token_refresh_interval: u64,
103134
/// The max number of simultaneous block simulations to run.
135+
#[from_env(
136+
var = "CONCURRENCY_LIMIT",
137+
desc = "The max number of simultaneous block simulations to run"
138+
)]
104139
pub concurrency_limit: usize,
105-
/// The anchor for slot time and number calculations before adjusting for chain offset.
106-
pub start_timestamp: u64,
140+
141+
/// The slot calculator for the builder.
142+
pub slot_calculator: SlotCalculator,
107143
}
108144

109145
/// Error loading the configuration.
@@ -159,44 +195,6 @@ pub type RuProvider = RootProvider<Ethereum>;
159195
pub type ZenithInstance<P = HostProvider> = Zenith::ZenithInstance<(), P, alloy::network::Ethereum>;
160196

161197
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-
200198
/// Connect to the Builder signer.
201199
pub async fn connect_builder_signer(&self) -> Result<LocalOrAws, ConfigError> {
202200
LocalOrAws::load(&self.builder_key, Some(self.host_chain_id)).await.map_err(Into::into)
@@ -276,50 +274,3 @@ impl BuilderConfig {
276274
SignetSystemConstants::new(host, rollup)
277275
}
278276
}
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

Comments
 (0)