feat: use helios as a library (#85)
* add root helios package * fix revm * copy blocktag when passing to funcs * run all tests * update readme * update readme * update readme
This commit is contained in:
parent
f605f009a7
commit
ba08cc1a3c
|
@ -21,7 +21,7 @@ jobs:
|
||||||
run: rustup target add aarch64-apple-darwin
|
run: rustup target add aarch64-apple-darwin
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cargo build --all --release --target aarch64-apple-darwin
|
run: cargo build --package cli --release --target aarch64-apple-darwin
|
||||||
|
|
||||||
- name: archive
|
- name: archive
|
||||||
run: gtar -czvf "helios_darwin_arm64.tar.gz" -C ./target/aarch64-apple-darwin/release helios
|
run: gtar -czvf "helios_darwin_arm64.tar.gz" -C ./target/aarch64-apple-darwin/release helios
|
||||||
|
@ -58,7 +58,7 @@ jobs:
|
||||||
run: rustup target add x86_64-apple-darwin
|
run: rustup target add x86_64-apple-darwin
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cargo build --all --release --target x86_64-apple-darwin
|
run: cargo build --package cli --release --target x86_64-apple-darwin
|
||||||
|
|
||||||
- name: archive
|
- name: archive
|
||||||
run: gtar -czvf "helios_darwin_amd64.tar.gz" -C ./target/x86_64-apple-darwin/release helios
|
run: gtar -czvf "helios_darwin_amd64.tar.gz" -C ./target/x86_64-apple-darwin/release helios
|
||||||
|
@ -101,7 +101,7 @@ jobs:
|
||||||
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cargo build --all --release --target aarch64-unknown-linux-gnu
|
run: cargo build --package cli --release --target aarch64-unknown-linux-gnu
|
||||||
|
|
||||||
- name: archive
|
- name: archive
|
||||||
run: tar -czvf "helios_linux_arm64.tar.gz" -C ./target/aarch64-unknown-linux-gnu/release helios
|
run: tar -czvf "helios_linux_arm64.tar.gz" -C ./target/aarch64-unknown-linux-gnu/release helios
|
||||||
|
@ -138,7 +138,7 @@ jobs:
|
||||||
run: rustup target add x86_64-unknown-linux-gnu
|
run: rustup target add x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
run: cargo build --all --release --target x86_64-unknown-linux-gnu
|
run: cargo build --package cli --release --target x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
- name: archive
|
- name: archive
|
||||||
run: tar -czvf "helios_linux_amd64.tar.gz" -C ./target/x86_64-unknown-linux-gnu/release helios
|
run: tar -czvf "helios_linux_amd64.tar.gz" -C ./target/x86_64-unknown-linux-gnu/release helios
|
||||||
|
|
|
@ -34,6 +34,7 @@ jobs:
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
|
args: --all
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
name: fmt
|
name: fmt
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
13
Cargo.toml
|
@ -1,3 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "helios"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
|
@ -9,5 +14,13 @@ members = [
|
||||||
"execution",
|
"execution",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
client = { path = "./client" }
|
||||||
|
config = { path = "./config" }
|
||||||
|
common = { path = "./common" }
|
||||||
|
consensus = { path = "./consensus" }
|
||||||
|
execution = { path = "./execution" }
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
ethers = { git = "https://github.com/ncitron/ethers-rs", branch = "fix-retry" }
|
ethers = { git = "https://github.com/ncitron/ethers-rs", branch = "fix-retry" }
|
||||||
|
|
||||||
|
|
36
README.md
36
README.md
|
@ -28,6 +28,8 @@ Helios will now run a local RPC server at `http://127.0.0.1:8545`.
|
||||||
|
|
||||||
`--rpc-port` or `-p` sets the port that the local RPC should run on. The default value is `8545`.
|
`--rpc-port` or `-p` sets the port that the local RPC should run on. The default value is `8545`.
|
||||||
|
|
||||||
|
`--data-dir` or `d` sets the directory that Helios should use to store cached weak subjectivity checkpoints in. Each network only stores the latest checkpoint, which is just 32 bytes.
|
||||||
|
|
||||||
### Configuration Files
|
### Configuration Files
|
||||||
All configuration options can be set on a per-network level in `~/.helios/helios.toml`. Here is an example config file:
|
All configuration options can be set on a per-network level in `~/.helios/helios.toml`. Here is an example config file:
|
||||||
```
|
```
|
||||||
|
@ -42,5 +44,39 @@ execution_rpc = "https://eth-goerli.g.alchemy.com/v2/XXXXX"
|
||||||
checkpoint = "0xb5c375696913865d7c0e166d87bc7c772b6210dc9edf149f4c7ddc6da0dd4495"
|
checkpoint = "0xb5c375696913865d7c0e166d87bc7c772b6210dc9edf149f4c7ddc6da0dd4495"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Using Helios as a Library
|
||||||
|
Helios can be imported into any Rust project. Helios requires the Rust nightly toolchain to compile.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::{str::FromStr, env};
|
||||||
|
|
||||||
|
use helios::{client::ClientBuilder, config::networks::Network, types::BlockTag};
|
||||||
|
use ethers::{types::Address, utils};
|
||||||
|
use eyre::Result;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
let untrusted_rpc_url = env::var("UNTRUSTED_RPC_URL")?;
|
||||||
|
|
||||||
|
let mut client = ClientBuilder::new()
|
||||||
|
.network(Network::MAINNET)
|
||||||
|
.consensus_rpc("https://www.lightclientdata.org")
|
||||||
|
.execution_rpc(&untrusted_rpc_url)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
client.start().await?;
|
||||||
|
|
||||||
|
let head_block_num = client.get_block_number().await?;
|
||||||
|
let addr = Address::from_str("0x00000000219ab540356cBB839Cbe05303d7705Fa")?;
|
||||||
|
let block = BlockTag::Latest;
|
||||||
|
let balance = client.get_balance(&addr, block).await?;
|
||||||
|
|
||||||
|
println!("synced up to block: {}", head_block_num);
|
||||||
|
println!("balance of deposit contract: {}", utils::format_ether(balance));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
All contributions to Helios are welcome. Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds on the nightly rust toolchain, has been linted with `cargo fmt`, and contains tests when applicable.
|
All contributions to Helios are welcome. Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds on the nightly rust toolchain, has been linted with `cargo fmt`, and contains tests when applicable.
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
|
cargo-features = ["different-binary-name"]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "helios"
|
name = "cli"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "cli"
|
||||||
|
filename = "helios"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
clap = { version = "3.2.18", features = ["derive", "env"] }
|
clap = { version = "3.2.18", features = ["derive", "env"] }
|
||||||
|
|
|
@ -15,7 +15,7 @@ ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "cb08f18ca919cc1
|
||||||
blst = "0.3.10"
|
blst = "0.3.10"
|
||||||
ethers = "1.0.0"
|
ethers = "1.0.0"
|
||||||
jsonrpsee = { version = "0.15.1", features = ["full"] }
|
jsonrpsee = { version = "0.15.1", features = ["full"] }
|
||||||
revm = "1.9.0"
|
revm = "2.1.0"
|
||||||
bytes = "1.2.1"
|
bytes = "1.2.1"
|
||||||
futures = "0.3.23"
|
futures = "0.3.23"
|
||||||
toml = "0.5.9"
|
toml = "0.5.9"
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::rpc::Rpc;
|
||||||
pub struct Client<DB: Database> {
|
pub struct Client<DB: Database> {
|
||||||
node: Arc<RwLock<Node>>,
|
node: Arc<RwLock<Node>>,
|
||||||
rpc: Option<Rpc>,
|
rpc: Option<Rpc>,
|
||||||
db: DB,
|
db: Option<DB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<FileDB> {
|
impl Client<FileDB> {
|
||||||
|
@ -38,7 +38,11 @@ impl Client<FileDB> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let data_dir = config.data_dir.clone();
|
let data_dir = config.data_dir.clone();
|
||||||
let db = FileDB::new(data_dir.ok_or(eyre!("data dir not found"))?);
|
let db = if let Some(dir) = data_dir {
|
||||||
|
Some(FileDB::new(dir))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Client { node, rpc, db })
|
Ok(Client { node, rpc, db })
|
||||||
}
|
}
|
||||||
|
@ -114,29 +118,29 @@ impl ClientBuilder {
|
||||||
config.to_base_config()
|
config.to_base_config()
|
||||||
};
|
};
|
||||||
|
|
||||||
let consensus_rpc = self.consensus_rpc.unwrap_or(
|
let consensus_rpc = self.consensus_rpc.unwrap_or_else(|| {
|
||||||
self.config
|
self.config
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(eyre!("missing consensus rpc"))?
|
.expect("missing consensus rpc")
|
||||||
.consensus_rpc
|
.consensus_rpc
|
||||||
.clone(),
|
.clone()
|
||||||
);
|
});
|
||||||
|
|
||||||
let execution_rpc = self.execution_rpc.unwrap_or(
|
let execution_rpc = self.execution_rpc.unwrap_or_else(|| {
|
||||||
self.config
|
self.config
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(eyre!("missing execution rpc"))?
|
.expect("missing execution rpc")
|
||||||
.execution_rpc
|
.execution_rpc
|
||||||
.clone(),
|
.clone()
|
||||||
);
|
});
|
||||||
|
|
||||||
let checkpoint = self.checkpoint.unwrap_or(
|
let checkpoint = if let Some(checkpoint) = self.checkpoint {
|
||||||
self.config
|
checkpoint
|
||||||
.as_ref()
|
} else if let Some(config) = &self.config {
|
||||||
.ok_or(eyre!("missing checkpoint"))?
|
config.checkpoint.clone()
|
||||||
.checkpoint
|
} else {
|
||||||
.clone(),
|
base_config.checkpoint
|
||||||
);
|
};
|
||||||
|
|
||||||
let rpc_port = if self.rpc_port.is_some() {
|
let rpc_port = if self.rpc_port.is_some() {
|
||||||
self.rpc_port
|
self.rpc_port
|
||||||
|
@ -170,15 +174,17 @@ impl ClientBuilder {
|
||||||
|
|
||||||
impl<DB: Database> Client<DB> {
|
impl<DB: Database> Client<DB> {
|
||||||
pub async fn start(&mut self) -> Result<()> {
|
pub async fn start(&mut self) -> Result<()> {
|
||||||
self.rpc.as_mut().unwrap().start().await?;
|
if let Some(rpc) = &mut self.rpc {
|
||||||
|
rpc.start().await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = self.node.write().await.sync().await;
|
||||||
|
if let Err(err) = res {
|
||||||
|
warn!("consensus error: {}", err);
|
||||||
|
}
|
||||||
|
|
||||||
let node = self.node.clone();
|
let node = self.node.clone();
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
let res = node.write().await.sync().await;
|
|
||||||
if let Err(err) = res {
|
|
||||||
warn!("consensus error: {}", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let res = node.write().await.advance().await;
|
let res = node.write().await.advance().await;
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
|
@ -202,13 +208,13 @@ impl<DB: Database> Client<DB> {
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("saving last checkpoint hash");
|
info!("saving last checkpoint hash");
|
||||||
let res = self.db.save_checkpoint(checkpoint);
|
let res = self.db.as_ref().map(|db| db.save_checkpoint(checkpoint));
|
||||||
if res.is_err() {
|
if res.is_some() && res.unwrap().is_err() {
|
||||||
warn!("checkpoint save failed");
|
warn!("checkpoint save failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn call(&self, opts: &CallOpts, block: &BlockTag) -> Result<Vec<u8>> {
|
pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> Result<Vec<u8>> {
|
||||||
self.node.read().await.call(opts, block).await
|
self.node.read().await.call(opts, block).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,15 +222,15 @@ impl<DB: Database> Client<DB> {
|
||||||
self.node.read().await.estimate_gas(opts).await
|
self.node.read().await.estimate_gas(opts).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_balance(&self, address: &Address, block: &BlockTag) -> Result<U256> {
|
pub async fn get_balance(&self, address: &Address, block: BlockTag) -> Result<U256> {
|
||||||
self.node.read().await.get_balance(address, block).await
|
self.node.read().await.get_balance(address, block).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_nonce(&self, address: &Address, block: &BlockTag) -> Result<u64> {
|
pub async fn get_nonce(&self, address: &Address, block: BlockTag) -> Result<u64> {
|
||||||
self.node.read().await.get_nonce(address, block).await
|
self.node.read().await.get_nonce(address, block).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_code(&self, address: &Address, block: &BlockTag) -> Result<Vec<u8>> {
|
pub async fn get_code(&self, address: &Address, block: BlockTag) -> Result<Vec<u8>> {
|
||||||
self.node.read().await.get_code(address, block).await
|
self.node.read().await.get_code(address, block).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +275,7 @@ impl<DB: Database> Client<DB> {
|
||||||
|
|
||||||
pub async fn get_block_by_number(
|
pub async fn get_block_by_number(
|
||||||
&self,
|
&self,
|
||||||
block: &BlockTag,
|
block: BlockTag,
|
||||||
full_tx: bool,
|
full_tx: bool,
|
||||||
) -> Result<Option<ExecutionBlock>> {
|
) -> Result<Option<ExecutionBlock>> {
|
||||||
self.node
|
self.node
|
||||||
|
|
|
@ -98,8 +98,8 @@ impl Node {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn call(&self, opts: &CallOpts, block: &BlockTag) -> Result<Vec<u8>> {
|
pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> Result<Vec<u8>> {
|
||||||
self.check_blocktag_age(block)?;
|
self.check_blocktag_age(&block)?;
|
||||||
|
|
||||||
let payload = self.get_payload(block)?;
|
let payload = self.get_payload(block)?;
|
||||||
let mut evm = Evm::new(self.execution.clone(), payload.clone(), self.chain_id());
|
let mut evm = Evm::new(self.execution.clone(), payload.clone(), self.chain_id());
|
||||||
|
@ -109,29 +109,29 @@ impl Node {
|
||||||
pub async fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
|
pub async fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> {
|
||||||
self.check_head_age()?;
|
self.check_head_age()?;
|
||||||
|
|
||||||
let payload = self.get_payload(&BlockTag::Latest)?;
|
let payload = self.get_payload(BlockTag::Latest)?;
|
||||||
let mut evm = Evm::new(self.execution.clone(), payload.clone(), self.chain_id());
|
let mut evm = Evm::new(self.execution.clone(), payload.clone(), self.chain_id());
|
||||||
evm.estimate_gas(opts).await
|
evm.estimate_gas(opts).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_balance(&self, address: &Address, block: &BlockTag) -> Result<U256> {
|
pub async fn get_balance(&self, address: &Address, block: BlockTag) -> Result<U256> {
|
||||||
self.check_blocktag_age(block)?;
|
self.check_blocktag_age(&block)?;
|
||||||
|
|
||||||
let payload = self.get_payload(block)?;
|
let payload = self.get_payload(block)?;
|
||||||
let account = self.execution.get_account(&address, None, payload).await?;
|
let account = self.execution.get_account(&address, None, payload).await?;
|
||||||
Ok(account.balance)
|
Ok(account.balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_nonce(&self, address: &Address, block: &BlockTag) -> Result<u64> {
|
pub async fn get_nonce(&self, address: &Address, block: BlockTag) -> Result<u64> {
|
||||||
self.check_blocktag_age(block)?;
|
self.check_blocktag_age(&block)?;
|
||||||
|
|
||||||
let payload = self.get_payload(block)?;
|
let payload = self.get_payload(block)?;
|
||||||
let account = self.execution.get_account(&address, None, payload).await?;
|
let account = self.execution.get_account(&address, None, payload).await?;
|
||||||
Ok(account.nonce)
|
Ok(account.nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_code(&self, address: &Address, block: &BlockTag) -> Result<Vec<u8>> {
|
pub async fn get_code(&self, address: &Address, block: BlockTag) -> Result<Vec<u8>> {
|
||||||
self.check_blocktag_age(block)?;
|
self.check_blocktag_age(&block)?;
|
||||||
|
|
||||||
let payload = self.get_payload(block)?;
|
let payload = self.get_payload(block)?;
|
||||||
let account = self.execution.get_account(&address, None, payload).await?;
|
let account = self.execution.get_account(&address, None, payload).await?;
|
||||||
|
@ -141,7 +141,7 @@ impl Node {
|
||||||
pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result<U256> {
|
pub async fn get_storage_at(&self, address: &Address, slot: H256) -> Result<U256> {
|
||||||
self.check_head_age()?;
|
self.check_head_age()?;
|
||||||
|
|
||||||
let payload = self.get_payload(&BlockTag::Latest)?;
|
let payload = self.get_payload(BlockTag::Latest)?;
|
||||||
let account = self
|
let account = self
|
||||||
.execution
|
.execution
|
||||||
.get_account(address, Some(&[slot]), payload)
|
.get_account(address, Some(&[slot]), payload)
|
||||||
|
@ -177,7 +177,7 @@ impl Node {
|
||||||
pub fn get_gas_price(&self) -> Result<U256> {
|
pub fn get_gas_price(&self) -> Result<U256> {
|
||||||
self.check_head_age()?;
|
self.check_head_age()?;
|
||||||
|
|
||||||
let payload = self.get_payload(&BlockTag::Latest)?;
|
let payload = self.get_payload(BlockTag::Latest)?;
|
||||||
let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le());
|
let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le());
|
||||||
let tip = U256::from(10_u64.pow(9));
|
let tip = U256::from(10_u64.pow(9));
|
||||||
Ok(base_fee + tip)
|
Ok(base_fee + tip)
|
||||||
|
@ -192,16 +192,16 @@ impl Node {
|
||||||
pub fn get_block_number(&self) -> Result<u64> {
|
pub fn get_block_number(&self) -> Result<u64> {
|
||||||
self.check_head_age()?;
|
self.check_head_age()?;
|
||||||
|
|
||||||
let payload = self.get_payload(&BlockTag::Latest)?;
|
let payload = self.get_payload(BlockTag::Latest)?;
|
||||||
Ok(payload.block_number)
|
Ok(payload.block_number)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_block_by_number(
|
pub async fn get_block_by_number(
|
||||||
&self,
|
&self,
|
||||||
block: &BlockTag,
|
block: BlockTag,
|
||||||
full_tx: bool,
|
full_tx: bool,
|
||||||
) -> Result<Option<ExecutionBlock>> {
|
) -> Result<Option<ExecutionBlock>> {
|
||||||
self.check_blocktag_age(block)?;
|
self.check_blocktag_age(&block)?;
|
||||||
|
|
||||||
match self.get_payload(block) {
|
match self.get_payload(block) {
|
||||||
Ok(payload) => self
|
Ok(payload) => self
|
||||||
|
@ -247,7 +247,7 @@ impl Node {
|
||||||
self.consensus.last_checkpoint.clone()
|
self.consensus.last_checkpoint.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_payload(&self, block: &BlockTag) -> Result<&ExecutionPayload> {
|
fn get_payload(&self, block: BlockTag) -> Result<&ExecutionPayload> {
|
||||||
match block {
|
match block {
|
||||||
BlockTag::Latest => {
|
BlockTag::Latest => {
|
||||||
let payload = self.payloads.last_key_value();
|
let payload = self.payloads.last_key_value();
|
||||||
|
@ -260,8 +260,8 @@ impl Node {
|
||||||
.1)
|
.1)
|
||||||
}
|
}
|
||||||
BlockTag::Number(num) => {
|
BlockTag::Number(num) => {
|
||||||
let payload = self.payloads.get(num);
|
let payload = self.payloads.get(&num);
|
||||||
payload.ok_or(BlockNotFoundError::new(BlockTag::Number(*num)).into())
|
payload.ok_or(BlockNotFoundError::new(BlockTag::Number(num)).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ impl EthRpcServer for RpcInner {
|
||||||
async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let balance = convert_err(node.get_balance(&address, &block).await)?;
|
let balance = convert_err(node.get_balance(&address, block).await)?;
|
||||||
|
|
||||||
Ok(balance.encode_hex())
|
Ok(balance.encode_hex())
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ impl EthRpcServer for RpcInner {
|
||||||
async fn get_transaction_count(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
async fn get_transaction_count(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let nonce = convert_err(node.get_nonce(&address, &block).await)?;
|
let nonce = convert_err(node.get_nonce(&address, block).await)?;
|
||||||
|
|
||||||
Ok(nonce.encode_hex())
|
Ok(nonce.encode_hex())
|
||||||
}
|
}
|
||||||
|
@ -127,14 +127,14 @@ impl EthRpcServer for RpcInner {
|
||||||
async fn get_code(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
async fn get_code(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let code = convert_err(node.get_code(&address, &block).await)?;
|
let code = convert_err(node.get_code(&address, block).await)?;
|
||||||
|
|
||||||
Ok(hex::encode(code))
|
Ok(hex::encode(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn call(&self, opts: CallOpts, block: BlockTag) -> Result<String, Error> {
|
async fn call(&self, opts: CallOpts, block: BlockTag) -> Result<String, Error> {
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let res = convert_err(node.call(&opts, &block).await)?;
|
let res = convert_err(node.call(&opts, block).await)?;
|
||||||
|
|
||||||
Ok(format!("0x{}", hex::encode(res)))
|
Ok(format!("0x{}", hex::encode(res)))
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ impl EthRpcServer for RpcInner {
|
||||||
full_tx: bool,
|
full_tx: bool,
|
||||||
) -> Result<Option<ExecutionBlock>, Error> {
|
) -> Result<Option<ExecutionBlock>, Error> {
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let block = convert_err(node.get_block_by_number(&block, full_tx).await)?;
|
let block = convert_err(node.get_block_by_number(block, full_tx).await)?;
|
||||||
Ok(block)
|
Ok(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ssz_rs::Vector;
|
||||||
|
|
||||||
pub type Bytes32 = Vector<u8, 32>;
|
pub type Bytes32 = Vector<u8, 32>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum BlockTag {
|
pub enum BlockTag {
|
||||||
Latest,
|
Latest,
|
||||||
Finalized,
|
Finalized,
|
||||||
|
|
|
@ -15,7 +15,7 @@ hex = "0.4.3"
|
||||||
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "cb08f18ca919cc1b685b861d0fa9e2daabe89737" }
|
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "cb08f18ca919cc1b685b861d0fa9e2daabe89737" }
|
||||||
blst = "0.3.10"
|
blst = "0.3.10"
|
||||||
ethers = "1.0.0"
|
ethers = "1.0.0"
|
||||||
revm = "1.9.0"
|
revm = "2.1.0"
|
||||||
bytes = "1.2.1"
|
bytes = "1.2.1"
|
||||||
futures = "0.3.23"
|
futures = "0.3.23"
|
||||||
toml = "0.5.9"
|
toml = "0.5.9"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{cmp, collections::HashMap, fmt::Display, str::FromStr, sync::Arc, thread};
|
use std::{cmp, collections::HashMap, str::FromStr, sync::Arc, thread};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use ethers::{
|
use ethers::{
|
||||||
|
@ -6,7 +6,7 @@ use ethers::{
|
||||||
prelude::{Address, H160, H256, U256},
|
prelude::{Address, H160, H256, U256},
|
||||||
types::transaction::eip2930::AccessListItem,
|
types::transaction::eip2930::AccessListItem,
|
||||||
};
|
};
|
||||||
use eyre::Result;
|
use eyre::{Report, Result};
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use revm::{AccountInfo, Bytecode, Database, Env, TransactOut, TransactTo, EVM};
|
use revm::{AccountInfo, Bytecode, Database, Env, TransactOut, TransactTo, EVM};
|
||||||
|
@ -44,10 +44,9 @@ impl<R: ExecutionRpc> Evm<R> {
|
||||||
self.evm.db.as_mut().unwrap().set_accounts(account_map);
|
self.evm.db.as_mut().unwrap().set_accounts(account_map);
|
||||||
|
|
||||||
self.evm.env = self.get_env(opts);
|
self.evm.env = self.get_env(opts);
|
||||||
let tx = self.evm.transact();
|
let tx = self.evm.transact().0;
|
||||||
let output = tx.1;
|
|
||||||
|
|
||||||
match tx.0 {
|
match tx.exit_reason {
|
||||||
revm::Return::Revert => Err(eyre::eyre!("execution reverted")),
|
revm::Return::Revert => Err(eyre::eyre!("execution reverted")),
|
||||||
revm::Return::OutOfGas => Err(eyre::eyre!("execution reverted: out of gas")),
|
revm::Return::OutOfGas => Err(eyre::eyre!("execution reverted: out of gas")),
|
||||||
revm::Return::OutOfFund => Err(eyre::eyre!("not enough funds")),
|
revm::Return::OutOfFund => Err(eyre::eyre!("not enough funds")),
|
||||||
|
@ -63,7 +62,7 @@ impl<R: ExecutionRpc> Evm<R> {
|
||||||
return Err(eyre::eyre!(err.clone()));
|
return Err(eyre::eyre!(err.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
match output {
|
match tx.out {
|
||||||
TransactOut::None => Err(eyre::eyre!("Invalid Call")),
|
TransactOut::None => Err(eyre::eyre!("Invalid Call")),
|
||||||
TransactOut::Create(..) => Err(eyre::eyre!("Invalid Call")),
|
TransactOut::Create(..) => Err(eyre::eyre!("Invalid Call")),
|
||||||
TransactOut::Call(bytes) => Ok(bytes.to_vec()),
|
TransactOut::Call(bytes) => Ok(bytes.to_vec()),
|
||||||
|
@ -77,10 +76,10 @@ impl<R: ExecutionRpc> Evm<R> {
|
||||||
self.evm.db.as_mut().unwrap().set_accounts(account_map);
|
self.evm.db.as_mut().unwrap().set_accounts(account_map);
|
||||||
|
|
||||||
self.evm.env = self.get_env(opts);
|
self.evm.env = self.get_env(opts);
|
||||||
let tx = self.evm.transact();
|
let tx = self.evm.transact().0;
|
||||||
let gas = tx.2;
|
let gas = tx.gas_used;
|
||||||
|
|
||||||
match tx.0 {
|
match tx.exit_reason {
|
||||||
revm::Return::Revert => Err(eyre::eyre!("execution reverted")),
|
revm::Return::Revert => Err(eyre::eyre!("execution reverted")),
|
||||||
revm::Return::OutOfGas => Err(eyre::eyre!("execution reverted: out of gas")),
|
revm::Return::OutOfGas => Err(eyre::eyre!("execution reverted: out of gas")),
|
||||||
revm::Return::OutOfFund => Err(eyre::eyre!("not enough funds")),
|
revm::Return::OutOfFund => Err(eyre::eyre!("not enough funds")),
|
||||||
|
@ -211,21 +210,11 @@ impl<R: ExecutionRpc> ProofDB<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn safe_unwrap<T: Default, E: Display>(&mut self, res: Result<T, E>) -> T {
|
|
||||||
match res {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(err) => {
|
|
||||||
self.error = Some(err.to_string());
|
|
||||||
T::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_accounts(&mut self, accounts: HashMap<Address, Account>) {
|
pub fn set_accounts(&mut self, accounts: HashMap<Address, Account>) {
|
||||||
self.accounts = accounts;
|
self.accounts = accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_account(&mut self, address: Address, slots: &[H256]) -> Account {
|
fn get_account(&mut self, address: Address, slots: &[H256]) -> Result<Account> {
|
||||||
let execution = self.execution.clone();
|
let execution = self.execution.clone();
|
||||||
let addr = address.clone();
|
let addr = address.clone();
|
||||||
let payload = self.payload.clone();
|
let payload = self.payload.clone();
|
||||||
|
@ -237,14 +226,16 @@ impl<R: ExecutionRpc> ProofDB<R> {
|
||||||
runtime.block_on(account_fut)
|
runtime.block_on(account_fut)
|
||||||
});
|
});
|
||||||
|
|
||||||
self.safe_unwrap(handle.join().unwrap())
|
handle.join().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: ExecutionRpc> Database for ProofDB<R> {
|
impl<R: ExecutionRpc> Database for ProofDB<R> {
|
||||||
fn basic(&mut self, address: H160) -> AccountInfo {
|
type Error = Report;
|
||||||
|
|
||||||
|
fn basic(&mut self, address: H160) -> Result<Option<AccountInfo>, Report> {
|
||||||
if is_precompile(&address) {
|
if is_precompile(&address) {
|
||||||
return AccountInfo::default();
|
return Ok(Some(AccountInfo::default()));
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
|
@ -254,18 +245,22 @@ impl<R: ExecutionRpc> Database for ProofDB<R> {
|
||||||
|
|
||||||
let account = match self.accounts.get(&address) {
|
let account = match self.accounts.get(&address) {
|
||||||
Some(account) => account.clone(),
|
Some(account) => account.clone(),
|
||||||
None => self.get_account(address, &[]),
|
None => self.get_account(address, &[])?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let bytecode = Bytecode::new_raw(Bytes::from(account.code.clone()));
|
let bytecode = Bytecode::new_raw(Bytes::from(account.code.clone()));
|
||||||
AccountInfo::new(account.balance, account.nonce, bytecode)
|
Ok(Some(AccountInfo::new(
|
||||||
|
account.balance,
|
||||||
|
account.nonce,
|
||||||
|
bytecode,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_hash(&mut self, _number: U256) -> H256 {
|
fn block_hash(&mut self, _number: U256) -> Result<H256, Report> {
|
||||||
H256::default()
|
Ok(H256::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn storage(&mut self, address: H160, slot: U256) -> U256 {
|
fn storage(&mut self, address: H160, slot: U256) -> Result<U256, Report> {
|
||||||
trace!(
|
trace!(
|
||||||
"fetch evm state for address=0x{}, slot={}",
|
"fetch evm state for address=0x{}, slot={}",
|
||||||
hex::encode(address.as_bytes()),
|
hex::encode(address.as_bytes()),
|
||||||
|
@ -274,27 +269,27 @@ impl<R: ExecutionRpc> Database for ProofDB<R> {
|
||||||
|
|
||||||
let slot = H256::from_uint(&slot);
|
let slot = H256::from_uint(&slot);
|
||||||
|
|
||||||
match self.accounts.get(&address) {
|
Ok(match self.accounts.get(&address) {
|
||||||
Some(account) => match account.slots.get(&slot) {
|
Some(account) => match account.slots.get(&slot) {
|
||||||
Some(slot) => slot.clone(),
|
Some(slot) => slot.clone(),
|
||||||
None => self
|
None => self
|
||||||
.get_account(address, &[slot])
|
.get_account(address, &[slot])?
|
||||||
.slots
|
.slots
|
||||||
.get(&slot)
|
.get(&slot)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone(),
|
.clone(),
|
||||||
},
|
},
|
||||||
None => self
|
None => self
|
||||||
.get_account(address, &[slot])
|
.get_account(address, &[slot])?
|
||||||
.slots
|
.slots
|
||||||
.get(&slot)
|
.get(&slot)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone(),
|
.clone(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn code_by_hash(&mut self, _code_hash: H256) -> Bytecode {
|
fn code_by_hash(&mut self, _code_hash: H256) -> Result<Bytecode, Report> {
|
||||||
panic!("should never be called");
|
Err(eyre::eyre!("should never be called"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
pub mod client {
|
||||||
|
pub use client::{database::FileDB, Client, ClientBuilder};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod config {
|
||||||
|
pub use config::{networks, Config};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod types {
|
||||||
|
pub use common::types::BlockTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod errors {
|
||||||
|
pub use common::errors::*;
|
||||||
|
pub use consensus::errors::*;
|
||||||
|
pub use execution::errors::*;
|
||||||
|
}
|
Loading…
Reference in New Issue