diff --git a/src/client.rs b/src/client/client.rs similarity index 91% rename from src/client.rs rename to src/client/client.rs index 0c79985..8945dd1 100644 --- a/src/client.rs +++ b/src/client/client.rs @@ -1,7 +1,9 @@ use ethers::prelude::{Address, U256}; use eyre::Result; -use crate::{consensus::ConsensusClient, execution::ExecutionClient, consensus_rpc::Header}; +use crate::consensus::types::Header; +use crate::consensus::ConsensusClient; +use crate::execution::ExecutionClient; pub struct Client { consensus: ConsensusClient, diff --git a/src/client/mod.rs b/src/client/mod.rs new file mode 100644 index 0000000..4f72e22 --- /dev/null +++ b/src/client/mod.rs @@ -0,0 +1,2 @@ +mod client; +pub use client::*; diff --git a/src/common/mod.rs b/src/common/mod.rs new file mode 100644 index 0000000..b5614dd --- /dev/null +++ b/src/common/mod.rs @@ -0,0 +1 @@ +pub mod utils; diff --git a/src/utils.rs b/src/common/utils.rs similarity index 91% rename from src/utils.rs rename to src/common/utils.rs index 708f92d..6e9d8e4 100644 --- a/src/utils.rs +++ b/src/common/utils.rs @@ -1,7 +1,7 @@ use eyre::Result; use ssz_rs::{Node, Vector}; -use crate::consensus_rpc::Bytes32; +use crate::consensus::types::Bytes32; pub fn hex_str_to_bytes(s: &str) -> Result> { let stripped = s.strip_prefix("0x").unwrap_or(s); diff --git a/src/consensus.rs b/src/consensus/consensus.rs similarity index 95% rename from src/consensus.rs rename to src/consensus/consensus.rs index 7e63c39..92d5aa6 100644 --- a/src/consensus.rs +++ b/src/consensus/consensus.rs @@ -3,11 +3,12 @@ use blst::BLST_ERROR; use eyre::Result; use ssz_rs::prelude::*; -use crate::consensus_rpc::*; -use crate::utils::*; +use crate::common::utils::*; +use super::types::*; +use super::rpc::Rpc; pub struct ConsensusClient { - consensus_rpc: ConsensusRpc, + rpc: Rpc, store: Store, } @@ -20,9 +21,9 @@ struct Store { impl ConsensusClient { pub async fn new(nimbus_rpc: &str, checkpoint_block_root: &str) -> Result { - let consensus_rpc = ConsensusRpc::new(nimbus_rpc); + let rpc = Rpc::new(nimbus_rpc); - let mut bootstrap = consensus_rpc.get_bootstrap(checkpoint_block_root).await?; + let mut bootstrap = rpc.get_bootstrap(checkpoint_block_root).await?; let committee_valid = is_current_committee_proof_valid( &bootstrap.header, @@ -44,14 +45,14 @@ impl ConsensusClient { }; Ok(ConsensusClient { - consensus_rpc, + rpc, store, }) } pub async fn get_execution_payload(&mut self) -> Result { let slot = self.store.header.slot; - let mut block = self.consensus_rpc.get_block(slot).await?; + let mut block = self.rpc.get_block(slot).await?; let block_hash = block.hash_tree_root()?; let verified_block_hash = self.store.header.hash_tree_root()?; @@ -68,14 +69,14 @@ impl ConsensusClient { pub async fn sync(&mut self) -> Result<()> { let current_period = calc_sync_period(self.store.header.slot); - let updates = self.consensus_rpc.get_updates(current_period).await?; + let updates = self.rpc.get_updates(current_period).await?; for mut update in updates { self.verify_update(&mut update)?; self.apply_update(&update); } - let finality_update = self.consensus_rpc.get_finality_update().await?; + let finality_update = self.rpc.get_finality_update().await?; let mut finality_update_generic = Update { attested_header: finality_update.attested_header, next_sync_committee: None, @@ -89,7 +90,7 @@ impl ConsensusClient { self.verify_update(&mut finality_update_generic)?; self.apply_update(&finality_update_generic); - self.consensus_rpc.get_block(self.store.header.slot).await?; + self.rpc.get_block(self.store.header.slot).await?; Ok(()) } diff --git a/src/consensus/mod.rs b/src/consensus/mod.rs new file mode 100644 index 0000000..6124af6 --- /dev/null +++ b/src/consensus/mod.rs @@ -0,0 +1,6 @@ +pub mod types; + +mod consensus; +pub use consensus::*; + +mod rpc; diff --git a/src/consensus/rpc.rs b/src/consensus/rpc.rs new file mode 100644 index 0000000..80bd2a0 --- /dev/null +++ b/src/consensus/rpc.rs @@ -0,0 +1,80 @@ +use eyre::Result; + +use super::types::*; + +pub struct Rpc { + rpc: String, +} + +impl Rpc { + pub fn new(rpc: &str) -> Self { + Rpc { rpc: rpc.to_string() } + } + + pub async fn get_bootstrap(&self, block_root: &str) -> Result { + let req = format!( + "{}/eth/v0/beacon/light_client/bootstrap/{}", + self.rpc, block_root + ); + let res = reqwest::get(req).await?.json::().await?; + Ok(res.data.v) + } + + pub async fn get_updates(&self, period: u64) -> Result> { + let req = format!( + "{}/eth/v0/beacon/light_client/updates?start_period={}&count=1000", + self.rpc, period + ); + let res = reqwest::get(req).await?.json::().await?; + Ok(res.data) + } + + pub async fn get_finality_update(&self) -> Result { + let req = format!("{}/eth/v0/beacon/light_client/finality_update", self.rpc); + let res = reqwest::get(req) + .await? + .json::() + .await?; + Ok(res.data) + } + + pub async fn get_block(&self, slot: u64) -> Result { + let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot); + let res = reqwest::get(req) + .await? + .json::() + .await?; + Ok(res.data.message) + } +} + +#[derive(serde::Deserialize, Debug)] +struct BeaconBlockResponse { + data: BeaconBlockData, +} + +#[derive(serde::Deserialize, Debug)] +struct BeaconBlockData { + message: BeaconBlock, +} + +#[derive(serde::Deserialize, Debug)] +struct UpdateResponse { + data: Vec, +} + +#[derive(serde::Deserialize, Debug)] +struct FinalityUpdateResponse { + data: FinalityUpdate, +} + +#[derive(serde::Deserialize, Debug)] +struct BootstrapResponse { + data: BootstrapData, +} + +#[derive(serde::Deserialize, Debug)] +struct BootstrapData { + v: Bootstrap, +} + diff --git a/src/consensus_rpc.rs b/src/consensus/types.rs similarity index 83% rename from src/consensus_rpc.rs rename to src/consensus/types.rs index 4d78b70..3351224 100644 --- a/src/consensus_rpc.rs +++ b/src/consensus/types.rs @@ -2,55 +2,7 @@ use eyre::Result; use serde::de::Error; use ssz_rs::prelude::*; -use crate::utils::*; - -pub struct ConsensusRpc { - rpc: String, -} - -impl ConsensusRpc { - pub fn new(rpc: &str) -> Self { - ConsensusRpc { - rpc: rpc.to_string(), - } - } - - pub async fn get_bootstrap(&self, block_root: &str) -> Result { - let req = format!( - "{}/eth/v0/beacon/light_client/bootstrap/{}", - self.rpc, block_root - ); - let res = reqwest::get(req).await?.json::().await?; - Ok(res.data.v) - } - - pub async fn get_updates(&self, period: u64) -> Result> { - let req = format!( - "{}/eth/v0/beacon/light_client/updates?start_period={}&count=1000", - self.rpc, period - ); - let res = reqwest::get(req).await?.json::().await?; - Ok(res.data) - } - - pub async fn get_finality_update(&self) -> Result { - let req = format!("{}/eth/v0/beacon/light_client/finality_update", self.rpc); - let res = reqwest::get(req) - .await? - .json::() - .await?; - Ok(res.data) - } - - pub async fn get_block(&self, slot: u64) -> Result { - let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot); - let res = reqwest::get(req) - .await? - .json::() - .await?; - Ok(res.data.message) - } -} +use crate::common::utils::hex_str_to_bytes; pub type BLSPubKey = Vector; pub type SignatureBytes = Vector; @@ -229,36 +181,6 @@ pub struct SyncAggregate { pub sync_committee_signature: SignatureBytes, } -#[derive(serde::Deserialize, Debug)] -struct BeaconBlockResponse { - data: BeaconBlockData, -} - -#[derive(serde::Deserialize, Debug)] -struct BeaconBlockData { - message: BeaconBlock, -} - -#[derive(serde::Deserialize, Debug)] -struct UpdateResponse { - data: Vec, -} - -#[derive(serde::Deserialize, Debug)] -struct FinalityUpdateResponse { - data: FinalityUpdate, -} - -#[derive(serde::Deserialize, Debug)] -struct BootstrapResponse { - data: BootstrapData, -} - -#[derive(serde::Deserialize, Debug)] -struct BootstrapData { - v: Bootstrap, -} - fn pubkey_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, diff --git a/src/execution.rs b/src/execution/execution.rs similarity index 90% rename from src/execution.rs rename to src/execution/execution.rs index 0a4953d..b7983d3 100644 --- a/src/execution.rs +++ b/src/execution/execution.rs @@ -2,9 +2,9 @@ use ethers::prelude::{Address, U256, H256}; use ethers::utils::keccak256; use eyre::Result; -use crate::consensus_rpc::ExecutionPayload; -use crate::execution_rpc::ExecutionRpc; -use crate::proof::{encode_account, verify_proof}; +use crate::consensus::types::ExecutionPayload; +use super::proof::{encode_account, verify_proof}; +use super::execution_rpc::ExecutionRpc; pub struct ExecutionClient { execution_rpc: ExecutionRpc, diff --git a/src/execution/execution_rpc.rs b/src/execution/execution_rpc.rs new file mode 100644 index 0000000..b57dfd3 --- /dev/null +++ b/src/execution/execution_rpc.rs @@ -0,0 +1,26 @@ +use ethers::prelude::Address; +use eyre::Result; +use jsonrpsee::{core::client::ClientT, http_client::HttpClientBuilder, rpc_params}; + +use super::types::Proof; + +pub struct ExecutionRpc { + rpc: String, +} + +impl ExecutionRpc { + pub fn new(rpc: &str) -> Self { + ExecutionRpc { + rpc: rpc.to_string(), + } + } + + pub async fn get_proof(&self, address: &Address, block: u64) -> Result { + let client = HttpClientBuilder::default().build(&self.rpc)?; + let block_hex = format!("0x{:x}", block); + let addr_hex = format!("0x{}", hex::encode(address.as_bytes())); + let params = rpc_params!(addr_hex, [""], block_hex); + Ok(client.request("eth_getProof", params).await?) + } +} + diff --git a/src/execution/mod.rs b/src/execution/mod.rs new file mode 100644 index 0000000..1a71be6 --- /dev/null +++ b/src/execution/mod.rs @@ -0,0 +1,7 @@ +pub mod types; + +mod execution; +pub use execution::*; + +mod execution_rpc; +mod proof; diff --git a/src/proof.rs b/src/execution/proof.rs similarity index 97% rename from src/proof.rs rename to src/execution/proof.rs index e9f414c..d340722 100644 --- a/src/proof.rs +++ b/src/execution/proof.rs @@ -1,7 +1,7 @@ use ethers::utils::keccak256; use ethers::utils::rlp::{decode_list, RlpStream}; -use crate::execution_rpc::Proof; +use crate::execution::types::Proof; pub fn verify_proof(proof: &Vec>, root: &Vec, path: &Vec, value: &Vec) -> bool { let mut expected_hash = root.clone(); diff --git a/src/execution/types.rs b/src/execution/types.rs new file mode 100644 index 0000000..7484eae --- /dev/null +++ b/src/execution/types.rs @@ -0,0 +1,30 @@ +use serde::de::Error; +use serde::Deserialize; +use ethers::prelude::{U256, H256, Address}; +use eyre::Result; + +use crate::common::utils::hex_str_to_bytes; + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Proof { + pub address: Address, + pub balance: U256, + pub code_hash: H256, + pub nonce: U256, + pub storage_hash: H256, + #[serde(deserialize_with = "proof_deserialize")] + pub account_proof: Vec>, +} + +fn proof_deserialize<'de, D>(deserializer: D) -> Result>, D::Error> +where + D: serde::Deserializer<'de>, +{ + let branch: Vec = serde::Deserialize::deserialize(deserializer)?; + Ok(branch + .iter() + .map(|elem| hex_str_to_bytes(elem)) + .collect::>() + .map_err(D::Error::custom)?) +} diff --git a/src/execution_rpc.rs b/src/execution_rpc.rs deleted file mode 100644 index 5fd2b07..0000000 --- a/src/execution_rpc.rs +++ /dev/null @@ -1,51 +0,0 @@ -use ethers::prelude::{Address, H256, U256}; -use eyre::Result; -use jsonrpsee::{core::client::ClientT, http_client::HttpClientBuilder, rpc_params}; -use serde::de::Error; -use serde::Deserialize; - -use crate::utils::hex_str_to_bytes; - -pub struct ExecutionRpc { - rpc: String, -} - -impl ExecutionRpc { - pub fn new(rpc: &str) -> Self { - ExecutionRpc { - rpc: rpc.to_string(), - } - } - - pub async fn get_proof(&self, address: &Address, block: u64) -> Result { - let client = HttpClientBuilder::default().build(&self.rpc)?; - let block_hex = format!("0x{:x}", block); - let addr_hex = format!("0x{}", hex::encode(address.as_bytes())); - let params = rpc_params!(addr_hex, [""], block_hex); - Ok(client.request("eth_getProof", params).await?) - } -} - -#[derive(Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct Proof { - pub address: Address, - pub balance: U256, - pub code_hash: H256, - pub nonce: U256, - pub storage_hash: H256, - #[serde(deserialize_with = "proof_deserialize")] - pub account_proof: Vec>, -} - -fn proof_deserialize<'de, D>(deserializer: D) -> Result>, D::Error> -where - D: serde::Deserializer<'de>, -{ - let branch: Vec = serde::Deserialize::deserialize(deserializer)?; - Ok(branch - .iter() - .map(|elem| hex_str_to_bytes(elem)) - .collect::>() - .map_err(D::Error::custom)?) -} diff --git a/src/main.rs b/src/main.rs index 1221179..15b7768 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,8 @@ use client::Client; pub mod client; pub mod consensus; -pub mod consensus_rpc; pub mod execution; -pub mod execution_rpc; -pub mod proof; -pub mod utils; +pub mod common; #[tokio::main] async fn main() -> Result<()> {