@@ -3,6 +3,10 @@ use alloy::primitives::{Address, B256, U256};
33use reth:: primitives:: { Account , Bytecode , Header , SealedHeader } ;
44use reth_db:: { BlockNumberList , models:: BlockNumberAddress } ;
55use reth_db_api:: models:: ShardedKey ;
6+ use trevm:: revm:: {
7+ database:: states:: { PlainStateReverts , PlainStorageRevert } ,
8+ state:: AccountInfo ,
9+ } ;
610
711/// Trait for database write operations on standard hot tables.
812///
@@ -13,54 +17,45 @@ pub trait UnsafeDbWrite: HotKvWrite + super::sealed::Sealed {
1317 /// Write a block header. This will leave the DB in an inconsistent state
1418 /// until the corresponding header number is also written. Users should
1519 /// prefer [`Self::put_header`] instead.
16- fn put_header_inconsistent ( & mut self , header : & Header ) -> Result < ( ) , Self :: Error > {
20+ fn put_header_inconsistent ( & self , header : & Header ) -> Result < ( ) , Self :: Error > {
1721 self . queue_put :: < tables:: Headers > ( & header. number , header)
1822 }
1923
2024 /// Write a block number by its hash. This will leave the DB in an
2125 /// inconsistent state until the corresponding header is also written.
2226 /// Users should prefer [`Self::put_header`] instead.
23- fn put_header_number_inconsistent (
24- & mut self ,
25- hash : & B256 ,
26- number : u64 ,
27- ) -> Result < ( ) , Self :: Error > {
27+ fn put_header_number_inconsistent ( & self , hash : & B256 , number : u64 ) -> Result < ( ) , Self :: Error > {
2828 self . queue_put :: < tables:: HeaderNumbers > ( hash, & number)
2929 }
3030
3131 /// Write contract Bytecode by its hash.
32- fn put_bytecode ( & mut self , code_hash : & B256 , bytecode : & Bytecode ) -> Result < ( ) , Self :: Error > {
32+ fn put_bytecode ( & self , code_hash : & B256 , bytecode : & Bytecode ) -> Result < ( ) , Self :: Error > {
3333 self . queue_put :: < tables:: Bytecodes > ( code_hash, bytecode)
3434 }
3535
3636 /// Write an account by its address.
37- fn put_account ( & mut self , address : & Address , account : & Account ) -> Result < ( ) , Self :: Error > {
37+ fn put_account ( & self , address : & Address , account : & Account ) -> Result < ( ) , Self :: Error > {
3838 self . queue_put :: < tables:: PlainAccountState > ( address, account)
3939 }
4040
4141 /// Write a storage entry by its address and key.
42- fn put_storage (
43- & mut self ,
44- address : & Address ,
45- key : & B256 ,
46- entry : & U256 ,
47- ) -> Result < ( ) , Self :: Error > {
42+ fn put_storage ( & self , address : & Address , key : & B256 , entry : & U256 ) -> Result < ( ) , Self :: Error > {
4843 self . queue_put_dual :: < tables:: PlainStorageState > ( address, key, entry)
4944 }
5045
5146 /// Write a sealed block header (header + number).
52- fn put_header ( & mut self , header : & SealedHeader ) -> Result < ( ) , Self :: Error > {
47+ fn put_header ( & self , header : & SealedHeader ) -> Result < ( ) , Self :: Error > {
5348 self . put_header_inconsistent ( header. header ( ) )
5449 . and_then ( |_| self . put_header_number_inconsistent ( & header. hash ( ) , header. number ) )
5550 }
5651
5752 /// Delete a header by block number.
58- fn delete_header ( & mut self , number : u64 ) -> Result < ( ) , Self :: Error > {
53+ fn delete_header ( & self , number : u64 ) -> Result < ( ) , Self :: Error > {
5954 self . queue_delete :: < tables:: Headers > ( & number)
6055 }
6156
6257 /// Delete a header number mapping by hash.
63- fn delete_header_number ( & mut self , hash : & B256 ) -> Result < ( ) , Self :: Error > {
58+ fn delete_header_number ( & self , hash : & B256 ) -> Result < ( ) , Self :: Error > {
6459 self . queue_delete :: < tables:: HeaderNumbers > ( hash)
6560 }
6661
@@ -85,7 +80,7 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HotHistoryRead {
8580 ///
8681 /// Accounts are keyed
8782 fn write_account_history (
88- & mut self ,
83+ & self ,
8984 address : & Address ,
9085 latest_height : u64 ,
9186 touched : & BlockNumberList ,
@@ -96,7 +91,7 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HotHistoryRead {
9691 /// Write an account change (pre-state) for an account at a specific
9792 /// block.
9893 fn write_account_prestate (
99- & mut self ,
94+ & self ,
10095 block_number : u64 ,
10196 address : Address ,
10297 pre_state : & Account ,
@@ -107,7 +102,7 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HotHistoryRead {
107102 /// Write storage history, by highest block number and touched block
108103 /// numbers.
109104 fn write_storage_history (
110- & mut self ,
105+ & self ,
111106 address : & Address ,
112107 slot : B256 ,
113108 highest_block_number : u64 ,
@@ -120,7 +115,7 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HotHistoryRead {
120115 /// Write a storage change (before state) for an account at a specific
121116 /// block.
122117 fn write_storage_prestate (
123- & mut self ,
118+ & self ,
124119 block_number : u64 ,
125120 address : Address ,
126121 slot : & B256 ,
@@ -129,6 +124,83 @@ pub trait UnsafeHistoryWrite: UnsafeDbWrite + HotHistoryRead {
129124 let block_number_address = BlockNumberAddress ( ( block_number, address) ) ;
130125 self . queue_put_dual :: < tables:: StorageChangeSets > ( & block_number_address, slot, prestate)
131126 }
127+
128+ /// Write a pre-state for every storage key that exists for an account at a
129+ /// specific block.
130+ fn write_wipe ( & self , block_number : u64 , address : & Address ) -> Result < ( ) , Self :: Error > {
131+ // SAFETY: the cursor is scoped to the transaction lifetime, which is
132+ // valid for the duration of this method.
133+ let mut cursor = self . traverse_dual :: < tables:: PlainStorageState > ( ) ?;
134+
135+ let Some ( start) = cursor. next_dual_above ( address, & B256 :: ZERO ) ? else {
136+ // No storage entries at or above this address
137+ return Ok ( ( ) ) ;
138+ } ;
139+
140+ if start. 0 != * address {
141+ // No storage entries for this address
142+ return Ok ( ( ) ) ;
143+ }
144+
145+ self . write_storage_prestate ( block_number, * address, & start. 1 , & start. 2 ) ?;
146+
147+ while let Some ( ( k, k2, v) ) = cursor. next_k2 ( ) ? {
148+ if k != * address {
149+ break ;
150+ }
151+
152+ self . write_storage_prestate ( block_number, * address, & k2, & v) ?;
153+ }
154+
155+ Ok ( ( ) )
156+ }
157+
158+ /// Write a block's plain state revert information.
159+ fn write_plain_revert (
160+ & self ,
161+ block_number : u64 ,
162+ accounts : & [ ( Address , Option < AccountInfo > ) ] ,
163+ storage : & [ PlainStorageRevert ] ,
164+ ) -> Result < ( ) , Self :: Error > {
165+ for ( address, info) in accounts {
166+ let account = info. as_ref ( ) . map ( Account :: from) . unwrap_or_default ( ) ;
167+
168+ if let Some ( bytecode) = info. as_ref ( ) . and_then ( |info| info. code . clone ( ) ) {
169+ let code_hash = account. bytecode_hash . expect ( "info has bytecode; hash must exist" ) ;
170+ let bytecode = Bytecode ( bytecode) ;
171+ self . put_bytecode ( & code_hash, & bytecode) ?;
172+ }
173+
174+ self . write_account_prestate ( block_number, * address, & account) ?;
175+ }
176+
177+ for entry in storage {
178+ if entry. wiped {
179+ return self . write_wipe ( block_number, & entry. address ) ;
180+ }
181+ for ( key, old_value) in entry. storage_revert . iter ( ) {
182+ self . write_storage_prestate (
183+ block_number,
184+ entry. address ,
185+ & B256 :: from ( key. to_be_bytes ( ) ) ,
186+ & old_value. to_previous_value ( ) ,
187+ ) ?;
188+ }
189+ }
190+
191+ Ok ( ( ) )
192+ }
193+
194+ /// Write multiple blocks' plain state revert information.
195+ fn write_plain_reverts (
196+ & self ,
197+ first_block_number : u64 ,
198+ PlainStateReverts { accounts, storage } : & PlainStateReverts ,
199+ ) -> Result < ( ) , Self :: Error > {
200+ accounts. iter ( ) . zip ( storage. iter ( ) ) . enumerate ( ) . try_for_each ( |( idx, ( acc, sto) ) | {
201+ self . write_plain_revert ( first_block_number + idx as u64 , acc, sto)
202+ } )
203+ }
132204}
133205
134206impl < T > UnsafeHistoryWrite for T where T : UnsafeDbWrite + HotKvWrite { }
0 commit comments