reth_db_api/models/
bal.rs1use crate::{
4 table::{Compress, Decode, Decompress, Encode},
5 DatabaseError,
6};
7use alloy_primitives::{keccak256, BlockNumber, Bytes, B256};
8use bytes::BufMut;
9use core::cmp::Ordering;
10use reth_codecs::DecompressError;
11use serde::{Deserialize, Serialize};
12
13const BLOCK_ACCESS_LIST_KEY_BYTES: usize = 8 + 32;
15
16const STORED_BLOCK_ACCESS_LIST_HASH_BYTES: usize = 32;
18
19#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
23pub struct StoredBlockAccessListKey {
24 block_number: BlockNumber,
25 block_hash: B256,
26}
27
28impl StoredBlockAccessListKey {
29 pub const fn new(block_number: BlockNumber, block_hash: B256) -> Self {
31 Self { block_number, block_hash }
32 }
33
34 pub const fn first_at_number(block_number: BlockNumber) -> Self {
36 Self::new(block_number, B256::ZERO)
37 }
38
39 pub const fn number(&self) -> BlockNumber {
41 self.block_number
42 }
43
44 pub const fn hash(&self) -> B256 {
46 self.block_hash
47 }
48}
49
50impl Ord for StoredBlockAccessListKey {
51 fn cmp(&self, other: &Self) -> Ordering {
52 self.block_number
53 .cmp(&other.block_number)
54 .then_with(|| self.block_hash.as_slice().cmp(other.block_hash.as_slice()))
55 }
56}
57
58impl PartialOrd for StoredBlockAccessListKey {
59 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
60 Some(self.cmp(other))
61 }
62}
63
64impl Encode for StoredBlockAccessListKey {
65 type Encoded = [u8; BLOCK_ACCESS_LIST_KEY_BYTES];
66
67 fn encode(self) -> Self::Encoded {
68 let mut buf = [0u8; BLOCK_ACCESS_LIST_KEY_BYTES];
69 buf[..8].copy_from_slice(&self.block_number.to_be_bytes());
70 buf[8..].copy_from_slice(self.block_hash.as_slice());
71 buf
72 }
73}
74
75impl Decode for StoredBlockAccessListKey {
76 fn decode(value: &[u8]) -> Result<Self, DatabaseError> {
77 if value.len() != BLOCK_ACCESS_LIST_KEY_BYTES {
78 return Err(DatabaseError::Decode)
79 }
80
81 let block_number =
82 u64::from_be_bytes(value[..8].try_into().map_err(|_| DatabaseError::Decode)?);
83 let block_hash = B256::decode(&value[8..])?;
84
85 Ok(Self::new(block_number, block_hash))
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
91pub struct StoredBlockAccessList {
92 hash: B256,
94 raw: Bytes,
96}
97
98impl StoredBlockAccessList {
99 pub fn new(raw: Bytes) -> Self {
101 let hash = keccak256(&raw);
102 Self::new_unchecked(hash, raw)
103 }
104
105 pub const fn new_unchecked(hash: B256, raw: Bytes) -> Self {
107 Self { hash, raw }
108 }
109
110 pub const fn hash(&self) -> B256 {
112 self.hash
113 }
114
115 pub fn into_raw(self) -> Bytes {
117 self.raw
118 }
119}
120
121impl Compress for StoredBlockAccessList {
122 type Compressed = Vec<u8>;
123
124 fn compress(self) -> Self::Compressed {
125 let mut out = Vec::with_capacity(STORED_BLOCK_ACCESS_LIST_HASH_BYTES + self.raw.len());
126 out.extend_from_slice(self.hash.as_slice());
127 out.extend_from_slice(&self.raw);
128 out
129 }
130
131 fn compress_to_buf<B: BufMut + AsMut<[u8]>>(&self, buf: &mut B) {
132 buf.put_slice(self.hash.as_slice());
133 buf.put_slice(&self.raw);
134 }
135}
136
137impl Decompress for StoredBlockAccessList {
138 fn decompress(value: &[u8]) -> Result<Self, DecompressError> {
139 if value.len() < STORED_BLOCK_ACCESS_LIST_HASH_BYTES {
140 return Err(DecompressError::new(StoredBlockAccessListDecodeError))
141 }
142
143 let hash = B256::from_slice(&value[..STORED_BLOCK_ACCESS_LIST_HASH_BYTES]);
144 let raw = Bytes::copy_from_slice(&value[STORED_BLOCK_ACCESS_LIST_HASH_BYTES..]);
145
146 Ok(Self::new_unchecked(hash, raw))
147 }
148}
149
150#[derive(Debug, derive_more::Display, derive_more::Error)]
152#[display("stored block access list value is missing its hash prefix")]
153struct StoredBlockAccessListDecodeError;
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use crate::table::{Compress, Decompress};
159
160 #[test]
161 fn key_encodes_number_first() {
162 let low_hash = B256::with_last_byte(0xff);
163 let high_hash = B256::ZERO;
164 let low_number = StoredBlockAccessListKey::new(1, low_hash).encode();
165 let high_number = StoredBlockAccessListKey::new(2, high_hash).encode();
166
167 assert!(low_number < high_number);
168 }
169
170 #[test]
171 fn key_roundtrip() {
172 let key = StoredBlockAccessListKey::new(42, B256::with_last_byte(7));
173 let encoded = key.encode();
174
175 assert_eq!(StoredBlockAccessListKey::decode(&encoded).unwrap(), key);
176 }
177
178 #[test]
179 fn stored_bal_roundtrip() {
180 let raw = Bytes::from_static(&[0xc0]);
181 let stored = StoredBlockAccessList::new(raw.clone());
182 let encoded = stored.clone().compress();
183 let decoded = StoredBlockAccessList::decompress(&encoded).unwrap();
184
185 assert_eq!(decoded, stored);
186 assert_eq!(decoded.hash(), keccak256(&raw));
187 assert_eq!(decoded.into_raw(), raw);
188 }
189
190 #[test]
191 fn stored_bal_unchecked_preserves_hash_and_raw_bytes() {
192 let hash = B256::with_last_byte(1);
193 let raw = Bytes::from_static(&[0xc0]);
194 let stored = StoredBlockAccessList::new_unchecked(hash, raw.clone());
195 let encoded = stored.compress();
196
197 assert_eq!(&encoded[..STORED_BLOCK_ACCESS_LIST_HASH_BYTES], hash.as_slice());
198 assert_eq!(&encoded[STORED_BLOCK_ACCESS_LIST_HASH_BYTES..], raw.as_ref());
199 }
200}