diff --git a/.gitmodules b/.gitmodules index 10cff206b..aa7791737 100644 --- a/.gitmodules +++ b/.gitmodules @@ -52,3 +52,6 @@ [submodule "vendor/zkllvm-metacraft-circuits/zkllvm-template"] path = vendor/zkllvm-metacraft-circuits/zkllvm-template url = https://github.com/NilFoundation/zkllvm-template.git +[submodule "vendor/consensus-spec-tests"] + path = vendor/consensus-spec-tests + url = https://github.com/ethereum/consensus-spec-tests.git diff --git a/casper-finality-proofs/Cargo.lock b/casper-finality-proofs/Cargo.lock index f485cb424..3165c440a 100644 --- a/casper-finality-proofs/Cargo.lock +++ b/casper-finality-proofs/Cargo.lock @@ -1175,9 +1175,9 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "const-random" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11df32a13d7892ec42d51d3d175faba5211ffe13ed25d4fb348ac9e9ce835593" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" dependencies = [ "const-random-macro", ] @@ -1400,10 +1400,12 @@ dependencies = [ [[package]] name = "curta" version = "0.1.0" -source = "git+https://github.com/succinctlabs/curta.git?branch=main#b397226c359a372726316e99397db68272f20b04" +source = "git+https://github.com/succinctlabs/curta.git?branch=main#7b10c6d041bb33ec1a3f7a85fc6f74e27cf655d4" dependencies = [ "anyhow", "bincode", + "curve25519-dalek 4.1.1", + "env_logger 0.9.3", "hex", "itertools 0.10.5", "log", @@ -1418,10 +1420,12 @@ dependencies = [ [[package]] name = "curta" version = "0.1.0" -source = "git+https://github.com/succinctlabs/curta.git#b397226c359a372726316e99397db68272f20b04" +source = "git+https://github.com/succinctlabs/curta.git#7b10c6d041bb33ec1a3f7a85fc6f74e27cf655d4" dependencies = [ "anyhow", "bincode", + "curve25519-dalek 4.1.1", + "env_logger 0.9.3", "hex", "itertools 0.10.5", "log", @@ -1440,9 +1444,9 @@ source = "git+https://github.com/succinctlabs/curve25519-dalek.git?branch=featur dependencies = [ "cfg-if", "cpufeatures", - "curve25519-dalek-derive 0.1.0 (git+https://github.com/succinctlabs/curve25519-dalek.git?branch=feature/edwards-point-getters)", + "curve25519-dalek-derive 0.1.0", "fiat-crypto 0.1.20", - "platforms 3.1.2", + "platforms 3.2.0", "rustc_version", "subtle", "zeroize", @@ -1456,10 +1460,10 @@ checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ "cfg-if", "cpufeatures", - "curve25519-dalek-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curve25519-dalek-derive 0.1.1", "digest 0.10.7", "fiat-crypto 0.2.2", - "platforms 3.1.2", + "platforms 3.2.0", "rustc_version", "subtle", "zeroize", @@ -1468,8 +1472,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +source = "git+https://github.com/succinctlabs/curve25519-dalek.git?branch=feature/edwards-point-getters#e2d1bd10d6d772af07cac5c8161cd7655016af6d" dependencies = [ "proc-macro2", "quote", @@ -1478,8 +1481,9 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" -source = "git+https://github.com/succinctlabs/curve25519-dalek.git?branch=feature/edwards-point-getters#e2d1bd10d6d772af07cac5c8161cd7655016af6d" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", @@ -2108,6 +2112,19 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -3838,9 +3855,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", @@ -3957,9 +3974,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -5436,9 +5453,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "a9dfc0783362704e97ef3bd24261995a699468440099ef95d869b4d9732f829a" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -5477,9 +5494,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "2f55da20b29f956fb01f0add8683eb26ee13ebe3ebd935e49898717c6b4b2830" dependencies = [ "cc", "libc", @@ -5725,7 +5742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] @@ -5855,14 +5872,14 @@ checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" [[package]] name = "platforms" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "plonky2" version = "0.1.4" -source = "git+https://github.com/mir-protocol/plonky2.git#0258ad4a3dfeeb92bc59e0b1be6be06731032bfe" +source = "git+https://github.com/mir-protocol/plonky2.git#f71f227d3ca8ac6da62ff3748a2279dc4fd23c77" dependencies = [ "ahash 0.8.6", "anyhow", @@ -5885,7 +5902,7 @@ dependencies = [ [[package]] name = "plonky2_field" version = "0.1.1" -source = "git+https://github.com/mir-protocol/plonky2.git#0258ad4a3dfeeb92bc59e0b1be6be06731032bfe" +source = "git+https://github.com/mir-protocol/plonky2.git#f71f227d3ca8ac6da62ff3748a2279dc4fd23c77" dependencies = [ "anyhow", "itertools 0.11.0", @@ -5909,7 +5926,7 @@ dependencies = [ [[package]] name = "plonky2_maybe_rayon" version = "0.1.1" -source = "git+https://github.com/mir-protocol/plonky2.git#0258ad4a3dfeeb92bc59e0b1be6be06731032bfe" +source = "git+https://github.com/mir-protocol/plonky2.git#f71f227d3ca8ac6da62ff3748a2279dc4fd23c77" dependencies = [ "rayon", ] @@ -5917,12 +5934,12 @@ dependencies = [ [[package]] name = "plonky2_util" version = "0.1.1" -source = "git+https://github.com/mir-protocol/plonky2.git#0258ad4a3dfeeb92bc59e0b1be6be06731032bfe" +source = "git+https://github.com/mir-protocol/plonky2.git#f71f227d3ca8ac6da62ff3748a2279dc4fd23c77" [[package]] name = "plonky2x" version = "0.1.0" -source = "git+https://github.com/succinctlabs/succinctx.git?branch=main#fa77412f0716468b30050b8b12835b15305b0007" +source = "git+https://github.com/succinctlabs/succinctx.git?branch=main#598e609dcfc7985afcb706c8775346ec9de081cb" dependencies = [ "anyhow", "array-macro", @@ -5936,7 +5953,7 @@ dependencies = [ "digest 0.10.7", "dotenv", "ed25519-consensus", - "env_logger", + "env_logger 0.10.0", "ethers", "ff 0.13.0", "futures", @@ -5964,7 +5981,7 @@ dependencies = [ [[package]] name = "plonky2x-derive" version = "0.1.0" -source = "git+https://github.com/succinctlabs/succinctx.git?branch=main#fa77412f0716468b30050b8b12835b15305b0007" +source = "git+https://github.com/succinctlabs/succinctx.git?branch=main#598e609dcfc7985afcb706c8775346ec9de081cb" dependencies = [ "proc-macro2", "quote", @@ -6049,9 +6066,9 @@ dependencies = [ [[package]] name = "primeorder" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" +checksum = "c7dbe9ed3b56368bd99483eb32fe9c17fdd3730aebadc906918ce78d54c7eeb4" dependencies = [ "elliptic-curve 0.13.6", ] @@ -7144,7 +7161,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_json", "serde_with_macros 3.4.0", @@ -7193,7 +7210,7 @@ version = "0.9.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "itoa", "ryu", "serde", @@ -8229,7 +8246,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -8242,7 +8259,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -8838,9 +8855,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -8848,9 +8865,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", @@ -8863,9 +8880,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -8875,9 +8892,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8885,9 +8902,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", @@ -8898,9 +8915,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-streams" @@ -8917,9 +8934,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -9139,9 +9156,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" dependencies = [ "memchr", ] @@ -9275,18 +9292,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.20" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd66a62464e3ffd4e37bd09950c2b9dd6c4f8767380fabba0d523f9a775bc85a" +checksum = "092cd76b01a033a9965b9097da258689d9e17c69ded5dcf41bca001dd20ebc6d" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.20" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255c4596d41e6916ced49cfafea18727b24d67878fa180ddfd69b9df34fd1726" +checksum = "a13a20a7c6a90e2034bcc65495799da92efcec6a8dd4f3fcb6f7a48988637ead" dependencies = [ "proc-macro2", "quote", diff --git a/casper-finality-proofs/Cargo.toml b/casper-finality-proofs/Cargo.toml index b1b6074d6..7d0b29ab6 100644 --- a/casper-finality-proofs/Cargo.toml +++ b/casper-finality-proofs/Cargo.toml @@ -32,9 +32,9 @@ walkdir = "2.4.0" hex = "0.4.3" itertools = { version = "0.10.0", default-features = false } clap = { version = "4.4.6", features = ["derive"] } -lighthouse_types = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "types"} -lighthouse_ef_tests = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "ef_tests"} -lighthouse_state_processing = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "state_processing"} -lighthouse_state_merkle_proof = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "merkle_proof"} -lighthouse_cached_tree_hash = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "cached_tree_hash"} +lighthouse_types = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "types" } +lighthouse_ef_tests = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "ef_tests" } +lighthouse_state_processing = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "state_processing" } +lighthouse_state_merkle_proof = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "merkle_proof" } +lighthouse_cached_tree_hash = { git = "https://github.com/sigp/lighthouse", tag = "v4.5.0", package = "cached_tree_hash" } snap = "1.1.0" diff --git a/casper-finality-proofs/bin/weigh_justification_and_finalization.rs b/casper-finality-proofs/bin/weigh_justification_and_finalization.rs index 8cf0d1d7e..f3f56828d 100644 --- a/casper-finality-proofs/bin/weigh_justification_and_finalization.rs +++ b/casper-finality-proofs/bin/weigh_justification_and_finalization.rs @@ -1,28 +1,9 @@ -use casper_finality_proofs::{ - constants::{ - BEACON_STATE_BLOCK_ROOTS_GINDEX, BEACON_STATE_CURRENT_JUSTIFIED_CHECKPOINT_GINDEX, - BEACON_STATE_FINALIZED_CHECKPOINT_GINDEX, BEACON_STATE_JUSTIFICATION_BITS_GINDEX, - BEACON_STATE_PREVIOUS_JUSTIFIED_CHECKPOINT_GINDEX, BEACON_STATE_SLOT_GINDEX, - SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT, - }, - weigh_justification_and_finalization::{ - checkpoint::{CheckpointValue, CheckpointVariable}, - justification_bits::{JustificationBitsValue, JustificationBitsVariable}, - WeighJustificationAndFinalization, - }, +use casper_finality_proofs::weigh_justification_and_finalization::{ + checkpoint::{CheckpointValue, CheckpointVariable}, + justification_bits::{JustificationBitsValue, JustificationBitsVariable}, + WeighJustificationAndFinalization, }; use ethers::types::H256; -use lighthouse_cached_tree_hash::{CacheArena, CachedTreeHash}; -use lighthouse_ef_tests::{self, testing_spec}; -use lighthouse_state_merkle_proof::MerkleTree; -use lighthouse_state_processing::{ - common::update_progressive_balances_cache::initialize_progressive_balances_cache, - per_epoch_processing::altair::ParticipationCache, -}; -use lighthouse_types::{ - consts::altair::TIMELY_TARGET_FLAG_INDEX, BeaconState, ChainSpec, Epoch, EthSpec, ForkName, - Hash256, MainnetEthSpec, RelativeEpoch, -}; use plonky2x::{ backend::circuit::Circuit, prelude::{ @@ -31,267 +12,8 @@ use plonky2x::{ }, utils::bytes32, }; -use snap::raw::Decoder; -use std::{fs, path::Path}; - -pub fn ssz_decode_state(path: &Path, spec: &ChainSpec) -> BeaconState { - let compressed_bytes = fs::read(path).unwrap(); - let mut decoder = Decoder::new(); - let ssz_bytes = decoder.decompress_vec(&compressed_bytes).unwrap(); - BeaconState::from_ssz_bytes(ssz_bytes.as_slice(), &spec).unwrap() -} - -struct Balances { - pub total_active_balance: u64, - pub previous_target_balance: u64, - pub current_target_balance: u64, -} - -fn extract_balances(state: &mut BeaconState, spec: &ChainSpec) -> Balances { - // Ensure the committee caches are built. - state - .build_committee_cache(RelativeEpoch::Previous, spec) - .unwrap(); - state - .build_committee_cache(RelativeEpoch::Current, spec) - .unwrap(); - state - .build_committee_cache(RelativeEpoch::Next, spec) - .unwrap(); - - // Pre-compute participating indices and total balances. - let participation_cache = ParticipationCache::new(state, spec).unwrap(); - // let sync_committee = state.current_sync_committee().unwrap().clone(); - initialize_progressive_balances_cache(state, Some(&participation_cache), spec).unwrap(); - - // Justification and finalization. - let previous_epoch = state.previous_epoch(); - let current_epoch = state.current_epoch(); - let previous_indices = participation_cache - .get_unslashed_participating_indices(TIMELY_TARGET_FLAG_INDEX, previous_epoch) - .unwrap(); - let current_indices = participation_cache - .get_unslashed_participating_indices(TIMELY_TARGET_FLAG_INDEX, current_epoch) - .unwrap(); - - Balances { - total_active_balance: participation_cache.current_epoch_total_active_balance(), - previous_target_balance: previous_indices.total_balance().unwrap(), - current_target_balance: current_indices.total_balance().unwrap(), - } -} - -fn compute_merkle_proof( - state: &mut BeaconState, - generalized_index: usize, -) -> Vec { - let mut cache = state.tree_hash_cache_mut().take().unwrap(); - let leaves = cache.recalculate_tree_hash_leaves(state).unwrap(); - state.tree_hash_cache_mut().restore(cache); - - let depth = 5; - let tree = MerkleTree::create(&leaves, depth); - let (_, proof) = tree.generate_proof(generalized_index, depth).unwrap(); - - proof -} - -fn compute_block_roots_merkle_proof( - state: &mut BeaconState, - index: usize, -) -> Vec { - let arena = &mut CacheArena::default(); - let mut cache = state.block_roots().new_tree_hash_cache(arena); - let _ = state - .block_roots() - .recalculate_tree_hash_root(arena, &mut cache); - - let mut leaves = Vec::new(); - cache - .leaves() - .iter(arena) - .unwrap() - .for_each(|leaf| leaves.push(*leaf)); - - let depth = 13; - let tree = MerkleTree::create(leaves.as_slice(), depth); - let (_, proof) = tree.generate_proof(2usize.pow(13) + index, depth).unwrap(); - proof -} - -fn compute_block_roots_start_epoch_slot_to_beacon_state_proof( - state: &mut BeaconState, - epoch: Epoch, -) -> Vec { - let block_roots_proof = compute_merkle_proof(state, BEACON_STATE_BLOCK_ROOTS_GINDEX as usize); - let index = ((epoch.as_u64() * SLOTS_PER_EPOCH) % SLOTS_PER_HISTORICAL_ROOT) as usize; - let block_roots_slot_proof = compute_block_roots_merkle_proof(state, index); - - [ - block_roots_slot_proof.as_slice(), - block_roots_proof.as_slice(), - ] - .concat() - .to_vec() -} - -pub fn compute_beacon_state_tree_hash_root(state: &mut BeaconState) -> Hash256 { - let mut cache = state.tree_hash_cache_mut().take().unwrap(); - let root_hash = cache.recalculate_tree_hash_root(state).unwrap(); - state.tree_hash_cache_mut().restore(cache); - root_hash -} - -pub fn get_block_root_epoch_start_slot_root( - state: &BeaconState, - epoch: Epoch, -) -> Hash256 { - state.block_roots()[((epoch.as_u64() * SLOTS_PER_EPOCH) % SLOTS_PER_HISTORICAL_ROOT) as usize] -} - -fn test_circuit_ssz_snappy() { - plonky2x::utils::setup_logger(); - type L = DefaultParameters; - const D: usize = 2; - - let spec = &testing_spec::(ForkName::Capella); - let mut state = ssz_decode_state::(Path::new("./bin/pre.ssz_snappy"), spec); - state.initialize_tree_hash_cache(); - let balances = extract_balances(&mut state, spec); - - let mut builder = CircuitBuilder::::new(); - WeighJustificationAndFinalization::define(&mut builder); - let circuit = builder.build(); - let mut input = circuit.input(); - - let slot = state.slot().as_u64(); - let slot_proof = compute_merkle_proof(&mut state, BEACON_STATE_SLOT_GINDEX as usize); - - let beacon_state_root = compute_beacon_state_tree_hash_root(&mut state); - - let previous_justified_checkpoint = CheckpointValue::<>::Field> { - epoch: state.previous_justified_checkpoint().epoch.as_u64(), - root: state.previous_justified_checkpoint().root, - }; - - let previous_justified_checkpoint_proof = compute_merkle_proof( - &mut state, - BEACON_STATE_PREVIOUS_JUSTIFIED_CHECKPOINT_GINDEX as usize, - ); - - let current_justified_checkpoint = CheckpointValue::<>::Field> { - epoch: state.current_justified_checkpoint().epoch.as_u64(), - root: state.current_justified_checkpoint().root, - }; - - let current_justified_checkpoint_proof = compute_merkle_proof( - &mut state, - BEACON_STATE_CURRENT_JUSTIFIED_CHECKPOINT_GINDEX as usize, - ); - - let justification_bits = JustificationBitsValue::<>::Field> { - bits: state - .justification_bits() - .iter() - .map(|byte| byte as bool) - .collect(), - }; - - let justification_bits_proof = - compute_merkle_proof(&mut state, BEACON_STATE_JUSTIFICATION_BITS_GINDEX as usize); - - let previous_epoch = state.previous_epoch(); - let previous_epoch_start_slot_root_in_block_roots_proof = - compute_block_roots_start_epoch_slot_to_beacon_state_proof(&mut state, previous_epoch); - - let current_epoch = state.current_epoch(); - let current_epoch_start_slot_root_in_block_roots_proof = - compute_block_roots_start_epoch_slot_to_beacon_state_proof(&mut state, current_epoch); - - let previous_epoch_start_slot_root_in_block_roots = - get_block_root_epoch_start_slot_root(&state, state.previous_epoch()); - let current_epoch_start_slot_root_in_block_roots = - get_block_root_epoch_start_slot_root(&state, state.current_epoch()); - - let finalized_checkpoint = CheckpointValue::<>::Field> { - epoch: state.finalized_checkpoint().epoch.as_u64(), - root: state.finalized_checkpoint().root, - }; - - let finalized_checkpoint_proof = compute_merkle_proof( - &mut state, - BEACON_STATE_FINALIZED_CHECKPOINT_GINDEX as usize, - ); - - input.write::(beacon_state_root); - input.write::(slot); - input.write::>(slot_proof.to_vec()); - input.write::(previous_justified_checkpoint); - input.write::>(previous_justified_checkpoint_proof.to_vec()); - input.write::(current_justified_checkpoint); - input.write::>(current_justified_checkpoint_proof.to_vec()); - input.write::(justification_bits); - input.write::>(justification_bits_proof.to_vec()); - input.write::(balances.total_active_balance); - input.write::(balances.previous_target_balance); - input.write::(balances.current_target_balance); - input.write::(previous_epoch_start_slot_root_in_block_roots); - input.write::>( - previous_epoch_start_slot_root_in_block_roots_proof.to_vec(), - ); - input.write::(current_epoch_start_slot_root_in_block_roots); - input.write::>( - current_epoch_start_slot_root_in_block_roots_proof.to_vec(), - ); - input.write::(finalized_checkpoint); - input.write::>(finalized_checkpoint_proof.to_vec()); - - let (proof, mut output) = circuit.prove(&input); - circuit.verify(&proof, &input, &output); - - let new_previous_justified_checkpoint = output.read::(); - let new_current_justified_checkpoint = output.read::(); - let new_finalized_checkpoint = output.read::(); - let new_justification_bits = output.read::(); - - println!("outputs:"); - println!( - "new_previous_justified_checkpoint: {:?}", - new_previous_justified_checkpoint - ); - println!( - "new_current_justified_checkpoint: {:?}", - new_current_justified_checkpoint - ); - println!("new_finalized_checkpoint: {:?}", new_finalized_checkpoint); - println!("new_justification_bits: {:?}", new_justification_bits); - - let post_state = ssz_decode_state::(Path::new("./bin/post.ssz_snappy"), spec); - - println!("expected outputs:"); - println!( - "new_previous_justified_checkpoint: {:?}", - post_state.previous_justified_checkpoint() - ); - println!( - "new_current_justified_checkpoint: {:?}", - post_state.current_justified_checkpoint() - ); - println!( - "new_finalized_checkpoint: {:?}", - post_state.finalized_checkpoint() - ); - println!( - "new_justification_bits: [{}, {}, {}, {}]", - post_state.justification_bits().get(0).unwrap(), - post_state.justification_bits().get(1).unwrap(), - post_state.justification_bits().get(2).unwrap(), - post_state.justification_bits().get(3).unwrap(), - ); -} -#[allow(unused)] -fn test_circuit_sample_data() { +fn main() { type L = DefaultParameters; const D: usize = 2; let mut builder = CircuitBuilder::::new(); @@ -457,8 +179,3 @@ fn test_circuit_sample_data() { println!("new_finalized_checkpoint: {:?}", new_finalized_checkpoint); println!("new_justification_bits: {:?}", new_justification_bits); } - -fn main() { - test_circuit_ssz_snappy(); - // test_circuit_sample_data(); -} diff --git a/casper-finality-proofs/src/hash_test.rs b/casper-finality-proofs/src/hash_test.rs deleted file mode 100644 index 42f322e1b..000000000 --- a/casper-finality-proofs/src/hash_test.rs +++ /dev/null @@ -1,42 +0,0 @@ -use itertools::Itertools; -use plonky2x::{ - backend::circuit::Circuit, - frontend::eth::{beacon::vars::BeaconValidatorVariable, vars::BLSPubkeyVariable}, - prelude::{ - Bytes32Variable, CircuitBuilder, CircuitVariable, Div, PlonkParameters, U64Variable, - }, -}; - -#[derive(Debug, Clone)] -pub struct HashTestCircuit; - -impl Circuit for HashTestCircuit { - fn define, const D: usize>(builder: &mut CircuitBuilder) { - let a = builder.read::(); - let b = builder.read::(); - - let slot = builder.read::(); - - let c = builder.sha256( - a.0 .0 - .iter() - .chain(b.0 .0.iter()) - .cloned() - .collect_vec() - .as_slice(), - ); - - let slots_per_epoch = U64Variable::constant(builder, 32); - - let epoch = slot.div(slots_per_epoch, builder); - - let mut validator = builder.read::(); - - validator.pubkey = BLSPubkeyVariable::constant(builder, [0; 48]); - - builder.write(c); - builder.write(epoch); - - builder.write(validator); - } -} diff --git a/casper-finality-proofs/src/lib.rs b/casper-finality-proofs/src/lib.rs index 74b11e451..80856a787 100644 --- a/casper-finality-proofs/src/lib.rs +++ b/casper-finality-proofs/src/lib.rs @@ -1,8 +1,5 @@ pub mod constants; -pub mod hash_test; -pub mod test; pub mod test_engine; -pub mod test_lte; mod types; mod utils; pub mod weigh_justification_and_finalization; diff --git a/casper-finality-proofs/src/test.rs b/casper-finality-proofs/src/test.rs deleted file mode 100644 index 880269124..000000000 --- a/casper-finality-proofs/src/test.rs +++ /dev/null @@ -1,18 +0,0 @@ -use plonky2x::{ - backend::circuit::Circuit, - prelude::{CircuitBuilder, PlonkParameters, Variable}, -}; - -#[derive(Debug, Clone)] -pub struct TestCircuit; - -impl Circuit for TestCircuit { - fn define, const D: usize>(builder: &mut CircuitBuilder) { - let a = builder.read::(); - let b = builder.read::(); - - let c = builder.add(a, b); - - builder.write::(c); - } -} diff --git a/casper-finality-proofs/src/test_engine/TestEngine.md b/casper-finality-proofs/src/test_engine/TestEngine.md index 05a6fda02..4fc5e04bd 100644 --- a/casper-finality-proofs/src/test_engine/TestEngine.md +++ b/casper-finality-proofs/src/test_engine/TestEngine.md @@ -50,7 +50,7 @@ The test engine is a tool for running unit tests for plonky2 circuits. To test a circuit, create a wrapper in `src/test_engine/wrappers/`. It represents a function that writes input data to the circuit and asserts its outputs. It uses `TestData` data to assert that the circuit is working correctly. - `path` is an argument to the `wrapper()` method, received from the test engine. It is the path to the JSON file containing the input and output data for the test. + `path` is an argument to the `wrapper()` method, received from the test engine. It is the path to the JSON/YAML file or directory containing the input and output data for the test. To use the serialized data: @@ -66,6 +66,8 @@ The test engine is a tool for running unit tests for plonky2 circuits. )); ``` + \*For ssz files, use `read_ssz_fixture()` instead of `read_fixture()`. + Then use `assert_equal!` to validate that the output of the circuit corresponds to the expected output: ```rust @@ -93,8 +95,13 @@ The test engine is a tool for running unit tests for plonky2 circuits. ```rust pub fn map_test_to_wrapper(test: TestWrappers) -> ... { match test { - TestWrappers::NewTestCircuit => Box::new(|path, should_assert| wrapper_new_test(path.as_str(), should_assert)), - ... + TestWrappers::NewTestCircuit => ( + Box::new(|| { + Lazy::force(&circuit_new_test); + }), + Box::new(|path, should_assert| wrapper_new_test(path.as_str(), should_assert)), + ), + ... } } ``` @@ -105,10 +112,12 @@ The test engine is a tool for running unit tests for plonky2 circuits. tests.push(TestCase::new( TestWrappers::NewTestCircuit, "./src/test_engine/tests/new_test/".to_string(), + false )); ... } ``` + The last parameter indicates whether the test is a folder containing multiple files which represent the data for a single test (`true`) or a single file (`json` or `yaml`) containing data for a single test (`false`). - ### Running tests @@ -140,12 +149,14 @@ The test engine is a tool for running unit tests for plonky2 circuits. b { color: lightblue; font-weight: bold } g { color: lightgreen } y { color: yellow } + yb { color: yellow; font-weight: bold } > Example: > - > Running circuit: WrapperTest\ - > -> sum_100.json\ + > Building WrapperTest\ + > Build took 8.241s!\ + > -> sum_100.json - 0.012s\ > -> sum_30.json > > Failed tests:\ diff --git a/casper-finality-proofs/src/test_engine/bin/main.rs b/casper-finality-proofs/src/test_engine/bin/main.rs index d598f3279..63fe9bcfa 100644 --- a/casper-finality-proofs/src/test_engine/bin/main.rs +++ b/casper-finality-proofs/src/test_engine/bin/main.rs @@ -1,11 +1,11 @@ use casper_finality_proofs::test_engine::utils::{ setup::init_tests, - test_engine::{build_function_map, handle_error}, + test_engine::{build_function_map, handle_error, handle_path}, }; use clap::Parser; use colored::Colorize; use crossbeam::thread; -use std::panic; +use std::{panic, process::exit, time::Instant}; use walkdir::WalkDir; static FAIL_EXT: &str = "_fail."; @@ -53,39 +53,56 @@ fn main() { let function_map = build_function_map(tests); let mut failed_tests: Vec = Vec::new(); - for (name, _) in function_map.iter() { + for (name, mapper) in function_map.iter() { let circuit_name = format!("{:?}", name).blue().bold(); - println!("\nRunning circuit: {}", circuit_name); let folder_path = if args.path.is_empty() { &function_map.get(&name).unwrap().folder_path } else { &args.path }; - for e in WalkDir::new(folder_path).into_iter().filter_map(|e| e.ok()) { - if e.metadata().unwrap().is_file() { - let path = e.path().display().to_string(); - let file_name = if args.r#ref { - path.clone() - } else { - e.file_name().to_str().unwrap().to_owned() - }; + println!("\n{}", format!("Building {}", circuit_name).bold().yellow()); + let now = Instant::now(); + (mapper.init)(); + println!( + "{}", + format!("Build took {:.3}s!", now.elapsed().as_secs_f32()).yellow() + ); + + let mut entries = WalkDir::new(folder_path).into_iter(); + loop { + let entry = match entries.next() { + None => break, + Some(Ok(it)) => it, + Some(Err(e)) => { + println!("{}", format!("Error: {}", e).bold().red()); + exit(1) + } + }; + + if let Some((path, file_name)) = handle_path(entry, mapper.is_folder_test, args.r#ref) { + if mapper.is_folder_test { + // The test is a folder and all its files are part of a single test. + entries.skip_current_dir(); + } + let now = Instant::now(); let r = thread::scope(|s| { let join_handle = s.spawn(|_| { - return (function_map.get(name).unwrap().wrapper)(path, !args.r#ref); + return (mapper.wrapper)(path, !args.r#ref); }); let res = join_handle.join(); return res; }); + let elapsed = now.elapsed().as_secs_f32(); let handle_success = |res: String| { let colored_file_name = String::from(file_name.clone()).green(); if args.r#ref { println!("{} {} {}", "[OK]".green().bold(), colored_file_name, res); } else { - println!("-> {}", colored_file_name); + println!("-> {} - {:.3}s", colored_file_name, elapsed); } }; diff --git a/casper-finality-proofs/src/test_engine/tests/hash_test/hash_test.json b/casper-finality-proofs/src/test_engine/tests/hash_test/hash_test.json deleted file mode 100644 index a3614f412..000000000 --- a/casper-finality-proofs/src/test_engine/tests/hash_test/hash_test.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "inputs": { - "pubkey": "0x123000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "slashed": false, - "a": "0x1230000000000000000000000000000000000000000000000000000000000000", - "b": "0x4560000000000000000000000000000000000000000000000000000000000000", - "slot": "0x1808" - }, - "outputs": { - "hash": "0x59961afe1c548c4827e0f729616b6737a6e304fd3b3299d7d1fef89cbbf7998d", - "epoch": "0xC0" - } -} \ No newline at end of file diff --git a/casper-finality-proofs/src/test_engine/tests/test/sum_100.json b/casper-finality-proofs/src/test_engine/tests/test/sum_100.json deleted file mode 100644 index b66fb204c..000000000 --- a/casper-finality-proofs/src/test_engine/tests/test/sum_100.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "a": 35, - "b": 65, - "outputs": [ - 100 - ] -} \ No newline at end of file diff --git a/casper-finality-proofs/src/test_engine/tests/test/sum_30.json b/casper-finality-proofs/src/test_engine/tests/test/sum_30.json deleted file mode 100644 index 5b827ab85..000000000 --- a/casper-finality-proofs/src/test_engine/tests/test/sum_30.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "a": 15, - "b": 15, - "outputs": [ - 30 - ] -} \ No newline at end of file diff --git a/casper-finality-proofs/src/test_engine/tests/test/yaml/sum_74.yaml b/casper-finality-proofs/src/test_engine/tests/test/yaml/sum_74.yaml deleted file mode 100644 index 0a2bef7b1..000000000 --- a/casper-finality-proofs/src/test_engine/tests/test/yaml/sum_74.yaml +++ /dev/null @@ -1,4 +0,0 @@ -a: 64 -b: 10 -outputs: - - 74 diff --git a/casper-finality-proofs/src/test_engine/tests/test_lte/lte_fail.json b/casper-finality-proofs/src/test_engine/tests/test_lte/lte_fail.json deleted file mode 100644 index 3133b0b1c..000000000 --- a/casper-finality-proofs/src/test_engine/tests/test_lte/lte_fail.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "a": 15, - "b": 10 -} \ No newline at end of file diff --git a/casper-finality-proofs/src/test_engine/tests/test_lte/lte_success.json b/casper-finality-proofs/src/test_engine/tests/test_lte/lte_success.json deleted file mode 100644 index 865f681d6..000000000 --- a/casper-finality-proofs/src/test_engine/tests/test_lte/lte_success.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "a": 15, - "b": 110 -} \ No newline at end of file diff --git a/casper-finality-proofs/src/test_engine/types/mod.rs b/casper-finality-proofs/src/test_engine/types/mod.rs index 7f0aafecb..e69de29bb 100644 --- a/casper-finality-proofs/src/test_engine/types/mod.rs +++ b/casper-finality-proofs/src/test_engine/types/mod.rs @@ -1,3 +0,0 @@ -pub mod test_data; -pub mod test_hash_data; -pub mod test_lte_data; diff --git a/casper-finality-proofs/src/test_engine/types/test_data.rs b/casper-finality-proofs/src/test_engine/types/test_data.rs deleted file mode 100644 index 466137fda..000000000 --- a/casper-finality-proofs/src/test_engine/types/test_data.rs +++ /dev/null @@ -1,9 +0,0 @@ -use core::fmt::Debug; -use serde_derive::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] -pub struct TestInput { - pub a: u64, - pub b: u64, - pub outputs: Vec, -} diff --git a/casper-finality-proofs/src/test_engine/types/test_hash_data.rs b/casper-finality-proofs/src/test_engine/types/test_hash_data.rs deleted file mode 100644 index cc1bcdf34..000000000 --- a/casper-finality-proofs/src/test_engine/types/test_hash_data.rs +++ /dev/null @@ -1,25 +0,0 @@ -use core::fmt::Debug; -use ethers::types::{H256, U256}; -use primitive_types::H384; -use serde_derive::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] -pub struct Inputs { - pub pubkey: H384, - pub slashed: bool, - pub a: H256, - pub b: H256, - pub slot: U256, -} - -#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] -pub struct Outputs { - pub hash: H256, - pub epoch: U256, -} - -#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] -pub struct TestInput { - pub inputs: Inputs, - pub outputs: Outputs, -} diff --git a/casper-finality-proofs/src/test_engine/types/test_lte_data.rs b/casper-finality-proofs/src/test_engine/types/test_lte_data.rs deleted file mode 100644 index 5379931cc..000000000 --- a/casper-finality-proofs/src/test_engine/types/test_lte_data.rs +++ /dev/null @@ -1,8 +0,0 @@ -use core::fmt::Debug; -use serde_derive::{Deserialize, Serialize}; - -#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] -pub struct TestInput { - pub a: u64, - pub b: u64, -} diff --git a/casper-finality-proofs/src/test_engine/utils/data_generation.rs b/casper-finality-proofs/src/test_engine/utils/data_generation.rs new file mode 100644 index 000000000..1d9f71c61 --- /dev/null +++ b/casper-finality-proofs/src/test_engine/utils/data_generation.rs @@ -0,0 +1,122 @@ +use lighthouse_cached_tree_hash::{CacheArena, CachedTreeHash}; +use lighthouse_state_merkle_proof::MerkleTree; +use lighthouse_state_processing::{ + common::update_progressive_balances_cache::initialize_progressive_balances_cache, + per_epoch_processing::altair::ParticipationCache, +}; +use lighthouse_types::{ + consts::altair::TIMELY_TARGET_FLAG_INDEX, BeaconState, ChainSpec, Epoch, EthSpec, Hash256, + RelativeEpoch, +}; + +use crate::constants::{ + BEACON_STATE_BLOCK_ROOTS_GINDEX, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT, +}; + +pub struct Balances { + pub total_active_balance: u64, + pub previous_target_balance: u64, + pub current_target_balance: u64, +} + +pub fn extract_balances(state: &mut BeaconState, spec: &ChainSpec) -> Balances { + // Ensure the committee caches are built. + state + .build_committee_cache(RelativeEpoch::Previous, spec) + .unwrap(); + state + .build_committee_cache(RelativeEpoch::Current, spec) + .unwrap(); + state + .build_committee_cache(RelativeEpoch::Next, spec) + .unwrap(); + + // Pre-compute participating indices and total balances. + let participation_cache = ParticipationCache::new(state, spec).unwrap(); + // let sync_committee = state.current_sync_committee().unwrap().clone(); + initialize_progressive_balances_cache(state, Some(&participation_cache), spec).unwrap(); + + // Justification and finalization. + let previous_epoch = state.previous_epoch(); + let current_epoch = state.current_epoch(); + let previous_indices = participation_cache + .get_unslashed_participating_indices(TIMELY_TARGET_FLAG_INDEX, previous_epoch) + .unwrap(); + let current_indices = participation_cache + .get_unslashed_participating_indices(TIMELY_TARGET_FLAG_INDEX, current_epoch) + .unwrap(); + + Balances { + total_active_balance: participation_cache.current_epoch_total_active_balance(), + previous_target_balance: previous_indices.total_balance().unwrap(), + current_target_balance: current_indices.total_balance().unwrap(), + } +} + +pub fn compute_merkle_proof( + state: &mut BeaconState, + generalized_index: usize, +) -> Vec { + let mut cache = state.tree_hash_cache_mut().take().unwrap(); + let leaves = cache.recalculate_tree_hash_leaves(state).unwrap(); + state.tree_hash_cache_mut().restore(cache); + + let depth = 5; + let tree = MerkleTree::create(&leaves, depth); + let (_, proof) = tree.generate_proof(generalized_index, depth).unwrap(); + + proof +} + +fn compute_block_roots_merkle_proof( + state: &mut BeaconState, + index: usize, +) -> Vec { + let arena = &mut CacheArena::default(); + let mut cache = state.block_roots().new_tree_hash_cache(arena); + let _ = state + .block_roots() + .recalculate_tree_hash_root(arena, &mut cache); + + let mut leaves = Vec::new(); + cache + .leaves() + .iter(arena) + .unwrap() + .for_each(|leaf| leaves.push(*leaf)); + + let depth = 13; + let tree = MerkleTree::create(leaves.as_slice(), depth); + let (_, proof) = tree.generate_proof(2usize.pow(13) + index, depth).unwrap(); + proof +} + +pub fn compute_block_roots_start_epoch_slot_to_beacon_state_proof( + state: &mut BeaconState, + epoch: Epoch, +) -> Vec { + let block_roots_proof = compute_merkle_proof(state, BEACON_STATE_BLOCK_ROOTS_GINDEX as usize); + let index = ((epoch.as_u64() * SLOTS_PER_EPOCH) % SLOTS_PER_HISTORICAL_ROOT) as usize; + let block_roots_slot_proof = compute_block_roots_merkle_proof(state, index); + + [ + block_roots_slot_proof.as_slice(), + block_roots_proof.as_slice(), + ] + .concat() + .to_vec() +} + +pub fn compute_beacon_state_tree_hash_root(state: &mut BeaconState) -> Hash256 { + let mut cache = state.tree_hash_cache_mut().take().unwrap(); + let root_hash = cache.recalculate_tree_hash_root(state).unwrap(); + state.tree_hash_cache_mut().restore(cache); + root_hash +} + +pub fn get_block_root_epoch_start_slot_root( + state: &BeaconState, + epoch: Epoch, +) -> Hash256 { + state.block_roots()[((epoch.as_u64() * SLOTS_PER_EPOCH) % SLOTS_PER_HISTORICAL_ROOT) as usize] +} diff --git a/casper-finality-proofs/src/test_engine/utils/mod.rs b/casper-finality-proofs/src/test_engine/utils/mod.rs index 7626542c9..685557475 100644 --- a/casper-finality-proofs/src/test_engine/utils/mod.rs +++ b/casper-finality-proofs/src/test_engine/utils/mod.rs @@ -1,4 +1,5 @@ +pub mod data_generation; pub mod macros; -pub mod parse_file; +pub mod parsers; pub mod setup; pub mod test_engine; diff --git a/casper-finality-proofs/src/test_engine/utils/parsers/mod.rs b/casper-finality-proofs/src/test_engine/utils/parsers/mod.rs new file mode 100644 index 000000000..21fe7c7cb --- /dev/null +++ b/casper-finality-proofs/src/test_engine/utils/parsers/mod.rs @@ -0,0 +1,2 @@ +pub mod parse_file; +pub mod ssz_decoder; diff --git a/casper-finality-proofs/src/test_engine/utils/parse_file.rs b/casper-finality-proofs/src/test_engine/utils/parsers/parse_file.rs similarity index 100% rename from casper-finality-proofs/src/test_engine/utils/parse_file.rs rename to casper-finality-proofs/src/test_engine/utils/parsers/parse_file.rs diff --git a/casper-finality-proofs/src/test_engine/utils/parsers/ssz_decoder.rs b/casper-finality-proofs/src/test_engine/utils/parsers/ssz_decoder.rs new file mode 100644 index 000000000..511e59c3d --- /dev/null +++ b/casper-finality-proofs/src/test_engine/utils/parsers/ssz_decoder.rs @@ -0,0 +1,10 @@ +use lighthouse_types::{BeaconState, ChainSpec, EthSpec}; +use snap::raw::Decoder; +use std::fs::{self}; + +pub fn read_ssz_fixture(path: &str, spec: &ChainSpec) -> BeaconState { + let compressed_bytes = fs::read(path).unwrap(); + let mut decoder = Decoder::new(); + let ssz_bytes = decoder.decompress_vec(&compressed_bytes).unwrap(); + BeaconState::from_ssz_bytes(ssz_bytes.as_slice(), &spec).unwrap() +} diff --git a/casper-finality-proofs/src/test_engine/utils/setup.rs b/casper-finality-proofs/src/test_engine/utils/setup.rs index b55cf0781..39b74eb5d 100644 --- a/casper-finality-proofs/src/test_engine/utils/setup.rs +++ b/casper-finality-proofs/src/test_engine/utils/setup.rs @@ -1,46 +1,40 @@ use super::test_engine::TestCase; -use crate::test_engine::wrappers::{ - wrapper_hash_test::wrapper as wrapper_hash_test, wrapper_test::wrapper as wrapper_test, - wrapper_test_lte::wrapper as wrapper_test_lte, +use crate::test_engine::wrappers::wrapper_weigh_justification_and_finalization::{ + wrapper as wrapper_weigh_justification_and_finalization, + CIRCUIT as circuit_weigh_justification_and_finalization, }; +use once_cell::sync::Lazy; use strum::{Display, EnumString}; #[derive(Debug, Eq, Hash, PartialEq, Copy, Clone, EnumString, Display)] pub enum TestWrappers { - WrapperTest, - WrapperHashTest, - WrapperTestLte, + WrapperWeighJustificationAndFinalizationConsensusMainnet, } pub fn map_test_to_wrapper( test: TestWrappers, -) -> Box Result + Send + Sync> { +) -> ( + Box () + Send + Sync>, + Box Result + Send + Sync>, +) { match test { - TestWrappers::WrapperTest => { - Box::new(|data, should_assert| wrapper_test(data.as_str(), should_assert)) - } - TestWrappers::WrapperHashTest => { - Box::new(|path, should_assert| wrapper_hash_test(path.as_str(), should_assert)) - } - TestWrappers::WrapperTestLte => { - Box::new(|path, should_assert| wrapper_test_lte(path.as_str(), should_assert)) - } + TestWrappers::WrapperWeighJustificationAndFinalizationConsensusMainnet => ( + Box::new(|| { + Lazy::force(&circuit_weigh_justification_and_finalization); + }), + Box::new(|path, should_assert| { + wrapper_weigh_justification_and_finalization(path, should_assert) + }), + ), } } pub fn init_tests() -> Vec { let mut tests: Vec = Vec::new(); tests.push(TestCase::new( - TestWrappers::WrapperTest, - "./src/test_engine/tests/test/".to_string(), - )); - tests.push(TestCase::new( - TestWrappers::WrapperHashTest, - "./src/test_engine/tests/hash_test/".to_string(), - )); - tests.push(TestCase::new( - TestWrappers::WrapperTestLte, - "./src/test_engine/tests/test_lte/".to_string(), + TestWrappers::WrapperWeighJustificationAndFinalizationConsensusMainnet, + "../vendor/consensus-spec-tests/tests/mainnet/capella/epoch_processing/justification_and_finalization/pyspec_tests/".to_string(), + true, )); tests diff --git a/casper-finality-proofs/src/test_engine/utils/test_engine.rs b/casper-finality-proofs/src/test_engine/utils/test_engine.rs index c5963dd20..045055027 100644 --- a/casper-finality-proofs/src/test_engine/utils/test_engine.rs +++ b/casper-finality-proofs/src/test_engine/utils/test_engine.rs @@ -1,31 +1,43 @@ use super::setup::{map_test_to_wrapper, TestWrappers}; use colored::{ColoredString, Colorize}; use std::collections::HashMap; +use walkdir::DirEntry; #[derive(Clone)] pub struct TestCase { pub name: TestWrappers, pub path: String, + pub is_folder_test: bool, } impl TestCase { - pub fn new(name: TestWrappers, path: String) -> TestCase { - TestCase { name, path } + pub fn new(name: TestWrappers, path: String, is_folder_test: bool) -> TestCase { + TestCase { + name, + path, + is_folder_test, + } } } pub struct Mapper { pub folder_path: String, + pub is_folder_test: bool, + pub init: Box () + Send + Sync>, pub wrapper: Box Result + Send + Sync>, } impl Mapper { fn new( folder_path: String, + is_folder_test: bool, + func: Box () + Send + Sync>, wrapper: Box Result + Send + Sync>, ) -> Mapper { Mapper { folder_path, + is_folder_test, + init: func, wrapper, } } @@ -67,11 +79,36 @@ pub fn build_function_map(tests: Vec) -> HashMap> = HashMap::new(); for test in tests { + let (init, wrapper) = map_test_to_wrapper(test.name); function_map.insert( test.name, - Box::new(Mapper::new(test.path, map_test_to_wrapper(test.name))), + Box::new(Mapper::new(test.path, test.is_folder_test, init, wrapper)), ); } function_map } + +pub fn handle_path( + entry: DirEntry, + should_test_folder: bool, + is_ref: bool, +) -> Option<(String, String)> { + let metadata = entry.metadata().unwrap(); + if metadata.is_file() { + let mut path = entry.path().display().to_string(); + if should_test_folder { + path = entry.path().parent().unwrap().display().to_string(); + } + + let file_name = if is_ref { + path.clone() + } else { + path[path.rfind('/').unwrap() + 1..].to_string() + }; + + return Some((path, file_name)); + } + + None +} diff --git a/casper-finality-proofs/src/test_engine/wrappers/mod.rs b/casper-finality-proofs/src/test_engine/wrappers/mod.rs index e6bf392eb..19cca2a1c 100644 --- a/casper-finality-proofs/src/test_engine/wrappers/mod.rs +++ b/casper-finality-proofs/src/test_engine/wrappers/mod.rs @@ -1,3 +1 @@ -pub mod wrapper_hash_test; -pub mod wrapper_test; -pub mod wrapper_test_lte; +pub mod wrapper_weigh_justification_and_finalization; diff --git a/casper-finality-proofs/src/test_engine/wrappers/wrapper_hash_test.rs b/casper-finality-proofs/src/test_engine/wrappers/wrapper_hash_test.rs deleted file mode 100644 index e3707374d..000000000 --- a/casper-finality-proofs/src/test_engine/wrappers/wrapper_hash_test.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::hash_test::HashTestCircuit; -use crate::test_engine::types::test_hash_data::TestInput; -use crate::test_engine::utils::parse_file::read_fixture; -use crate::{assert_equal, to_string}; -use once_cell::sync::Lazy; -use plonky2x::backend::circuit::CircuitBuild; -use plonky2x::frontend::eth::beacon::vars::BeaconValidatorVariable; -use plonky2x::prelude::{Bytes32Variable, U64Variable}; -use plonky2x::utils::eth::beacon::BeaconValidator; -use plonky2x::{ - backend::circuit::Circuit, - prelude::{CircuitBuilder, DefaultParameters}, -}; - -// Singleton-like pattern -static CIRCUIT: Lazy> = Lazy::new(|| { - let mut builder = CircuitBuilder::::new(); - HashTestCircuit::define(&mut builder); - builder.build() -}); - -pub fn wrapper(path: &str, should_assert: bool) -> Result { - let json_data: TestInput = read_fixture::(path); - - // a way to convert hex string to U256 - // let u256_from_str = U256::from_str_radix(json_data.inputs.str.as_str(), 16).unwrap(); - - let mut input = CIRCUIT.input(); - - input.write::(json_data.inputs.a); - input.write::(json_data.inputs.b); - - let slot = json_data.inputs.slot.as_u64(); - input.write::(slot); - - let value = BeaconValidator { - pubkey: to_string!(json_data.inputs.pubkey), - withdrawal_credentials: to_string!(json_data.inputs.a), - activation_epoch: slot.to_string(), - activation_eligibility_epoch: slot.to_string(), - exit_epoch: slot.to_string(), - slashed: json_data.inputs.slashed, - effective_balance: 32, - withdrawable_epoch: slot.to_string(), - }; - - input.write::(value); - - let (proof, mut output) = CIRCUIT.prove(&input); - - CIRCUIT.verify(&proof, &input, &output); - - let hash = output.read::(); - - let epoch = output.read::(); - - if should_assert { - assert_equal!(hash, json_data.outputs.hash); - assert_equal!(epoch, json_data.outputs.epoch.as_u64()); - } - Ok(format!("{} {}", to_string!(hash), epoch)) -} diff --git a/casper-finality-proofs/src/test_engine/wrappers/wrapper_test.rs b/casper-finality-proofs/src/test_engine/wrappers/wrapper_test.rs deleted file mode 100644 index 0217c08d7..000000000 --- a/casper-finality-proofs/src/test_engine/wrappers/wrapper_test.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::assert_equal; -use crate::test::TestCircuit; -use crate::test_engine::types::test_data::TestInput; -use crate::test_engine::utils::parse_file::read_fixture; -use once_cell::sync::Lazy; -use plonky2x::backend::circuit::CircuitBuild; -use plonky2x::prelude::Field; -use plonky2x::{ - backend::circuit::Circuit, - prelude::{CircuitBuilder, DefaultParameters, PlonkParameters, Variable}, -}; - -// Singleton-like pattern -static CIRCUIT: Lazy> = Lazy::new(|| { - let mut builder = CircuitBuilder::::new(); - TestCircuit::define(&mut builder); - builder.build() -}); - -pub fn wrapper(path: &str, should_assert: bool) -> Result { - type L = DefaultParameters; - const D: usize = 2; - - let json_data: TestInput = read_fixture::(path); - - let mut input = CIRCUIT.input(); - input.write::(>::Field::from_canonical_u64( - json_data.a, - )); - input.write::(>::Field::from_canonical_u64( - json_data.b, - )); - - let (proof, mut output) = CIRCUIT.prove(&input); - CIRCUIT.verify(&proof, &input, &output); - let sum = output.read::(); - - if should_assert { - assert_equal!( - sum, - >::Field::from_canonical_u64(json_data.outputs[0]) - ); - } - - Ok(sum.to_string()) -} diff --git a/casper-finality-proofs/src/test_engine/wrappers/wrapper_test_lte.rs b/casper-finality-proofs/src/test_engine/wrappers/wrapper_test_lte.rs deleted file mode 100644 index 703e90dff..000000000 --- a/casper-finality-proofs/src/test_engine/wrappers/wrapper_test_lte.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::test_engine::types::test_lte_data::TestInput; -use crate::test_engine::utils::parse_file::read_fixture; -use crate::test_lte::TestCircuit; -use once_cell::sync::Lazy; -use plonky2x::backend::circuit::CircuitBuild; -use plonky2x::prelude::Field; -use plonky2x::{ - backend::circuit::Circuit, - prelude::{CircuitBuilder, DefaultParameters, PlonkParameters, Variable}, -}; - -// Singleton-like pattern -static CIRCUIT: Lazy> = Lazy::new(|| { - let mut builder = CircuitBuilder::::new(); - TestCircuit::define(&mut builder); - builder.build() -}); - -pub fn wrapper(path: &str, _: bool) -> Result { - type L = DefaultParameters; - const D: usize = 2; - let json_data: TestInput = read_fixture::(path); - - let mut input = CIRCUIT.input(); - input.write::(>::Field::from_canonical_u64( - json_data.a, - )); - input.write::(>::Field::from_canonical_u64( - json_data.b, - )); - - let (proof, output) = CIRCUIT.prove(&input); - CIRCUIT.verify(&proof, &input, &output); - Ok("".to_string()) -} diff --git a/casper-finality-proofs/src/test_engine/wrappers/wrapper_weigh_justification_and_finalization.rs b/casper-finality-proofs/src/test_engine/wrappers/wrapper_weigh_justification_and_finalization.rs new file mode 100644 index 000000000..1d66f8132 --- /dev/null +++ b/casper-finality-proofs/src/test_engine/wrappers/wrapper_weigh_justification_and_finalization.rs @@ -0,0 +1,192 @@ +use crate::{ + assert_equal, + constants::{ + BEACON_STATE_CURRENT_JUSTIFIED_CHECKPOINT_GINDEX, BEACON_STATE_FINALIZED_CHECKPOINT_GINDEX, + BEACON_STATE_JUSTIFICATION_BITS_GINDEX, BEACON_STATE_PREVIOUS_JUSTIFIED_CHECKPOINT_GINDEX, + BEACON_STATE_SLOT_GINDEX, + }, + test_engine::utils::{ + data_generation::{ + compute_beacon_state_tree_hash_root, + compute_block_roots_start_epoch_slot_to_beacon_state_proof, compute_merkle_proof, + extract_balances, get_block_root_epoch_start_slot_root, + }, + parsers::ssz_decoder::read_ssz_fixture, + }, + weigh_justification_and_finalization::{ + checkpoint::{CheckpointValue, CheckpointVariable}, + justification_bits::{JustificationBitsValue, JustificationBitsVariable}, + WeighJustificationAndFinalization, + }, +}; +use lighthouse_ef_tests::{self, testing_spec}; +use lighthouse_types::{ForkName, MainnetEthSpec}; +use once_cell::sync::Lazy; +use plonky2x::{ + backend::circuit::{Circuit, CircuitBuild}, + prelude::{ + ArrayVariable, Bytes32Variable, CircuitBuilder, DefaultParameters, PlonkParameters, + U64Variable, + }, +}; + +// Singleton-like pattern +pub static CIRCUIT: Lazy> = Lazy::new(|| { + let mut builder = CircuitBuilder::::new(); + WeighJustificationAndFinalization::define(&mut builder); + builder.build() +}); + +pub fn wrapper(path: String, should_assert: bool) -> Result { + type L = DefaultParameters; + const D: usize = 2; + + let spec = &testing_spec::(ForkName::Capella); + let mut state = read_ssz_fixture::( + String::from(path.clone() + "/pre.ssz_snappy").as_str(), + spec, + ); + state.initialize_tree_hash_cache(); + let balances = extract_balances(&mut state, spec); + + let mut builder = CircuitBuilder::::new(); + WeighJustificationAndFinalization::define(&mut builder); + let mut input = CIRCUIT.input(); + + let slot = state.slot().as_u64(); + let slot_proof = compute_merkle_proof(&mut state, BEACON_STATE_SLOT_GINDEX as usize); + + let beacon_state_root = compute_beacon_state_tree_hash_root(&mut state); + + let previous_justified_checkpoint = CheckpointValue::<>::Field> { + epoch: state.previous_justified_checkpoint().epoch.as_u64(), + root: state.previous_justified_checkpoint().root, + }; + + let previous_justified_checkpoint_proof = compute_merkle_proof( + &mut state, + BEACON_STATE_PREVIOUS_JUSTIFIED_CHECKPOINT_GINDEX as usize, + ); + + let current_justified_checkpoint = CheckpointValue::<>::Field> { + epoch: state.current_justified_checkpoint().epoch.as_u64(), + root: state.current_justified_checkpoint().root, + }; + + let current_justified_checkpoint_proof = compute_merkle_proof( + &mut state, + BEACON_STATE_CURRENT_JUSTIFIED_CHECKPOINT_GINDEX as usize, + ); + + let justification_bits = JustificationBitsValue::<>::Field> { + bits: state + .justification_bits() + .iter() + .map(|byte| byte as bool) + .collect(), + }; + + let justification_bits_proof = + compute_merkle_proof(&mut state, BEACON_STATE_JUSTIFICATION_BITS_GINDEX as usize); + + let previous_epoch = state.previous_epoch(); + let previous_epoch_start_slot_root_in_block_roots_proof = + compute_block_roots_start_epoch_slot_to_beacon_state_proof(&mut state, previous_epoch); + + let current_epoch = state.current_epoch(); + let current_epoch_start_slot_root_in_block_roots_proof = + compute_block_roots_start_epoch_slot_to_beacon_state_proof(&mut state, current_epoch); + + let previous_epoch_start_slot_root_in_block_roots = + get_block_root_epoch_start_slot_root(&state, state.previous_epoch()); + let current_epoch_start_slot_root_in_block_roots = + get_block_root_epoch_start_slot_root(&state, state.current_epoch()); + + let finalized_checkpoint = CheckpointValue::<>::Field> { + epoch: state.finalized_checkpoint().epoch.as_u64(), + root: state.finalized_checkpoint().root, + }; + + let finalized_checkpoint_proof = compute_merkle_proof( + &mut state, + BEACON_STATE_FINALIZED_CHECKPOINT_GINDEX as usize, + ); + + input.write::(beacon_state_root); + input.write::(slot); + input.write::>(slot_proof.to_vec()); + input.write::(previous_justified_checkpoint); + input.write::>(previous_justified_checkpoint_proof.to_vec()); + input.write::(current_justified_checkpoint); + input.write::>(current_justified_checkpoint_proof.to_vec()); + input.write::(justification_bits); + input.write::>(justification_bits_proof.to_vec()); + input.write::(balances.total_active_balance); + input.write::(balances.previous_target_balance); + input.write::(balances.current_target_balance); + input.write::(previous_epoch_start_slot_root_in_block_roots); + input.write::>( + previous_epoch_start_slot_root_in_block_roots_proof.to_vec(), + ); + input.write::(current_epoch_start_slot_root_in_block_roots); + input.write::>( + current_epoch_start_slot_root_in_block_roots_proof.to_vec(), + ); + input.write::(finalized_checkpoint); + input.write::>(finalized_checkpoint_proof.to_vec()); + + let (proof, mut output) = CIRCUIT.prove(&input); + CIRCUIT.verify(&proof, &input, &output); + + let new_previous_justified_checkpoint = output.read::(); + let new_current_justified_checkpoint = output.read::(); + let new_finalized_checkpoint = output.read::(); + let new_justification_bits = output.read::(); + + let post_state = read_ssz_fixture::( + String::from(path.clone() + "/post.ssz_snappy").as_str(), + spec, + ); + + if should_assert { + assert_equal!( + new_previous_justified_checkpoint.epoch, + post_state.previous_justified_checkpoint().epoch.as_u64() + ); + assert_equal!( + new_current_justified_checkpoint.epoch, + post_state.current_justified_checkpoint().epoch.as_u64() + ); + assert_equal!( + new_current_justified_checkpoint.root, + post_state.current_justified_checkpoint().root + ); + assert_equal!( + new_finalized_checkpoint.epoch, + post_state.finalized_checkpoint().epoch.as_u64() + ); + assert_equal!( + new_finalized_checkpoint.root, + post_state.finalized_checkpoint().root + ); + assert_equal!( + new_justification_bits.bits, + post_state + .justification_bits() + .iter() + .map(|byte| byte as bool) + .collect::>() + ); + } + + Ok(format!( + "previous_justified_checkpoint: {:?};\n", + new_previous_justified_checkpoint + ) + format!( + "current_justified_checkpoint: {:?};\n", + new_current_justified_checkpoint + ) + .as_str() + + format!("finalized_checkpoint: {:?};\n", new_finalized_checkpoint).as_str() + + format!("justification_bits: {:?};\n", new_justification_bits.bits).as_str()) +} diff --git a/casper-finality-proofs/src/test_lte.rs b/casper-finality-proofs/src/test_lte.rs deleted file mode 100644 index ef19868d9..000000000 --- a/casper-finality-proofs/src/test_lte.rs +++ /dev/null @@ -1,18 +0,0 @@ -use plonky2x::{ - backend::circuit::Circuit, - prelude::{CircuitBuilder, PlonkParameters, Variable}, -}; - -#[derive(Debug, Clone)] -pub struct TestCircuit; - -impl Circuit for TestCircuit { - fn define, const D: usize>(builder: &mut CircuitBuilder) { - let a = builder.read::(); - let b = builder.read::(); - - let c = builder.lte(a, b); - let _true = builder._true(); - builder.assert_is_equal(c, _true); - } -}