6
6
//! jumpdest table, before the actual CPU carries on with contract execution.
7
7
8
8
use std:: collections:: { BTreeSet , HashMap } ;
9
+ use std:: str:: FromStr ;
9
10
10
11
use anyhow:: anyhow;
11
- use ethereum_types:: { BigEndianHash , U256 } ;
12
+ use ethereum_types:: { BigEndianHash , H256 , U256 } ;
12
13
use log:: Level ;
13
14
use mpt_trie:: partial_trie:: PartialTrie ;
14
15
use plonky2:: field:: types:: Field ;
@@ -19,6 +20,10 @@ use crate::cpu::kernel::aggregator::KERNEL;
19
20
use crate :: cpu:: kernel:: constants:: global_metadata:: GlobalMetadata ;
20
21
use crate :: generation:: debug_inputs;
21
22
use crate :: generation:: mpt:: load_all_mpts;
23
+ use crate :: generation:: prover_input:: {
24
+ get_proofs_and_jumpdests, CodeDb , ContextJumpDests , JumpDestTableProcessed ,
25
+ JumpDestTableWitness ,
26
+ } ;
22
27
use crate :: generation:: rlp:: all_rlp_prover_inputs_reversed;
23
28
use crate :: generation:: state:: {
24
29
all_withdrawals_prover_inputs_reversed, GenerationState , GenerationStateCheckpoint ,
@@ -52,6 +57,7 @@ pub(crate) struct Interpreter<F: Field> {
52
57
/// Counts the number of appearances of each opcode. For debugging purposes.
53
58
#[ allow( unused) ]
54
59
pub ( crate ) opcode_count : [ usize ; 0x100 ] ,
60
+ /// A table of contexts and their reached JUMPDESTs.
55
61
jumpdest_table : HashMap < usize , BTreeSet < usize > > ,
56
62
/// `true` if the we are currently carrying out a jumpdest analysis.
57
63
pub ( crate ) is_jumpdest_analysis : bool ,
@@ -60,14 +66,15 @@ pub(crate) struct Interpreter<F: Field> {
60
66
pub ( crate ) clock : usize ,
61
67
}
62
68
63
- /// Simulates the CPU execution from `state` until the program counter reaches
64
- /// `final_label` in the current context.
65
69
pub ( crate ) fn simulate_cpu_and_get_user_jumps < F : Field > (
66
70
final_label : & str ,
67
71
state : & GenerationState < F > ,
68
- ) -> Option < HashMap < usize , Vec < usize > > > {
72
+ ) -> (
73
+ Option < HashMap < usize , Vec < usize > > > ,
74
+ HashMap < usize , BTreeSet < usize > > ,
75
+ ) {
69
76
match state. jumpdest_table {
70
- Some ( _) => None ,
77
+ Some ( _) => ( None , Default :: default ( ) ) ,
71
78
None => {
72
79
let halt_pc = KERNEL . global_labels [ final_label] ;
73
80
let initial_context = state. registers . context ;
@@ -82,14 +89,60 @@ pub(crate) fn simulate_cpu_and_get_user_jumps<F: Field>(
82
89
83
90
interpreter
84
91
. generation_state
85
- . set_jumpdest_analysis_inputs ( interpreter. jumpdest_table ) ;
92
+ . set_jumpdest_analysis_inputs ( interpreter. jumpdest_table . clone ( ) ) ;
86
93
87
94
log:: debug!( "Simulated CPU for jumpdest analysis halted." ) ;
88
- interpreter. generation_state . jumpdest_table
95
+ (
96
+ interpreter. generation_state . jumpdest_table ,
97
+ interpreter. jumpdest_table ,
98
+ )
89
99
}
90
100
}
91
101
}
92
102
103
+ /// Computes the JUMPDEST proofs for each context.
104
+ ///
105
+ /// # Arguments
106
+ ///
107
+ /// - `jumpdest_table_rpc`: The raw table received from RPC.
108
+ /// - `code_db`: The corresponding database of contract code used in the trace.
109
+ pub ( crate ) fn set_jumpdest_analysis_inputs_rpc (
110
+ jumpdest_table_rpc : & JumpDestTableWitness ,
111
+ code_db : & CodeDb ,
112
+ ) -> JumpDestTableProcessed {
113
+ let ctx_proofs = jumpdest_table_rpc
114
+ . 0
115
+ . iter ( )
116
+ . flat_map ( |( code_addr, ctx_jumpdests) | {
117
+ prove_context_jumpdests ( & code_db[ code_addr] , ctx_jumpdests)
118
+ } )
119
+ . collect ( ) ;
120
+ JumpDestTableProcessed ( ctx_proofs)
121
+ }
122
+
123
+ /// Orchestrates the proving of all contexts in a specific bytecode.
124
+ ///
125
+ /// # Arguments
126
+ ///
127
+ /// - `ctx_jumpdests`: Map from `ctx` to its list of offsets to reached
128
+ /// `JUMPDEST`s.
129
+ /// - `code`: The bytecode for the contexts. This is the same for all contexts.
130
+ fn prove_context_jumpdests (
131
+ code : & [ u8 ] ,
132
+ ctx_jumpdests : & ContextJumpDests ,
133
+ ) -> HashMap < usize , Vec < usize > > {
134
+ ctx_jumpdests
135
+ . 0
136
+ . iter ( )
137
+ . map ( |( & ctx, jumpdests) | {
138
+ let proofs = jumpdests. last ( ) . map_or ( Vec :: default ( ) , |& largest_address| {
139
+ get_proofs_and_jumpdests ( code, largest_address, jumpdests. clone ( ) )
140
+ } ) ;
141
+ ( ctx, proofs)
142
+ } )
143
+ . collect ( )
144
+ }
145
+
93
146
impl < F : Field > Interpreter < F > {
94
147
/// Returns an instance of `Interpreter` given `GenerationInputs`, and
95
148
/// assuming we are initializing with the `KERNEL` code.
@@ -508,14 +561,29 @@ impl<F: Field> State<F> for Interpreter<F> {
508
561
509
562
let op = decode ( registers, opcode) ?;
510
563
564
+ // log here
511
565
fill_op_flag ( op, & mut row) ;
512
566
513
567
self . fill_stack_fields ( & mut row) ?;
514
568
515
569
if registers. is_kernel {
516
570
log_kernel_instruction ( self , op) ;
517
571
} else {
518
- self . log_debug ( format ! ( "User instruction: {:?}" , op) ) ;
572
+ //self.log_debug(format!("User instruction: {:?} CTX {:?}", op,
573
+ let hash = "0xc02ea02af1da253b9cf3d1de648c3355211f490cf4b8641b3146e69450870ba6" ;
574
+ let debug_tx = H256 :: from_str ( hash) . unwrap ( ) ;
575
+ let curr_tx =
576
+ keccak_hash:: keccak ( self . generation_state . inputs . signed_txn . as_ref ( ) . unwrap ( ) ) ;
577
+
578
+ if curr_tx == debug_tx {
579
+ log:: info!(
580
+ "JMP: {:<5} TX: {:?} CTX: {:<2} OP: {:<10?}" ,
581
+ self . is_jumpdest_analysis,
582
+ curr_tx,
583
+ registers. code_context( ) ,
584
+ op
585
+ ) ;
586
+ }
519
587
}
520
588
521
589
let generation_state = self . get_mut_generation_state ( ) ;
0 commit comments