add execution_rpc package

This commit is contained in:
Noah Citron 2022-08-20 10:10:28 -04:00
parent 2040614e1b
commit 4dd8ba253f
3 changed files with 64 additions and 36 deletions

43
src/execution_rpc.rs Normal file
View File

@ -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<Proof> {
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<Vec<u8>>,
}
fn proof_deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error> where D: serde::Deserializer<'de> {
let branch: Vec<String> = serde::Deserialize::deserialize(deserializer)?;
Ok(branch.iter().map(|elem| {
hex_str_to_bytes(elem)
}).collect::<Result<_>>().map_err(D::Error::custom)?)
}

View File

@ -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(())
}

View File

@ -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<Proof> {
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<Vec<u8>>, root: &Vec<u8>, path: &Vec<u8>, value: &Vec<u8>) -> 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<u8>, offset: usize) -> u8 {
}
}
fn encode_account(proof: &Proof) -> Vec<u8> {
pub fn encode_account(proof: &Proof) -> Vec<u8> {
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<u8> {
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<Vec<u8>>,
}
fn proof_deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error> where D: serde::Deserializer<'de> {
let branch: Vec<String> = serde::Deserialize::deserialize(deserializer)?;
Ok(branch.iter().map(|elem| {
hex_str_to_bytes(elem)
}).collect::<Result<_>>().map_err(D::Error::custom)?)
pub fn get_account_path(addr: &Vec<u8>) -> Vec<u8> {
keccak256(addr).to_vec()
}