alloy_trie/
account.rs

1use crate::{EMPTY_ROOT_HASH, KECCAK_EMPTY};
2use alloy_primitives::{keccak256, B256, U256};
3use alloy_rlp::{RlpDecodable, RlpEncodable};
4
5/// Represents an TrieAccount in the account trie.
6#[derive(Copy, Clone, Debug, PartialEq, Eq, RlpDecodable, RlpEncodable)]
7#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
10pub struct TrieAccount {
11    /// The account's nonce.
12    #[cfg_attr(feature = "serde", serde(with = "quantity"))]
13    pub nonce: u64,
14    /// The account's balance.
15    pub balance: U256,
16    /// The hash of the storage account data.
17    pub storage_root: B256,
18    /// The hash of the code of the account.
19    pub code_hash: B256,
20}
21
22impl Default for TrieAccount {
23    fn default() -> Self {
24        Self {
25            nonce: 0,
26            balance: U256::ZERO,
27            storage_root: EMPTY_ROOT_HASH,
28            code_hash: KECCAK_EMPTY,
29        }
30    }
31}
32
33impl TrieAccount {
34    /// Compute  hash as committed to in the MPT trie without memorizing.
35    pub fn trie_hash_slow(&self) -> B256 {
36        keccak256(alloy_rlp::encode(self))
37    }
38}
39
40#[cfg(feature = "serde")]
41mod quantity {
42    use alloy_primitives::U64;
43    use serde::{Deserialize, Deserializer, Serialize, Serializer};
44
45    /// Serializes a primitive number as a "quantity" hex string.
46    pub(crate) fn serialize<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
47    where
48        S: Serializer,
49    {
50        U64::from(*value).serialize(serializer)
51    }
52
53    /// Deserializes a primitive number from a "quantity" hex string.
54    pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
55    where
56        D: Deserializer<'de>,
57    {
58        U64::deserialize(deserializer).map(|value| value.to())
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use alloy_primitives::{hex, U256};
66    use alloy_rlp::Decodable;
67
68    #[test]
69    fn test_account_encoding() {
70        let account = TrieAccount {
71            nonce: 1,
72            balance: U256::from(1000),
73            storage_root: B256::from_slice(&hex!(
74                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
75            )),
76            code_hash: keccak256(hex!("5a465a905090036002900360015500")),
77        };
78
79        let encoded = alloy_rlp::encode(account);
80
81        let decoded = TrieAccount::decode(&mut &encoded[..]).unwrap();
82        assert_eq!(account, decoded);
83    }
84
85    #[test]
86    fn test_trie_hash_slow() {
87        let account = TrieAccount {
88            nonce: 1,
89            balance: U256::from(1000),
90            storage_root: B256::from_slice(&hex!(
91                "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
92            )),
93            code_hash: keccak256(hex!("5a465a905090036002900360015500")),
94        };
95
96        let expected_hash = keccak256(alloy_rlp::encode(account));
97        let actual_hash = account.trie_hash_slow();
98        assert_eq!(expected_hash, actual_hash);
99    }
100}