Skip to content

Commit

Permalink
initial config
Browse files Browse the repository at this point in the history
  • Loading branch information
ManojJiSharma committed Dec 9, 2024
1 parent 6d1c052 commit 4781d89
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 2 deletions.
18 changes: 18 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ members = [
"chains/binance",
"chains/avalanche",
"chains/rosetta-chain-testing",
"chains/base",
"chains/base", "chains/linea",
]
resolver = "2"

Expand Down
20 changes: 20 additions & 0 deletions chains/ethereum/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,21 @@ pub fn base_config(network: &str) -> anyhow::Result<BlockchainConfig> {
Ok(evm_config("avalanche", network, "AVAX", bip44_id, is_dev))
}

/// Retrieve the [`BlockchainConfig`] from the provided base `network`
///
/// # Errors
/// Returns `Err` if the network is not supported
pub fn linea_config(network: &str) -> anyhow::Result<BlockchainConfig> {
// All available networks are listed here:
let (network, bip44_id, is_dev) = match network {
"dev" => ("dev", 1, true),
"sepolia" => ("sepolia", 59141, true),
"mainnet" => ("mainnet", 59144, false),
_ => anyhow::bail!("unsupported network: {}", network),
};
Ok(evm_config("linea", network, "ETH", bip44_id, is_dev))
}

/// Retrieve the [`BlockchainConfig`] from the provided ethereum `network`
///
/// # Errors
Expand Down Expand Up @@ -320,6 +335,11 @@ pub fn config(network: &str) -> anyhow::Result<BlockchainConfig> {
"base" => return base_config("mainnet"),
"base-sepolia" => return base_config("fuji"),

// Base
"linea-local" => return base_config("dev"),
"linea" => return base_config("mainnet"),
"linea-sepolia" => return base_config("basu"),

network => return astar_config(network),
};

Expand Down
1 change: 1 addition & 0 deletions chains/ethereum/server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl MaybeWsEthereumClient {
"binance" => rosetta_config_ethereum::binance_config(network)?,
"avalanche" => rosetta_config_ethereum::avalanche_config(network)?,
"base" => rosetta_config_ethereum::base_config(network)?,
"linea" => rosetta_config_ethereum::linea_config(network)?,
blockchain => anyhow::bail!("unsupported blockchain: {blockchain}"),
};
Self::from_config(config, addr, private_key).await
Expand Down
21 changes: 21 additions & 0 deletions chains/linea/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "linea"
version = "0.1.0"
edition = "2021"
license = "MIT"
repository = "https://github.com/analog-labs/chain-connectors"
description = "linea rosetta test."

