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" }
|
||||
consensus = { path = "./consensus" }
|
||||
execution = { path = "./execution" }
|
||||
serde = { version = "1.0.154", features = ["derive"] }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
eyre = "0.6.8"
|
||||
home = "0.5.4"
|
||||
ethers = "1.0.0"
|
||||
dirs = "4.0.0"
|
||||
ethers = { version = "1.0.2", features = [ "abigen" ] }
|
||||
env_logger = "0.9.0"
|
||||
log = "0.4.17"
|
||||
tracing-test = "0.2.3"
|
||||
tracing-test = "0.2.4"
|
||||
criterion = { version = "0.4", features = [ "async_tokio", "plotters" ]}
|
||||
plotters = "0.3.3"
|
||||
tempfile = "3.3.0"
|
||||
plotters = "0.3.4"
|
||||
tempfile = "3.4.0"
|
||||
hex = "0.4.3"
|
||||
|
||||
[patch.crates-io]
|
||||
ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "c17c0c3c956f12d205a5ede3176599d8a30ca739" }
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
opt-level = "z"
|
||||
|
@ -65,6 +63,10 @@ path = "examples/client.rs"
|
|||
name = "config"
|
||||
path = "examples/config.rs"
|
||||
|
||||
[[example]]
|
||||
name = "call"
|
||||
path = "examples/call.rs"
|
||||
|
||||
######################################
|
||||
# Benchmarks
|
||||
######################################
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use ethers::types::H256;
|
||||
use thiserror::Error;
|
||||
|
||||
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)]
|
||||
#[error("rpc error on method: {method}, message: {error}")]
|
||||
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 dirs::home_dir;
|
||||
use eyre::Result;
|
||||
|
||||
use helios::prelude::*;
|
||||
|
@ -6,7 +7,7 @@ use helios::prelude::*;
|
|||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// 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());
|
||||
println!("Constructed config: {config:#?}");
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@ use std::{
|
|||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use common::{errors::BlockNotFoundError, types::BlockTag};
|
||||
use common::{
|
||||
errors::{BlockNotFoundError, SlotNotFoundError},
|
||||
types::BlockTag,
|
||||
};
|
||||
use ethers::{
|
||||
abi::ethereum_types::BigEndianHash,
|
||||
types::transaction::eip2930::AccessListItem,
|
||||
|
@ -224,8 +227,6 @@ impl<'a, R: ExecutionRpc> ProofDB<'a, R> {
|
|||
|
||||
let handle = thread::spawn(move || {
|
||||
let account_fut = execution.get_account(&address, Some(&slots), &payload);
|
||||
// let runtime = Runtime::new()?;
|
||||
// runtime.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> {
|
||||
trace!(
|
||||
"fetch evm state for address=0x{}, slot={}",
|
||||
hex::encode(address.as_bytes()),
|
||||
slot
|
||||
);
|
||||
trace!("fetch evm state for address={:?}, slot={}", address, slot);
|
||||
|
||||
let slot = H256::from_uint(&slot);
|
||||
|
||||
|
@ -284,13 +281,13 @@ impl<'a, R: ExecutionRpc> Database for ProofDB<'a, R> {
|
|||
.get_account(address, &[slot])?
|
||||
.slots
|
||||
.get(&slot)
|
||||
.unwrap(),
|
||||
.ok_or(SlotNotFoundError::new(slot))?,
|
||||
},
|
||||
None => *self
|
||||
.get_account(address, &[slot])?
|
||||
.slots
|
||||
.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.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