Skip to content

Commit 05e065a

Browse files
committed
Implement JumpDest fetching from RPC.
1 parent 85e72f2 commit 05e065a

File tree

26 files changed

+533
-39
lines changed

26 files changed

+533
-39
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

evm_arithmetization/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ homepage.workspace = true
1515
keywords.workspace = true
1616

1717
[dependencies]
18+
__compat_primitive_types = { workspace = true }
1819
anyhow = { workspace = true }
1920
bytes = { workspace = true }
2021
env_logger = { workspace = true }

evm_arithmetization/benches/fibonacci_25m_gas.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ fn prepare_setup() -> anyhow::Result<GenerationInputs> {
194194
prev_hashes: vec![H256::default(); 256],
195195
cur_hash: H256::default(),
196196
},
197+
batch_jumpdest_table: None,
197198
})
198199
}
199200

evm_arithmetization/src/cpu/kernel/interpreter.rs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use crate::cpu::columns::CpuColumnsView;
1919
use crate::cpu::kernel::aggregator::KERNEL;
2020
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
2121
use crate::generation::debug_inputs;
22+
use crate::generation::jumpdest::{ContextJumpDests, JumpDestTableProcessed, JumpDestTableWitness};
2223
use crate::generation::mpt::{load_linked_lists_and_txn_and_receipt_mpts, TrieRootPtrs};
24+
use crate::generation::prover_input::{get_proofs_and_jumpdests, CodeDb};
2325
use crate::generation::rlp::all_rlp_prover_inputs_reversed;
2426
use crate::generation::state::{
2527
all_ger_prover_inputs_reversed, all_withdrawals_prover_inputs_reversed, GenerationState,
@@ -56,6 +58,7 @@ pub(crate) struct Interpreter<F: Field> {
5658
/// Counts the number of appearances of each opcode. For debugging purposes.
5759
#[allow(unused)]
5860
pub(crate) opcode_count: [usize; 0x100],
61+
/// A table of contexts and their reached JUMPDESTs.
5962
jumpdest_table: HashMap<usize, BTreeSet<usize>>,
6063
/// `true` if the we are currently carrying out a jumpdest analysis.
6164
pub(crate) is_jumpdest_analysis: bool,
@@ -71,9 +74,9 @@ pub(crate) struct Interpreter<F: Field> {
7174
pub(crate) fn simulate_cpu_and_get_user_jumps<F: Field>(
7275
final_label: &str,
7376
state: &GenerationState<F>,
74-
) -> Option<HashMap<usize, Vec<usize>>> {
77+
) -> (Option<JumpDestTableProcessed>, ContextJumpDests) {
7578
match state.jumpdest_table {
76-
Some(_) => None,
79+
Some(_) => (None, Default::default()),
7780
None => {
7881
let halt_pc = KERNEL.global_labels[final_label];
7982
let initial_context = state.registers.context;
@@ -94,14 +97,16 @@ pub(crate) fn simulate_cpu_and_get_user_jumps<F: Field>(
9497

9598
interpreter
9699
.generation_state
97-
.set_jumpdest_analysis_inputs(interpreter.jumpdest_table);
100+
.set_jumpdest_analysis_inputs(interpreter.jumpdest_table.clone());
98101

99102
log::debug!(
100103
"Simulated CPU for jumpdest analysis halted after {:?} cycles.",
101104
clock
102105
);
103-
104-
interpreter.generation_state.jumpdest_table
106+
(
107+
interpreter.generation_state.jumpdest_table,
108+
ContextJumpDests(interpreter.jumpdest_table),
109+
)
105110
}
106111
}
107112
}
@@ -114,7 +119,7 @@ pub(crate) struct ExtraSegmentData {
114119
pub(crate) withdrawal_prover_inputs: Vec<U256>,
115120
pub(crate) ger_prover_inputs: Vec<U256>,
116121
pub(crate) trie_root_ptrs: TrieRootPtrs,
117-
pub(crate) jumpdest_table: Option<HashMap<usize, Vec<usize>>>,
122+
pub(crate) jumpdest_table: Option<JumpDestTableProcessed>,
118123
pub(crate) next_txn_index: usize,
119124
}
120125

@@ -148,6 +153,49 @@ pub(crate) fn set_registers_and_run<F: Field>(
148153
interpreter.run()
149154
}
150155

156+
/// Computes the JUMPDEST proofs for each context.
157+
///
158+
/// # Arguments
159+
///
160+
/// - `jumpdest_table_rpc`: The raw table received from RPC.
161+
/// - `code_db`: The corresponding database of contract code used in the trace.
162+
pub(crate) fn set_jumpdest_analysis_inputs_rpc(
163+
jumpdest_table_rpc: &JumpDestTableWitness,
164+
code_db: &CodeDb,
165+
) -> JumpDestTableProcessed {
166+
let ctx_proofs = jumpdest_table_rpc
167+
.0
168+
.iter()
169+
.flat_map(|(code_addr, ctx_jumpdests)| {
170+
prove_context_jumpdests(&code_db[code_addr], ctx_jumpdests)
171+
})
172+
.collect();
173+
JumpDestTableProcessed(ctx_proofs)
174+
}
175+
176+
/// Orchestrates the proving of all contexts in a specific bytecode.
177+
///
178+
/// # Arguments
179+
///
180+
/// - `ctx_jumpdests`: Map from `ctx` to its list of offsets to reached
181+
/// `JUMPDEST`s.
182+
/// - `code`: The bytecode for the contexts. This is the same for all contexts.
183+
fn prove_context_jumpdests(
184+
code: &[u8],
185+
ctx_jumpdests: &ContextJumpDests,
186+
) -> HashMap<usize, Vec<usize>> {
187+
ctx_jumpdests
188+
.0
189+
.iter()
190+
.map(|(&ctx, jumpdests)| {
191+
let proofs = jumpdests.last().map_or(Vec::default(), |&largest_address| {
192+
get_proofs_and_jumpdests(code, largest_address, jumpdests.clone())
193+
});
194+
(ctx, proofs)
195+
})
196+
.collect()
197+
}
198+
151199
impl<F: Field> Interpreter<F> {
152200
/// Returns an instance of `Interpreter` given `GenerationInputs`, and
153201
/// assuming we are initializing with the `KERNEL` code.

evm_arithmetization/src/cpu/kernel/tests/add11.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ fn test_add11_yml() {
195195
prev_hashes: vec![H256::default(); 256],
196196
cur_hash: H256::default(),
197197
},
198+
batch_jumpdest_table: None,
198199
};
199200

200201
let initial_stack = vec![];
@@ -376,6 +377,7 @@ fn test_add11_yml_with_exception() {
376377
prev_hashes: vec![H256::default(); 256],
377378
cur_hash: H256::default(),
378379
},
380+
batch_jumpdest_table: None,
379381
};
380382

381383
let initial_stack = vec![];

evm_arithmetization/src/cpu/kernel/tests/core/jumpdest_analysis.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use plonky2::field::goldilocks_field::GoldilocksField as F;
77
use crate::cpu::kernel::aggregator::KERNEL;
88
use crate::cpu::kernel::interpreter::Interpreter;
99
use crate::cpu::kernel::opcodes::{get_opcode, get_push_opcode};
10+
use crate::generation::jumpdest::JumpDestTableProcessed;
1011
use crate::witness::operation::CONTEXT_SCALING_FACTOR;
1112

1213
#[test]
@@ -67,7 +68,10 @@ fn test_jumpdest_analysis() -> Result<()> {
6768
interpreter.generation_state.jumpdest_table,
6869
// Context 3 has jumpdest 1, 5, 7. All have proof 0 and hence
6970
// the list [proof_0, jumpdest_0, ... ] is [0, 1, 0, 5, 0, 7, 8, 40]
70-
Some(HashMap::from([(3, vec![0, 1, 0, 5, 0, 7, 8, 40])]))
71+
Some(JumpDestTableProcessed(HashMap::from([(
72+
3,
73+
vec![0, 1, 0, 5, 0, 7, 8, 40]
74+
)])))
7175
);
7276

7377
// Run jumpdest analysis with context = 3
@@ -89,6 +93,7 @@ fn test_jumpdest_analysis() -> Result<()> {
8993
.jumpdest_table
9094
.as_mut()
9195
.unwrap()
96+
.0
9297
.get_mut(&CONTEXT)
9398
.unwrap()
9499
.pop();
@@ -136,7 +141,8 @@ fn test_packed_verification() -> Result<()> {
136141
let mut interpreter: Interpreter<F> =
137142
Interpreter::new(write_table_if_jumpdest, initial_stack.clone(), None);
138143
interpreter.set_code(CONTEXT, code.clone());
139-
interpreter.generation_state.jumpdest_table = Some(HashMap::from([(3, vec![1, 33])]));
144+
interpreter.generation_state.jumpdest_table =
145+
Some(JumpDestTableProcessed(HashMap::from([(3, vec![1, 33])])));
140146

141147
interpreter.run()?;
142148

@@ -149,7 +155,8 @@ fn test_packed_verification() -> Result<()> {
149155
let mut interpreter: Interpreter<F> =
150156
Interpreter::new(write_table_if_jumpdest, initial_stack.clone(), None);
151157
interpreter.set_code(CONTEXT, code.clone());
152-
interpreter.generation_state.jumpdest_table = Some(HashMap::from([(3, vec![1, 33])]));
158+
interpreter.generation_state.jumpdest_table =
159+
Some(JumpDestTableProcessed(HashMap::from([(3, vec![1, 33])])));
153160

154161
assert!(interpreter.run().is_err());
155162

evm_arithmetization/src/cpu/kernel/tests/init_exc_stop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ fn test_init_exc_stop() {
110110
cur_hash: H256::default(),
111111
},
112112
global_exit_roots: vec![],
113+
batch_jumpdest_table: None,
113114
};
114115
let initial_stack = vec![];
115116
let initial_offset = KERNEL.global_labels["init"];
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use std::{
2+
collections::{BTreeSet, HashMap},
3+
fmt::Display,
4+
};
5+
6+
use keccak_hash::H256;
7+
use serde::{Deserialize, Serialize};
8+
9+
/// Each `CodeAddress` can be called one or more times, each time creating a new
10+
/// `Context`. Each `Context` will one or more `JumpDests`.
11+
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, Default)]
12+
pub struct ContextJumpDests(pub HashMap<usize, BTreeSet<usize>>);
13+
14+
/// The result after proving a `JumpDestTableWitness`.
15+
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, Default)]
16+
pub(crate) struct JumpDestTableProcessed(pub HashMap<usize, Vec<usize>>);
17+
18+
/// Map `CodeAddress -> (Context -> [JumpDests])`
19+
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, Default)]
20+
pub struct JumpDestTableWitness(pub HashMap<H256, ContextJumpDests>);
21+
22+
impl JumpDestTableWitness {
23+
pub fn insert(&mut self, code_hash: &H256, ctx: usize, offset: usize) {
24+
self.0.entry(*code_hash).or_default();
25+
26+
self.0.get_mut(code_hash).unwrap().0.entry(ctx).or_default();
27+
28+
self.0
29+
.get_mut(code_hash)
30+
.unwrap()
31+
.0
32+
.get_mut(&ctx)
33+
.unwrap()
34+
.insert(offset);
35+
36+
assert!(self.0.contains_key(code_hash));
37+
assert!(self.0[code_hash].0.contains_key(&ctx));
38+
assert!(self.0[code_hash].0[&ctx].contains(&offset));
39+
}
40+
}
41+
42+
impl Display for JumpDestTableWitness {
43+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44+
writeln!(f, "=== JumpDest table ===")?;
45+
46+
for (code, ctxtbls) in &self.0 {
47+
write!(f, "codehash: {:?}\n{}", code, ctxtbls)?;
48+
}
49+
Ok(())
50+
}
51+
}
52+
53+
impl Display for ContextJumpDests {
54+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55+
for (ctx, offsets) in &self.0 {
56+
write!(f, " ctx: {}, offsets: [", ctx)?;
57+
for offset in offsets {
58+
write!(f, "{:#10x} ", offset)?;
59+
}
60+
writeln!(f, "]")?;
61+
}
62+
Ok(())
63+
}
64+
}

