Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use alloy-rs #106

Merged
merged 13 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
2,851 changes: 1,403 additions & 1,448 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" }
hal3e marked this conversation as resolved.
Show resolved Hide resolved
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
13 changes: 5 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,12 @@ 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().expect("Could not load AWS config");
hal3e marked this conversation as resolved.
Show resolved Hide resolved
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
17 changes: 8 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,10 +32,10 @@ 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_SECRET_ACCESS_KEY", "test")
.env("COMMITTER__ETH__MAIN_KEY_ID", get_field!(main_key_id))
Expand Down Expand Up @@ -79,13 +78,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
Loading