Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
38 changes: 36 additions & 2 deletions common/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ pub struct Config {
pub preconfer_address: Option<Address>,
pub web3signer_l1_url: Option<String>,
pub web3signer_l2_url: Option<String>,
pub web3signer_root_certificate_path: Option<String>,
pub web3signer_client_certificate_path: Option<String>,
pub web3signer_client_key_path: Option<String>,
pub catalyst_node_ecdsa_private_key: Option<String>,
// L1
pub l1_rpc_urls: Vec<String>,
Expand Down Expand Up @@ -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"
));
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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): {}
Expand Down Expand Up @@ -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,
Expand Down
13 changes: 8 additions & 5 deletions common/src/l1/config.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -26,12 +26,15 @@ pub struct EthereumL1Config {

impl EthereumL1Config {
pub async fn new(config: &Config) -> Result<Self, Error> {
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(),
Expand Down
6 changes: 2 additions & 4 deletions common/src/shared/alloy_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?)
Expand Down
2 changes: 1 addition & 1 deletion common/src/shared/transaction_monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub struct TxMonitorHandles {
pub tx_result_receiver: tokio::sync::oneshot::Receiver<bool>,
}

#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct TransactionMonitorConfig {
min_priority_fee_per_gas_wei: u128,
tx_fees_increase_percentage: u128,
Expand Down
25 changes: 11 additions & 14 deletions common/src/signer/mod.rs
Original file line number Diff line number Diff line change
@@ -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<Web3Signer>, Address),
PrivateKey(String, Address),
}

const SIGNER_TIMEOUT: Duration = Duration::from_secs(10);

pub async fn create_signer(
web3signer_url: Option<String>,
web3signer_info: Option<Web3SignerInfo>,
catalyst_node_ecdsa_private_key: Option<String>,
preconfer_address: Option<Address>,
) -> Result<Arc<Signer>, 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())
Expand Down
33 changes: 20 additions & 13 deletions common/src/signer/web3signer.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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<Self, Error> {
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<Self, Error> {
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 })
Expand Down Expand Up @@ -137,7 +143,7 @@ impl Web3Signer {
}
}

#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Web3TxSigner {
inner: Arc<Web3Signer>,
address: Address,
Expand Down Expand Up @@ -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() {
Expand Down
46 changes: 46 additions & 0 deletions common/src/signer/web3signer_info.rs
Original file line number Diff line number Diff line change
@@ -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<String>,
web3signer_root_certificate_path: Option<String>,
web3signer_client_certificate_path: Option<String>,
web3signer_client_key_path: Option<String>,
preconfer_address: Option<Address>,
) -> Result<Option<Self>> {
let Some(url) = web3signer_url else {
// Web3Signer is not configured.
return Ok(None);
};

Ok(Some(Self {
url,
timeout: SIGNER_TIMEOUT,
signer_address: preconfer_address
.ok_or_else(|| anyhow!("preconfer_address is required when using Web3Signer"))?
.to_string(),
ca_cert: PathBuf::from(web3signer_root_certificate_path.ok_or_else(|| {
anyhow!("web3signer_root_certificate_path is required when using Web3Signer")
})?),
client_cert: PathBuf::from(web3signer_client_certificate_path.ok_or_else(|| {
anyhow!("web3signer_client_certificate_path is required when using Web3Signer")
})?),
client_key: PathBuf::from(web3signer_client_key_path.ok_or_else(|| {
anyhow!("web3signer_client_key_path is required when using Web3Signer")
})?),
}))
}
}
Loading
Loading