@@ -14,6 +14,7 @@ use reth_interfaces::provider::ProviderResult;
1414use reth_primitives:: {
1515 trie:: AccountProof , Account , Address , BlockNumber , Bytecode , StorageKey , StorageValue , B256 ,
1616} ;
17+ use std:: fmt:: Debug ;
1718
1819/// State provider for a given block number which takes a tx reference.
1920///
@@ -109,36 +110,42 @@ impl<'b, TX: DbTx> HistoricalStateProviderRef<'b, TX> {
109110 // index, the first chunk for the next key will be returned so we filter out chunks that
110111 // have a different key.
111112 if let Some ( chunk) = cursor. seek ( key) ?. filter ( |( key, _) | key_filter ( key) ) . map ( |x| x. 1 . 0 ) {
112- // Get the rank of the first entry after our block.
113- let rank = chunk. rank ( self . block_number ) ;
113+ // Get the rank of the first entry before or equal to our block.
114+ let mut rank = chunk. rank ( self . block_number ) ;
114115
115- let Some ( block_number) = chunk. select ( rank) else {
116- // The chunk does not contain an entry for a write after our block. This can only
117- // happen if this is the last chunk and so we need to look in the plain state.
118- return Ok ( HistoryInfo :: InPlainState )
116+ // Adjust the rank, so that we have the rank of the first entry before our block
117+ if rank. checked_sub ( 1 ) . and_then ( |rank| chunk. select ( rank) ) == Some ( self . block_number ) {
118+ rank -= 1
119119 } ;
120120
121+ let block_number = chunk. select ( rank) ;
122+
121123 // If our block is before the first entry in the index chunk and this first entry
122- // doesn't equal to our block, it might be before the first write ever. To check, we
124+ // doesn't equal to our block it might be before the first write ever. To check, we
123125 // look at the previous entry and check if the key is the same.
124126 // This check is worth it, the `cursor.prev()` check is rarely triggered (the if will
125127 // short-circuit) and when it passes we save a full seek into the changeset/plain state
126128 // table.
127129 if rank == 0 &&
128- block_number != self . block_number &&
130+ block_number != Some ( self . block_number ) &&
129131 !cursor. prev ( ) ?. is_some_and ( |( key, _) | key_filter ( & key) )
130132 {
131- if lowest_available_block_number. is_some ( ) {
133+ if let ( Some ( _) , Some ( block_number) ) = ( lowest_available_block_number, block_number)
134+ {
132135 // The key may have been written, but due to pruning we may not have changesets
133136 // and history, so we need to make a changeset lookup.
134137 Ok ( HistoryInfo :: InChangeset ( block_number) )
135138 } else {
136139 // The key is written to, but only after our block.
137140 Ok ( HistoryInfo :: NotYetWritten )
138141 }
139- } else {
142+ } else if let Some ( block_number ) = block_number {
140143 // The chunk contains an entry for a write after our block, return it.
141144 Ok ( HistoryInfo :: InChangeset ( block_number) )
145+ } else {
146+ // The chunk does not contain an entry for a write after our block. This can only
147+ // happen if this is the last chunk and so we need to look in the plain state.
148+ Ok ( HistoryInfo :: InPlainState )
142149 }
143150 } else if lowest_available_block_number. is_some ( ) {
144151 // The key may have been written, but due to pruning we may not have changesets and
0 commit comments