add configuration file support
This commit is contained in:
parent
e0beceb8dd
commit
99d7ff4043
|
@ -1609,6 +1609,7 @@ dependencies = [
|
|||
"serde",
|
||||
"ssz-rs",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -18,3 +18,4 @@ jsonrpsee = { version = "0.15.1", features = ["full"] }
|
|||
revm = "1.9.0"
|
||||
bytes = "1.2.1"
|
||||
futures = "0.3.23"
|
||||
toml = "0.5.9"
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
[general]
|
||||
chain_id = 5
|
||||
genesis_root = "0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb"
|
||||
checkpoint = "0x172128eadf1da46467f4d6a822206698e2d3f957af117dd650954780d680dc99"
|
||||
consensus_rpc = "http://testing.prater.beacon-api.nimbus.team"
|
||||
execution_rpc = "https://eth-goerli.g.alchemy.com:443/v2/o_8Qa9kgwDPf9G8sroyQ-uQtyhyWa3ao"
|
||||
|
||||
[forks]
|
||||
|
||||
[forks.genesis]
|
||||
epoch = 0
|
||||
fork_version = "0x00001020"
|
||||
|
||||
[forks.altair]
|
||||
epoch = 36660
|
||||
fork_version = "0x01001020"
|
||||
|
||||
[forks.bellatrix]
|
||||
epoch = 112260
|
||||
fork_version = "0x02001020"
|
|
@ -1,6 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ethers::prelude::{Address, U256};
|
||||
use eyre::Result;
|
||||
|
||||
use crate::common::config::Config;
|
||||
use crate::consensus::types::Header;
|
||||
use crate::consensus::ConsensusClient;
|
||||
use crate::execution::evm::Evm;
|
||||
|
@ -9,20 +12,23 @@ use crate::execution::ExecutionClient;
|
|||
pub struct Client {
|
||||
consensus: ConsensusClient,
|
||||
execution: ExecutionClient,
|
||||
config: Arc<Config>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub async fn new(
|
||||
consensus_rpc: &str,
|
||||
execution_rpc: &str,
|
||||
checkpoint_hash: &str,
|
||||
) -> Result<Self> {
|
||||
let consensus = ConsensusClient::new(consensus_rpc, checkpoint_hash).await?;
|
||||
pub async fn new(config: Arc<Config>) -> Result<Self> {
|
||||
let consensus_rpc = &config.general.consensus_rpc;
|
||||
let checkpoint_hash = &config.general.checkpoint;
|
||||
let execution_rpc = &config.general.execution_rpc;
|
||||
|
||||
let consensus =
|
||||
ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone()).await?;
|
||||
let execution = ExecutionClient::new(execution_rpc);
|
||||
|
||||
Ok(Client {
|
||||
consensus,
|
||||
execution,
|
||||
config,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -66,6 +72,10 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn chain_id(&self) -> u64 {
|
||||
self.config.general.chain_id
|
||||
}
|
||||
|
||||
pub fn get_header(&self) -> &Header {
|
||||
self.consensus.get_head()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use ethers::{abi::AbiEncode, types::{Address, U256}};
|
||||
use ethers::{
|
||||
abi::AbiEncode,
|
||||
types::{Address, U256},
|
||||
};
|
||||
use eyre::Result;
|
||||
use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc};
|
||||
|
||||
use jsonrpsee::{
|
||||
core::{async_trait, Error},
|
||||
|
@ -9,7 +12,7 @@ use jsonrpsee::{
|
|||
proc_macros::rpc,
|
||||
};
|
||||
|
||||
use crate::common::utils::hex_str_to_bytes;
|
||||
use crate::common::utils::{hex_str_to_bytes, u64_to_hex_string};
|
||||
|
||||
use super::Client;
|
||||
|
||||
|
@ -46,6 +49,8 @@ trait EthRpc {
|
|||
async fn get_code(&self, address: &str, block: &str) -> Result<String, Error>;
|
||||
#[method(name = "call")]
|
||||
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error>;
|
||||
#[method(name = "chainId")]
|
||||
fn chain_id(&self) -> Result<String, Error>;
|
||||
}
|
||||
|
||||
struct RpcInner {
|
||||
|
@ -95,14 +100,22 @@ impl EthRpcServer for RpcInner {
|
|||
"latest" => {
|
||||
let to = convert_err(Address::from_str(&opts.to))?;
|
||||
let data = convert_err(hex_str_to_bytes(&opts.data.unwrap_or("0x".to_string())))?;
|
||||
let value = convert_err(U256::from_str_radix(&opts.value.unwrap_or("0x0".to_string()), 16))?;
|
||||
let value = convert_err(U256::from_str_radix(
|
||||
&opts.value.unwrap_or("0x0".to_string()),
|
||||
16,
|
||||
))?;
|
||||
|
||||
let res = convert_err(self.client.call(&to, &data, value).await)?;
|
||||
Ok(hex::encode(res))
|
||||
},
|
||||
}
|
||||
_ => Err(Error::Custom("Invalid Block Number".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn chain_id(&self) -> Result<String, Error> {
|
||||
let id = self.client.chain_id();
|
||||
Ok(u64_to_hex_string(id))
|
||||
}
|
||||
}
|
||||
|
||||
async fn start(rpc: RpcInner) -> Result<(HttpServerHandle, SocketAddr)> {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
use std::{fs, path::Path};
|
||||
|
||||
use eyre::Result;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::utils::hex_str_to_bytes;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Config {
|
||||
pub general: General,
|
||||
pub forks: Forks,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct General {
|
||||
pub chain_id: u64,
|
||||
#[serde(deserialize_with = "bytes_deserialize")]
|
||||
pub genesis_root: Vec<u8>,
|
||||
#[serde(deserialize_with = "bytes_deserialize")]
|
||||
pub checkpoint: Vec<u8>,
|
||||
pub consensus_rpc: String,
|
||||
pub execution_rpc: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Forks {
|
||||
pub genesis: Fork,
|
||||
pub altair: Fork,
|
||||
pub bellatrix: Fork,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Fork {
|
||||
pub epoch: u64,
|
||||
#[serde(deserialize_with = "bytes_deserialize")]
|
||||
pub fork_version: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_file(path: &Path) -> Result<Self> {
|
||||
let contents = fs::read_to_string(path)?;
|
||||
Ok(toml::from_str(&contents)?)
|
||||
}
|
||||
|
||||
pub fn fork_version(&self, slot: u64) -> Vec<u8> {
|
||||
let epoch = slot / 32;
|
||||
|
||||
if epoch >= self.forks.bellatrix.epoch {
|
||||
self.forks.bellatrix.fork_version.clone()
|
||||
} else if epoch >= self.forks.altair.epoch {
|
||||
self.forks.altair.fork_version.clone()
|
||||
} else {
|
||||
self.forks.genesis.fork_version.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bytes_deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let bytes: String = serde::Deserialize::deserialize(deserializer)?;
|
||||
Ok(hex_str_to_bytes(&bytes).unwrap())
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
pub mod config;
|
||||
pub mod utils;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use blst::min_pk::{PublicKey, Signature};
|
||||
use blst::BLST_ERROR;
|
||||
use eyre::Result;
|
||||
|
@ -5,11 +7,13 @@ use ssz_rs::prelude::*;
|
|||
|
||||
use super::rpc::Rpc;
|
||||
use super::types::*;
|
||||
use crate::common::config::Config;
|
||||
use crate::common::utils::*;
|
||||
|
||||
pub struct ConsensusClient {
|
||||
rpc: Rpc,
|
||||
store: Store,
|
||||
config: Arc<Config>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -20,7 +24,11 @@ struct Store {
|
|||
}
|
||||
|
||||
impl ConsensusClient {
|
||||
pub async fn new(nimbus_rpc: &str, checkpoint_block_root: &str) -> Result<ConsensusClient> {
|
||||
pub async fn new(
|
||||
nimbus_rpc: &str,
|
||||
checkpoint_block_root: &Vec<u8>,
|
||||
config: Arc<Config>,
|
||||
) -> Result<ConsensusClient> {
|
||||
let rpc = Rpc::new(nimbus_rpc);
|
||||
|
||||
let mut bootstrap = rpc.get_bootstrap(checkpoint_block_root).await?;
|
||||
|
@ -32,7 +40,8 @@ impl ConsensusClient {
|
|||
);
|
||||
|
||||
let header_hash = bootstrap.header.hash_tree_root()?;
|
||||
let header_valid = header_hash.to_string() == checkpoint_block_root.to_string();
|
||||
let header_valid =
|
||||
header_hash.to_string() == format!("0x{}", hex::encode(checkpoint_block_root));
|
||||
|
||||
if !(header_valid && committee_valid) {
|
||||
return Err(eyre::eyre!("Invalid Bootstrap"));
|
||||
|
@ -44,7 +53,7 @@ impl ConsensusClient {
|
|||
next_sync_committee: None,
|
||||
};
|
||||
|
||||
Ok(ConsensusClient { rpc, store })
|
||||
Ok(ConsensusClient { rpc, store, config })
|
||||
}
|
||||
|
||||
pub async fn get_execution_payload(&self) -> Result<ExecutionPayload> {
|
||||
|
@ -147,7 +156,7 @@ impl ConsensusClient {
|
|||
}
|
||||
|
||||
let header_root = bytes_to_bytes32(update.attested_header.hash_tree_root()?.as_bytes());
|
||||
let signing_root = compute_committee_sign_root(header_root)?;
|
||||
let signing_root = self.compute_committee_sign_root(header_root, update.signature_slot)?;
|
||||
let sig = &update.sync_aggregate.sync_committee_signature;
|
||||
let is_valid_sig = is_aggregate_valid(sig, signing_root.as_bytes(), &pks);
|
||||
|
||||
|
@ -174,6 +183,21 @@ impl ConsensusClient {
|
|||
Some(update.next_sync_committee.as_ref().unwrap().clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_committee_sign_root(&self, header: Bytes32, slot: u64) -> Result<Node> {
|
||||
let genesis_root = self
|
||||
.config
|
||||
.general
|
||||
.genesis_root
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let domain_type = &hex::decode("07000000")?[..];
|
||||
let fork_version = Vector::from_iter(self.config.fork_version(slot));
|
||||
let domain = compute_domain(domain_type, fork_version, genesis_root)?;
|
||||
compute_signing_root(header, domain)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_participating_keys(
|
||||
|
@ -300,18 +324,6 @@ fn branch_to_nodes(branch: Vec<Bytes32>) -> Result<Vec<Node>> {
|
|||
.collect::<Result<Vec<Node>>>()
|
||||
}
|
||||
|
||||
fn compute_committee_sign_root(header: Bytes32) -> Result<Node> {
|
||||
let genesis_root =
|
||||
hex::decode("043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb")?
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let domain_type = &hex::decode("07000000")?[..];
|
||||
let fork_version = Vector::from_iter(hex::decode("02001020").unwrap());
|
||||
let domain = compute_domain(domain_type, fork_version, genesis_root)?;
|
||||
compute_signing_root(header, domain)
|
||||
}
|
||||
|
||||
#[derive(SimpleSerialize, Default, Debug)]
|
||||
struct SigningData {
|
||||
object_root: Bytes32,
|
||||
|
|
|
@ -13,10 +13,11 @@ impl Rpc {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get_bootstrap(&self, block_root: &str) -> Result<Bootstrap> {
|
||||
pub async fn get_bootstrap(&self, block_root: &Vec<u8>) -> Result<Bootstrap> {
|
||||
let root_hex = hex::encode(block_root);
|
||||
let req = format!(
|
||||
"{}/eth/v0/beacon/light_client/bootstrap/{}",
|
||||
self.rpc, block_root
|
||||
"{}/eth/v0/beacon/light_client/bootstrap/0x{}",
|
||||
self.rpc, root_hex
|
||||
);
|
||||
let res = reqwest::get(req).await?.json::<BootstrapResponse>().await?;
|
||||
Ok(res.data.v)
|
||||
|
|
|
@ -74,7 +74,6 @@ impl ProofDB {
|
|||
|
||||
impl Database for ProofDB {
|
||||
fn basic(&mut self, address: H160) -> AccountInfo {
|
||||
|
||||
if is_precompile(&address) {
|
||||
return AccountInfo::default();
|
||||
}
|
||||
|
@ -112,7 +111,6 @@ impl Database for ProofDB {
|
|||
}
|
||||
|
||||
fn storage(&mut self, address: H160, slot: U256) -> U256 {
|
||||
|
||||
let execution = self.execution.clone();
|
||||
let addr = address.clone();
|
||||
let slots = [slot];
|
||||
|
|
|
@ -30,7 +30,7 @@ impl ExecutionClient {
|
|||
payload: &ExecutionPayload,
|
||||
) -> Result<Account> {
|
||||
let slots = slots.unwrap_or(&[]);
|
||||
|
||||
|
||||
let proof = self
|
||||
.rpc
|
||||
.get_proof(&address, slots, payload.block_number)
|
||||
|
|
|
@ -7,7 +7,6 @@ pub fn verify_proof(proof: &Vec<Vec<u8>>, root: &Vec<u8>, path: &Vec<u8>, value:
|
|||
let mut expected_hash = root.clone();
|
||||
let mut path_offset = 0;
|
||||
|
||||
|
||||
for (i, node) in proof.iter().enumerate() {
|
||||
if expected_hash != keccak256(node).to_vec() {
|
||||
return false;
|
||||
|
@ -22,10 +21,11 @@ pub fn verify_proof(proof: &Vec<Vec<u8>>, root: &Vec<u8>, path: &Vec<u8>, value:
|
|||
path_offset += 1;
|
||||
} else if node_list.len() == 2 {
|
||||
if i == proof.len() - 1 {
|
||||
|
||||
// exclusion proof
|
||||
if &node_list[0][skip_length(&node_list[0])..] != &path[path_offset..] && value[0] == 0x80 {
|
||||
return true
|
||||
if &node_list[0][skip_length(&node_list[0])..] != &path[path_offset..]
|
||||
&& value[0] == 0x80
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// inclusion proof
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -1,9 +1,10 @@
|
|||
use std::{sync::Arc, time::Duration};
|
||||
use std::{path::Path, sync::Arc, time::Duration};
|
||||
|
||||
use eyre::Result;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use client::{rpc::Rpc, Client};
|
||||
use tokio::time::sleep;
|
||||
use common::config::Config;
|
||||
|
||||
pub mod client;
|
||||
pub mod common;
|
||||
|
@ -12,11 +13,9 @@ pub mod execution;
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let consensus_rpc = "http://testing.prater.beacon-api.nimbus.team";
|
||||
let execution_rpc = "https://eth-goerli.g.alchemy.com:443/v2/o_8Qa9kgwDPf9G8sroyQ-uQtyhyWa3ao";
|
||||
let checkpoint = "0x172128eadf1da46467f4d6a822206698e2d3f957af117dd650954780d680dc99";
|
||||
let config = Config::from_file(Path::new("./configs/goerli.toml"))?;
|
||||
|
||||
let mut client = Client::new(consensus_rpc, execution_rpc, checkpoint).await?;
|
||||
let mut client = Client::new(Arc::new(config)).await?;
|
||||
client.sync().await?;
|
||||
|
||||
let mut rpc = Rpc::new(Arc::new(client));
|
||||
|
|
Loading…
Reference in New Issue