Skip to content

Commit

Permalink
feat: use alloy-rs (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
MujkicA authored Aug 29, 2024
1 parent 03ad531 commit f98e764
Show file tree
Hide file tree
Showing 28 changed files with 1,849 additions and 6,601 deletions.
3,009 changes: 1,474 additions & 1,535 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 4 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,20 @@ services = { path = "./packages/services", default-features = false }
validator = { path = "./packages/validator", default-features = false }

actix-web = { version = "4", default-features = false }
alloy = { version = "0.2.1", default-features = false }
alloy-chains = { version = "0.1.0", default-features = false }
anyhow = { version = "1.0", default-features = false }
aws-config = { version = "1.5.5", default-features = false }
aws-sdk-kms = { version = "1.36", default-features = false }
async-trait = { version = "0.1", default-features = false }
c-kzg = { version = "1.0", default-features = false }
clap = { version = "4.5", default-features = false }
config = { version = "0.14", default-features = false }
ethers = { version = "2.0", default-features = false }
ethers-core = { version = "2.0", default-features = false }
fuel-core-client = { version = "0.31", default-features = false }
fuel-crypto = { version = "0.55", default-features = false }
futures = { version = "0.3", default-features = false }
hex = { version = "0.4", default-features = false }
humantime = { version = "2.1", default-features = false }
# `ethers` uses `rusoto_kms` for its AWS signer. To configure the AWS client,
# both `hyper` and `hyper-rustls` are required. The versions specified here
# are taken from the `Cargo.toml` of the `rusoto_kms` version that ethers
# uses. These crates are necessary because ethers doesn't re-export the
# types required to configure the AWS client.
hyper = { version = "0.14", default-features = false }
hyper-rustls = { version = "0.23", default-features = false }
impl-tools = { version = "0.10.0", default-features = false }
itertools = { version = "0.13", default-features = false }
mockall = { version = "0.12", default-features = false }
Expand All @@ -59,9 +54,6 @@ prometheus = { version = "0.13", default-features = false }
rand = { version = "0.8", default-features = false }
reqwest = { version = "0.12", default-features = false }
rlp = { version = "0.5.2", default-features = false }
rusoto_core = { version = "0.48", default-features = false }
rusoto_kms = { version = "0.48", default-features = false }
rusoto_sts = { version = "0.48", default-features = false }
secp256k1 = { version = "0.29", default-features = false }
serde = { version = "1.0", default-features = false }
serde_json = { version = "1.0", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions committer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ rust-version = { workspace = true }

[dependencies]
actix-web = { workspace = true, features = ["macros"] }
alloy-chains = { workspace = true, features = [ "serde" ] }
clap = { workspace = true, features = ["default", "derive"] }
config = { workspace = true, features = ["toml", "async"] }
eth = { workspace = true }
Expand Down
21 changes: 8 additions & 13 deletions committer/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::{net::Ipv4Addr, path::PathBuf, str::FromStr, time::Duration};

use alloy_chains::NamedChain;
use clap::{command, Parser};
use eth::{Address, Chain};
use eth::Address;
use serde::Deserialize;
use storage::DbConfig;
use url::Url;
Expand All @@ -11,7 +12,6 @@ pub struct Config {
pub eth: Eth,
pub fuel: Fuel,
pub app: App,
pub aws: Aws,
}

impl Config {
Expand Down Expand Up @@ -47,19 +47,19 @@ pub struct Eth {
#[serde(deserialize_with = "parse_url")]
pub rpc: Url,
/// Chain id of the ethereum network.
#[serde(deserialize_with = "parse_chain_id")]
pub chain_id: Chain,
#[serde(deserialize_with = "deserialize_named_chain")]
pub chain_id: NamedChain,
/// Ethereum address of the fuel chain state contract.
pub state_contract_address: Address,
}

fn parse_chain_id<'de, D>(deserializer: D) -> Result<Chain, D::Error>
fn deserialize_named_chain<'de, D>(deserializer: D) -> Result<NamedChain, D::Error>
where
D: serde::Deserializer<'de>,
{
let chain_id: String = Deserialize::deserialize(deserializer)?;
Chain::from_str(&chain_id).map_err(|_| {
let msg = format!("Failed to parse chain id '{chain_id}'");
let chain_str: String = Deserialize::deserialize(deserializer).unwrap();
NamedChain::from_str(&chain_str).map_err(|_| {
let msg = format!("Failed to parse chain from '{chain_str}'");
serde::de::Error::custom(msg)
})
}
Expand All @@ -75,11 +75,6 @@ where
})
}

#[derive(Debug, Clone, Deserialize)]
pub struct Aws {
pub allow_http: bool,
}

#[derive(Debug, Clone, Deserialize)]
pub struct App {
/// Port used by the started server
Expand Down
14 changes: 6 additions & 8 deletions committer/src/setup.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{num::NonZeroU32, time::Duration};

use eth::{AwsCredentialsProvider, AwsRegion};
use eth::AwsConfig;
use metrics::{prometheus::Registry, HealthChecker, RegistersMetrics};
use ports::storage::Storage;
use services::{BlockCommitter, CommitListener, Runner, WalletBalanceTracker};
Expand Down Expand Up @@ -127,15 +127,13 @@ pub async fn l1_adapter(
internal_config: &config::Internal,
registry: &Registry,
) -> Result<(L1, HealthChecker)> {
let aws_client = AwsClient::try_new(
config.aws.allow_http,
AwsRegion::default(),
AwsCredentialsProvider::new_chain(),
)?;
let aws_config = AwsConfig::from_env().await;

let aws_client = AwsClient::new(aws_config).await;

let l1 = L1::connect(
&config.eth.rpc,
config.eth.chain_id,
config.eth.rpc.clone(),
config.eth.chain_id.into(),
config.eth.state_contract_address,
config.eth.main_key_id.clone(),
config.eth.blob_pool_key_id.clone(),
Expand Down
2 changes: 1 addition & 1 deletion configurations/development/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ block_producer_public_key = "0x73dc6cc8cc0041e4924954b35a71a22ccb520664c522198a6
port = 8080
host = "0.0.0.0"
block_check_interval = "1s"
num_blocks_to_finalize_tx = 12
num_blocks_to_finalize_tx = "12"

[app.db]
host = "localhost"
Expand Down
9 changes: 4 additions & 5 deletions e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,21 @@ walkdir = { workspace = true }
zip = { workspace = true, features = ["deflate"] }

[dev-dependencies]
alloy = { workspace = true, features = [ "signer-aws", "signer-mnemonic", "serde" ] }
alloy-chains = { workspace = true }
anyhow = { workspace = true, features = ["std"] }
aws-sdk-kms = { workspace = true, features = ["rustls"] }
aws-config = { workspace = true, features = ["rustls"] }
eth = { workspace = true, features = ["test-helpers"] }
ethers = { workspace = true, features = ["aws"] }
fuel = { workspace = true, features = ["test-helpers"] }
hex = { workspace = true }
hyper = { workspace = true }
hyper-rustls = { workspace = true }
portpicker = { workspace = true }
ports = { workspace = true, features = ["fuel", "l1"] }
rand = { workspace = true, features = ["std"] }
reqwest = { workspace = true }
# `rustls` must be used because `ethers` enables it, and it cannot be enabled
# simultaneously with `native-tls`. Since we cannot configure this within
# `ethers`, we must also use `rustls`.
rusoto_core = { workspace = true, features = ["rustls"] }
rusoto_kms = { workspace = true, features = ["rustls"] }
secp256k1 = { workspace = true, features = ["rand-std"] }
serde = { workspace = true }
serde_json = { workspace = true }
Expand Down
18 changes: 9 additions & 9 deletions e2e/src/committer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::{path::Path, time::Duration};

use anyhow::Context;
use eth::AwsRegion;
use ethers::abi::Address;
use ports::types::Address;
use url::Url;

#[derive(Default)]
Expand All @@ -16,7 +15,7 @@ pub struct Committer {
fuel_block_producer_addr: Option<String>,
db_port: Option<u16>,
db_name: Option<String>,
aws_region: Option<AwsRegion>,
kms_url: Option<String>,
}

impl Committer {
Expand All @@ -33,11 +32,12 @@ impl Committer {
let unused_port = portpicker::pick_unused_port()
.ok_or_else(|| anyhow::anyhow!("No free port to start fuel-block-committer"))?;

let kms_url = get_field!(kms_url);
let mut cmd = tokio::process::Command::new("fuel-block-committer");
let region_serialized = serde_json::to_string(&get_field!(aws_region))?;
cmd.arg(config)
.env("AWS_REGION", region_serialized)
.env("E2E_TEST_AWS_ENDPOINT", kms_url)
.env("AWS_ACCESS_KEY_ID", "test")
.env("AWS_REGION", "us-east-1")
.env("AWS_SECRET_ACCESS_KEY", "test")
.env("COMMITTER__ETH__MAIN_KEY_ID", get_field!(main_key_id))
.env("COMMITTER__ETH__RPC", get_field!(eth_rpc).as_str())
Expand Down Expand Up @@ -79,13 +79,13 @@ impl Committer {
})
}

pub fn with_aws_region(mut self, region: AwsRegion) -> Self {
self.aws_region = Some(region);
pub fn with_main_key_id(mut self, wallet_id: String) -> Self {
self.main_key_id = Some(wallet_id);
self
}

pub fn with_main_key_id(mut self, wallet_id: String) -> Self {
self.main_key_id = Some(wallet_id);
pub fn with_kms_url(mut self, kms_url: String) -> Self {
self.kms_url = Some(kms_url);
self
}

Expand Down
60 changes: 33 additions & 27 deletions e2e/src/eth_node.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
mod state_contract;
use std::time::Duration;

use ethers::{
abi::Address,
middleware::{Middleware, SignerMiddleware},
providers::{Provider, Ws},
use alloy::{
network::{EthereumWallet, TransactionBuilder},
providers::{Provider, ProviderBuilder, WsConnect},
rpc::types::TransactionRequest,
signers::{
coins_bip39::{English, Mnemonic},
LocalWallet, MnemonicBuilder, Signer,
local::{coins_bip39::English, MnemonicBuilder, PrivateKeySigner},
Signer,
},
types::{Chain, TransactionRequest, U256},
};
use alloy_chains::NamedChain;
use eth::Address;
use ports::types::U256;
use state_contract::CreateTransactions;
pub use state_contract::{ContractArgs, DeployedContract};
use url::Url;
Expand All @@ -27,7 +29,9 @@ impl EthNode {
let unused_port = portpicker::pick_unused_port()
.ok_or_else(|| anyhow::anyhow!("No free port to start anvil"))?;

let mnemonic = Mnemonic::<English>::new(&mut rand::thread_rng()).to_phrase();
let mnemonic =
alloy::signers::local::coins_bip39::Mnemonic::<English>::new(&mut rand::thread_rng())
.to_phrase();

let mut cmd = tokio::process::Command::new("anvil");

Expand All @@ -52,7 +56,7 @@ impl EthNode {
Ok(EthNodeProcess::new(
child,
unused_port,
Chain::AnvilHardhat.into(),
NamedChain::AnvilHardhat.into(),
mnemonic,
))
}
Expand Down Expand Up @@ -94,17 +98,17 @@ impl EthNodeProcess {
.deploy(self.ws_url(), &kms_key)
.await?;

DeployedContract::connect(&self.ws_url(), proxy_contract_address, kms_key).await
DeployedContract::connect(self.ws_url(), proxy_contract_address, kms_key).await
}

fn wallet(&self, index: u32) -> LocalWallet {
fn wallet(&self, index: u32) -> PrivateKeySigner {
MnemonicBuilder::<English>::default()
.phrase(self.mnemonic.as_str())
.index(index)
.expect("Should generate a valid derivation path")
.build()
.expect("phrase to be correct")
.with_chain_id(self.chain_id)
.with_chain_id(Some(self.chain_id))
}

pub fn ws_url(&self) -> Url {
Expand All @@ -118,26 +122,28 @@ impl EthNodeProcess {
}

pub async fn fund(&self, address: Address, amount: U256) -> anyhow::Result<()> {
let wallet = self.wallet(0);
let provider = Provider::<Ws>::connect(self.ws_url())
.await
.expect("to connect to the provider");

let signer_middleware = SignerMiddleware::new(provider, wallet);
let wallet = EthereumWallet::from(self.wallet(0));
let ws = WsConnect::new(self.ws_url());
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet)
.on_ws(ws)
.await?;

let tx = TransactionRequest::pay(address, amount);
let tx = TransactionRequest::default()
.with_to(address)
.with_value(amount);

let status = signer_middleware
.send_transaction(tx, None)
let succeeded = provider
.send_transaction(tx)
.await?
.confirmations(1)
.interval(Duration::from_millis(100))
.with_required_confirmations(1)
.with_timeout(Some(Duration::from_secs(1)))
.get_receipt()
.await?
.unwrap()
.status
.unwrap();
.status();

if status == 1.into() {
if succeeded {
Ok(())
} else {
Err(anyhow::anyhow!("Failed to fund address {address}"))
Expand Down
Loading

0 comments on commit f98e764

Please sign in to comment.