use alloy_primitives::{B256, Keccak256, U256};
#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[cfg(feature = "serde")]
use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
use crate::errors::PreimageOracleError;
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(u8)]
#[cfg_attr(
feature = "rkyv",
derive(Archive, RkyvSerialize, RkyvDeserialize),
rkyv(derive(Eq, PartialEq, Ord, PartialOrd, Hash))
)]
#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
pub enum PreimageKeyType {
Local = 1,
#[default]
Keccak256 = 2,
GlobalGeneric = 3,
Sha256 = 4,
Blob = 5,
Precompile = 6,
}
impl TryFrom<u8> for PreimageKeyType {
type Error = PreimageOracleError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
let key_type = match value {
1 => Self::Local,
2 => Self::Keccak256,
3 => Self::GlobalGeneric,
4 => Self::Sha256,
5 => Self::Blob,
6 => Self::Precompile,
_ => return Err(PreimageOracleError::InvalidPreimageKey),
};
Ok(key_type)
}
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(
feature = "rkyv",
derive(Archive, RkyvSerialize, RkyvDeserialize),
rkyv(derive(Eq, PartialEq, Ord, PartialOrd, Hash))
)]
#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
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 new_keccak256(digest: [u8; 32]) -> Self {
Self::new(digest, PreimageKeyType::Keccak256)
}
pub fn new_precompile(precompile_addr: [u8; 20], input: &[u8]) -> Self {
let mut data = [0u8; 31];
let mut hasher = Keccak256::new();
hasher.update(precompile_addr);
hasher.update(input);
data.copy_from_slice(&hasher.finalize()[1..]);
Self { data, key_type: PreimageKeyType::Precompile }
}
pub const fn key_type(&self) -> PreimageKeyType {
self.key_type
}
pub const 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();
Self::from(raw)
}
}
impl TryFrom<[u8; 32]> for PreimageKey {
type Error = PreimageOracleError;
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_key_from_u8() {
assert_eq!(PreimageKeyType::try_from(1).unwrap(), PreimageKeyType::Local);
assert_eq!(PreimageKeyType::try_from(2).unwrap(), PreimageKeyType::Keccak256);
assert_eq!(PreimageKeyType::try_from(3).unwrap(), PreimageKeyType::GlobalGeneric);
assert_eq!(PreimageKeyType::try_from(4).unwrap(), PreimageKeyType::Sha256);
assert_eq!(PreimageKeyType::try_from(5).unwrap(), PreimageKeyType::Blob);
assert_eq!(PreimageKeyType::try_from(6).unwrap(), PreimageKeyType::Precompile);
assert!(PreimageKeyType::try_from(0).is_err());
assert!(PreimageKeyType::try_from(7).is_err());
}
#[test]
fn test_preimage_key_new_local() {
let key = PreimageKey::new_local(0xFFu64);
assert_eq!(key.key_type(), PreimageKeyType::Local);
assert_eq!(key.key_value(), U256::from(0xFFu64));
}
#[test]
fn test_preimage_key_value() {
let key = PreimageKey::new([0xFFu8; 32], PreimageKeyType::Local);
assert_eq!(
key.key_value(),
alloy_primitives::uint!(
452312848583266388373324160190187140051835877600158453279131187530910662655_U256
)
);
}
#[test]
fn test_preimage_key_roundtrip_b256() {
let key = PreimageKey::new([0xFFu8; 32], PreimageKeyType::Local);
let b256: B256 = key.into();
let key2 = PreimageKey::try_from(<[u8; 32]>::from(b256)).unwrap();
assert_eq!(key, key2);
}
#[test]
fn test_preimage_key_display() {
let key = PreimageKey::new([0xFFu8; 32], PreimageKeyType::Local);
assert_eq!(
key.to_string(),
"0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
}
#[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);
}
}
}