diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 6961d7eb..de283114 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -226,6 +226,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let (mesh, mesh_state) = Mesh::init(&client, mesh_options); let contract_state = Arc::new(RwLock::new(None)); + let eth = eth.into_config(); let network = NetworkConfig { cipher_sk: hpke::SecretKey::try_from_bytes(&hex::decode(cipher_sk)?)?, cipher_pk: hpke::PublicKey::try_from_bytes(&hex::decode(cipher_pk)?)?, @@ -244,7 +245,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { ?account_id, ?my_address, near_rpc_url = ?near_client.rpc_addr(), - eth_rpc_url = ?eth.eth_rpc_http_url, + ?eth, "starting node", ); rt.block_on(async { diff --git a/chain-signatures/node/src/indexer_eth.rs b/chain-signatures/node/src/indexer_eth.rs index d887ac8c..e0d61e51 100644 --- a/chain-signatures/node/src/indexer_eth.rs +++ b/chain-signatures/node/src/indexer_eth.rs @@ -7,12 +7,36 @@ use hex::ToHex; use k256::Scalar; use near_account_id::AccountId; use serde::{Deserialize, Serialize}; +use std::fmt; use std::str::FromStr; use std::time::{Duration, Instant}; use tokio::sync::mpsc; use web3::futures::StreamExt; use web3::types::{FilterBuilder, Log, H160, H256, U256}; +#[derive(Clone)] +pub struct EthConfig { + /// The ethereum account secret key used to sign eth respond txn. + pub account_sk: String, + /// Ethereum WebSocket RPC URL + pub rpc_ws_url: String, + /// Ethereum HTTP RPC URL + pub rpc_http_url: String, + /// The contract address to watch without the `0x` prefix + pub contract_address: String, +} + +impl fmt::Debug for EthConfig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EthConfig") + .field("account_sk", &"") + .field("rpc_ws_url", &self.rpc_ws_url) + .field("rpc_http_url", &self.rpc_http_url) + .field("contract_address", &self.contract_address) + .finish() + } +} + /// Configures Ethereum indexer. #[derive(Debug, Clone, clap::Parser)] #[group(id = "indexer_eth_options")] @@ -49,11 +73,13 @@ impl EthArgs { args } - pub fn is_none(&self) -> bool { - self.eth_account_sk.is_none() - || self.eth_rpc_ws_url.is_none() - || self.eth_rpc_http_url.is_none() - || self.eth_contract_address.is_none() + pub fn into_config(self) -> Option { + Some(EthConfig { + account_sk: self.eth_account_sk?, + rpc_ws_url: self.eth_rpc_ws_url?, + rpc_http_url: self.eth_rpc_http_url?, + contract_address: self.eth_contract_address?, + }) } } @@ -160,17 +186,17 @@ fn parse_event(log: &Log) -> anyhow::Result { } pub async fn run( - args: EthArgs, + eth: Option, sign_tx: mpsc::Sender, node_near_account_id: AccountId, ) -> anyhow::Result<()> { - if args.is_none() { + let Some(eth) = eth else { tracing::warn!("ethereum indexer is disabled"); return Ok(()); - } + }; tracing::info!("running ethereum indexer"); - let contract_address = H160::from_str(&args.eth_contract_address.unwrap())?; + let contract_address = H160::from_str(ð.contract_address)?; let signature_requested_topic = H256::from_slice(&web3::signing::keccak256( b"SignatureRequested(bytes32,address,uint256,uint256,string)", )); @@ -180,9 +206,8 @@ pub async fn run( .topics(Some(vec![signature_requested_topic]), None, None, None) .build(); - let rpc_ws = args.eth_rpc_ws_url.unwrap(); loop { - match web3::transports::WebSocket::new(&rpc_ws).await { + match web3::transports::WebSocket::new(ð.rpc_ws_url).await { Ok(ws) => { let web3_ws = web3::Web3::new(ws); match web3_ws.eth_subscribe().subscribe_logs(filter.clone()).await { diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 2ad54667..b2314086 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -336,7 +336,7 @@ fn update_system_metrics(node_account_id: &str) { .set(total_disk_space); } -#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq, Copy, Hash)] pub enum Chain { NEAR, Ethereum, diff --git a/chain-signatures/node/src/rpc.rs b/chain-signatures/node/src/rpc.rs index 93f46e2c..380d7ebe 100644 --- a/chain-signatures/node/src/rpc.rs +++ b/chain-signatures/node/src/rpc.rs @@ -1,5 +1,5 @@ use crate::config::{Config, ContractConfig, NetworkConfig}; -use crate::indexer_eth::EthArgs; +use crate::indexer_eth::EthConfig; use crate::protocol::signature::ToPublish; use crate::protocol::{Chain, ProtocolState}; use crate::util::AffinePointExt as _; @@ -69,14 +69,14 @@ pub struct RpcExecutor { } impl RpcExecutor { - pub fn new(near: &NearClient, eth: &EthArgs) -> (RpcChannel, Self) { - let eth = EthClient::new(eth); + pub fn new(near: &NearClient, eth: &Option) -> (RpcChannel, Self) { + let eth = eth.as_ref().map(EthClient::new); let (tx, rx) = mpsc::channel(MAX_CONCURRENT_RPC_REQUESTS); ( RpcChannel { tx }, Self { near: near.clone(), - eth: eth.clone(), + eth, action_rx: rx, }, ) @@ -285,10 +285,10 @@ pub struct EthClient { } impl EthClient { - pub fn new(args: &crate::indexer_eth::EthArgs) -> Option { - let transport = web3::transports::Http::new(args.eth_rpc_http_url.as_ref()?).unwrap(); + pub fn new(eth: &EthConfig) -> Self { + let transport = web3::transports::Http::new(ð.rpc_http_url).unwrap(); let client = web3::Web3::new(transport); - let address = web3::types::H160::from_str(args.eth_contract_address.as_ref()?).unwrap(); + let address = web3::types::H160::from_str(ð.contract_address).unwrap(); let contract_json: serde_json::Value = serde_json::from_slice(include_bytes!( "../../contract-eth/artifacts/contracts/ChainSignatures.sol/ChainSignatures.json" @@ -300,12 +300,12 @@ impl EthClient { contract_json["abi"].to_string().as_bytes(), ) .unwrap(); - Some(Self { + Self { client, contract, - account_sk: web3::signing::SecretKey::from_str(args.eth_account_sk.as_ref()?) + account_sk: web3::signing::SecretKey::from_str(ð.account_sk) .expect("failed to parse eth account sk, should not begin with 0x"), - }) + } } } diff --git a/integration-tests/src/containers.rs b/integration-tests/src/containers.rs index f1250042..52293b97 100644 --- a/integration-tests/src/containers.rs +++ b/integration-tests/src/containers.rs @@ -123,10 +123,10 @@ impl Node { behind_threshold: 120, }; let eth_args = mpc_node::indexer_eth::EthArgs { - eth_account_sk: Some(config.cfg.eth_account_sk.clone()), - eth_rpc_ws_url: Some(config.cfg.eth_rpc_ws_url.clone()), - eth_rpc_http_url: Some(config.cfg.eth_rpc_http_url.clone()), - eth_contract_address: Some(config.cfg.eth_contract_address.clone()), + eth_account_sk: Some(config.cfg.eth.account_sk.clone()), + eth_rpc_ws_url: Some(config.cfg.eth.rpc_ws_url.clone()), + eth_rpc_http_url: Some(config.cfg.eth.rpc_http_url.clone()), + eth_contract_address: Some(config.cfg.eth.contract_address.clone()), }; let args = mpc_node::cli::Cli::Start { near_rpc: config.near_rpc.clone(), diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index 5eac4901..26f36afb 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -8,6 +8,7 @@ pub mod utils; use cluster::spawner::ClusterSpawner; use containers::Container; use deadpool_redis::Pool; +use mpc_node::indexer_eth::EthConfig; use std::collections::HashMap; use self::local::NodeEnvConfig; @@ -33,10 +34,7 @@ pub struct NodeConfig { pub nodes: usize, pub threshold: usize, pub protocol: ProtocolConfig, - pub eth_rpc_ws_url: String, - pub eth_rpc_http_url: String, - pub eth_contract_address: String, - pub eth_account_sk: String, + pub eth: EthConfig, } impl Default for NodeConfig { @@ -59,11 +57,13 @@ impl Default for NodeConfig { }, ..Default::default() }, - eth_rpc_http_url: "http://localhost:8545".to_string(), - eth_rpc_ws_url: "ws://localhost:8545".to_string(), - eth_contract_address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512".to_string(), - eth_account_sk: "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" - .to_string(), + eth: EthConfig { + rpc_http_url: "http://localhost:8545".to_string(), + rpc_ws_url: "ws://localhost:8545".to_string(), + contract_address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512".to_string(), + account_sk: "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" + .to_string(), + }, } } } diff --git a/integration-tests/src/local.rs b/integration-tests/src/local.rs index dc4cce2d..eaebca7d 100644 --- a/integration-tests/src/local.rs +++ b/integration-tests/src/local.rs @@ -71,10 +71,10 @@ impl Node { behind_threshold: 120, }; let eth = mpc_node::indexer_eth::EthArgs { - eth_account_sk: Some(cfg.eth_account_sk.clone()), - eth_rpc_ws_url: Some(cfg.eth_rpc_ws_url.clone()), - eth_rpc_http_url: Some(cfg.eth_rpc_http_url.clone()), - eth_contract_address: Some(cfg.eth_contract_address.clone()), + eth_account_sk: Some(cfg.eth.account_sk.clone()), + eth_rpc_ws_url: Some(cfg.eth.rpc_ws_url.clone()), + eth_rpc_http_url: Some(cfg.eth.rpc_http_url.clone()), + eth_contract_address: Some(cfg.eth.contract_address.clone()), }; let near_rpc = ctx.lake_indexer.rpc_host_address.clone(); let mpc_contract_id = ctx.mpc_contract.id().clone(); @@ -180,10 +180,10 @@ impl Node { }; let eth = mpc_node::indexer_eth::EthArgs { - eth_account_sk: Some(config.cfg.eth_account_sk.clone()), - eth_rpc_ws_url: Some(config.cfg.eth_rpc_ws_url.clone()), - eth_rpc_http_url: Some(config.cfg.eth_rpc_http_url.clone()), - eth_contract_address: Some(config.cfg.eth_contract_address.clone()), + eth_account_sk: Some(config.cfg.eth.account_sk.clone()), + eth_rpc_ws_url: Some(config.cfg.eth.rpc_ws_url.clone()), + eth_rpc_http_url: Some(config.cfg.eth.rpc_http_url.clone()), + eth_contract_address: Some(config.cfg.eth.contract_address.clone()), }; let cli = mpc_node::cli::Cli::Start { near_rpc: config.near_rpc.clone(), diff --git a/integration-tests/src/main.rs b/integration-tests/src/main.rs index 7e553bac..04f4eaa9 100644 --- a/integration-tests/src/main.rs +++ b/integration-tests/src/main.rs @@ -6,6 +6,7 @@ use std::vec; use clap::Parser; use integration_tests::cluster::spawner::ClusterSpawner; use integration_tests::{utils, NodeConfig}; +use mpc_node::indexer_eth::EthConfig; use near_account_id::AccountId; use near_crypto::PublicKey; use serde_json::json; @@ -63,10 +64,12 @@ async fn main() -> anyhow::Result<()> { let config = NodeConfig { nodes, threshold, - eth_rpc_ws_url, - eth_rpc_http_url, - eth_contract_address, - eth_account_sk, + eth: EthConfig { + account_sk: eth_account_sk, + rpc_ws_url: eth_rpc_ws_url, + rpc_http_url: eth_rpc_http_url, + contract_address: eth_contract_address, + }, ..Default::default() }; println!("Full config: {:?}", config);