Skip to content

Commit 500f8ad

Browse files
feat: private keys support for testing (#159)
Co-authored-by: hal3e <git@hal3e.io>
1 parent 9126180 commit 500f8ad

File tree

14 files changed

+408
-93
lines changed

14 files changed

+408
-93
lines changed

.github/workflows/ci.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,7 @@ jobs:
218218
arch: [
219219
# build on native runners instead of using emulation
220220
{platform: linux/amd64, runner: buildjet-8vcpu-ubuntu-2204},
221-
# don't currently need arm builds
222-
# {platform: linux/arm64, runner: buildjet-8vcpu-ubuntu-2204-arm}
221+
{platform: linux/arm64, runner: buildjet-8vcpu-ubuntu-2204-arm}
223222
]
224223
runs-on: ${{ matrix.arch.runner }}
225224
permissions:

Cargo.lock

+1-27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+188
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,191 @@ Before running the script, ensure you have the following installed:
4040

4141
- [Docker](https://www.docker.com/get-started) (required for running SchemaSpy)
4242
- [Sqlx CLI](https://github.com/launchbadge/sqlx/tree/main/sqlx-cli) (required for running migrations)
43+
44+
## Configuration
45+
46+
The Fuel Block Committer is configured primarily through environment variables.
47+
48+
### Environment Variables
49+
50+
#### Ethereum (ETH) Configuration
51+
52+
- **`COMMITTER__ETH__L1_KEYS__MAIN`**
53+
54+
- **Description:** The Ethereum key authorized by the L1 fuel chain state contract to post block commitments.
55+
- **Format:** `Kms(<KEY_ARN>)` or `Private(<PRIVATE_KEY>)`
56+
- **Example:** `Kms(arn:aws:kms:us-east-1:123456789012:key/abcd-1234)`
57+
58+
- **`COMMITTER__ETH__L1_KEYS__BLOB`**
59+
60+
- **Description:** (Optional) The Ethereum key for posting L2 state to L1.
61+
- **Format:** `Kms(<KEY_ARN>)` or `Private(<PRIVATE_KEY>)`
62+
- **Example:** `Kms(arn:aws:kms:us-east-1:123456789012:key/efgh-5678)`
63+
64+
- **`COMMITTER__ETH__RPC`**
65+
66+
- **Description:** URL to the Ethereum RPC endpoint.
67+
- **Example:** `https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID`
68+
69+
- **`COMMITTER__ETH__STATE_CONTRACT_ADDRESS`**
70+
- **Description:** Ethereum address of the Fuel chain state contract.
71+
- **Example:** `0xYourStateContractAddress`
72+
73+
#### Fuel Configuration
74+
75+
- **`COMMITTER__FUEL__GRAPHQL_ENDPOINT`**
76+
77+
- **Description:** URL to a Fuel Core GraphQL endpoint.
78+
- **Example:** `http://localhost:4000/graphql`
79+
80+
- **`COMMITTER__FUEL__NUM_BUFFERED_REQUESTS`**
81+
- **Description:** Number of concurrent http requests towards the fuel node.
82+
- **Type:** Positive integer
83+
- **Example:** `5`
84+
85+
#### Database (DB) Configuration
86+
87+
- **`COMMITTER__APP__DB__HOST`**
88+
89+
- **Description:** Hostname or IP address of the PostgreSQL server.
90+
- **Example:** `localhost`
91+
92+
- **`COMMITTER__APP__DB__PORT`**
93+
94+
- **Description:** Port number on which the PostgreSQL server is listening.
95+
- **Type:** `u16`
96+
- **Example:** `5432`
97+
98+
- **`COMMITTER__APP__DB__USERNAME`**
99+
100+
- **Description:** Username for authenticating with the PostgreSQL server.
101+
- **Example:** `username`
102+
103+
- **`COMMITTER__APP__DB__PASSWORD`**
104+
105+
- **Description:** Password for authenticating with the PostgreSQL server.
106+
- **Example:** `password`
107+
108+
- **`COMMITTER__APP__DB__DATABASE`**
109+
110+
- **Description:** Name of the database to connect to on the PostgreSQL server.
111+
- **Example:** `fuel_db`
112+
113+
- **`COMMITTER__APP__DB__MAX_CONNECTIONS`**
114+
115+
- **Description:** Maximum number of connections allowed in the connection pool.
116+
- **Type:** `u32`
117+
- **Example:** `10`
118+
119+
- **`COMMITTER__APP__DB__USE_SSL`**
120+
- **Description:** Whether to use SSL when connecting to the PostgreSQL server.
121+
- **Type:** `bool`
122+
- **Values:** `true` or `false`
123+
- **Example:** `false`
124+
125+
#### Application (App) Configuration
126+
127+
- **`COMMITTER__APP__PORT`**
128+
129+
- **Description:** Port used by the started server.
130+
- **Type:** `u16`
131+
- **Example:** `8080`
132+
133+
- **`COMMITTER__APP__HOST`**
134+
135+
- **Description:** IPv4 address on which the server will listen for connections.
136+
- **Example:** `127.0.0.1`
137+
138+
- **`COMMITTER__APP__BLOCK_CHECK_INTERVAL`**
139+
140+
- **Description:** How often to check for new fuel blocks.
141+
- **Format:** Human-readable duration (e.g., `5s`, `1m`)
142+
- **Example:** `5s`
143+
144+
- **`COMMITTER__APP__TX_FINALIZATION_CHECK_INTERVAL`**
145+
146+
- **Description:** How often to check for finalized L1 transactions.
147+
- **Format:** Human-readable duration
148+
- **Example:** `5s`
149+
150+
- **`COMMITTER__APP__NUM_BLOCKS_TO_FINALIZE_TX`**
151+
152+
- **Description:** Number of L1 blocks that need to pass to accept the transaction as finalized.
153+
- **Type:** `u64`
154+
- **Example:** `3`
155+
156+
- **`COMMITTER__APP__GAS_BUMP_TIMEOUT`**
157+
158+
- **Description:** Interval after which to bump a pending transaction.
159+
- **Format:** Human-readable duration
160+
- **Example:** `300s`
161+
162+
- **`COMMITTER__APP__TX_MAX_FEE`**
163+
164+
- **Description:** Maximum gas fee permitted for a transaction in wei.
165+
- **Type:** `u64`
166+
- **Example:** `4000000000000000`
167+
168+
- **`COMMITTER__APP__SEND_TX_REQUEST_TIMEOUT`**
169+
- **Description:** Duration for timeout when sending transaction requests.
170+
- **Format:** Human-readable duration
171+
- **Example:** `10s`
172+
173+
#### Bundle Configuration
174+
175+
- **`COMMITTER__APP__BUNDLE__ACCUMULATION_TIMEOUT`**
176+
177+
- **Description:** Duration to wait for additional fuel blocks before initiating the bundling process.
178+
- **Format:** Human-readable duration
179+
- **Example:** `30s`
180+
181+
- **`COMMITTER__APP__BUNDLE__BLOCKS_TO_ACCUMULATE`**
182+
183+
- **Description:** Number of fuel blocks to accumulate before initiating the bundling process.
184+
- **Type:** Positive integer
185+
- **Example:** `5`
186+
187+
- **`COMMITTER__APP__BUNDLE__OPTIMIZATION_TIMEOUT`**
188+
189+
- **Description:** Maximum duration allocated for determining the optimal bundle size.
190+
- **Format:** Human-readable duration
191+
- **Example:** `60s`
192+
193+
- **`COMMITTER__APP__BUNDLE__COMPRESSION_LEVEL`**
194+
195+
- **Description:** Compression level used for compressing block data before submission.
196+
- **Values:** `"disabled"`, `"min"`, `"level1"`..`"level9"`, `"max"`
197+
- **Example:** `"min"`
198+
199+
- **`COMMITTER__APP__BUNDLE__OPTIMIZATION_STEP`**
200+
201+
- **Description:** Size of the optimization step at the start of the optimization process.
202+
- **Type:** Positive integer (`NonZeroUsize`)
203+
- **Example:** `100`
204+
205+
- **`COMMITTER__APP__BUNDLE__FRAGMENTS_TO_ACCUMULATE`**
206+
207+
- **Description:** Number of fragments to accumulate before submitting them in a transaction to L1.
208+
- **Type:** Positive integer (`NonZeroUsize`)
209+
- **Example:** `6`
210+
211+
- **`COMMITTER__APP__BUNDLE__FRAGMENT_ACCUMULATION_TIMEOUT`**
212+
213+
- **Description:** Duration to wait for additional fragments before submitting them.
214+
- **Format:** Human-readable duration
215+
- **Example:** `30s`
216+
217+
- **`COMMITTER__APP__BUNDLE__NEW_BUNDLE_CHECK_INTERVAL`**
218+
- **Description:** Duration to wait before checking if a new bundle can be made.
219+
- **Format:** Human-readable duration
220+
- **Example:** `15s`
221+
222+
### Configuration Validation
223+
224+
The committer performs validation on the provided configuration to ensure consistency and correctness. For example:
225+
226+
- **Wallet Keys:** The main wallet key and blob pool wallet key must be different.
227+
- **Fragments to Accumulate:** Must be less than or equal to 6.
228+
- **Block Height Lookback:** Must be greater than or equal to the number of blocks to accumulate.
229+
230+
If any validation fails, the committer will return an error, preventing it from running with invalid settings.

committer/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ rust-version = { workspace = true }
1313
actix-web = { workspace = true, features = ["macros"] }
1414
clap = { workspace = true, features = ["default", "derive"] }
1515
clock = { workspace = true }
16-
config = { workspace = true, features = ["toml", "async"] }
16+
config = { workspace = true, features = ["async"] }
1717
eth = { workspace = true }
1818
fuel = { workspace = true }
1919
fuel-block-committer-encoding = { workspace = true }

committer/src/config.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66
};
77

88
use clap::{command, Parser};
9-
use eth::Address;
9+
use eth::{Address, L1Keys};
1010
use fuel_block_committer_encoding::bundle::CompressionLevel;
1111
use serde::Deserialize;
1212
use storage::DbConfig;
@@ -21,12 +21,15 @@ pub struct Config {
2121

2222
impl Config {
2323
pub fn validate(&self) -> crate::errors::Result<()> {
24-
if let Some(blob_pool_wallet_key) = &self.eth.blob_pool_key_arn {
25-
if blob_pool_wallet_key == &self.eth.main_key_arn {
26-
return Err(crate::errors::Error::Other(
27-
"Wallet key and blob pool wallet key must be different".to_string(),
28-
));
29-
}
24+
let keys = &self.eth.l1_keys;
25+
if keys
26+
.blob
27+
.as_ref()
28+
.is_some_and(|blob_key| blob_key == &keys.main)
29+
{
30+
return Err(crate::errors::Error::Other(
31+
"Wallet key and blob pool wallet key must be different".to_string(),
32+
));
3033
}
3134

3235
if self.app.bundle.fragments_to_accumulate.get() > 6 {
@@ -56,10 +59,8 @@ pub struct Fuel {
5659

5760
#[derive(Debug, Clone, Deserialize)]
5861
pub struct Eth {
59-
/// The AWS KMS key ID authorized by the L1 bridging contracts to post block commitments.
60-
pub main_key_arn: String,
61-
/// The AWS KMS key ID for posting L2 state to L1.
62-
pub blob_pool_key_arn: Option<String>,
62+
/// L1 keys for calling the state contract and for posting state
63+
pub l1_keys: L1Keys,
6364
/// URL to a Ethereum RPC endpoint.
6465
#[serde(deserialize_with = "parse_url")]
6566
pub rpc: Url,

committer/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ async fn main() -> Result<()> {
6767

6868
// If the blob pool wallet key is set, we need to start
6969
// the state committer and state importer
70-
if config.eth.blob_pool_key_arn.is_some() {
70+
if config.eth.l1_keys.blob.is_some() {
7171
let block_bundler = setup::block_bundler(
7272
fuel_adapter.clone(),
7373
storage.clone(),

committer/src/setup.rs

+3-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{num::NonZeroU32, time::Duration};
22

33
use clock::SystemClock;
4-
use eth::{AwsConfig, BlobEncoder, KmsKeys};
4+
use eth::{BlobEncoder, Signers};
55
use fuel_block_committer_encoding::bundle;
66
use metrics::{
77
prometheus::{IntGauge, Registry},
@@ -13,7 +13,7 @@ use tokio::task::JoinHandle;
1313
use tokio_util::sync::CancellationToken;
1414
use tracing::{error, info};
1515

16-
use crate::{config, errors::Result, AwsClient, Database, FuelApi, L1};
16+
use crate::{config, errors::Result, Database, FuelApi, L1};
1717

1818
pub fn wallet_balance_tracker(
1919
internal_config: &config::Internal,
@@ -190,19 +190,11 @@ pub async fn l1_adapter(
190190
internal_config: &config::Internal,
191191
registry: &Registry,
192192
) -> Result<(L1, HealthChecker)> {
193-
let aws_config = AwsConfig::from_env().await;
194-
195-
let aws_client = AwsClient::new(aws_config);
196-
197193
let l1 = L1::connect(
198194
config.eth.rpc.clone(),
199195
config.eth.state_contract_address,
200-
KmsKeys {
201-
main_key_arn: config.eth.main_key_arn.clone(),
202-
blob_pool_key_arn: config.eth.blob_pool_key_arn.clone(),
203-
},
196+
Signers::for_keys(config.eth.l1_keys.clone()).await?,
204197
internal_config.eth_errors_before_unhealthy,
205-
aws_client,
206198
eth::TxConfig {
207199
tx_max_fee: config.app.tx_max_fee as u128,
208200
send_tx_request_timeout: config.app.send_tx_request_timeout,

e2e/src/committer.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ impl Committer {
4343
let db_port = get_field!(db_port);
4444
let db_name = get_field!(db_name);
4545

46+
let main_key = format!("Kms({})", get_field!(main_key_arn));
47+
let blob_key = self.blob_key_arn.map(|k| format!("Kms({k})"));
4648
cmd.env("E2E_TEST_AWS_ENDPOINT", kms_url)
4749
.env("AWS_REGION", "us-east-1")
4850
.env("AWS_ACCESS_KEY_ID", "test")
4951
.env("AWS_SECRET_ACCESS_KEY", "test")
50-
.env("COMMITTER__ETH__MAIN_KEY_ARN", get_field!(main_key_arn))
52+
.env("COMMITTER__ETH__L1_KEYS__MAIN", main_key)
5153
.env("COMMITTER__ETH__RPC", get_field!(eth_rpc).as_str())
5254
.env(
5355
"COMMITTER__ETH__STATE_CONTRACT_ADDRESS",
@@ -112,8 +114,8 @@ impl Committer {
112114
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap())
113115
.kill_on_drop(true);
114116

115-
if let Some(blob_wallet_key_arn) = self.blob_key_arn {
116-
cmd.env("COMMITTER__ETH__BLOB_POOL_KEY_ARN", blob_wallet_key_arn);
117+
if let Some(key) = blob_key {
118+
cmd.env("COMMITTER__ETH__L1_KEYS__BLOB", key);
117119
}
118120

119121
let sink = if self.show_logs {

0 commit comments

Comments
 (0)