Skip to content

Commit

Permalink
feat: eth_getAccount
Browse files Browse the repository at this point in the history
  • Loading branch information
ratankaliani committed Aug 28, 2023
1 parent d566db2 commit 7628c0a
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 10 deletions.
64 changes: 58 additions & 6 deletions plonky2x/src/frontend/eth/storage/builder.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use ethers::types::{Address, U256};
use ethers::types::{U256};
use plonky2::field::extension::Extendable;
use plonky2::hash::hash_types::RichField;

use super::generators::block::EthBlockGenerator;
use super::generators::storage::EthStorageProofGenerator;
use super::generators::storage::{EthStorageProofGenerator, EthAccountProofGenerator};
use super::vars::{EthAccountVariable, EthHeaderVariable, EthLogVariable};
use crate::frontend::builder::CircuitBuilder;
use crate::frontend::eth::vars::AddressVariable;
Expand Down Expand Up @@ -40,10 +40,12 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
#[allow(non_snake_case)]
pub fn eth_get_account(
&mut self,
_address: Address,
_block_hash: Bytes32Variable,
address: AddressVariable,
block_hash: Bytes32Variable,
) -> EthAccountVariable {
todo!()
let generator = EthAccountProofGenerator::new(self, address, block_hash);
self.add_simple_generator(&generator);
generator.value
}

#[allow(non_snake_case)]
Expand All @@ -65,7 +67,7 @@ mod tests {
use plonky2::plonk::config::PoseidonGoldilocksConfig;

use super::*;
use crate::frontend::eth::storage::vars::EthHeader;
use crate::frontend::eth::storage::vars::{EthHeader, EthAccount};
use crate::prelude::CircuitBuilderX;
use crate::utils::{address, bytes32};

Expand Down Expand Up @@ -117,6 +119,56 @@ mod tests {
let _ = circuit.serialize().unwrap();
}

#[test]
#[cfg_attr(feature = "ci", ignore)]
#[allow(non_snake_case)]
fn test_eth_get_account() {
dotenv::dotenv().ok();
let rpc_url = env::var("RPC_1").unwrap();
let provider = Provider::<Http>::try_from(rpc_url).unwrap();

// This is the circuit definition
let mut builder = CircuitBuilderX::new();
builder.set_execution_client(provider);
let block_hash = builder.read::<Bytes32Variable>();
let address = builder.read::<AddressVariable>();

let value = builder.eth_get_account(address, block_hash);
builder.write(value);

// Build your circuit.
let circuit = builder.build::<PoseidonGoldilocksConfig>();

// Write to the circuit input.
// These values are taken from Ethereum block https://etherscan.io/block/17880427
let mut input = circuit.input();
input.write::<Bytes32Variable>(bytes32!(
"0x281dc31bb78779a1ede7bf0f4d2bc5f07ddebc9f9d1155e413d8804384604bbe"
));
input.write::<AddressVariable>(address!("0x55032650b14df07b85bF18A3a3eC8E0Af2e028d5"));

// Generate a proof.
let (proof, output) = circuit.prove(&input);

// Verify proof.
circuit.verify(&proof, &input, &output);

// Read output.
let circuit_value = output.read::<EthAccountVariable>();
println!("{:?}", circuit_value);
assert_eq!(
circuit_value,
EthAccount {
nonce: U256::from(1),
balance: U256::from(0),
code_hash: bytes32!("0xb9c1c929064cd21734c102a698e68bf617feefcfa5a9f62407c45401546736bf"),
storage_hash: bytes32!("0x073d71569b4b986bc20b6921dbbc1b74145588f765627dd5e566d65a6b7b33cc"),
},
);

let _ = circuit.serialize().unwrap();
}

#[test]
#[cfg_attr(feature = "ci", ignore)]
#[allow(non_snake_case)]
Expand Down
110 changes: 110 additions & 0 deletions plonky2x/src/frontend/eth/storage/generators/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use plonky2::util::serialization::{Buffer, IoResult, Read, Write};
use tokio::runtime::Runtime;

use crate::frontend::builder::CircuitBuilder;
use crate::frontend::eth::storage::vars::{EthAccountVariable, EthAccount};
use crate::frontend::eth::utils::u256_to_h256_be;
use crate::frontend::eth::vars::AddressVariable;
use crate::frontend::vars::{Bytes32Variable, CircuitVariable};
Expand Down Expand Up @@ -118,3 +119,112 @@ impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F, D>
})
}
}

#[derive(Debug, Clone)]
pub struct EthAccountProofGenerator<F: RichField + Extendable<D>, const D: usize> {
address: AddressVariable,
block_hash: Bytes32Variable,
pub value: EthAccountVariable,
chain_id: u64,
_phantom: PhantomData<F>,
}

