Skip to content

Commit e54d562

Browse files
committed
chore: move main program into program/operations
1 parent 7b04142 commit e54d562

8 files changed

Lines changed: 161 additions & 122 deletions

File tree

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"rust-analyzer.linkedProjects": [
3-
"program/Cargo.toml",
3+
"program/operations/Cargo.toml",
44
"script/Cargo.toml"
55
],
66
"rust-analyzer.check.overrideCommand": [

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["lib", "program", "script"]
2+
members = ["lib", "program/operations", "script"]
33
resolver = "2"
44

55
[workspace.dependencies]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ ethereum_ssz = { workspace = true }
1313

1414
# Ream dependencies
1515
ream-consensus = { workspace = true }
16-
ream-lib = { path = "../lib" }
16+
ream-lib = { path = "../../lib" }
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn main() {
1818
// NOTE: BeaconState/OperationInput should implement Serialize & Deserialize trait.
1919

2020
println!("cycle-tracker-report-start: read-pre-state");
21-
let mut pre_state = sp1_zkvm::io::read::<BeaconState>();
21+
let mut pre_state: BeaconState = sp1_zkvm::io::read();
2222
println!("cycle-tracker-report-end: read-pre-state");
2323

2424
println!("cycle-tracker-report-start: read-operation-input");

script/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ $(addprefix run-, $(OPERATIONS)): run-%: $(EXTRACT_DIR)
2626
@mkdir -p $(LOGS_DIR)
2727
@mkdir -p $(SUMMARIES_DIR)
2828
@echo "Running benchmarks for $*..."
29-
@NO_COLOR=1 cargo run --release -- --execute -o $* \
30-
--excluded-cases multi_proposer_index_iterations \ # attestation
31-
--excluded-cases random_with_exits_with_duplicates \ # sync_aggregate
29+
@NO_COLOR=1 cargo run --release -- --execute --ef-test -o $* \
30+
--excluded-cases multi_proposer_index_iterations \
31+
--excluded-cases random_with_exits_with_duplicates \
3232
&> $(LOGS_DIR)/execution_$*.log
3333
@echo "Execution complete for $*."
3434
@$(PARSE_SCRIPT) $*

script/build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use sp1_build::build_program_with_args;
1+
use sp1_build::build_program;
22

33
fn main() {
4-
build_program_with_args("../program", Default::default())
4+
build_program("../program/operations")
55
}

script/src/bin/cli/operation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use derive_more::Display;
44
#[derive(Debug, Clone, Parser)]
55
pub struct OperationArgs {
66
#[clap(long, short)]
7-
pub operation_name: OperationName,
7+
pub operation_name: Option<OperationName>,
88
}
99

1010
#[derive(ValueEnum, Debug, Clone, Display)]

script/src/bin/main.rs

Lines changed: 151 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
use clap::Parser;
22
use sp1_sdk::{ProverClient, SP1Stdin, include_elf};
3+
use ssz::{Decode, Encode};
34
use tracing::{error, info};
45

5-
use ream_consensus::electra::beacon_state::BeaconState;
6+
use ream_consensus::electra::{beacon_block::SignedBeaconBlock, beacon_state::BeaconState};
67
use ream_lib::{file::read_file, input::OperationInput};
78

89
mod cli;
910
use cli::operation::OperationName;
1011

1112
/// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM.
12-
pub const REAM_ELF: &[u8] = include_elf!("ream-operations");
13+
pub const OPERATIONS_ELF: &[u8] = include_elf!("ream-operations");
1314

1415
/// The arguments for the command.
1516
#[derive(Parser, Debug)]
1617
#[clap(author, version, about, long_about = None)]
1718
struct Args {
18-
/// Argument for zkVMs
19-
19+
// Argument for zkVMs
2020
#[clap(long)]
2121
execute: bool,
2222

2323
#[clap(long)]
2424
prove: bool,
2525

26-
/// Argument for STFs
26+
// Argument for STFs
27+
28+
// EF test (default flow)
29+
#[clap(long, conflicts_with = "replay")]
30+
ef_test: bool,
2731

2832
#[clap(flatten)]
2933
fork: cli::fork::ForkArgs,
@@ -32,19 +36,20 @@ struct Args {
3236
operation: cli::operation::OperationArgs,
3337

3438
#[clap(long)]
35-
excluded_cases: Vec<String>,
39+
excluded_cases: Option<Vec<String>>,
40+
41+
// Replay test: requires state and block file paths
42+
#[clap(long, conflicts_with = "ef_test")]
43+
replay: bool,
44+
45+
#[clap(long, requires = "replay")]
46+
state_path: Option<String>,
47+
48+
#[clap(long, requires = "replay")]
49+
block_path: Option<String>,
3650
}
3751

3852
fn main() {
39-
let test_case_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
40-
.join("mainnet")
41-
.join("tests")
42-
.join("mainnet");
43-
if !std::path::Path::new(&test_case_dir).exists() {
44-
eprintln!("Error: You must first download test data via `make download`");
45-
std::process::exit(1);
46-
}
47-
4853
if std::env::var("RUST_LOG").is_err() {
4954
unsafe {
5055
std::env::set_var("RUST_LOG", "info");
@@ -63,115 +68,149 @@ fn main() {
6368
std::process::exit(1);
6469
}
6570

66-
let fork = args.fork.fork;
67-
let operation_name = args.operation.operation_name;
68-
let excluded_cases = args.excluded_cases;
69-
70-
// Load the test assets.
71-
// These assets are from consensus-specs repo.
72-
let base_dir = test_case_dir
73-
.join(format!("{}", fork))
74-
.join("operations")
75-
.join(format!("{}", operation_name))
76-
.join("pyspec_tests");
77-
78-
let test_cases = ream_lib::file::get_test_cases(&base_dir);
79-
for test_case in test_cases {
80-
if excluded_cases.contains(&test_case) {
81-
info!("Skipping test case: {}", test_case);
82-
continue;
83-
}
71+
if args.ef_test == args.replay {
72+
error!("Error: You must specify either --ef-test or --replay");
73+
std::process::exit(1);
74+
}
8475

85-
info!("{}", "-".repeat(50));
86-
info!("[{}] Test case: {}", operation_name, test_case);
76+
if args.replay {
77+
info!("Executing with replay test...");
78+
todo!();
79+
}
8780

88-
let case_dir = &base_dir.join(&test_case);
89-
let input_path = &case_dir.join(format!("{}.ssz_snappy", operation_name.to_input_name()));
81+
if args.ef_test {
82+
info!("Executing with EF test...");
9083

91-
let pre_state: BeaconState = read_file(&case_dir.join("pre.ssz_snappy"));
92-
let input = match operation_name {
93-
OperationName::Attestation => OperationInput::Attestation(read_file(input_path)),
94-
OperationName::AttesterSlashing => {
95-
OperationInput::AttesterSlashing(read_file(input_path))
96-
}
97-
OperationName::BlockHeader => OperationInput::BeaconBlock(read_file(input_path)),
98-
OperationName::BLSToExecutionChange => {
99-
OperationInput::SignedBLSToExecutionChange(read_file(input_path))
100-
}
101-
OperationName::Deposit => OperationInput::Deposit(read_file(input_path)),
102-
OperationName::ExecutionPayload => {
103-
OperationInput::BeaconBlockBody(read_file(input_path))
104-
}
105-
OperationName::ProposerSlashing => {
106-
OperationInput::ProposerSlashing(read_file(input_path))
107-
}
108-
OperationName::SyncAggregate => OperationInput::SyncAggregate(read_file(input_path)),
109-
OperationName::VoluntaryExit => {
110-
OperationInput::SignedVoluntaryExit(read_file(input_path))
111-
}
112-
OperationName::Withdrawals => OperationInput::ExecutionPayload(read_file(input_path)),
113-
};
114-
let post_state_opt: Option<BeaconState> = {
115-
if case_dir.join("post.ssz_snappy").exists() {
116-
Some(read_file(&case_dir.join("post.ssz_snappy")))
117-
} else {
118-
None
119-
}
120-
};
84+
let test_case_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
85+
.join("mainnet")
86+
.join("tests")
87+
.join("mainnet");
88+
if !std::path::Path::new(&test_case_dir).exists() {
89+
eprintln!("Error: You must first download test data via `make download`");
90+
std::process::exit(1);
91+
}
12192

122-
// Setup the prover client.
123-
let client = ProverClient::from_env();
93+
let fork = args.fork.fork;
94+
let operation_name = args
95+
.operation
96+
.operation_name
97+
.expect("Operation name is required");
98+
let excluded_cases = args.excluded_cases.unwrap_or_default();
99+
100+
// Load the test assets.
101+
// These assets are from consensus-specs repo.
102+
let base_dir = test_case_dir
103+
.join(format!("{}", fork))
104+
.join("operations")
105+
.join(format!("{}", operation_name))
106+
.join("pyspec_tests");
107+
108+
let test_cases = ream_lib::file::get_test_cases(&base_dir);
109+
for test_case in test_cases {
110+
if excluded_cases.contains(&test_case) {
111+
info!("Skipping test case: {}", test_case);
112+
continue;
113+
}
124114

125-
// Setup the inputs.
126-
let mut stdin = SP1Stdin::new();
127-
stdin.write(&pre_state);
128-
stdin.write(&input);
115+
info!("{}", "-".repeat(50));
116+
info!("[{}] Test case: {}", operation_name, test_case);
129117

130-
if args.execute {
131-
// Execute the program
132-
let (output, report) = client.execute(REAM_ELF, &stdin).run().unwrap();
133-
info!("Program executed successfully.");
118+
let case_dir = &base_dir.join(&test_case);
119+
let input_path =
120+
&case_dir.join(format!("{}.ssz_snappy", operation_name.to_input_name()));
134121

135-
// Decode the output
136-
let result: BeaconState = ssz::Decode::from_ssz_bytes(output.as_slice()).unwrap();
122+
println!("case path: {:?}", case_dir);
137123

138-
// Match `post_state_opt`: some test cases should not mutate beacon state.
139-
match post_state_opt {
140-
Some(post_state) => {
141-
assert_eq!(result, post_state);
142-
info!("Execution is correct!: State mutated");
124+
let pre_state: BeaconState = read_file(&case_dir.join("pre.ssz_snappy"));
125+
let input = match operation_name {
126+
OperationName::Attestation => OperationInput::Attestation(read_file(input_path)),
127+
OperationName::AttesterSlashing => {
128+
OperationInput::AttesterSlashing(read_file(input_path))
143129
}
144-
None => {
145-
assert_eq!(result, pre_state);
146-
info!("Execution is correct!: State should not be mutated");
130+
OperationName::BlockHeader => OperationInput::BeaconBlock(read_file(input_path)),
131+
OperationName::BLSToExecutionChange => {
132+
OperationInput::SignedBLSToExecutionChange(read_file(input_path))
133+
}
134+
OperationName::Deposit => OperationInput::Deposit(read_file(input_path)),
135+
OperationName::ExecutionPayload => {
136+
OperationInput::BeaconBlockBody(read_file(input_path))
137+
}
138+
OperationName::ProposerSlashing => {
139+
OperationInput::ProposerSlashing(read_file(input_path))
140+
}
141+
OperationName::SyncAggregate => {
142+
OperationInput::SyncAggregate(read_file(input_path))
143+
}
144+
OperationName::VoluntaryExit => {
145+
OperationInput::SignedVoluntaryExit(read_file(input_path))
146+
}
147+
OperationName::Withdrawals => {
148+
OperationInput::ExecutionPayload(read_file(input_path))
149+
}
150+
};
151+
let post_state_opt: Option<BeaconState> = {
152+
if case_dir.join("post.ssz_snappy").exists() {
153+
Some(read_file(&case_dir.join("post.ssz_snappy")))
154+
} else {
155+
None
156+
}
157+
};
158+
159+
// Setup the prover client.
160+
let client = ProverClient::from_env();
161+
162+
// Setup the inputs.
163+
let mut stdin = SP1Stdin::new();
164+
165+
stdin.write(&pre_state);
166+
stdin.write(&input);
167+
168+
if args.execute {
169+
// Execute the program
170+
let (output, report) = client.execute(OPERATIONS_ELF, &stdin).run().unwrap();
171+
info!("Program executed successfully.");
172+
173+
// Decode the output
174+
let result: BeaconState = ssz::Decode::from_ssz_bytes(output.as_slice()).unwrap();
175+
176+
// Match `post_state_opt`: some test cases should not mutate beacon state.
177+
match post_state_opt {
178+
Some(post_state) => {
179+
assert_eq!(result, post_state);
180+
info!("Execution is correct!: State mutated");
181+
}
182+
None => {
183+
assert_eq!(result, pre_state);
184+
info!("Execution is correct!: State should not be mutated");
185+
}
147186
}
148-
}
149187

150-
// Record the number of cycles executed.
151-
info!("----- Cycle Tracker -----");
152-
info!("[{}] Test case: {}", operation_name, test_case);
153-
info!("Number of cycles: {}", report.total_instruction_count());
154-
info!("Number of syscall count: {}", report.total_syscall_count());
155-
for (key, value) in report.cycle_tracker.iter() {
156-
info!("{}: {}", key, value);
188+
// Record the number of cycles executed.
189+
info!("----- Cycle Tracker -----");
190+
info!("[{}] Test case: {}", operation_name, test_case);
191+
info!("Number of cycles: {}", report.total_instruction_count());
192+
info!("Number of syscall count: {}", report.total_syscall_count());
193+
for (key, value) in report.cycle_tracker.iter() {
194+
info!("{}: {}", key, value);
195+
}
196+
info!("----- Cycle Tracker End -----");
197+
} else {
198+
// Setup the program for proving.
199+
let (pk, vk) = client.setup(OPERATIONS_ELF);
200+
201+
// Generate the proof
202+
let proof = client
203+
.prove(&pk, &stdin)
204+
.run()
205+
.expect("failed to generate proof");
206+
207+
info!("Successfully generated proof!");
208+
209+
// Verify the proof.
210+
client.verify(&proof, &vk).expect("failed to verify proof");
211+
info!("Successfully verified proof!");
157212
}
158-
info!("----- Cycle Tracker End -----");
159-
} else {
160-
// Setup the program for proving.
161-
let (pk, vk) = client.setup(REAM_ELF);
162-
163-
// Generate the proof
164-
let proof = client
165-
.prove(&pk, &stdin)
166-
.run()
167-
.expect("failed to generate proof");
168-
169-
info!("Successfully generated proof!");
170-
171-
// Verify the proof.
172-
client.verify(&proof, &vk).expect("failed to verify proof");
173-
info!("Successfully verified proof!");
213+
info!("{}", "-".repeat(50));
174214
}
175-
info!("{}", "-".repeat(50));
176215
}
177216
}

0 commit comments

Comments
 (0)