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