From 249d9885ccd07d7a4c8c4222655aa9a7bc10e9c9 Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 10 Jan 2024 20:59:23 -0800 Subject: [PATCH] feat: cache validator batches (#8) * 2048 * 131072 * wip * builds * wip broken * working probably * fix * separate batch sizes * tweak constants * try to reduce degree * smaller * cleanup * fix + cleanup * cleanup * cleanup * 2097152 * updates * succinct.json * 16384 * 2097152 * B=4096 * cargo * update succinctx * temp * Revert "temp" This reverts commit 66d12f2d52305e82668dda7949717e8f4ac6ea44. * cargo update --- Cargo.lock | 93 ++++++++------- Cargo.toml | 9 +- circuits/v1.rs | 315 +++++++++++++++++++++++++++++-------------------- succinct.json | 3 + 4 files changed, 242 insertions(+), 178 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df37a05..888733a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,13 +163,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -474,7 +474,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -692,7 +692,7 @@ dependencies = [ [[package]] name = "curta" version = "0.1.0" -source = "git+https://github.com/succinctlabs/curta.git#c4dd8dd43709134051303f1353dd4131078faca6" +source = "git+https://github.com/succinctlabs/curta.git#59e489d21622a92b25a2e4a5b710ce322f309b87" dependencies = [ "anyhow", "bincode", @@ -734,7 +734,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -758,7 +758,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -769,7 +769,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1159,7 +1159,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "syn 2.0.41", + "syn 2.0.48", "toml", "walkdir", ] @@ -1177,7 +1177,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1203,7 +1203,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.41", + "syn 2.0.48", "tempfile", "thiserror", "tiny-keccak", @@ -1541,7 +1541,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2123,13 +2123,16 @@ dependencies = [ name = "lido-oracle-demo" version = "0.1.0" dependencies = [ + "async-trait", "dotenv", "env_logger 0.10.1", "ethers", + "hex", "itertools 0.11.0", "log", "plonky2", "plonky2x", + "serde", ] [[package]] @@ -2347,7 +2350,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2413,7 +2416,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2593,7 +2596,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2631,7 +2634,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2671,7 +2674,7 @@ checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "plonky2" version = "0.1.4" -source = "git+https://github.com/mir-protocol/plonky2.git#7eff4e2751dea6ef67bd09b184599ff97f509ebf" +source = "git+https://github.com/mir-protocol/plonky2.git#0bf9cd2f868303abb67e2ff10ab0e7802d054ae3" dependencies = [ "ahash", "anyhow", @@ -2695,7 +2698,7 @@ dependencies = [ [[package]] name = "plonky2_field" version = "0.1.1" -source = "git+https://github.com/mir-protocol/plonky2.git#7eff4e2751dea6ef67bd09b184599ff97f509ebf" +source = "git+https://github.com/mir-protocol/plonky2.git#0bf9cd2f868303abb67e2ff10ab0e7802d054ae3" dependencies = [ "anyhow", "itertools 0.11.0", @@ -2719,7 +2722,7 @@ dependencies = [ [[package]] name = "plonky2_maybe_rayon" version = "0.1.1" -source = "git+https://github.com/mir-protocol/plonky2.git#7eff4e2751dea6ef67bd09b184599ff97f509ebf" +source = "git+https://github.com/mir-protocol/plonky2.git#0bf9cd2f868303abb67e2ff10ab0e7802d054ae3" dependencies = [ "rayon", ] @@ -2727,12 +2730,12 @@ dependencies = [ [[package]] name = "plonky2_util" version = "0.1.1" -source = "git+https://github.com/mir-protocol/plonky2.git#7eff4e2751dea6ef67bd09b184599ff97f509ebf" +source = "git+https://github.com/mir-protocol/plonky2.git#0bf9cd2f868303abb67e2ff10ab0e7802d054ae3" [[package]] name = "plonky2x" version = "0.1.0" -source = "git+https://github.com/succinctlabs/succinctx.git#df0725962e4933c853606510e2e1cfcf56867200" +source = "git+https://github.com/succinctlabs/succinctx.git#5005786dc2d407eec7acfeeeed6a42eafe92a20f" dependencies = [ "anyhow", "array-macro", @@ -2774,11 +2777,11 @@ dependencies = [ [[package]] name = "plonky2x-derive" version = "0.1.0" -source = "git+https://github.com/succinctlabs/succinctx.git#df0725962e4933c853606510e2e1cfcf56867200" +source = "git+https://github.com/succinctlabs/succinctx.git#5005786dc2d407eec7acfeeeed6a42eafe92a20f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2806,7 +2809,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2879,9 +2882,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" dependencies = [ "unicode-ident", ] @@ -2904,9 +2907,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -3360,29 +3363,29 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -3445,7 +3448,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -3635,7 +3638,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -3686,9 +3689,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -3772,7 +3775,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -3855,7 +3858,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -3977,7 +3980,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -4198,7 +4201,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -4232,7 +4235,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4501,7 +4504,7 @@ checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 71d9ffd..1d05bd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,16 +7,21 @@ edition = "2021" [dependencies] ethers = "2.0.9" -plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", default-features = false} +plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", default-features = false } plonky2x = { git = "https://github.com/succinctlabs/succinctx.git" } dotenv = "0.15.0" env_logger = "0.10.0" itertools = "0.11.0" log = "0.4.20" +serde = "1.0.194" +hex = "0.4.3" +async-trait = "0.1.77" [[bin]] name = "v1" path = "circuits/v1.rs" [dev-dependencies] -plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", features = ["gate_testing"]} +plonky2 = { git = "https://github.com/mir-protocol/plonky2.git", features = [ + "gate_testing", +] } diff --git a/circuits/v1.rs b/circuits/v1.rs index 526ced5..849dd29 100644 --- a/circuits/v1.rs +++ b/circuits/v1.rs @@ -14,33 +14,38 @@ //! Note that using the withdrawal credentials as a filter is not secure as acknowledged in this //! thread: https://research.lido.fi/t/zkllvm-trustless-zk-proof-tvl-oracle/5028/8. #![allow(clippy::needless_range_loop)] +#![feature(async_fn_in_trait)] -use itertools::Itertools; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2x::backend::circuit::{Circuit, PlonkParameters}; use plonky2x::backend::function::Plonky2xFunction; use plonky2x::frontend::eth::beacon::generators::{ - BeaconPartialBalancesHint, BeaconPartialValidatorsHint, + BeaconPartialBalancesHint, BeaconPartialValidatorsHint, BeaconValidatorSubtreeHint, + BeaconValidatorSubtreePoseidonHint, BeaconValidatorSubtreesHint, }; -use plonky2x::frontend::eth::beacon::vars::{BeaconBalancesVariable, BeaconValidatorsVariable}; -use plonky2x::frontend::mapreduce::generator::MapReduceGenerator; +use plonky2x::frontend::eth::beacon::vars::BeaconBalancesVariable; +use plonky2x::frontend::hash::poseidon::poseidon256::PoseidonHashOutVariable; +use plonky2x::frontend::mapreduce::generator::{MapReduceDynamicGenerator, MapReduceGenerator}; use plonky2x::frontend::uint::uint64::U64Variable; -use plonky2x::frontend::vars::{SSZVariable, U256Variable, U32Variable}; +use plonky2x::frontend::vars::{CircuitVariable, SSZVariable, U256Variable, U32Variable}; use plonky2x::prelude::{Bytes32Variable, CircuitBuilder, HintRegistry}; /// The number of slots per epoch in the consensus layer. const SLOTS_PER_EPOCH: u64 = 32; -/// The number of validators to fetch. -const NB_VALIDATORS: usize = 262144; +/// The batch size for building the validator tree and computing numValidators. +const VALIDATOR_BATCH_SIZE: usize = 512; + +/// The batch size for building the balance tree and computing clBalancesGwei and numExitedValidators. +const BALANCE_BATCH_SIZE: usize = 4096; -/// The batch size for fetching balances and computing the local balance roots. -const BATCH_SIZE: usize = 512; +/// The number of validators to fetch. +const NB_VALIDATORS: usize = 2097152; #[derive(Debug, Clone)] -struct LidoOracleV1; +struct LidoOracleV1; -impl Circuit for LidoOracleV1 { +impl Circuit for LidoOracleV1 { fn define, const D: usize>(builder: &mut CircuitBuilder) where <>::Config as GenericConfig>::Hasher: @@ -56,52 +61,39 @@ impl Circuit for LidoOracleV1 { let slots_per_epoch = builder.constant::(SLOTS_PER_EPOCH); let epoch = builder.div(slot, slots_per_epoch).to_u256(builder); - // Get the validators and balances root. + // Get the validator and balance roots, and the validator subtree hashes. let validators = builder.beacon_get_partial_validators::(block_root); let balances = builder.beacon_get_partial_balances::(block_root); - let idxs = (0..N).map(|i| i as u64).collect_vec(); + let subtrees = builder.beacon_witness_validator_subtrees::(block_root); - let output = builder.mapreduce::<( - BeaconValidatorsVariable, - BeaconBalancesVariable, - U256Variable, + // Process all the validators in batches of V. + // Note that the context does not include slot/epoch information so subproofs can be cached. + let validator_output = builder.mapreduce_dynamic::( - (validators, balances, epoch, withdrawal_credentials), - idxs, - |(validators, balances, epoch, withdrawal_credentials), idxs, builder| { - // Witness validators. - let validators = - builder.beacon_witness_validator_batch::(validators, idxs[0]); - - // Witness balances. - let balances = - builder.beacon_witness_balance_batch::(balances, idxs[0]); + ), Self, 1, _, _>( + withdrawal_credentials, + subtrees, + |withdrawal_credentials, hashes, builder| { + // Witness this batch of validators. + let subtree_hash = hashes[0]; + let validators = builder.beacon_witness_validator_subtree::(subtree_hash); // Compute the SSZ leaf representation of the validators. + // Compute whether the validator matches the provided withdrawal credentials and + // update num_validators accordingly. let mut validator_leafs = Vec::new(); + let one = builder.one::(); + let mut num_validators = builder.zero::(); + let mut acc_leaves = Vec::new(); for i in 0..validators.len() { let validator_root = validators[i].hash_tree_root(builder); validator_leafs.push(validator_root); - } - // Compute whether the validator matches the provided withdrawal credentials and - // satisfies validator.activation_epoch <= epoch < validator.exit_epoch. - let one = builder.one::(); - let mut num_validators = builder.zero::(); - let mut num_exited_validators = builder.zero::(); - let mut mask = Vec::new(); - for i in 0..validators.len() { // Compute validator.withdrawal_credentials == withdrawal_credentials. let withdrawal_credentials_match = builder .is_equal(validators[i].withdrawal_credentials, withdrawal_credentials); - mask.push(withdrawal_credentials_match); // Add to the total validator count. let num_validators_plus_one = builder.add(num_validators, one); @@ -111,128 +103,185 @@ impl Circuit for LidoOracleV1 { num_validators, ); - // Check whether it is an exited validator. If it is, add to the - // total exited validator count. - let is_exited_validator = builder.gte(epoch, validators[i].exit_epoch); - let is_exited_validator = - builder.and(withdrawal_credentials_match, is_exited_validator); - let num_exited_validators_plus_one = builder.add(num_exited_validators, one); - num_exited_validators = builder.select( - is_exited_validator, - num_exited_validators_plus_one, - num_exited_validators, - ); - } - - // Convert balances to leafs. - let mut balance_leafs = Vec::new(); - let zero = builder.zero::(); - let mut cl_balances_gwei = builder.zero::(); - for i in 0..idxs.len() / 4 { - let balances = [ - balances[i * 4], - balances[i * 4 + 1], - balances[i * 4 + 2], - balances[i * 4 + 3], - ]; - let masked_balances = [ - builder.select(mask[i * 4], balances[0], zero), - builder.select(mask[i * 4 + 1], balances[1], zero), - builder.select(mask[i * 4 + 2], balances[2], zero), - builder.select(mask[i * 4 + 3], balances[3], zero), - ]; - let cl_balances_gwei_term = builder.add_many(&masked_balances); - cl_balances_gwei = builder.add(cl_balances_gwei, cl_balances_gwei_term); - balance_leafs.push(builder.beacon_u64s_to_leaf(balances)); + // Because we don't have epoch/balances here (to allow for proof caching), + // accumulate this info into a tree that we can verify in the balances step. + acc_leaves.push((withdrawal_credentials_match, validators[i].exit_epoch)); } // Reduce validator leafs to a single root. - let validators_root = builder.ssz_hash_leafs(&validator_leafs); - let balances_root = builder.ssz_hash_leafs(&balance_leafs); - - // Return the partial roots and statistics. - ( - validators_root, - balances_root, - cl_balances_gwei, - num_validators, - num_exited_validators, - ) + let computed_subtree_hash = builder.ssz_hash_leafs(&validator_leafs); + + // Reduce accumulated leaves to a single root. + let poseidon_hash = builder.poseidon_hash( + &acc_leaves + .iter() + .flat_map(|v| v.variables()) + .collect::>(), + ); + (poseidon_hash.clone(), computed_subtree_hash, num_validators) }, |_, left, right, builder| { ( - builder.sha256_pair(left.0, right.0), + builder.poseidon_hash_pair(left.0, right.0), builder.sha256_pair(left.1, right.1), builder.add(left.2, right.2), - builder.add(left.3, right.3), - builder.add(left.4, right.4), ) }, ); + // Process all the balances in batches of B. + let idxs = (0..N).map(|i| i as u64).step_by(B).collect::>(); + let balance_output = builder + .mapreduce::<(BeaconBalancesVariable, U256Variable, Bytes32Variable), U64Variable, ( + PoseidonHashOutVariable, + Bytes32Variable, + U64Variable, + U32Variable, + ), Self, 1, _, _>( + (balances, epoch, withdrawal_credentials), + idxs, + |(balances, epoch, withdrawal_credentials), idxs, builder| { + // Witness balances. + let balances_witness = + builder.beacon_witness_balance_batch::(balances, idxs[0]); + // Witness the data we committed to (as a poseidon tree) in the validator step. + let poseidon_leafs = builder.beacon_witness_validator_subtree_poseidon::( + balances.block_root, + withdrawal_credentials, + idxs[0], + ); + + // Pack balances into leafs. + let mut balance_leafs = Vec::new(); + let zero = builder.zero::(); + let mut cl_balances_gwei = builder.zero::(); + for i in 0..B / 4 { + let four_balances = [ + balances_witness[i * 4], + balances_witness[i * 4 + 1], + balances_witness[i * 4 + 2], + balances_witness[i * 4 + 3], + ]; + let masked_balances = [ + builder.select(poseidon_leafs[i * 4].0, four_balances[0], zero), + builder.select(poseidon_leafs[i * 4 + 1].0, four_balances[1], zero), + builder.select(poseidon_leafs[i * 4 + 2].0, four_balances[2], zero), + builder.select(poseidon_leafs[i * 4 + 3].0, four_balances[3], zero), + ]; + let cl_balances_gwei_term = builder.add_many(&masked_balances); + cl_balances_gwei = builder.add(cl_balances_gwei, cl_balances_gwei_term); + balance_leafs.push(builder.beacon_u64s_to_leaf(four_balances)); + } + + // Hash leafs in batches of V, then reduce into a single root. (since B>V) + let mut poseidons = poseidon_leafs + .chunks(V) + .map(|b| { + builder.poseidon_hash( + &b.iter().flat_map(|v| v.variables()).collect::>(), + ) + }) + .collect::>(); + while poseidons.len() > 1 { + let mut new_poseidons = Vec::new(); + for i in 0..poseidons.len() / 2 { + let (left, right) = + (poseidons[i * 2].clone(), poseidons[i * 2 + 1].clone()); + new_poseidons.push(builder.poseidon_hash_pair(left, right)); + } + poseidons = new_poseidons; + } + + // Reduce validator leafs to a single root. + let balances_root = builder.ssz_hash_leafs(&balance_leafs); + + let one = builder.one::(); + let mut num_exited_validators = builder.zero::(); + for i in 0..poseidon_leafs.len() { + let (withdrawal_credentials_match, exit_epoch) = poseidon_leafs[i]; + let is_exited_validator = builder.gte(epoch, exit_epoch); + let is_exited_validator = + builder.and(withdrawal_credentials_match, is_exited_validator); + let num_exited_validators_plus_one = + builder.add(num_exited_validators, one); + num_exited_validators = builder.select( + is_exited_validator, + num_exited_validators_plus_one, + num_exited_validators, + ); + } + + // Return the partial roots and statistics. + ( + poseidons[0].clone(), + balances_root, + cl_balances_gwei, + num_exited_validators, + ) + }, + |_, left, right, builder| { + ( + builder.poseidon_hash_pair(left.0, right.0), + builder.sha256_pair(left.1, right.1), + builder.add(left.2, right.2), + builder.add(left.3, right.3), + ) + }, + ); + + // Assert that the poseidon tree roots match from validator and balance steps. + builder.assert_is_equal(validator_output.0, balance_output.0); // Assert that the reconstructed commitments match to what we proved exists in the block. - builder.assert_is_equal(output.0, validators.validators_root); - builder.assert_is_equal(output.1, balances.root); + builder.assert_is_equal(validator_output.1, validators.validators_root); + builder.assert_is_equal(balance_output.1, balances.root); // Write outputs back to the EVM. - builder.evm_write::(output.2); - builder.evm_write::(output.3); - builder.evm_write::(output.4); + builder.evm_write::(balance_output.2); + builder.evm_write::(validator_output.2); + builder.evm_write::(balance_output.3); } fn register_generators, const D: usize>(registry: &mut HintRegistry) where <>::Config as GenericConfig>::Hasher: AlgebraicHasher, { - let id = MapReduceGenerator::< + let dynamic_id = MapReduceDynamicGenerator::::id(); + registry.register_simple::::id(); + >>(dynamic_id); + let id = MapReduceGenerator::::id(); registry.register_simple::>(id); - if N > usize::pow(2, 20) { - registry.register_hint::>(); - registry.register_hint::>(); + if N > usize::pow(2, 21) { + registry.register_async_hint::>(); + registry.register_async_hint::>(); } + registry.register_async_hint::>(); + registry.register_async_hint::>(); + registry.register_async_hint::>(); } } fn main() { - LidoOracleV1::::entrypoint(); + LidoOracleV1::::entrypoint(); } #[cfg(test)] @@ -249,11 +298,13 @@ mod tests { /// An example source block root (mainnet slot 7959300). const BLOCK_ROOT: &str = "0x46da8a07811bd86a9430d8d188afc39e19e84414df6c82ac99a31a94d556d5f4"; - /// Test withdrawal credentials, used by 400 of the first 1024 mainnet validators. + /// Test withdrawal credentials, used by 454 of the first 2048 mainnet validators. const WITHDRAWAL_CREDENTIALS: &str = - "0x010000000000000000000000f4d1645dd1a8a44a3dd197cba2626161b01163c5"; + "0x010000000000000000000000ae6e23880345eb52aa887bc625cf358f244a3fc4"; - const TEST_NB_VALIDATORS: usize = 1024; + const TEST_V: usize = 512; + const TEST_B: usize = 1024; + const TEST_NB_VALIDATORS: usize = 2048; /// A test of the circuit on slot 7959300. /// @@ -266,9 +317,11 @@ mod tests { dotenv::dotenv().ok(); // Build the circuit. + debug!("TEST_V: {}", TEST_V); + debug!("TEST_B: {}", TEST_B); debug!("TEST_NB_VALIDATORS: {}", TEST_NB_VALIDATORS); let mut builder = CircuitBuilder::::new(); - LidoOracleV1::::define(&mut builder); + LidoOracleV1::::define(&mut builder); let circuit = builder.build(); // Generate input. @@ -290,11 +343,11 @@ mod tests { debug!("> numExitedValidators: {}", num_exited_validators); // Assert output. - assert_eq!(cl_balances_gwei, 12804421770945); - assert_eq!(num_validators, 400); + assert_eq!(cl_balances_gwei, 14533313413475); + assert_eq!(num_validators, 454); assert_eq!(num_exited_validators, 0); // Test circuit serialization. - LidoOracleV1::::test_serialization::(); + LidoOracleV1::::test_serialization::(); } } diff --git a/succinct.json b/succinct.json index 83f24e3..1fd5c83 100644 --- a/succinct.json +++ b/succinct.json @@ -8,6 +8,9 @@ "proveCommand": "RUST_LOG=debug ./build/v1 prove input.json", "requiredArtifacts": [ "v1" + ], + "defaultArtifacts": [ + "main.circuit" ] } ]