alloy_trie/nodes/
rlp.rs

1use alloy_primitives::{hex, keccak256, B256};
2use alloy_rlp::EMPTY_STRING_CODE;
3use arrayvec::ArrayVec;
4use core::fmt;
5
6const MAX: usize = 33;
7
8/// An RLP-encoded node.
9#[derive(Clone, Default, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct RlpNode(ArrayVec<u8, MAX>);
12
13impl alloy_rlp::Decodable for RlpNode {
14    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
15        let bytes = alloy_rlp::Header::decode_bytes(buf, false)?;
16        Self::from_raw_rlp(bytes)
17    }
18}
19
20impl core::ops::Deref for RlpNode {
21    type Target = [u8];
22
23    #[inline]
24    fn deref(&self) -> &Self::Target {
25        &self.0
26    }
27}
28
29impl core::ops::DerefMut for RlpNode {
30    #[inline]
31    fn deref_mut(&mut self) -> &mut Self::Target {
32        &mut self.0
33    }
34}
35
36impl AsRef<[u8]> for RlpNode {
37    #[inline]
38    fn as_ref(&self) -> &[u8] {
39        &self.0
40    }
41}
42
43impl fmt::Debug for RlpNode {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(f, "RlpNode({})", hex::encode_prefixed(&self.0))
46    }
47}
48
49impl RlpNode {
50    /// Creates a new RLP-encoded node from the given data.
51    ///
52    /// Returns `None` if the data is too large (greater than 33 bytes).
53    #[inline]
54    pub fn from_raw(data: &[u8]) -> Option<Self> {
55        let mut arr = ArrayVec::new();
56        arr.try_extend_from_slice(data).ok()?;
57        Some(Self(arr))
58    }
59
60    /// Creates a new RLP-encoded node from the given data.
61    #[inline]
62    pub fn from_raw_rlp(data: &[u8]) -> alloy_rlp::Result<Self> {
63        Self::from_raw(data).ok_or(alloy_rlp::Error::Custom("RLP node too large"))
64    }
65
66    /// Given an RLP-encoded node, returns it either as `rlp(node)` or `rlp(keccak(rlp(node)))`.
67    #[doc(alias = "rlp_node")]
68    #[inline]
69    pub fn from_rlp(rlp: &[u8]) -> Self {
70        if rlp.len() < 32 {
71            // SAFETY: `rlp` is less than max capacity (33).
72            unsafe { Self::from_raw(rlp).unwrap_unchecked() }
73        } else {
74            Self::word_rlp(&keccak256(rlp))
75        }
76    }
77
78    /// RLP-encodes the given word and returns it as a new RLP node.
79    #[inline]
80    pub fn word_rlp(word: &B256) -> Self {
81        let mut arr = [0u8; 33];
82        arr[0] = EMPTY_STRING_CODE + 32;
83        arr[1..].copy_from_slice(word.as_slice());
84        Self(ArrayVec::from(arr))
85    }
86
87    /// Returns true if this is an RLP-encoded hash.
88    #[inline]
89    pub fn is_hash(&self) -> bool {
90        self.len() == B256::len_bytes() + 1
91    }
92
93    /// Returns the RLP-encoded node as a slice.
94    #[inline]
95    pub fn as_slice(&self) -> &[u8] {
96        &self.0
97    }
98
99    /// Returns hash if this is an RLP-encoded hash
100    #[inline]
101    pub fn as_hash(&self) -> Option<B256> {
102        if self.is_hash() {
103            Some(B256::from_slice(&self.0[1..]))
104        } else {
105            None
106        }
107    }
108}
109
110#[cfg(feature = "arbitrary")]
111impl<'u> arbitrary::Arbitrary<'u> for RlpNode {
112    fn arbitrary(g: &mut arbitrary::Unstructured<'u>) -> arbitrary::Result<Self> {
113        let len = g.int_in_range(0..=MAX)?;
114        let mut arr = ArrayVec::new();
115        arr.try_extend_from_slice(g.bytes(len)?).unwrap();
116        Ok(Self(arr))
117    }
118}
119
120#[cfg(feature = "arbitrary")]
121impl proptest::arbitrary::Arbitrary for RlpNode {
122    type Parameters = ();
123    type Strategy = proptest::strategy::BoxedStrategy<Self>;
124
125    fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
126        use proptest::prelude::*;
127        proptest::collection::vec(proptest::prelude::any::<u8>(), 0..=MAX)
128            .prop_map(|vec| Self::from_raw(&vec).unwrap())
129            .boxed()
130    }
131}