fix: cleanup call example (#212)
* fix: evm panic on slot not found (#208) * cleanup and example --------- Co-authored-by: refcell.eth <abigger87@gmail.com>
This commit is contained in:
parent
a73f9c648b
commit
3c471c2bef
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
18
Cargo.toml
|
@ -21,23 +21,21 @@ config = { path = "./config" }
|
||||||
common = { path = "./common" }
|
common = { path = "./common" }
|
||||||
consensus = { path = "./consensus" }
|
consensus = { path = "./consensus" }
|
||||||
execution = { path = "./execution" }
|
execution = { path = "./execution" }
|
||||||
|
serde = { version = "1.0.154", features = ["derive"] }
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
eyre = "0.6.8"
|
eyre = "0.6.8"
|
||||||
home = "0.5.4"
|
dirs = "4.0.0"
|
||||||
ethers = "1.0.0"
|
ethers = { version = "1.0.2", features = [ "abigen" ] }
|
||||||
env_logger = "0.9.0"
|
env_logger = "0.9.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
tracing-test = "0.2.3"
|
tracing-test = "0.2.4"
|
||||||
criterion = { version = "0.4", features = [ "async_tokio", "plotters" ]}
|
criterion = { version = "0.4", features = [ "async_tokio", "plotters" ]}
|
||||||
plotters = "0.3.3"
|
plotters = "0.3.4"
|
||||||
tempfile = "3.3.0"
|
tempfile = "3.4.0"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "c17c0c3c956f12d205a5ede3176599d8a30ca739" }
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
strip = true
|
strip = true
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
|
@ -65,6 +63,10 @@ path = "examples/client.rs"
|
||||||
name = "config"
|
name = "config"
|
||||||
path = "examples/config.rs"
|
path = "examples/config.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "call"
|
||||||
|
path = "examples/call.rs"
|
||||||
|
|
||||||
######################################
|
######################################
|
||||||
# Benchmarks
|
# Benchmarks
|
||||||
######################################
|
######################################
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use ethers::types::H256;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::types::BlockTag;
|
use crate::types::BlockTag;
|
||||||
|
@ -14,6 +15,18 @@ impl BlockNotFoundError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[error("slot not found: {slot:?}")]
|
||||||
|
pub struct SlotNotFoundError {
|
||||||
|
slot: H256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SlotNotFoundError {
|
||||||
|
pub fn new(slot: H256) -> Self {
|
||||||
|
Self { slot }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[error("rpc error on method: {method}, message: {error}")]
|
#[error("rpc error on method: {method}, message: {error}")]
|
||||||
pub struct RpcError<E: ToString> {
|
pub struct RpcError<E: ToString> {
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
|
use env_logger::Env;
|
||||||
|
use ethers::prelude::*;
|
||||||
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
|
use helios::{
|
||||||
|
client::{Client, ClientBuilder, FileDB},
|
||||||
|
config::networks::Network,
|
||||||
|
types::{BlockTag, CallOpts},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate the type-safe contract bindings with an ABI
|
||||||
|
abigen!(
|
||||||
|
Renderer,
|
||||||
|
r#"[
|
||||||
|
function renderBroker(uint256) external view returns (string memory)
|
||||||
|
function renderBroker(uint256, uint256) external view returns (string memory)
|
||||||
|
]"#,
|
||||||
|
event_derives(serde::Deserialize, serde::Serialize)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init();
|
||||||
|
|
||||||
|
// Load the rpc url using the `MAINNET_RPC_URL` environment variable
|
||||||
|
let eth_rpc_url = std::env::var("MAINNET_RPC_URL")?;
|
||||||
|
let consensus_rpc = "https://www.lightclientdata.org";
|
||||||
|
log::info!("Consensus RPC URL: {}", consensus_rpc);
|
||||||
|
|
||||||
|
// Construct the client
|
||||||
|
let data_dir = PathBuf::from("/tmp/helios");
|
||||||
|
let mut client: Client<FileDB> = ClientBuilder::new()
|
||||||
|
.network(Network::MAINNET)
|
||||||
|
.data_dir(data_dir)
|
||||||
|
.consensus_rpc(consensus_rpc)
|
||||||
|
.execution_rpc(ð_rpc_url)
|
||||||
|
.load_external_fallback()
|
||||||
|
.build()?;
|
||||||
|
log::info!(
|
||||||
|
"[\"{}\"] Client built with external checkpoint fallbacks",
|
||||||
|
Network::MAINNET
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start the client
|
||||||
|
client.start().await?;
|
||||||
|
|
||||||
|
// Call the erroneous account method
|
||||||
|
// The expected asset is: https://0x8bb9a8baeec177ae55ac410c429cbbbbb9198cac.w3eth.io/renderBroker/5
|
||||||
|
// Retrieved by calling `renderBroker(5)` on the contract: https://etherscan.io/address/0x8bb9a8baeec177ae55ac410c429cbbbbb9198cac#code
|
||||||
|
let account = "0x8bb9a8baeec177ae55ac410c429cbbbbb9198cac";
|
||||||
|
let method = "renderBroker(uint256)";
|
||||||
|
let method2 = "renderBroker(uint256, uint256)";
|
||||||
|
let argument = U256::from(5);
|
||||||
|
let address = account.parse::<Address>()?;
|
||||||
|
let block = BlockTag::Latest;
|
||||||
|
let provider = Provider::<Http>::try_from(eth_rpc_url)?;
|
||||||
|
let render = Renderer::new(address, Arc::new(provider.clone()));
|
||||||
|
log::debug!("Context: call @ {account}::{method} <{argument}>");
|
||||||
|
|
||||||
|
// Call using abigen
|
||||||
|
let result = render.render_broker_0(argument).call().await?;
|
||||||
|
log::info!(
|
||||||
|
"[ABIGEN] {account}::{method} -> Response Length: {:?}",
|
||||||
|
result.len()
|
||||||
|
);
|
||||||
|
let render = Renderer::new(address, Arc::new(provider.clone()));
|
||||||
|
let result = render
|
||||||
|
.render_broker_1(argument, U256::from(10))
|
||||||
|
.call()
|
||||||
|
.await?;
|
||||||
|
log::info!(
|
||||||
|
"[ABIGEN] {account}::{method2} -> Response Length: {:?}",
|
||||||
|
result.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Call on helios client
|
||||||
|
let encoded_call = render.render_broker_0(argument).calldata().unwrap();
|
||||||
|
let call_opts = CallOpts {
|
||||||
|
from: Some("0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8".parse::<Address>()?),
|
||||||
|
to: Some(address),
|
||||||
|
gas: Some(U256::from(U64::MAX.as_u64())),
|
||||||
|
gas_price: None,
|
||||||
|
value: None,
|
||||||
|
data: Some(encoded_call.to_vec()),
|
||||||
|
};
|
||||||
|
log::debug!("Calling helios client on block: {block:?}");
|
||||||
|
let result = client.call(&call_opts, block).await?;
|
||||||
|
log::info!("[HELIOS] {account}::{method} ->{:?}", result.len());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
use config::CliConfig;
|
use config::CliConfig;
|
||||||
|
use dirs::home_dir;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
|
||||||
use helios::prelude::*;
|
use helios::prelude::*;
|
||||||
|
@ -6,7 +7,7 @@ use helios::prelude::*;
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
// Load the config from the global config file
|
// Load the config from the global config file
|
||||||
let config_path = home::home_dir().unwrap().join(".helios/helios.toml");
|
let config_path = home_dir().unwrap().join(".helios/helios.toml");
|
||||||
let config = Config::from_file(&config_path, "mainnet", &CliConfig::default());
|
let config = Config::from_file(&config_path, "mainnet", &CliConfig::default());
|
||||||
println!("Constructed config: {config:#?}");
|
println!("Constructed config: {config:#?}");
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,10 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use common::{errors::BlockNotFoundError, types::BlockTag};
|
use common::{
|
||||||
|
errors::{BlockNotFoundError, SlotNotFoundError},
|
||||||
|
types::BlockTag,
|
||||||
|
};
|
||||||
use ethers::{
|
use ethers::{
|
||||||
abi::ethereum_types::BigEndianHash,
|
abi::ethereum_types::BigEndianHash,
|
||||||
types::transaction::eip2930::AccessListItem,
|
types::transaction::eip2930::AccessListItem,
|
||||||
|
@ -224,8 +227,6 @@ impl<'a, R: ExecutionRpc> ProofDB<'a, R> {
|
||||||
|
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
let account_fut = execution.get_account(&address, Some(&slots), &payload);
|
let account_fut = execution.get_account(&address, Some(&slots), &payload);
|
||||||
// let runtime = Runtime::new()?;
|
|
||||||
// runtime.block_on(account_fut)
|
|
||||||
block_on(account_fut)
|
block_on(account_fut)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -269,11 +270,7 @@ impl<'a, R: ExecutionRpc> Database for ProofDB<'a, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn storage(&mut self, address: H160, slot: U256) -> Result<U256, Report> {
|
fn storage(&mut self, address: H160, slot: U256) -> Result<U256, Report> {
|
||||||
trace!(
|
trace!("fetch evm state for address={:?}, slot={}", address, slot);
|
||||||
"fetch evm state for address=0x{}, slot={}",
|
|
||||||
hex::encode(address.as_bytes()),
|
|
||||||
slot
|
|
||||||
);
|
|
||||||
|
|
||||||
let slot = H256::from_uint(&slot);
|
let slot = H256::from_uint(&slot);
|
||||||
|
|
||||||
|
@ -284,13 +281,13 @@ impl<'a, R: ExecutionRpc> Database for ProofDB<'a, R> {
|
||||||
.get_account(address, &[slot])?
|
.get_account(address, &[slot])?
|
||||||
.slots
|
.slots
|
||||||
.get(&slot)
|
.get(&slot)
|
||||||
.unwrap(),
|
.ok_or(SlotNotFoundError::new(slot))?,
|
||||||
},
|
},
|
||||||
None => *self
|
None => *self
|
||||||
.get_account(address, &[slot])?
|
.get_account(address, &[slot])?
|
||||||
.slots
|
.slots
|
||||||
.get(&slot)
|
.get(&slot)
|
||||||
.unwrap(),
|
.ok_or(SlotNotFoundError::new(slot))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,3 +300,59 @@ fn is_precompile(address: &Address) -> bool {
|
||||||
address.le(&Address::from_str("0x0000000000000000000000000000000000000009").unwrap())
|
address.le(&Address::from_str("0x0000000000000000000000000000000000000009").unwrap())
|
||||||
&& address.gt(&Address::zero())
|
&& address.gt(&Address::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use common::utils::hex_str_to_bytes;
|
||||||
|
use ssz_rs::Vector;
|
||||||
|
|
||||||
|
use crate::rpc::mock_rpc::MockRpc;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn get_client() -> ExecutionClient<MockRpc> {
|
||||||
|
ExecutionClient::new("testdata/").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_proof_db() {
|
||||||
|
// Construct proofdb params
|
||||||
|
let execution = get_client();
|
||||||
|
let address = Address::from_str("14f9D4aF749609c1438528C0Cce1cC3f6D411c47").unwrap();
|
||||||
|
let payload = ExecutionPayload {
|
||||||
|
state_root: Vector::from_iter(
|
||||||
|
hex_str_to_bytes(
|
||||||
|
"0xaa02f5db2ee75e3da400d10f3c30e894b6016ce8a2501680380a907b6674ce0d",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
..ExecutionPayload::default()
|
||||||
|
};
|
||||||
|
let mut payloads = BTreeMap::new();
|
||||||
|
payloads.insert(7530933, payload.clone());
|
||||||
|
|
||||||
|
// Construct the proof database with the given client and payloads
|
||||||
|
let mut proof_db = ProofDB::new(Arc::new(execution), &payload, &payloads);
|
||||||
|
|
||||||
|
// Set the proof db accounts
|
||||||
|
let slot = U256::from(1337);
|
||||||
|
let mut accounts = HashMap::new();
|
||||||
|
let account = Account {
|
||||||
|
balance: U256::from(100),
|
||||||
|
code: hex_str_to_bytes("0x").unwrap(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
accounts.insert(address, account);
|
||||||
|
proof_db.set_accounts(accounts);
|
||||||
|
|
||||||
|
// Get the account from the proof database
|
||||||
|
let storage_proof = proof_db.storage(address, slot);
|
||||||
|
|
||||||
|
// Check that the storage proof correctly returns a slot not found error
|
||||||
|
let expected_err: eyre::Report = SlotNotFoundError::new(H256::from_uint(&slot)).into();
|
||||||
|
assert_eq!(
|
||||||
|
expected_err.to_string(),
|
||||||
|
storage_proof.unwrap_err().to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue