Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.

Commit 7ea56e9

Browse files
author
adria0
committed
format
1 parent 08eb017 commit 7ea56e9

File tree

11 files changed

+148
-74
lines changed

11 files changed

+148
-74
lines changed

bin/mpt-test/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web3_rpc_cache.bin

bin/mpt-test/README.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This tool aims to verify mainnet blocks for the MPT circuit.
44

55
## Running tests
66

7-
Just run `cargo run --release`
7+
Just run `./test_mainnet_blocks.sh`
88

99
## Adding new blocks to prove
1010

@@ -13,7 +13,11 @@ In order to add more blocks to prove you have to:
1313
- Add new entry in the `access-lists` folder
1414
- Set the environment variable `WEB3_SERVICE_PROVIDER` to a mainnet JSON-RPC provider
1515
- Run the tests again
16+
- You will have to upload the cache file again (web3_rpc_cache.bin) and update the `test_mainnet_blocks.sh` file
1617

18+
## How can get an access list for other blocks?
1719

18-
## How
20+
There's a [modified version of geth](https://github.com/adria0/go-ethereum/tree/zklight) that [tracks access lists](https://github.com/adria0/go-ethereum/commit/fd2d7cea3747e1003a817cd18e200bf2b00be03c#diff-c3757dc9e9d868f63bc84a0cc67159c1d5c22cc5d8c9468757098f0492e0658cR1306) and allows to retrieve them via [RPC eth_accessListByNumber call](https://github.com/adria0/go-ethereum/commit/fd2d7cea3747e1003a817cd18e200bf2b00be03c#diff-c426ecd2f7d247753b9ea8c1cc003f21fa412661c1f967d203d4edf8163da344R1587), so you can deploy this version and grab some access lists there.
21+
22+
Note: of course this is just a method for testing , do not use in production.
1923

bin/mpt-test/src/cache.rs

+45-18
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
//! A simple cache for web3 rpc requests
2+
13
use eth_types::keccak256;
2-
use eyre::{ensure, Result};
4+
use eyre::{ensure, eyre, Result};
35
use flate2::{read::ZlibDecoder, write::ZlibEncoder, Compression};
46
use hyper::{
57
body::{self},
68
service::{make_service_fn, service_fn},
79
Body, Client, Request, Response, Server,
810
};
911
use serde::Deserialize;
12+
use serde_json::Value;
1013
use std::{
1114
collections::HashMap,
1215
convert::Infallible,
@@ -20,6 +23,10 @@ lazy_static! {
2023
static ref CACHE: tokio::sync::Mutex<CacheFile> = tokio::sync::Mutex::new(CacheFile::new());
2124
}
2225

26+
/// Cache file format is a consecutive list of entries, each entry is:
27+
/// - 32 bytes: key (keccak256 of the request)
28+
/// - 4 bytes: length of the compressed response
29+
/// - N bytes: compressed response
2330
struct CacheFile {
2431
offsets: HashMap<[u8; 32], u64>,
2532
}
@@ -29,6 +36,7 @@ impl CacheFile {
2936
offsets: HashMap::new(),
3037
}
3138
}
39+
/// Load all existing entries from the cache file
3240
pub async fn load(&mut self) -> Result<()> {
3341
if let Ok(mut f) = File::open(CACHE_PATH) {
3442
let mut hash = [0u8; 32];
@@ -44,7 +52,7 @@ impl CacheFile {
4452
}
4553
Ok(())
4654
}
47-
55+
/// Write a new entry
4856
async fn write(&mut self, key: [u8; 32], value: &[u8]) -> Result<()> {
4957
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best());
5058
encoder.write_all(value)?;
@@ -60,11 +68,12 @@ impl CacheFile {
6068

6169
Ok(())
6270
}
63-
71+
/// Read an entry, returns Ok(None) if not found
6472
async fn read(&self, key: [u8; 32]) -> Result<Option<Vec<u8>>> {
6573
let offset = self.offsets.get(&key).cloned();
6674
if let Some(offset) = offset {
67-
let mut f = File::open(CACHE_PATH).unwrap();
75+
let mut f =
76+
File::open(CACHE_PATH).expect("since offset exists, file should exist. qed.");
6877
f.seek(std::io::SeekFrom::Start(offset))?;
6978

7079
let mut len_buf = [0u8; 4];
@@ -84,10 +93,8 @@ impl CacheFile {
8493
}
8594
}
8695

87-
#[allow(dead_code)]
8896
#[derive(Deserialize, Debug)]
8997
struct RequestBody {
90-
jsonrpc: String,
9198
method: String,
9299
params: Option<Vec<Param>>,
93100
id: u32,
@@ -100,25 +107,27 @@ enum Param {
100107
Bool(bool),
101108
StringVec(Vec<String>),
102109
}
110+
103111
impl RequestBody {
104-
fn name(&self) -> String {
112+
fn hash(&self) -> [u8; 32] {
105113
let params = if let Some(params) = &self.params {
106114
params
107115
.iter()
108116
.map(|s| match s {
109117
Param::String(s) => s.to_owned(),
110118
Param::Bool(b) => format!("{}", b),
111-
Param::StringVec(v) => v.join(""),
119+
Param::StringVec(v) => v.join("-"),
112120
})
113121
.collect::<Vec<_>>()
114122
.join("-")
115123
} else {
116124
"".to_owned()
117125
};
118-
format!("{}_{}", self.method, params)
126+
keccak256(format!("{}-{}", self.method, params).as_bytes())
119127
}
120128
}
121129

130+
/// Handle a web3 rpc request with error handling
122131
async fn infallible_web3_proxy(req: Request<Body>) -> Result<Response<Body>, Infallible> {
123132
match web3_proxy(req).await {
124133
Ok(res) => Ok(res),
@@ -132,32 +141,40 @@ async fn infallible_web3_proxy(req: Request<Body>) -> Result<Response<Body>, Inf
132141
}
133142
}
134143

144+
/// Handle a web3 rpc request, return cached result or call the env!("WEB3_PROVIDER_URL") RPC server
135145
async fn web3_proxy(req: Request<Body>) -> Result<Response<Body>> {
136146
let method = req.method().clone();
137147
let headers = req.headers().clone();
148+
149+
// try to read the result from the cache
138150
let request_body_bytes = hyper::body::to_bytes(req.into_body()).await?.to_vec();
139151
let request_body_json: RequestBody = serde_json::from_slice(&request_body_bytes)?;
140-
141-
let key = keccak256(request_body_json.name().as_bytes());
142-
143-
let response_body = CACHE.lock().await.read(key).await?;
144-
145-
let response_body = if let Some(response_body) = response_body {
146-
response_body
152+
let key = request_body_json.hash();
153+
let response_result = CACHE.lock().await.read(key).await?;
154+
155+
let response_body = if let Some(response_result) = response_result {
156+
// return cached result
157+
format!(
158+
"{{\"id\":{}, \"jsonrpc\":\"2.0\", \"result\":{}}}",
159+
request_body_json.id,
160+
String::from_utf8(response_result).unwrap()
161+
)
162+
.into_bytes()
147163
} else {
148164
println!(
149165
"=>{}",
150166
String::from_utf8(request_body_bytes.clone()).unwrap()
151167
);
152168

169+
// call RPC server, copying headers and method from the original request
153170
let connector = hyper_rustls::HttpsConnectorBuilder::new()
154171
.with_native_roots()
155172
.https_or_http()
156173
.enable_http1()
157174
.build();
158175

159176
let client = Client::builder().build(connector);
160-
let provider_url = std::env::var("PROVIDER_URL")?;
177+
let provider_url = std::env::var("WEB3_PROVIDER_URL")?;
161178

162179
let mut req = Request::builder()
163180
.method(method)
@@ -176,23 +193,33 @@ async fn web3_proxy(req: Request<Body>) -> Result<Response<Body>> {
176193
let (head, response_body) = resp.into_parts();
177194
ensure!(head.status.is_success(), "Provider does not return 200");
178195

196+
// parse response and cache it
179197
let response_bytes = body::to_bytes(response_body).await?.to_vec();
180-
CACHE.lock().await.write(key, &response_bytes).await?;
198+
199+
let root: Value = serde_json::from_slice(&response_bytes)?;
200+
let Some(result) = root.get("result") else {
201+
return Err(eyre!("Provider does not return result"));
202+
};
203+
let result_bytes = serde_json::to_vec(result)?;
204+
CACHE.lock().await.write(key, &result_bytes).await?;
181205

182206
response_bytes
183207
};
184208

209+
// return HTTP 200 response
185210
let response = Response::builder()
186211
.status(200)
187212
.body(Body::from(response_body))?;
188213

189214
Ok(response)
190215
}
191216

217+
/// Load the cache file
192218
pub async fn load() -> Result<()> {
193219
CACHE.lock().await.load().await
194220
}
195221

222+
/// Start the cache server at localhost:3000
196223
pub async fn start() -> Result<()> {
197224
let make_svc =
198225
make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(infallible_web3_proxy)) });

bin/mpt-test/src/circuit/equal_words.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! A simple chip to compare two words for equality.
2+
13
use eth_types::Field;
24
use eyre::Result;
35
use gadgets::{

bin/mpt-test/src/circuit/state_update.rs

+49-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! A circuit to verify chained proofs of state updates in a block.
2+
13
use eth_types::Field;
24
use eyre::Result;
35
use gadgets::{
@@ -25,7 +27,7 @@ use zkevm_circuits::{
2527

2628
use crate::circuit::{
2729
equal_words::EqualWordsConfig,
28-
witness::{FieldTrieModification, FieldTrieModifications, Transforms, Witness},
30+
witness::{FieldTrieModification, FieldTrieModifications, Witness},
2931
};
3032

3133
#[cfg(not(feature = "disable-keccak"))]
@@ -39,36 +41,69 @@ pub fn xnif<F: Field>(a: Expression<F>, b: Expression<F>) -> Expression<F> {
3941
and::expr([a, not::expr(b)])
4042
}
4143

42-
///
44+
/// This
4345
#[derive(Clone)]
4446
pub struct StateUpdateCircuitConfig<F: Field> {
4547
#[cfg(not(feature = "disable-keccak"))]
48+
/// If enabled by feature, the verification of keccaks
49+
/// Please note that the keccak circuit will dramatically increase the time to generate the
50+
/// proof this is the reason why it is disabled by default (check the `disable-keccak`
51+
/// feature)
4652
pub keccak_config: KeccakCircuitConfig<F>,
53+
54+
/// The MPT configuration
4755
pub mpt_config: MPTConfig<F>,
4856

57+
/// The MPT table, where the state updates are stored
4958
pub pi_mpt: MptTable,
50-
pub pi_instance: Column<Instance>,
5159

60+
/// Intance column, used to check public inputs
61+
pub instance: Column<Instance>,
62+
63+
/// ONE if the first row, ZERO otherwise
5264
pub is_first: Column<Fixed>,
65+
66+
/// ONE if row is paddding, ZERO otherwise
5367
pub is_padding: IsZeroConfig<F>,
68+
69+
/// ONE is the last used row, ZERO otherwise
5470
pub is_last: IsZeroConfig<F>,
5571

72+
/// Check if new_root is propagated
5673
pub new_root_propagation: EqualWordsConfig<F>,
74+
75+
/// Check if previous old_root, and new_root are equal
5776
pub root_chained: EqualWordsConfig<F>,
5877

78+
/// A down counter, that is decreased by one in each row
5979
pub count: Column<Advice>,
80+
81+
/// Check if the counter is monotonic decreasing
6082
pub count_decrement: IsZeroConfig<F>,
6183

6284
pub q_enable: Selector,
6385
}
6486

65-
/// MPT Circuit for proving the storage modification is valid.
87+
/// MPT Circuit for proving that a from a given root, a set of state updates are valid.
88+
/// Public inputs:
89+
/// old_root_lo
90+
/// old_root_hi
91+
/// new_root_lo
92+
/// new_root_hi
93+
/// number of MPT changes
94+
/// for each change
95+
/// | change_type
96+
/// | address
97+
/// | value_lo
98+
/// | value_hi
99+
/// | key_lo
100+
/// | key_hi
66101
#[derive(Default)]
67102
pub struct StateUpdateCircuit<F: Field> {
68-
pub transforms: Transforms,
69103
#[cfg(not(feature = "disable-keccak"))]
70104
pub keccak_circuit: KeccakCircuit<F>,
71105
pub mpt_circuit: MPTCircuit<F>,
106+
72107
pub lc_witness: FieldTrieModifications<F>,
73108
pub degree: usize,
74109
pub max_proof_count: usize,
@@ -110,7 +145,7 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
110145
let is_first = meta.fixed_column();
111146
let count = meta.advice_column();
112147
let q_enable = meta.complex_selector();
113-
let pi_instance = meta.instance_column();
148+
let instance = meta.instance_column();
114149
let pi_mpt = MptTable {
115150
address: meta.advice_column(),
116151
storage_key: word::Word::new([meta.advice_column(), meta.advice_column()]),
@@ -140,7 +175,7 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
140175
meta.enable_equality(*col);
141176
}
142177

143-
meta.enable_equality(pi_instance);
178+
meta.enable_equality(instance);
144179
meta.enable_equality(count);
145180

146181
let is_padding_inv = meta.advice_column();
@@ -279,7 +314,7 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
279314
new_root_propagation,
280315
root_chained,
281316
q_enable,
282-
pi_instance,
317+
instance,
283318
pi_mpt,
284319
};
285320

@@ -297,7 +332,7 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
297332
) -> Result<(), Error> {
298333
let challenges = _challenges.values(&mut layouter);
299334

300-
// assign MPT witness
335+
// MPT witness
301336

302337
config
303338
.mpt_config
@@ -309,6 +344,8 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
309344
self.mpt_circuit.max_nodes,
310345
)?;
311346

347+
// Keccak witness ( if apply )
348+
312349
#[cfg(feature = "disable-keccak")]
313350
config.mpt_config.keccak_table.dev_load(
314351
&mut layouter,
@@ -320,7 +357,7 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
320357
self.keccak_circuit
321358
.synthesize_sub(&config.keccak_config, &challenges, &mut layouter)?;
322359

323-
// assign LC witness
360+
// Circuit witness, returns the public inputs for the state update
324361

325362
let pi = layouter.assign_region(
326363
|| "lc witness",
@@ -342,7 +379,7 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
342379
|| "LC_count_monodec_inv",
343380
config.count_decrement.value_inv,
344381
);
345-
region.name_column(|| "LC_pi_instance", config.pi_instance);
382+
region.name_column(|| "LC_instance", config.instance);
346383

347384
region.assign_fixed(|| "", config.is_first, 0, || Value::known(F::ONE))?;
348385

@@ -454,7 +491,7 @@ impl<F: Field> Circuit<F> for StateUpdateCircuit<F> {
454491

455492
// check that state updates to lookup are the same that the specified in the public inputs
456493
for (n, value) in pi.into_iter().enumerate() {
457-
layouter.constrain_instance(value.unwrap().cell(), config.pi_instance, n)?;
494+
layouter.constrain_instance(value.unwrap().cell(), config.instance, n)?;
458495
}
459496

460497
Ok(())
@@ -470,7 +507,6 @@ impl StateUpdateCircuit<Fr> {
470507
) -> Result<StateUpdateCircuit<Fr>> {
471508
let Witness {
472509
mpt_witness,
473-
transforms,
474510
lc_witness,
475511
} = witness;
476512

@@ -498,7 +534,6 @@ impl StateUpdateCircuit<Fr> {
498534
let keccak_circuit = KeccakCircuit::<Fr>::new(2usize.pow(degree as u32), keccak_data);
499535

500536
let lc_circuit = StateUpdateCircuit::<Fr> {
501-
transforms,
502537
#[cfg(not(feature = "disable-keccak"))]
503538
keccak_circuit,
504539
mpt_circuit,

bin/mpt-test/src/circuit/utils.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Some utilities.
2+
13
use crate::circuit::witness::FieldTrieModifications;
24
use eth_types::Field;
35
use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr};

0 commit comments

Comments
 (0)