1
1
use std:: iter:: once;
2
2
3
3
use bumpalo:: Bump ;
4
- use eyre:: { bail, OptionExt , Result } ;
4
+ use eyre:: { bail, Result } ;
5
5
use itertools:: Itertools ;
6
- use openvm_witness_db :: WitnessDb ;
6
+ use reth_evm :: execute :: ProviderError ;
7
7
use reth_primitives:: { Block , Header , TransactionSigned } ;
8
8
use reth_trie:: TrieAccount ;
9
- use revm:: state:: { AccountInfo , Bytecode } ;
9
+ use revm:: {
10
+ state:: { AccountInfo , Bytecode } ,
11
+ DatabaseRef ,
12
+ } ;
10
13
use revm_primitives:: { keccak256, map:: DefaultHashBuilder , Address , HashMap , B256 , U256 } ;
11
14
use serde:: { Deserialize , Serialize } ;
12
15
use serde_with:: serde_as;
@@ -30,8 +33,6 @@ pub struct ClientExecutorInput {
30
33
pub ancestor_headers : Vec < Header > ,
31
34
/// Network state as of the parent block.
32
35
pub parent_state_bytes : mptnew:: EthereumStateBytes ,
33
- /// Requests to account state and storage slots.
34
- pub state_requests : HashMap < Address , Vec < U256 > > ,
35
36
/// Account bytecodes.
36
37
pub bytecodes : Vec < Bytecode > ,
37
38
}
@@ -65,7 +66,7 @@ impl ClientExecutorInputWithState {
65
66
& input. parent_state_bytes . storage_tries
66
67
{
67
68
let account_in_trie =
68
- state_trie. get_rlp :: < TrieAccount > ( hashed_address. as_slice ( ) ) . unwrap ( ) ;
69
+ state_trie. get_rlp :: < TrieAccount > ( hashed_address. as_slice ( ) ) ? ;
69
70
let expected_storage_root =
70
71
account_in_trie. map_or ( reth_trie:: EMPTY_ROOT_HASH , |a| a. storage_root ) ;
71
72
@@ -80,6 +81,7 @@ impl ClientExecutorInputWithState {
80
81
81
82
storage_tries. insert ( * hashed_address, storage_trie) ;
82
83
}
84
+
83
85
mptnew:: EthereumState { state_trie, storage_tries, bump }
84
86
} ;
85
87
@@ -95,7 +97,7 @@ impl ClientExecutorInputWithState {
95
97
}
96
98
97
99
/// Creates a [`WitnessDb`].
98
- pub fn witness_db ( & self ) -> Result < WitnessDb > {
100
+ pub fn witness_db ( & self ) -> Result < WitnessDb < ' _ > > {
99
101
<Self as WitnessInput >:: witness_db ( self )
100
102
}
101
103
}
@@ -111,11 +113,6 @@ impl WitnessInput for ClientExecutorInputWithState {
111
113
self . parent_header ( ) . state_root
112
114
}
113
115
114
- #[ inline( always) ]
115
- fn state_requests ( & self ) -> impl Iterator < Item = ( & Address , & Vec < U256 > ) > {
116
- self . input . state_requests . iter ( )
117
- }
118
-
119
116
#[ inline( always) ]
120
117
fn bytecodes ( & self ) -> impl Iterator < Item = & Bytecode > {
121
118
self . input . bytecodes . iter ( )
@@ -125,6 +122,11 @@ impl WitnessInput for ClientExecutorInputWithState {
125
122
fn headers ( & self ) -> impl Iterator < Item = & Header > {
126
123
once ( & self . input . current_block . header ) . chain ( self . input . ancestor_headers . iter ( ) )
127
124
}
125
+
126
+ #[ inline( always) ]
127
+ fn headers_len ( & self ) -> usize {
128
+ 1 + self . input . ancestor_headers . len ( )
129
+ }
128
130
}
129
131
130
132
/// A trait for constructing [`WitnessDb`].
@@ -136,18 +138,16 @@ pub trait WitnessInput {
136
138
/// [state()](trait.WitnessInput#tymethod.state) must conform to.
137
139
fn state_anchor ( & self ) -> B256 ;
138
140
139
- /// Gets an iterator over address state requests. For each request, the account info and storage
140
- /// slots are loaded from the relevant tries in the state returned by
141
- /// [state()](trait.WitnessInput#tymethod.state).
142
- fn state_requests ( & self ) -> impl Iterator < Item = ( & Address , & Vec < U256 > ) > ;
143
-
144
141
/// Gets an iterator over account bytecodes.
145
142
fn bytecodes ( & self ) -> impl Iterator < Item = & Bytecode > ;
146
143
147
144
/// Gets an iterator over references to a consecutive, reverse-chronological block headers
148
145
/// starting from the current block header.
149
146
fn headers ( & self ) -> impl Iterator < Item = & Header > ;
150
147
148
+ /// Gets the number of headers.
149
+ fn headers_len ( & self ) -> usize ;
150
+
151
151
/// Creates a [`WitnessDb`] from a [`WitnessInput`] implementation. To do so, it verifies the
152
152
/// state root, ancestor headers and account bytecodes, and constructs the account and
153
153
/// storage values by reading against state tries.
@@ -156,68 +156,16 @@ pub trait WitnessInput {
156
156
/// implementing this trait causes a zkVM run to cost over 5M cycles more. To avoid this, define
157
157
/// a method inside the type that calls this trait method instead.
158
158
#[ inline( always) ]
159
- fn witness_db ( & self ) -> Result < WitnessDb > {
159
+ fn witness_db ( & self ) -> Result < WitnessDb < ' _ > > {
160
160
let state = self . state ( ) ;
161
161
162
- let bytecodes_by_hash =
162
+ let bytecode_by_hash =
163
163
self . bytecodes ( ) . map ( |code| ( code. hash_slow ( ) , code) ) . collect :: < HashMap < _ , _ > > ( ) ;
164
164
165
- let state_requests_iter = self . state_requests ( ) ;
166
- let ( lower, _) = state_requests_iter. size_hint ( ) ;
167
- let mut accounts = HashMap :: with_capacity_and_hasher ( lower, DefaultHashBuilder :: default ( ) ) ;
168
- let mut storage = HashMap :: with_capacity_and_hasher ( lower, DefaultHashBuilder :: default ( ) ) ;
169
-
170
- for ( & address, slots) in state_requests_iter {
171
- let hashed_address = keccak256 ( address) ;
172
-
173
- let account_in_trie =
174
- state. state_trie . get_rlp :: < TrieAccount > ( hashed_address. as_slice ( ) ) ?;
175
-
176
- accounts. insert (
177
- address,
178
- match account_in_trie {
179
- Some ( account_in_trie) => AccountInfo {
180
- balance : account_in_trie. balance ,
181
- nonce : account_in_trie. nonce ,
182
- code_hash : account_in_trie. code_hash ,
183
- code : Some (
184
- ( * bytecodes_by_hash
185
- . get ( & account_in_trie. code_hash )
186
- . ok_or_eyre ( "missing bytecode" ) ?)
187
- // Cloning here is fine as `Bytes` is cheap to clone.
188
- . to_owned ( ) ,
189
- ) ,
190
- } ,
191
- _ => Default :: default ( ) ,
192
- } ,
193
- ) ;
194
-
195
- if !slots. is_empty ( ) {
196
- let mut address_storage =
197
- HashMap :: with_capacity_and_hasher ( slots. len ( ) , DefaultHashBuilder :: default ( ) ) ;
198
-
199
- let storage_trie = state
200
- . storage_tries
201
- . get ( & hashed_address)
202
- . ok_or_eyre ( "parent state does not contain storage trie" ) ?;
203
-
204
- for & slot in slots {
205
- let slot_value = storage_trie
206
- . get_rlp :: < U256 > ( keccak256 ( slot. to_be_bytes :: < 32 > ( ) ) . as_slice ( ) ) ?
207
- . unwrap_or_default ( ) ;
208
- address_storage. insert ( slot, slot_value) ;
209
- }
210
-
211
- storage. insert ( address, address_storage) ;
212
- }
213
- }
214
-
215
165
// Verify and build block hashes
216
- let headers_iter = self . headers ( ) ;
217
- let ( lower, _) = headers_iter. size_hint ( ) ;
218
166
let mut block_hashes: HashMap < u64 , B256 , _ > =
219
- HashMap :: with_capacity_and_hasher ( lower , DefaultHashBuilder :: default ( ) ) ;
220
- for ( child_header, parent_header) in headers_iter . tuple_windows ( ) {
167
+ HashMap :: with_capacity_and_hasher ( self . headers_len ( ) , DefaultHashBuilder :: default ( ) ) ;
168
+ for ( child_header, parent_header) in self . headers ( ) . tuple_windows ( ) {
221
169
if parent_header. number != child_header. number - 1 {
222
170
eyre:: bail!( "non-consecutive blocks" ) ;
223
171
}
@@ -229,6 +177,76 @@ pub trait WitnessInput {
229
177
block_hashes. insert ( parent_header. number , child_header. parent_hash ) ;
230
178
}
231
179
232
- Ok ( WitnessDb { accounts, storage, block_hashes } )
180
+ Ok ( WitnessDb { inner : state, block_hashes, bytecode_by_hash } )
181
+ }
182
+ }
183
+
184
+ #[ derive( Debug ) ]
185
+ pub struct WitnessDb < ' a > {
186
+ inner : & ' a mptnew:: EthereumState ,
187
+ block_hashes : HashMap < u64 , B256 > ,
188
+ bytecode_by_hash : HashMap < B256 , & ' a Bytecode > ,
189
+ }
190
+
191
+ impl < ' a > WitnessDb < ' a > {
192
+ pub fn new (
193
+ inner : & ' a mptnew:: EthereumState ,
194
+ block_hashes : HashMap < u64 , B256 > ,
195
+ bytecode_by_hash : HashMap < B256 , & ' a Bytecode > ,
196
+ ) -> Self {
197
+ Self { inner, block_hashes, bytecode_by_hash }
198
+ }
199
+ }
200
+
201
+ impl DatabaseRef for WitnessDb < ' _ > {
202
+ /// The database error type.
203
+ type Error = ProviderError ;
204
+
205
+ /// Get basic account information.
206
+ fn basic_ref ( & self , address : Address ) -> Result < Option < AccountInfo > , Self :: Error > {
207
+ let hashed_address = keccak256 ( address) ;
208
+
209
+ let account_in_trie =
210
+ self . inner . state_trie . get_rlp :: < TrieAccount > ( hashed_address. as_slice ( ) ) . unwrap ( ) ;
211
+
212
+ let account = account_in_trie. map ( |account_in_trie| AccountInfo {
213
+ balance : account_in_trie. balance ,
214
+ nonce : account_in_trie. nonce ,
215
+ code_hash : account_in_trie. code_hash ,
216
+ code : None ,
217
+ } ) ;
218
+
219
+ Ok ( account)
220
+ }
221
+
222
+ /// Get account code by its hash.
223
+ fn code_by_hash_ref ( & self , hash : B256 ) -> Result < Bytecode , Self :: Error > {
224
+ // Cloning here is fine as `Bytes` is cheap to clone.
225
+ Ok ( self . bytecode_by_hash . get ( & hash) . map ( |code| ( * code) . clone ( ) ) . unwrap ( ) )
226
+ }
227
+
228
+ /// Get storage value of address at index.
229
+ fn storage_ref ( & self , address : Address , index : U256 ) -> Result < U256 , Self :: Error > {
230
+ let hashed_address = keccak256 ( address) ;
231
+
232
+ let storage_trie = self
233
+ . inner
234
+ . storage_tries
235
+ . get ( & hashed_address)
236
+ . expect ( "A storage trie must be provided for each account" ) ;
237
+
238
+ let hashed_slot = keccak256 ( index. to_be_bytes :: < 32 > ( ) ) ;
239
+ Ok ( storage_trie
240
+ . get_rlp :: < U256 > ( hashed_slot. as_slice ( ) )
241
+ . expect ( "Can get from MPT" )
242
+ . unwrap_or_default ( ) )
243
+ }
244
+
245
+ /// Get block hash by block number.
246
+ fn block_hash_ref ( & self , number : u64 ) -> Result < B256 , Self :: Error > {
247
+ Ok ( * self
248
+ . block_hashes
249
+ . get ( & number)
250
+ . expect ( "A block hash must be provided for each block number" ) )
233
251
}
234
252
}
0 commit comments