use std::array::TryFromSliceError;
use fil_actor_evm_shared_v11::uints::U256;
use fvm_shared3::ActorID;
use cid::Cid;
use fvm_ipld_encoding::strict_bytes;
use fvm_ipld_encoding::tuple::*;
use serde::{Deserialize, Serialize};
use serde_tuple::{Deserialize_tuple, Serialize_tuple};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize_tuple, Deserialize_tuple)]
pub struct Tombstone {
pub origin: ActorID,
pub nonce: u64,
}
#[derive(Deserialize, Serialize, Clone, Copy, Eq, PartialEq)]
#[serde(transparent)]
pub struct BytecodeHash(#[serde(with = "strict_bytes")] [u8; 32]);
impl std::fmt::Debug for BytecodeHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("BytecodeHash")
.field(&format_args!("{}", self))
.finish()
}
}
impl std::fmt::Display for BytecodeHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
write!(f, "0x")?;
}
for b in self.0 {
write!(f, "{b:02X}")?;
}
Ok(())
}
}
impl BytecodeHash {
pub const ZERO: Self = Self([0; 32]);
pub const NATIVE_ACTOR: Self = Self(hex_literal::hex!(
"bcc90f2d6dada5b18e155c17a1c0a55920aae94f39857d39d0d8ed07ae8f228b"
));
pub const EMPTY: Self = Self(hex_literal::hex!(
"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
));
pub fn as_slice(&self) -> &[u8] {
&self.0
}
}
impl From<[u8; 32]> for BytecodeHash {
fn from(digest: [u8; 32]) -> Self {
BytecodeHash(digest)
}
}
impl From<BytecodeHash> for [u8; 32] {
fn from(digest: BytecodeHash) -> Self {
digest.0
}
}
impl From<BytecodeHash> for Vec<u8> {
fn from(digest: BytecodeHash) -> Self {
digest.0.into()
}
}
impl From<BytecodeHash> for U256 {
fn from(bytecode: BytecodeHash) -> Self {
let bytes: [u8; 32] = bytecode.into();
Self::from(bytes)
}
}
impl TryFrom<&[u8]> for BytecodeHash {
type Error = TryFromSliceError;
fn try_from(value: &[u8]) -> Result<Self, TryFromSliceError> {
Ok(Self(value.try_into()?))
}
}
#[derive(Debug, Serialize_tuple, Deserialize_tuple)]
pub struct State {
pub bytecode: Cid,
pub bytecode_hash: BytecodeHash,
pub contract_state: Cid,
pub nonce: u64,
pub tombstone: Option<Tombstone>,
}
#[cfg(test)]
mod test {
use fvm_ipld_encoding::{from_slice, to_vec, BytesDe};
use crate::BytecodeHash;
#[test]
fn test_bytecode_hash_serde() {
let encoded = to_vec(&BytecodeHash::EMPTY).unwrap();
let BytesDe(decoded) = from_slice(&encoded).unwrap();
assert_eq!(
BytecodeHash::try_from(&decoded[..]).unwrap(),
BytecodeHash::EMPTY
);
}
#[test]
fn test_bytecode_hash_format() {
assert_eq!(
BytecodeHash::ZERO.to_string(),
"0000000000000000000000000000000000000000000000000000000000000000"
);
assert_eq!(
format!("{:#}", BytecodeHash::ZERO),
"0x0000000000000000000000000000000000000000000000000000000000000000"
);
assert_eq!(
format!("{:?}", BytecodeHash::ZERO),
"BytecodeHash(0000000000000000000000000000000000000000000000000000000000000000)"
);
}
}