1use alloy_primitives::{B256, keccak256};
2use arb_storage::{Storage, StorageBackedUint64, StorageBackend, SystemStateBackend};
3use revm::Database;
4
5mod error;
6pub use error::BlockhashesError;
7
8pub struct Blockhashes<'a, D> {
9 backing_storage: Storage<'a, D>,
10 l1_block_number: StorageBackedUint64,
11}
12
13pub fn initialize_blockhashes<D: Database>(_backing_storage: &Storage<'_, D>) {
14 }
16
17pub fn open_blockhashes<D>(backing_storage: Storage<'_, D>) -> Blockhashes<'_, D> {
18 let l1_block_number = StorageBackedUint64::new(backing_storage.base_key(), 0);
19 Blockhashes {
20 backing_storage,
21 l1_block_number,
22 }
23}
24
25impl<D: Database> Blockhashes<'_, D> {
26 pub fn l1_block_number<B: SystemStateBackend>(
27 &self,
28 backend: &mut B,
29 ) -> Result<u64, BlockhashesError> {
30 Ok(self.l1_block_number.get(backend)?)
31 }
32
33 pub fn block_hash<B: SystemStateBackend>(
34 &self,
35 backend: &mut B,
36 number: u64,
37 ) -> Result<Option<B256>, BlockhashesError> {
38 let current_number = self.l1_block_number.get(backend)?;
39 if number >= current_number || number + 256 < current_number {
40 return Ok(None);
41 }
42 let hash = self.backing_storage.get_by_uint64(1 + (number % 256))?;
43 Ok(Some(hash))
44 }
45
46 pub fn record_new_l1_block<B: StorageBackend>(
47 &self,
48 backend: &mut B,
49 number: u64,
50 block_hash: B256,
51 arbos_version: u64,
52 ) -> Result<(), BlockhashesError> {
53 let mut next_number = self.l1_block_number.get(backend)?;
54
55 if number < next_number {
56 return Ok(());
57 }
58
59 if next_number + 256 < number {
60 next_number = number - 256;
61 }
62
63 while next_number + 1 < number {
64 next_number += 1;
65
66 let mut next_num_buf = [0u8; 8];
67 if arbos_version >= 8 {
68 next_num_buf.copy_from_slice(&next_number.to_le_bytes());
69 }
70
71 let mut combined = Vec::with_capacity(40);
72 combined.extend_from_slice(block_hash.as_slice());
73 combined.extend_from_slice(&next_num_buf);
74 let fill = keccak256(&combined);
75
76 self.backing_storage
77 .set_by_uint64(1 + (next_number % 256), fill)?;
78 }
79
80 self.backing_storage
81 .set_by_uint64(1 + (number % 256), block_hash)?;
82 Ok(self.l1_block_number.set(backend, number + 1)?)
83 }
84}