impl<F: RichField + Extendable<D>, const D: usize> EthAccountProofGenerator<F, D> {
pub fn new(
builder: &mut CircuitBuilder<F, D>,
address: AddressVariable,
block_hash: Bytes32Variable,
) -> EthAccountProofGenerator<F, D> {
let chain_id = builder.get_chain_id();
let value = builder.init::<EthAccountVariable>();
EthAccountProofGenerator {
address,
block_hash,
value,
chain_id,
_phantom: PhantomData::<F>,
}
}
}

impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F, D>
for EthAccountProofGenerator<F, D>
{
fn id(&self) -> String {
"EthStorageProofGenerator".to_string()
}

fn dependencies(&self) -> Vec<Target> {
let mut targets = Vec::new();
targets.extend(self.address.targets());
targets.extend(self.block_hash.targets());
targets
}

fn run_once(&self, witness: &PartitionWitness<F>, buffer: &mut GeneratedValues<F>) {
let address = self.address.get(witness);
let block_hash = self.block_hash.get(witness);
let provider = get_provider(self.chain_id);
let rt = Runtime::new().expect("failed to create tokio runtime");
let result: EIP1186ProofResponse = rt.block_on(async {
provider
.get_proof(address, vec![], Some(block_hash.into()))
.await
.expect("Failed to get proof")
});
// Copy u64 into U256
let mut bytes = [0u8; 8];
result
.nonce
.to_big_endian(&mut bytes);
// Append 24 zero bytes to the beginning of the number
let mut total_bytes = [0u8; 32];
total_bytes[24..].copy_from_slice(&bytes);

let nonce = ethers::types::U256::from_big_endian(&total_bytes);

self.value.set(buffer, EthAccount {
balance: result.balance,
code_hash: result.code_hash,
nonce,
storage_hash: result.storage_hash,
});
}

#[allow(unused_variables)]
fn serialize(&self, dst: &mut Vec<u8>, common_data: &CommonCircuitData<F, D>) -> IoResult<()> {
let chain_id_bytes = self.chain_id.to_be_bytes();
dst.write_all(&chain_id_bytes)?;

dst.write_target_vec(&self.block_hash.targets())?;
dst.write_target_vec(&self.address.targets())?;
dst.write_target_vec(&self.value.targets())
}

#[allow(unused_variables)]
fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData<F, D>) -> IoResult<Self> {
let mut chain_id_bytes = [0u8; 8];
src.read_exact(&mut chain_id_bytes)?;
let chain_id = u64::from_be_bytes(chain_id_bytes);

let block_hash_targets = src.read_target_vec()?;
let block_hash = Bytes32Variable::from_targets(&block_hash_targets);

let address_targets = src.read_target_vec()?;
let address = AddressVariable::from_targets(&address_targets);

let storage_key_targets = src.read_target_vec()?;
let storage_key = Bytes32Variable::from_targets(&storage_key_targets);

let value_targets = src.read_target_vec()?;
let value = EthAccountVariable::from_targets(&value_targets);

Ok(Self {
address,
block_hash,
value,
chain_id,
_phantom: PhantomData::<F>,
})
}
}
12 changes: 8 additions & 4 deletions plonky2x/src/frontend/eth/storage/vars/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ impl CircuitVariable for EthProofVariable {
}
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct EthAccount {
pub balance: U256,
pub code_hash: H256,
// Update to U64 once we have U64 variables
pub nonce: U256,
pub storage_hash: H256,
}
Expand All @@ -74,6 +75,7 @@ pub struct EthAccount {
pub struct EthAccountVariable {
pub balance: U256Variable,
pub code_hash: Bytes32Variable,
// Update to U64 once we have U64 variables
pub nonce: U256Variable,
pub storage_hash: Bytes32Variable,
}
Expand Down Expand Up @@ -115,11 +117,13 @@ impl CircuitVariable for EthAccountVariable {

fn from_variables(variables: &[Variable]) -> Self {
let balance = U256Variable::from_variables(&variables[0..4]);
let code_hash = Bytes32Variable::from_variables(&variables[4..4 + 32 * 8]);
let offset = 4 + 32 * 8;
let mut offset = 4;
let code_hash = Bytes32Variable::from_variables(&variables[offset..offset + 32 * 8]);
offset += 32 * 8;
let nonce = U256Variable::from_variables(&variables[offset..offset + 4]);
offset += 4;
let storage_hash =
Bytes32Variable::from_variables(&variables[offset + 4..offset + 4 + 32 * 8]);
Bytes32Variable::from_variables(&variables[offset..offset + 32 * 8]);
Self {
balance,
code_hash,
Expand Down

0 comments on commit 7628c0a

Please sign in to comment.