diff --git a/Cargo.lock b/Cargo.lock
index 9049f23f..7db93510 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2360,6 +2360,7 @@ dependencies = [
"prometheus",
"protocol",
"reqwest",
+ "rustls",
"serde",
"serde_json",
"strum",
@@ -2738,7 +2739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
dependencies = [
"data-encoding",
- "syn 1.0.109",
+ "syn 2.0.117",
]
[[package]]
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 9304add0..9fa7367f 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -32,6 +32,7 @@ jsonwebtoken = { workspace = true }
k256 = { workspace = true }
prometheus = { workspace = true }
reqwest = { workspace = true }
+rustls = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
strum = { workspace = true, features = ["derive"] }
diff --git a/common/src/config/mod.rs b/common/src/config/mod.rs
index 2a0ab348..86b9d046 100644
--- a/common/src/config/mod.rs
+++ b/common/src/config/mod.rs
@@ -16,6 +16,9 @@ pub struct Config {
pub preconfer_address: Option
,
pub web3signer_l1_url: Option,
pub web3signer_l2_url: Option,
+ pub web3signer_root_certificate_path: Option,
+ pub web3signer_client_certificate_path: Option,
+ pub web3signer_client_key_path: Option,
pub catalyst_node_ecdsa_private_key: Option,
// L1
pub l1_rpc_urls: Vec,
@@ -141,22 +144,35 @@ impl Config {
let web3signer_l1_url = std::env::var(WEB3SIGNER_L1_URL).ok();
const WEB3SIGNER_L2_URL: &str = "WEB3SIGNER_L2_URL";
let web3signer_l2_url = std::env::var(WEB3SIGNER_L2_URL).ok();
+ const WEB3SIGNER_ROOT_CERTIFICATE_PATH: &str = "WEB3SIGNER_ROOT_CERTIFICATE_PATH";
+ let web3signer_root_certificate_path = std::env::var(WEB3SIGNER_ROOT_CERTIFICATE_PATH).ok();
+ const WEB3SIGNER_CLIENT_CERTIFICATE_PATH: &str = "WEB3SIGNER_CLIENT_CERTIFICATE_PATH";
+ let web3signer_client_certificate_path =
+ std::env::var(WEB3SIGNER_CLIENT_CERTIFICATE_PATH).ok();
+ const WEB3SIGNER_CLIENT_KEY_PATH: &str = "WEB3SIGNER_CLIENT_KEY_PATH";
+ let web3signer_client_key_path = std::env::var(WEB3SIGNER_CLIENT_KEY_PATH).ok();
if catalyst_node_ecdsa_private_key.is_none() {
if web3signer_l1_url.is_none()
|| web3signer_l2_url.is_none()
|| preconfer_address.is_none()
+ || web3signer_root_certificate_path.is_none()
+ || web3signer_client_certificate_path.is_none()
+ || web3signer_client_key_path.is_none()
{
return Err(anyhow::anyhow!(
- "When {CATALYST_NODE_ECDSA_PRIVATE_KEY} is not set, {WEB3SIGNER_L1_URL}, {WEB3SIGNER_L2_URL} and {PRECONFER_ADDRESS} must be set"
+ "When {CATALYST_NODE_ECDSA_PRIVATE_KEY} is not set, {WEB3SIGNER_L1_URL}, {WEB3SIGNER_L2_URL}, {WEB3SIGNER_ROOT_CERTIFICATE_PATH}, {WEB3SIGNER_CLIENT_CERTIFICATE_PATH}, {WEB3SIGNER_CLIENT_KEY_PATH} and {PRECONFER_ADDRESS} must be set"
));
}
} else if web3signer_l1_url.is_some()
|| web3signer_l2_url.is_some()
|| preconfer_address.is_some()
+ || web3signer_root_certificate_path.is_some()
+ || web3signer_client_certificate_path.is_some()
+ || web3signer_client_key_path.is_some()
{
return Err(anyhow::anyhow!(
- "When {CATALYST_NODE_ECDSA_PRIVATE_KEY} is set, {WEB3SIGNER_L1_URL}, {WEB3SIGNER_L2_URL} and {PRECONFER_ADDRESS} must not be set"
+ "When {CATALYST_NODE_ECDSA_PRIVATE_KEY} is set, {WEB3SIGNER_L1_URL}, {WEB3SIGNER_L2_URL}, {WEB3SIGNER_ROOT_CERTIFICATE_PATH}, {WEB3SIGNER_CLIENT_CERTIFICATE_PATH}, {WEB3SIGNER_CLIENT_KEY_PATH} and {PRECONFER_ADDRESS} must not be set"
));
}
@@ -531,6 +547,9 @@ impl Config {
blob_indexer_url: std::env::var("BLOB_INDEXER_URL").ok(),
web3signer_l1_url,
web3signer_l2_url,
+ web3signer_root_certificate_path,
+ web3signer_client_certificate_path,
+ web3signer_client_key_path,
l1_slot_duration_sec,
l1_slots_per_epoch,
preconf_heartbeat_ms,
@@ -588,6 +607,9 @@ Consensus layer timeout: {}ms,
Blob Indexer URL: {},
Web3signer L1 URL: {},
Web3signer L2 URL: {},
+Web3signer root certificate path: {},
+Web3signer client certificate path: {},
+Web3signer client key path: {},
L1 slot duration: {}s
L1 slots per epoch: {}
L2 slot duration (heart beat): {}
@@ -651,6 +673,18 @@ internal server port: {}
config.blob_indexer_url.as_deref().unwrap_or("not set"),
config.web3signer_l1_url.as_deref().unwrap_or("not set"),
config.web3signer_l2_url.as_deref().unwrap_or("not set"),
+ config
+ .web3signer_root_certificate_path
+ .as_deref()
+ .unwrap_or("not set"),
+ config
+ .web3signer_client_certificate_path
+ .as_deref()
+ .unwrap_or("not set"),
+ config
+ .web3signer_client_key_path
+ .as_deref()
+ .unwrap_or("not set"),
config.l1_slot_duration_sec,
config.l1_slots_per_epoch,
config.preconf_heartbeat_ms,
diff --git a/common/src/l1/config.rs b/common/src/l1/config.rs
index 970de99c..c15032ed 100644
--- a/common/src/l1/config.rs
+++ b/common/src/l1/config.rs
@@ -1,5 +1,5 @@
use crate::config::Config;
-use crate::signer::{Signer, create_signer};
+use crate::signer::{Signer, Web3SignerInfo, create_signer};
use alloy::primitives::Address;
use anyhow::Error;
use std::sync::Arc;
@@ -26,12 +26,15 @@ pub struct EthereumL1Config {
impl EthereumL1Config {
pub async fn new(config: &Config) -> Result {
- let signer = create_signer(
+ let w3s_info = Web3SignerInfo::new(
config.web3signer_l1_url.clone(),
- config.catalyst_node_ecdsa_private_key.clone(),
+ config.web3signer_root_certificate_path.clone(),
+ config.web3signer_client_certificate_path.clone(),
+ config.web3signer_client_key_path.clone(),
config.preconfer_address,
- )
- .await?;
+ )?;
+ let signer =
+ create_signer(w3s_info, config.catalyst_node_ecdsa_private_key.clone()).await?;
Ok(Self {
execution_rpc_urls: config.l1_rpc_urls.clone(),
diff --git a/common/src/shared/alloy_tools.rs b/common/src/shared/alloy_tools.rs
index 3bc8df9a..5a89a578 100644
--- a/common/src/shared/alloy_tools.rs
+++ b/common/src/shared/alloy_tools.rs
@@ -94,10 +94,8 @@ pub async fn construct_alloy_provider(
);
let preconfer_address = *address;
- let tx_signer = crate::signer::web3signer::Web3TxSigner::new(
- web3signer.clone(),
- preconfer_address,
- )?;
+ let tx_signer =
+ crate::signer::Web3TxSigner::new(web3signer.clone(), preconfer_address)?;
let wallet = EthereumWallet::new(tx_signer);
Ok(create_alloy_provider_with_wallet(wallet, execution_ws_rpc_url).await?)
diff --git a/common/src/shared/transaction_monitor.rs b/common/src/shared/transaction_monitor.rs
index 7f5a4b54..32acbc4b 100644
--- a/common/src/shared/transaction_monitor.rs
+++ b/common/src/shared/transaction_monitor.rs
@@ -42,7 +42,7 @@ pub struct TxMonitorHandles {
pub tx_result_receiver: tokio::sync::oneshot::Receiver,
}
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct TransactionMonitorConfig {
min_priority_fee_per_gas_wei: u128,
tx_fees_increase_percentage: u128,
diff --git a/common/src/signer/mod.rs b/common/src/signer/mod.rs
index ccc00334..05836b88 100644
--- a/common/src/signer/mod.rs
+++ b/common/src/signer/mod.rs
@@ -1,33 +1,30 @@
-pub mod web3signer;
+mod web3signer;
+mod web3signer_info;
use alloy::primitives::Address;
use alloy::signers::local::PrivateKeySigner;
use anyhow::Error;
use std::str::FromStr;
use std::sync::Arc;
-use tokio::time::Duration;
use web3signer::Web3Signer;
+pub use web3signer::Web3TxSigner;
+pub use web3signer_info::Web3SignerInfo;
-#[derive(Debug)]
pub enum Signer {
Web3signer(Arc, Address),
PrivateKey(String, Address),
}
-const SIGNER_TIMEOUT: Duration = Duration::from_secs(10);
-
pub async fn create_signer(
- web3signer_url: Option,
+ web3signer_info: Option,
catalyst_node_ecdsa_private_key: Option,
- preconfer_address: Option,
) -> Result, Error> {
- Ok(Arc::new(if let Some(web3signer_url) = web3signer_url {
- let address =
- preconfer_address.expect("preconfer address is required for web3signer usage");
- Signer::Web3signer(
- Arc::new(Web3Signer::new(&web3signer_url, SIGNER_TIMEOUT, &address.to_string()).await?),
- address,
- )
+ Ok(Arc::new(if let Some(web3signer_info) = web3signer_info {
+ let address = web3signer_info
+ .signer_address
+ .parse()
+ .expect("signer address is required for web3signer usage");
+ Signer::Web3signer(Arc::new(Web3Signer::new(web3signer_info).await?), address)
} else if let Some(catalyst_node_ecdsa_private_key) = catalyst_node_ecdsa_private_key {
let signer = PrivateKeySigner::from_str(catalyst_node_ecdsa_private_key.as_str())?;
Signer::PrivateKey(catalyst_node_ecdsa_private_key, signer.address())
diff --git a/common/src/signer/web3signer.rs b/common/src/signer/web3signer.rs
index 7628954c..d5b190b7 100644
--- a/common/src/signer/web3signer.rs
+++ b/common/src/signer/web3signer.rs
@@ -1,4 +1,7 @@
-use crate::utils::rpc_client::JSONRPCClient;
+use crate::{
+ signer::web3signer_info::Web3SignerInfo,
+ utils::rpc_client::{JSONRPCClient, TlsConfig},
+};
use alloy::{
consensus::{
Transaction, TxEnvelope,
@@ -13,26 +16,29 @@ use async_trait::async_trait;
use hex;
use serde_json::{Map, Value};
use std::sync::Arc;
-use std::time::Duration;
+
use tracing::{debug, error, info};
-#[derive(Debug)]
pub struct Web3Signer {
client: JSONRPCClient,
}
impl Web3Signer {
- pub async fn new(
- rpc_url: &str,
- timeout: Duration,
- signer_address: &str,
- ) -> Result {
- info!("Web3Signer: Creating new Web3Signer with URL: {}", rpc_url);
- let client = JSONRPCClient::new_with_timeout(rpc_url, timeout)?;
- if !Self::is_signer_key_available(&client, signer_address).await? {
+ pub async fn new(info: Web3SignerInfo) -> Result {
+ info!("Web3Signer: Creating new Web3Signer with URL: {}", info.url);
+ let client = JSONRPCClient::new_with_tls_and_timeout(
+ &info.url,
+ info.timeout,
+ TlsConfig {
+ ca_cert: info.ca_cert,
+ client_cert: info.client_cert,
+ client_key: info.client_key,
+ },
+ )?;
+ if !Self::is_signer_key_available(&client, &info.signer_address).await? {
return Err(anyhow::anyhow!(
"Web3Signer: Signer key is not available for address {}",
- signer_address
+ info.signer_address
));
}
Ok(Self { client })
@@ -137,7 +143,7 @@ impl Web3Signer {
}
}
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct Web3TxSigner {
inner: Arc,
address: Address,
@@ -208,6 +214,7 @@ async fn check_signer_correctness(tx_envelope: &TxEnvelope, from: Address) -> bo
#[cfg(test)]
mod tests {
use super::*;
+ use std::time::Duration;
#[tokio::test]
async fn test_is_signer_key_available() {
diff --git a/common/src/signer/web3signer_info.rs b/common/src/signer/web3signer_info.rs
new file mode 100644
index 00000000..b9d1da6f
--- /dev/null
+++ b/common/src/signer/web3signer_info.rs
@@ -0,0 +1,46 @@
+use alloy::primitives::Address;
+use anyhow::{Result, anyhow};
+use std::path::PathBuf;
+use std::time::Duration;
+
+const SIGNER_TIMEOUT: Duration = Duration::from_secs(10);
+pub struct Web3SignerInfo {
+ pub url: String,
+ pub timeout: Duration,
+ pub signer_address: String,
+ pub ca_cert: PathBuf,
+ pub client_cert: PathBuf,
+ pub client_key: PathBuf,
+}
+
+impl Web3SignerInfo {
+ pub fn new(
+ web3signer_url: Option,
+ web3signer_root_certificate_path: Option,
+ web3signer_client_certificate_path: Option,
+ web3signer_client_key_path: Option,
+ preconfer_address: Option,
+ ) -> Result