[dependencies]
alloy-sol-types = { version = "0.8" }
anyhow = "1.0"
ethers = { version = "2.0", default-features = true, features = ["abigen", "rustls", "ws"] }
ethers-solc = "2.0"
hex-literal = "0.4"
rosetta-chain-testing = { path = "../rosetta-chain-testing" }
rosetta-client.workspace = true
rosetta-config-ethereum.workspace = true
rosetta-core.workspace = true
rosetta-server-ethereum.workspace = true
sha3 = "0.10"
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
254 changes: 254 additions & 0 deletions chains/linea/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
//! # Binance Rosetta Server Test Suite
//!
//! This module contains a test suite for an Ethereum Rosetta server implementation
//! specifically designed for interacting with the Binance network. The code includes
//! tests for network status, account management, and smart contract interaction.
//!
//! ## Features
//!
//! - Network status tests to ensure proper connection and consistency with the Binance network.
//! - Account tests, including faucet funding, balance retrieval, and error handling.
//! - Smart contract tests covering deployment, event emission, and view function calls.
//!
//! ## Dependencies
//!
//! - `anyhow`: For flexible error handling.
//! - `alloy_sol_types`: Custom types and macros for interacting with Solidity contracts.
//! - `ethers`: Ethereum library for interaction with Ethereum clients.
//! - `ethers_solc`: Integration for compiling Solidity code using the Solc compiler.
//! - `hex_literal`: Macro for creating byte array literals from hexadecimal strings.
//! - `rosetta_client`: Client library for Rosetta API interactions.
//! - `rosetta_config_ethereum`: Configuration for Ethereum Rosetta server.
//! - `rosetta_server_ethereum`: Custom client implementation for interacting with Ethereum.
//! - `sha3`: SHA-3 (Keccak) implementation for hashing.
//! - `tokio`: Asynchronous runtime for running async functions.
//!
//! ## Usage
//!
//! To run the tests, execute the following command:
//!
//! ```sh
//! cargo test --package rosetta-testing-linea --lib -- tests --nocapture
//! ```
//!
//! Note: The code assumes a local Binance RPC node running on `ws://127.0.0.1:8546`. Ensure
//! that this endpoint is configured correctly.
#[allow(clippy::ignored_unit_patterns, clippy::pub_underscore_fields)]
#[cfg(test)]
mod tests {
use alloy_sol_types::{sol, SolCall};
use anyhow::Result;
use ethers::types::H256;

use ethers_solc::{artifacts::Source, CompilerInput, EvmVersion, Solc};
use hex_literal::hex;
use rosetta_chain_testing::run_test;
use rosetta_client::Wallet;
use rosetta_config_ethereum::{AtBlock, CallResult};
use rosetta_core::BlockchainClient;
use rosetta_server_ethereum::MaybeWsEthereumClient;
use sha3::Digest;
use std::{collections::BTreeMap, path::Path};

/// Binance rpc url
const LINEA_RPC_WS_URL: &str = "http://localhost:8545";

sol! {
interface TestContract {
event AnEvent();
function emitEvent() external;

function identity(bool a) external view returns (bool);
}
}

#[tokio::test]
async fn network_status() {
run_test(async move {
let client = MaybeWsEthereumClient::new("linea", "dev", LINEA_RPC_WS_URL, None)
.await
.expect("Error creating client");
// Check if the genesis is consistent
let genesis_block = client.genesis_block();
assert_eq!(genesis_block.index, 0);

// Check if the current block is consistent
let current_block = client.current_block().await.unwrap();
if current_block.index > 0 {
assert_ne!(current_block.hash, genesis_block.hash);
} else {
assert_eq!(current_block.hash, genesis_block.hash);
}

// Check if the finalized block is consistent
let finalized_block = client.finalized_block().await.unwrap();
assert!(finalized_block.index >= genesis_block.index);
})
.await;
}

#[tokio::test]
async fn test_account() {
run_test(async move {
let client = MaybeWsEthereumClient::new("linea", "dev", LINEA_RPC_WS_URL, None)
.await
.expect("Error creating LineaClient");
let wallet =
Wallet::from_config(client.config().clone(), LINEA_RPC_WS_URL, None, None)
.await
.unwrap();
let value = 10 * u128::pow(10, client.config().currency_decimals);
let _ = wallet.faucet(value, None).await;
let amount = wallet.balance().await.unwrap();
assert_eq!(amount, value);
})
.await;
}

#[tokio::test]
async fn test_construction() {
run_test(async move {
let client = MaybeWsEthereumClient::new("linea", "dev", LINEA_RPC_WS_URL, None)
.await
.expect("Error creating LineaClient");
let faucet = 100 * u128::pow(10, client.config().currency_decimals);
let value = u128::pow(10, client.config().currency_decimals);
let alice =
Wallet::from_config(client.config().clone(), LINEA_RPC_WS_URL, None, None)
.await
.unwrap();
let bob = Wallet::from_config(client.config().clone(), LINEA_RPC_WS_URL, None, None)
.await
.unwrap();
assert_ne!(alice.public_key(), bob.public_key());

// Alice and bob have no balance
let balance = alice.balance().await.unwrap();
assert_eq!(balance, 0);
let balance = bob.balance().await.unwrap();
assert_eq!(balance, 0);

// Transfer faucets to alice
alice.faucet(faucet, None).await.unwrap();
let balance = alice.balance().await.unwrap();
assert_eq!(balance, faucet);

// Alice transfers to bob
alice.transfer(bob.account(), value, None, None).await.unwrap();
let amount = bob.balance().await.unwrap();
assert_eq!(amount, value);
})
.await;
}

fn compile_snippet(source: &str) -> Result<Vec<u8>> {
let solc = Solc::default();
let source = format!("contract Contract {{ {source} }}");
let mut sources = BTreeMap::new();
sources.insert(Path::new("contract.sol").into(), Source::new(source));
let input = CompilerInput::with_sources(sources)[0]
.clone()
.evm_version(EvmVersion::Homestead);
let output = solc.compile_exact(&input)?;
let file = output.contracts.get("contract.sol").unwrap();
let contract = file.get("Contract").unwrap();
let bytecode = contract
.evm
.as_ref()
.unwrap()
.bytecode
.as_ref()
.unwrap()
.object
.as_bytes()
.unwrap()
.to_vec();
Ok(bytecode)
}

#[tokio::test]
async fn test_smart_contract() {
run_test(async move {
let client = MaybeWsEthereumClient::new("linea", "dev", LINEA_RPC_WS_URL, None)
.await
.expect("Error creating LineaClient");
let faucet = 10 * u128::pow(10, client.config().currency_decimals);
let wallet =
Wallet::from_config(client.config().clone(), LINEA_RPC_WS_URL, None, None)
.await
.unwrap();
wallet.faucet(faucet, None).await.unwrap();

let bytes = compile_snippet(
r"
event AnEvent();
function emitEvent() public {
emit AnEvent();
}
",
)
.unwrap();
let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap().tx_hash().0;
let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap();
let contract_address = receipt.contract_address.unwrap();
let tx_hash = {
let call = TestContract::emitEventCall {};
wallet
.eth_send_call(contract_address.0, call.abi_encode(), 0, None, None)
.await
.unwrap()
.tx_hash()
.0
};
let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap();
assert_eq!(receipt.logs.len(), 1);
let topic = receipt.logs[0].topics[0];
let expected = H256(sha3::Keccak256::digest("AnEvent()").into());
assert_eq!(topic, expected);
})
.await;
}

#[tokio::test]
async fn test_smart_contract_view() {
run_test(async move {
let client = MaybeWsEthereumClient::new("linea", "dev", LINEA_RPC_WS_URL, None)
.await
.expect("Error creating LineaClient");
let faucet = 10 * u128::pow(10, client.config().currency_decimals);
let wallet =
Wallet::from_config(client.config().clone(), LINEA_RPC_WS_URL, None, None)
.await
.unwrap();
wallet.faucet(faucet, None).await.unwrap();
let bytes = compile_snippet(
r"
function identity(bool a) public view returns (bool) {
return a;
}
",
)
.unwrap();
let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap().tx_hash().0;
let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap();
let contract_address = receipt.contract_address.unwrap();

let response = {
let call = TestContract::identityCall { a: true };
wallet
.eth_view_call(contract_address.0, call.abi_encode(), AtBlock::Latest)
.await
.unwrap()
};
assert_eq!(
response,
CallResult::Success(
hex!("0000000000000000000000000000000000000000000000000000000000000001")
.to_vec()
)
);
})
.await;
}
}
5 changes: 5 additions & 0 deletions rosetta-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ impl GenericClient {
let client = EthereumClient::new("base", network, url, private_key).await?;
Self::Ethereum(client)
},
Blockchain::Linea => {
let client = EthereumClient::new("linea", network, url, private_key).await?;
Self::Ethereum(client)
},
Blockchain::Avalanche => {
let client = EthereumClient::new("avalanche", network, url, private_key).await?;
Self::Ethereum(client)
Expand Down Expand Up @@ -92,6 +96,7 @@ impl GenericClient {
Blockchain::Arbitrum |
Blockchain::Binance |
Blockchain::Base |
Blockchain::Linea |
Blockchain::Avalanche => {
let client = EthereumClient::from_config(config, url, private_key).await?;
Self::Ethereum(client)
Expand Down
3 changes: 3 additions & 0 deletions rosetta-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub enum Blockchain {
Avalanche,
/// Base
Base,
/// Linea
Linea,
}

impl std::str::FromStr for Blockchain {
Expand All @@ -72,6 +74,7 @@ impl std::str::FromStr for Blockchain {
"binance" => Self::Binance,
"avalanche" => Self::Avalanche,
"base" => Self::Base,
"linea" => Self::Linea,
_ => anyhow::bail!("unsupported blockchain {}", blockchain),
})
}
Expand Down
2 changes: 1 addition & 1 deletion rosetta-client/src/tx_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl GenericTransactionBuilder {
pub fn new(config: &BlockchainConfig) -> Result<Self> {
Ok(match config.blockchain {
"astar" => Self::Astar(rosetta_tx_ethereum::EthereumTransactionBuilder),
"ethereum" | "polygon" | "arbitrum" | "binance" | "base" | "avalanche" => {
"ethereum" | "polygon" | "arbitrum" | "binance" | "base" | "avalanche" | "linea" => {
Self::Ethereum(rosetta_tx_ethereum::EthereumTransactionBuilder)
},
"polkadot" | "westend" | "rococo" => {
Expand Down

0 comments on commit 4781d89

Please sign in to comment.