evm_arithmetization/src/generation/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::HashMap;
22

33
use anyhow::anyhow;
44
use ethereum_types::{Address, BigEndianHash, H256, U256};
5+
use jumpdest::JumpDestTableWitness;
56
use keccak_hash::keccak;
67
use log::log_enabled;
78
use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie};
@@ -33,6 +34,7 @@ use crate::util::{h2u, u256_to_usize};
3334
use crate::witness::memory::{MemoryAddress, MemoryChannel, MemoryState};
3435
use crate::witness::state::RegistersState;
3536

37+
pub mod jumpdest;
3638
pub(crate) mod linked_list;
3739
pub mod mpt;
3840
pub(crate) mod prover_input;
@@ -93,6 +95,10 @@ pub struct GenerationInputs {
9395
/// The hash of the current block, and a list of the 256 previous block
9496
/// hashes.
9597
pub block_hashes: BlockHashes,
98+
99+
/// A table listing each JUMPDESTs reached in each call context under
100+
/// associated code hash.
101+
pub batch_jumpdest_table: Option<JumpDestTableWitness>,
96102
}
97103

98104
/// A lighter version of [`GenerationInputs`], which have been trimmed
@@ -135,6 +141,10 @@ pub struct TrimmedGenerationInputs {
135141
/// The hash of the current block, and a list of the 256 previous block
136142
/// hashes.
137143
pub block_hashes: BlockHashes,
144+
145+
/// A list of tables listing each JUMPDESTs reached in each call context
146+
/// under associated code hash.
147+
pub batch_jumpdest_table: Option<JumpDestTableWitness>,
138148
}
139149

140150
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
@@ -207,6 +217,7 @@ impl GenerationInputs {
207217
contract_code: self.contract_code.clone(),
208218
block_metadata: self.block_metadata.clone(),
209219
block_hashes: self.block_hashes.clone(),
220+
batch_jumpdest_table: self.batch_jumpdest_table.clone(),
210221
}
211222
}
212223
}

0 commit comments

Comments
 (0)