arbos/blockhash/
mod.rs

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    // no-op: next_block_number is already zero
15}
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}