trevm 0.33.1

A typestate API wrapper for the revm EVM implementation
Documentation
use crate::journal::{BundleStateIndex, JournalDecode, JournalDecodeError, JournalEncode};
use alloy::primitives::{keccak256, Bytes, B256};
use std::sync::OnceLock;

/// Journal associated with a block
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlockUpdate<'a> {
    /// The height of the block.
    height: u64,

    /// The previous journal hash.
    prev_journal_hash: B256,

    /// The indexed changes.
    journal: BundleStateIndex<'a>,

    /// The serialized journal
    serialized: OnceLock<Bytes>,

    /// The hash of the serialized journal
    hash: OnceLock<B256>,
}

impl<'a> BlockUpdate<'a> {
    /// Create a new block update.
    pub const fn new(height: u64, prev_journal_hash: B256, journal: BundleStateIndex<'a>) -> Self {
        Self {
            height,
            prev_journal_hash,
            journal,
            serialized: OnceLock::new(),
            hash: OnceLock::new(),
        }
    }

    /// Get the height of the block.
    pub const fn height(&self) -> u64 {
        self.height
    }

    /// Get the previous journal hash.
    pub const fn prev_journal_hash(&self) -> B256 {
        self.prev_journal_hash
    }

    /// Get the journal index.
    pub const fn journal(&self) -> &BundleStateIndex<'a> {
        &self.journal
    }

    /// Decompose the block update into its parts.
    pub fn into_parts(self) -> (u64, B256, BundleStateIndex<'a>) {
        (self.height, self.prev_journal_hash, self.journal)
    }

    /// Serialize the block update.
    pub fn serialized(&self) -> &[u8] {
        self.serialized.get_or_init(|| JournalEncode::encoded(self)).as_ref()
    }

    /// Serialize and hash the block update.
    pub fn journal_hash(&self) -> B256 {
        *self.hash.get_or_init(|| keccak256(self.serialized()))
    }
}

impl JournalEncode for BlockUpdate<'_> {
    fn serialized_size(&self) -> usize {
        8 + 32 + self.journal.serialized_size()
    }

    fn encode(&self, buf: &mut dyn alloy::rlp::BufMut) {
        self.height.encode(buf);
        self.prev_journal_hash.encode(buf);
        self.journal.encode(buf);
    }
}

impl JournalDecode for BlockUpdate<'static> {
    fn decode(buf: &mut &[u8]) -> Result<Self, JournalDecodeError> {
        let original = *buf;
        let height = JournalDecode::decode(buf)?;
        let prev_journal_hash = JournalDecode::decode(buf)?;
        let journal = JournalDecode::decode(buf)?;

        let bytes_read = original.len() - buf.len();
        let original = &original[..bytes_read];

        Ok(Self {
            height,
            prev_journal_hash,
            journal,
            serialized: OnceLock::from(Bytes::copy_from_slice(original)),
            hash: OnceLock::from(keccak256(original)),
        })
    }
}