From 4dd8ba253ff819995ac92f098dd2771ea1a9d484 Mon Sep 17 00:00:00 2001 From: Noah Citron Date: Sat, 20 Aug 2022 10:10:28 -0400 Subject: [PATCH] add execution_rpc package --- src/execution_rpc.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 17 +++++++++++++++++ src/proof.rs | 40 ++++------------------------------------ 3 files changed, 64 insertions(+), 36 deletions(-) create mode 100644 src/execution_rpc.rs diff --git a/src/execution_rpc.rs b/src/execution_rpc.rs new file mode 100644 index 0000000..1f9d30a --- /dev/null +++ b/src/execution_rpc.rs @@ -0,0 +1,43 @@ +use ethers::prelude::{Address, U256, H256}; +use jsonrpsee::{http_client::HttpClientBuilder, rpc_params, core::client::ClientT}; +use eyre::Result; +use serde::Deserialize; +use serde::de::Error; +use super::utils::*; + +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: &str, block: u64) -> Result { + let client = HttpClientBuilder::default().build(&self.rpc)?; + let block_hex = format!("0x{:x}", block); + let params = rpc_params!(address, [""], 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 33ce23e..7bd443f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ use eyre::Result; use consensus::*; +use execution_rpc::*; +use proof::*; +use utils::hex_str_to_bytes; pub mod consensus; pub mod consensus_rpc; +pub mod execution_rpc; pub mod utils; pub mod proof; @@ -14,11 +18,24 @@ async fn main() -> Result<()> { let checkpoint = "0x172128eadf1da46467f4d6a822206698e2d3f957af117dd650954780d680dc99"; let mut client = ConsensusClient::new(rpc, checkpoint).await?; + let rpc = "https://eth-goerli.g.alchemy.com:443/v2/o_8Qa9kgwDPf9G8sroyQ-uQtyhyWa3ao"; + let execution = ExecutionRpc::new(rpc); + client.sync().await?; let payload = client.get_execution_payload().await?; println!("verified execution block hash: {}", hex::encode(payload.block_hash)); + let addr = "0x25c4a76E7d118705e7Ea2e9b7d8C59930d8aCD3b"; + let proof = execution.get_proof(addr, payload.block_number).await?; + + let account_path = get_account_path(&hex_str_to_bytes(addr)?); + let account_encoded = encode_account(&proof); + + let is_valid = verify_proof(&proof.account_proof, &payload.state_root, &account_path, &account_encoded); + + println!("is account proof valid: {}", is_valid); + Ok(()) } diff --git a/src/proof.rs b/src/proof.rs index 7ca20dd..15771f0 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -1,26 +1,9 @@ use ethers::utils::keccak256; -use eyre::Result; -use serde::Deserialize; -use serde::de::Error; -use jsonrpsee::{http_client::HttpClientBuilder, rpc_params, core::client::ClientT}; use ethers::utils::rlp::{RlpStream, decode_list}; -use ethers::prelude::{U256, H256, Address}; -use super::utils::hex_str_to_bytes; - -pub async fn get_proof(address: &str, block: u64) -> Result { - let rpc = "https://eth-mainnet.g.alchemy.com:443/v2/sUiZsY3BSTYXjSHIvPc9rGDipR7lAlT4"; - let client = HttpClientBuilder::default().build(rpc)?; - let block_hex = format!("0x{:x}", block); - let params = rpc_params!(address, [""], block_hex); - Ok(client.request("eth_getProof", params).await?) -} +use super::execution_rpc::Proof; pub fn verify_proof(proof: &Vec>, root: &Vec, path: &Vec, value: &Vec) -> bool { - // let account_encoded = encode_account(proof); - // let state_root = hex_str_to_bytes("0x1d006918a3fef7ff7c843f20747c757a38a0a13fe7723f53e349f462c2cfdd71").unwrap(); - // let path = keccak256(proof.address).to_vec(); - let mut expected_hash = root.clone(); let mut path_offset = 0; @@ -63,7 +46,7 @@ fn get_nibble(path: &Vec, offset: usize) -> u8 { } } -fn encode_account(proof: &Proof) -> Vec { +pub fn encode_account(proof: &Proof) -> Vec { let mut stream = RlpStream::new_list(4); stream.append(&proof.nonce); stream.append(&proof.balance); @@ -73,22 +56,7 @@ fn encode_account(proof: &Proof) -> Vec { encoded.to_vec() } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct Proof { - address: Address, - balance: U256, - code_hash: H256, - nonce: U256, - storage_hash: H256, - #[serde(deserialize_with = "proof_deserialize")] - 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)?) +pub fn get_account_path(addr: &Vec) -> Vec { + keccak256(addr).to_vec() }