use alloy_primitives::{B256, U256};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[repr(u8)]
pub enum PreimageKeyType {
Local = 1,
#[default]
Keccak256 = 2,
GlobalGeneric = 3,
Sha256 = 4,
Blob = 5,
Precompile = 6,
}
impl TryFrom<u8> for PreimageKeyType {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
1 => PreimageKeyType::Local,
2 => PreimageKeyType::Keccak256,
3 => PreimageKeyType::GlobalGeneric,
4 => PreimageKeyType::Sha256,
5 => PreimageKeyType::Blob,
6 => PreimageKeyType::Precompile,
_ => anyhow::bail!("Invalid preimage key type"),
})
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
pub struct PreimageKey {
data: [u8; 31],
key_type: PreimageKeyType,
}
impl PreimageKey {
pub fn new(key: [u8; 32], key_type: PreimageKeyType) -> Self {
let mut data = [0u8; 31];
data.copy_from_slice(&key[1..]);
Self { data, key_type }
}
pub fn new_local(local_ident: u64) -> Self {
let mut data = [0u8; 31];
data[23..].copy_from_slice(&local_ident.to_be_bytes());
Self { data, key_type: PreimageKeyType::Local }
}
pub fn key_type(&self) -> PreimageKeyType {
self.key_type
}
pub fn key_value(&self) -> U256 {
U256::from_be_slice(self.data.as_slice())
}
}
impl From<PreimageKey> for [u8; 32] {
fn from(key: PreimageKey) -> Self {
let mut rendered_key = [0u8; 32];
rendered_key[0] = key.key_type as u8;
rendered_key[1..].copy_from_slice(&key.data);
rendered_key
}
}
impl From<PreimageKey> for B256 {
fn from(value: PreimageKey) -> Self {
let raw: [u8; 32] = value.into();
B256::from(raw)
}
}
impl TryFrom<[u8; 32]> for PreimageKey {
type Error = anyhow::Error;
fn try_from(value: [u8; 32]) -> Result<Self, Self::Error> {
let key_type = PreimageKeyType::try_from(value[0])?;
Ok(Self::new(value, key_type))
}
}
impl core::fmt::Display for PreimageKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let raw: [u8; 32] = (*self).into();
write!(f, "{}", B256::from(raw))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_preimage_keys() {
let types = [
PreimageKeyType::Local,
PreimageKeyType::Keccak256,
PreimageKeyType::GlobalGeneric,
PreimageKeyType::Sha256,
PreimageKeyType::Blob,
PreimageKeyType::Precompile,
];
for key_type in types {
let key = PreimageKey::new([0xFFu8; 32], key_type);
assert_eq!(key.key_type(), key_type);
let mut rendered_key = [0xFFu8; 32];
rendered_key[0] = key_type as u8;
let actual: [u8; 32] = key.into();
assert_eq!(actual, rendered_key);
}
}
}