revm_rwasm_bytecode/
ownable_account.rs

1use core::fmt;
2use primitives::{b256, bytes, Address, Bytes, B256};
3
4/// Hash of EF44 bytes that is used for EXTCODEHASH when called from legacy bytecode.
5pub const OWNABLE_ACCOUNT_MAGIC_HASH: B256 =
6    b256!("0x85160e14613bd11c0e87050b7f84bbea3095f7f0ccd58026f217fdff9043c16b");
7
8/// Version Magic in u16 form
9pub const OWNABLE_ACCOUNT_MAGIC: u16 = 0xEF44;
10
11/// Magic number in array form
12pub static OWNABLE_ACCOUNT_MAGIC_BYTES: Bytes = bytes!("ef44");
13
14/// First version of metadata
15pub const OWNABLE_ACCOUNT_VERSION: u8 = 0;
16
17/// Ownable account bytecode representation
18///
19/// Format consists of:
20/// `0xEF44` (MAGIC) + `0x00` (VERSION) + 20 bytes of address.
21#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct OwnableAccountBytecode {
24    /// Address of the delegated account.
25    pub owner_address: Address,
26    /// Version. Currently, only version 0 is supported.
27    pub version: u8,
28    /// Metadata. Extra bytes stored by runtime.
29    pub metadata: Bytes,
30    /// Raw bytecode.
31    pub raw: Bytes,
32}
33
34impl OwnableAccountBytecode {
35    /// Creates a new metadata representation or returns None if the metadata is invalid.
36    #[inline]
37    pub fn new_raw(raw: Bytes) -> Result<Self, OwnableAccountDecodeError> {
38        if raw.len() < 23 {
39            return Err(OwnableAccountDecodeError::InvalidLength);
40        } else if !raw.starts_with(&OWNABLE_ACCOUNT_MAGIC_BYTES) {
41            return Err(OwnableAccountDecodeError::InvalidMagic);
42        }
43        // The only supported version is version 0.
44        if raw[2] != OWNABLE_ACCOUNT_VERSION {
45            return Err(OwnableAccountDecodeError::UnsupportedVersion);
46        }
47        Ok(Self {
48            owner_address: Address::new(raw[3..23].try_into().unwrap()),
49            version: OWNABLE_ACCOUNT_VERSION,
50            metadata: raw.slice(23..),
51            raw,
52        })
53    }
54
55    /// Creates a new metadata representation with the given address.
56    pub fn new(address: Address, metadata: Bytes) -> Self {
57        let mut raw = OWNABLE_ACCOUNT_MAGIC_BYTES.to_vec();
58        raw.push(OWNABLE_ACCOUNT_VERSION);
59        raw.extend(&address);
60        raw.extend(&metadata);
61        Self {
62            owner_address: address,
63            version: OWNABLE_ACCOUNT_VERSION,
64            metadata,
65            raw: raw.into(),
66        }
67    }
68
69    /// Returns the raw metadata with version MAGIC number.
70    #[inline]
71    pub fn metadata(&self) -> &Bytes {
72        &self.metadata
73    }
74
75    /// Returns the address of the delegated contract.
76    #[inline]
77    pub fn owner(&self) -> Address {
78        self.owner_address
79    }
80
81    /// Returns the raw bytecode with version MAGIC number.
82    #[inline]
83    pub fn raw(&self) -> &Bytes {
84        &self.raw
85    }
86}
87
88/// Bytecode errors
89#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91pub enum OwnableAccountDecodeError {
92    /// Invalid length of the raw bytecode
93    ///
94    /// It should be 23 bytes.
95    InvalidLength,
96    /// Invalid magic number
97    ///
98    /// All metadata should start with the magic number 0xEF44.
99    InvalidMagic,
100    /// Unsupported version
101    ///
102    /// The only supported version is version 0x00
103    UnsupportedVersion,
104}
105
106impl fmt::Display for OwnableAccountDecodeError {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        let s = match self {
109            Self::InvalidLength => "Metadata is not 23 bytes long",
110            Self::InvalidMagic => "Metadata is not starting with 0xEF44",
111            Self::UnsupportedVersion => "Unsupported Metadata version.",
112        };
113        f.write_str(s)
114    }
115}
116
117impl core::error::Error for OwnableAccountDecodeError {}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122    use primitives::keccak256;
123
124    #[test]
125    fn magic_bytes_hash_check() {
126        let result = keccak256(&OWNABLE_ACCOUNT_MAGIC_BYTES);
127        assert_eq!(OWNABLE_ACCOUNT_MAGIC_HASH.as_slice(), result.as_slice());
128    }
129
130    #[test]
131    fn sanity_decode() {
132        let metadata = bytes!("ef44deadbeef");
133        assert_eq!(
134            OwnableAccountBytecode::new_raw(metadata),
135            Err(OwnableAccountDecodeError::InvalidLength)
136        );
137        let metadata = bytes!("ef4401deadbeef00000000000000000000000000000000");
138        assert_eq!(
139            OwnableAccountBytecode::new_raw(metadata),
140            Err(OwnableAccountDecodeError::UnsupportedVersion)
141        );
142        let raw = bytes!("ef4400deadbeef00000000000000000000000000000000");
143        let address = raw[3..].try_into().unwrap();
144        assert_eq!(
145            OwnableAccountBytecode::new_raw(raw.clone()),
146            Ok(OwnableAccountBytecode {
147                owner_address: address,
148                version: 0,
149                metadata: raw.slice(23..),
150                raw,
151            })
152        );
153    }
154
155    #[test]
156    fn create_metadata_from_address() {
157        let address = Address::new([0x01; 20]);
158        let bytecode = OwnableAccountBytecode::new(address, bytes!("0102030405"));
159        assert_eq!(bytecode.owner_address, address);
160        assert_eq!(bytecode.metadata, bytes!("0102030405"));
161    }
162}