diff --git a/.github/workflows/prove.yml b/.github/workflows/prove.yml index d878dd2..dbce696 100644 --- a/.github/workflows/prove.yml +++ b/.github/workflows/prove.yml @@ -35,5 +35,9 @@ jobs: - name: Build SP1 program run: | - cd program + cd program/operations + ~/.sp1/bin/cargo-prove prove build + + cd - + cd program/slashings_reset ~/.sp1/bin/cargo-prove prove build diff --git a/.vscode/settings.json b/.vscode/settings.json index 55674b5..83e256a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "rust-analyzer.linkedProjects": [ "program/operations/Cargo.toml", + "program/slashings_reset/Cargo.toml", "script/Cargo.toml" ], "rust-analyzer.check.overrideCommand": [ diff --git a/Cargo.lock b/Cargo.lock index 173b4a6..f821403 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1731,7 +1731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3721,7 +3721,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3842,7 +3842,7 @@ dependencies = [ [[package]] name = "ream-bls" version = "0.1.0" -source = "git+https://github.com/ReamLabs/ream#39bcd36f87954351ce5396fa996a910a397a3ab8" +source = "git+https://github.com/syjn99/ream?rev=f5327406270b374b6caeaed05fc1549c5a21dd53#f5327406270b374b6caeaed05fc1549c5a21dd53" dependencies = [ "alloy-primitives 1.1.0", "anyhow", @@ -3860,7 +3860,7 @@ dependencies = [ [[package]] name = "ream-consensus" version = "0.1.0" -source = "git+https://github.com/ReamLabs/ream#39bcd36f87954351ce5396fa996a910a397a3ab8" +source = "git+https://github.com/syjn99/ream?rev=f5327406270b374b6caeaed05fc1549c5a21dd53#f5327406270b374b6caeaed05fc1549c5a21dd53" dependencies = [ "alloy-consensus 0.15.9", "alloy-primitives 1.1.0", @@ -3898,11 +3898,12 @@ dependencies = [ [[package]] name = "ream-merkle" version = "0.1.0" -source = "git+https://github.com/ReamLabs/ream#39bcd36f87954351ce5396fa996a910a397a3ab8" +source = "git+https://github.com/syjn99/ream?rev=f5327406270b374b6caeaed05fc1549c5a21dd53#f5327406270b374b6caeaed05fc1549c5a21dd53" dependencies = [ "alloy-primitives 1.1.0", "anyhow", "ethereum_hashing", + "serde", ] [[package]] @@ -3920,6 +3921,7 @@ dependencies = [ name = "ream-script" version = "0.1.0" dependencies = [ + "bincode", "clap", "derive_more 2.0.1", "dotenv", @@ -3927,11 +3929,22 @@ dependencies = [ "hex", "ream-consensus", "ream-lib", + "ream-merkle", "serde", "serde_json", "sp1-build", "sp1-sdk", "tracing", + "tree_hash", +] + +[[package]] +name = "ream-slashings-reset" +version = "0.1.0" +dependencies = [ + "ream-consensus", + "sp1-derive", + "sp1-zkvm", ] [[package]] @@ -4189,7 +4202,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4494,8 +4507,7 @@ dependencies = [ [[package]] name = "sha2" version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +source = "git+https://github.com/sp1-patches/RustCrypto-hashes?tag=patch-sha2-0.10.8-sp1-4.0.0#1f224388fdede7cef649bce0d63876d1a9e3f515" dependencies = [ "cfg-if", "cpufeatures", @@ -5246,7 +5258,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3efc7c5..fb74a7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,13 @@ [workspace] -members = ["lib", "program/operations", "script"] +members = ["lib", "program/operations", "program/slashings_reset", "script"] resolver = "2" [workspace.dependencies] ethereum_ssz = "0.9" tracing = "0.1.40" -ream-consensus = { git = "https://github.com/ReamLabs/ream", package = "ream-consensus" } +ream-consensus = { git = "https://github.com/syjn99/ream", package = "ream-consensus", rev = "f5327406270b374b6caeaed05fc1549c5a21dd53" } +ream-merkle = { git = "https://github.com/syjn99/ream", package = "ream-merkle", rev = "f5327406270b374b6caeaed05fc1549c5a21dd53" } [patch.crates-io] ethereum_hashing = { git = "https://github.com/ReamLabs/ethereum_hashing" } +sha2 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", tag = "patch-sha2-0.10.8-sp1-4.0.0" } diff --git a/post.ssz_snappy b/post.ssz_snappy new file mode 100644 index 0000000..0b890bc Binary files /dev/null and b/post.ssz_snappy differ diff --git a/pre.ssz_snappy b/pre.ssz_snappy new file mode 100644 index 0000000..4d0fb15 Binary files /dev/null and b/pre.ssz_snappy differ diff --git a/program/slashings_reset/Cargo.toml b/program/slashings_reset/Cargo.toml new file mode 100644 index 0000000..8a4b11b --- /dev/null +++ b/program/slashings_reset/Cargo.toml @@ -0,0 +1,12 @@ +[package] +version = "0.1.0" +name = "ream-slashings-reset" +edition = "2024" + +[dependencies] +# SP1 dependencies +sp1-zkvm = "4.0.0" +sp1-derive = "4.0.0" + +# Ream dependencies +ream-consensus = { workspace = true } diff --git a/program/slashings_reset/src/main.rs b/program/slashings_reset/src/main.rs new file mode 100644 index 0000000..a8aa0cb --- /dev/null +++ b/program/slashings_reset/src/main.rs @@ -0,0 +1,42 @@ +// These two lines are necessary for the program to properly compile. +// +// Under the hood, we wrap your main function with some extra code so that it behaves properly +// inside the zkVM. +#![no_main] +sp1_zkvm::entrypoint!(main); + +use ream_consensus::view::PartialBeaconStateBuilder; + +#[sp1_derive::cycle_tracker] +pub fn main() { + // Read an input to the program. + // + // Behind the scenes, this compiles down to a custom system call which handles reading inputs + // from the prover. + + println!("cycle-tracker-report-start: read-builder"); + let builder: PartialBeaconStateBuilder = sp1_zkvm::io::read(); + println!("cycle-tracker-report-end: read-builder"); + + println!("cycle-tracker-report-start: build-partial-beacon-state"); + let mut partial_beacon_state = builder + .build() + .expect("Failed to build partial beacon state"); + println!("cycle-tracker-report-end: build-partial-beacon-state"); + + // Main logic of the program. + // State transition of the beacon state. + + println!("cycle-tracker-report-start: process-slashings-reset"); + partial_beacon_state + .process_slashings_reset() + .expect("Failed to process slashings reset"); + println!("cycle-tracker-report-end: process-slashings-reset"); + + // Commit to the public values of the program. The final proof will have a commitment to all the + // bytes that were committed to. + + println!("cycle-tracker-report-start: commit"); + sp1_zkvm::io::commit(&partial_beacon_state); + println!("cycle-tracker-report-end: commit"); +} diff --git a/script/Cargo.toml b/script/Cargo.toml index a5890ba..78228fc 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -10,6 +10,7 @@ path = "src/bin/main.rs" [dependencies] sp1-sdk = "4.0.0" +bincode = "1.3.3" serde_json = { version = "1.0", default-features = false, features = ["alloc"] } serde = { version = "1.0.200", default-features = false, features = ["derive"] } derive_more = { version = "2.0.1", features = ["full"] } @@ -20,9 +21,11 @@ dotenv = "0.15.0" # Ethereum dependencies ethereum_ssz = { workspace = true } +tree_hash = "0.10" # Ream dependencies ream-consensus = { workspace = true } +ream-merkle = { workspace = true } ream-lib = { path = "../lib" } [build-dependencies] diff --git a/script/build.rs b/script/build.rs index 9b14415..6228c16 100644 --- a/script/build.rs +++ b/script/build.rs @@ -1,5 +1,6 @@ use sp1_build::build_program; fn main() { - build_program("../program/operations") + build_program("../program/operations"); + build_program("../program/slashings_reset"); } diff --git a/script/src/bin/main.rs b/script/src/bin/main.rs index a0f9f80..1d0e3ab 100644 --- a/script/src/bin/main.rs +++ b/script/src/bin/main.rs @@ -1,9 +1,16 @@ use clap::Parser; use sp1_sdk::{ProverClient, SP1Stdin, include_elf}; -use ssz::{Decode, Encode}; use tracing::{error, info}; - -use ream_consensus::electra::{beacon_block::SignedBeaconBlock, beacon_state::BeaconState}; +use tree_hash::TreeHash; + +use ream_consensus::{ + constants::{ + BEACON_STATE_MERKLE_DEPTH, BEACON_STATE_SLASHINGS_GENERALIZED_INDEX, + BEACON_STATE_SLASHINGS_INDEX, BEACON_STATE_SLOT_INDEX, + }, + electra::beacon_state::BeaconState, + view::{PartialBeaconState, PartialBeaconStateBuilder, SlashingsView}, +}; use ream_lib::{file::read_file, input::OperationInput}; mod cli; @@ -11,6 +18,7 @@ use cli::operation::OperationName; /// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM. pub const OPERATIONS_ELF: &[u8] = include_elf!("ream-operations"); +pub const SLASHINGS_RESET_ELF: &[u8] = include_elf!("ream-slashings-reset"); /// The arguments for the command. #[derive(Parser, Debug)] @@ -45,6 +53,9 @@ struct Args { #[clap(long, requires = "replay")] state_path: Option, + #[clap(long, requires = "replay")] + expected_post_path: Option, + #[clap(long, requires = "replay")] block_path: Option, } @@ -75,7 +86,68 @@ fn main() { if args.replay { info!("Executing with replay test..."); - todo!(); + + let mut pre_state: BeaconState = read_file(&std::path::PathBuf::from( + args.state_path.unwrap_or_default(), + )); + let expected_post: BeaconState = read_file(&std::path::PathBuf::from( + args.expected_post_path.unwrap_or_default(), + )); + let root = pre_state.tree_hash_root(); + + let all_leaves = pre_state.merkle_leaves(); + let tree = ream_merkle::merkle_tree(&all_leaves, BEACON_STATE_MERKLE_DEPTH) + .expect("Failed to create merkle tree"); + + let target_indices = vec![BEACON_STATE_SLOT_INDEX, BEACON_STATE_SLASHINGS_INDEX]; + let multiproof = + ream_merkle::multiproof::Multiproof::generate::( + &tree, + &target_indices, + ) + .expect("Failed to generate multiproof"); + + let builder = PartialBeaconStateBuilder::from_root(root) + .with_multiproof(multiproof) + .with_slot(pre_state.slot) + .with_slashings(&pre_state.slashings); + + // Setup the prover client. + let client = ProverClient::from_env(); + + // Setup the inputs. + let mut stdin = SP1Stdin::new(); + + stdin.write(&builder); + + // Execute the program + let (output, report) = client.execute(SLASHINGS_RESET_ELF, &stdin).run().unwrap(); + info!("Program executed successfully."); + + // Decode the output + let result: PartialBeaconState = bincode::deserialize(output.as_slice()).unwrap(); + + for &mutated in result.dirty.iter() { + match mutated { + BEACON_STATE_SLASHINGS_GENERALIZED_INDEX => { + pre_state.slashings = result.slashings().unwrap().clone(); + } + _ => { + panic!("Unexpected mutated index: {}", mutated); + } + } + } + + assert_eq!(expected_post.tree_hash_root(), pre_state.tree_hash_root()); + + // Record the number of cycles executed. + info!("----- Cycle Tracker -----"); + info!("Number of cycles: {}", report.total_instruction_count()); + info!("Number of syscall count: {}", report.total_syscall_count()); + for (key, value) in report.cycle_tracker.iter() { + info!("{}: {}", key, value); + } + info!("----- Cycle Tracker End -----"); } if args.ef_test {