1use std::collections::BTreeMap;
2use std::sync::{Arc, LazyLock};
3
4use bytes::{BufMut, Bytes};
5use ethereum_types::{H256, U256};
6use ethrex_crypto::{Crypto, NativeCrypto};
7use ethrex_trie::Trie;
8use rustc_hash::FxHashMap;
9use serde::{Deserialize, Serialize};
10
11use ethrex_rlp::{
12 decode::RLPDecode,
13 encode::RLPEncode,
14 error::RLPDecodeError,
15 structs::{Decoder, Encoder},
16};
17
18use super::GenesisAccount;
19use crate::constants::{EMPTY_KECCAK_HASH, EMPTY_TRIE_HASH};
20
21static EMPTY_JUMP_TARGETS: LazyLock<Arc<[u32]>> = LazyLock::new(|| Arc::from(Vec::new()));
26
27pub const BYTECODE_PADDING: usize = 33;
32
33#[derive(Clone, Debug, PartialEq, Eq, Hash)]
34pub struct Code {
35 pub hash: H256,
41 bytecode: Bytes,
43 bytecode_len: usize,
45 pub jump_targets: Arc<[u32]>,
52}
53
54impl Code {
55 pub fn from_bytecode_unchecked(code: Bytes, hash: H256) -> Self {
62 let jump_targets = Self::compute_jump_targets(&code);
63 Self::from_parts_unchecked(hash, &code, jump_targets)
64 }
65
66 pub fn from_bytecode(code: Bytes, crypto: &dyn Crypto) -> Self {
69 let jump_targets = Self::compute_jump_targets(&code);
70 let hash = H256(crypto.keccak256(code.as_ref()));
71 Self::from_parts_unchecked(hash, &code, jump_targets)
72 }
73
74 pub fn from_parts_unchecked(hash: H256, code: &[u8], jump_targets: Arc<[u32]>) -> Self {
82 let bytecode_len = code.len();
83 let mut padded_code = Vec::with_capacity(bytecode_len + BYTECODE_PADDING);
84 padded_code.extend_from_slice(code);
85 padded_code.extend_from_slice(&[0u8; BYTECODE_PADDING]);
86 Self {
87 hash,
88 bytecode: Bytes::from_owner(padded_code),
89 bytecode_len,
90 jump_targets,
91 }
92 }
93
94 fn compute_jump_targets(code: &[u8]) -> Arc<[u32]> {
95 debug_assert!(code.len() <= u32::MAX as usize);
96 let mut targets = Vec::new();
97 let mut i = 0;
98 while i < code.len() {
99 match code[i] {
101 0x5B => {
103 targets.push(i as u32);
104 }
105 c @ 0x60..0x80 => {
107 i += (c - 0x5F) as usize;
109 }
110 _ => (),
111 }
112 i += 1;
113 }
114 if targets.is_empty() {
117 EMPTY_JUMP_TARGETS.clone()
118 } else {
119 Arc::from(targets)
120 }
121 }
122
123 #[inline]
124 pub fn code(&self) -> &[u8] {
125 self.bytecode.get(..self.bytecode_len).unwrap_or_default()
126 }
127
128 #[inline]
129 pub fn code_bytes(&self) -> Bytes {
130 self.bytecode.slice(..self.bytecode_len)
131 }
132
133 #[inline]
134 pub fn len(&self) -> usize {
135 self.bytecode_len
136 }
137
138 #[inline]
139 pub fn is_empty(&self) -> bool {
140 self.bytecode_len == 0
141 }
142
143 #[inline]
147 pub fn dispatch_buf(&self) -> &[u8] {
148 &self.bytecode
149 }
150
151 pub fn size(&self) -> usize {
160 let hash_size = size_of::<H256>();
161 let bytes_size = size_of::<Bytes>();
162 let vec_size = size_of::<Arc<[u32]>>() + self.jump_targets.len() * size_of::<u32>();
163 hash_size + bytes_size + vec_size
164 }
165}
166
167#[derive(Serialize, Deserialize)]
174struct CodeSerde {
175 hash: H256,
176 code: Bytes,
177 jump_targets: Arc<[u32]>,
178}
179
180impl Serialize for Code {
181 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
182 CodeSerde {
183 hash: self.hash,
184 code: self.code_bytes(),
185 jump_targets: self.jump_targets.clone(),
186 }
187 .serialize(serializer)
188 }
189}
190
191impl<'de> Deserialize<'de> for Code {
192 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
193 let CodeSerde {
194 hash,
195 code,
196 jump_targets,
197 } = CodeSerde::deserialize(deserializer)?;
198 Ok(Self::from_parts_unchecked(hash, &code, jump_targets))
199 }
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
203pub struct CodeMetadata {
204 pub length: u64,
205}
206
207#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
208pub struct Account {
209 pub info: AccountInfo,
210 pub code: Code,
211 pub storage: FxHashMap<H256, U256>,
212}
213
214#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
215pub struct AccountInfo {
216 pub code_hash: H256,
217 pub balance: U256,
218 pub nonce: u64,
219}
220
221#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
222pub struct AccountState {
223 pub nonce: u64,
224 pub balance: U256,
225 pub storage_root: H256,
226 pub code_hash: H256,
227}
228
229#[derive(Clone, Copy, Debug, Default, PartialEq)]
237pub struct AccountStateSlimCodec(pub AccountState);
238
239impl Default for AccountInfo {
240 fn default() -> Self {
241 Self {
242 code_hash: *EMPTY_KECCAK_HASH,
243 balance: Default::default(),
244 nonce: Default::default(),
245 }
246 }
247}
248
249impl Default for AccountState {
250 fn default() -> Self {
251 Self {
252 nonce: Default::default(),
253 balance: Default::default(),
254 storage_root: *EMPTY_TRIE_HASH,
255 code_hash: *EMPTY_KECCAK_HASH,
256 }
257 }
258}
259
260impl Default for Code {
261 fn default() -> Self {
262 Self {
263 bytecode: Bytes::from_static(&[0u8; BYTECODE_PADDING]),
264 bytecode_len: 0,
265 hash: *EMPTY_KECCAK_HASH,
266 jump_targets: EMPTY_JUMP_TARGETS.clone(),
267 }
268 }
269}
270
271impl From<GenesisAccount> for Account {
272 fn from(genesis: GenesisAccount) -> Self {
273 let code = Code::from_bytecode(genesis.code, &NativeCrypto);
274 Self {
275 info: AccountInfo {
276 code_hash: code.hash,
277 balance: genesis.balance,
278 nonce: genesis.nonce,
279 },
280 code,
281 storage: genesis
282 .storage
283 .iter()
284 .map(|(k, v)| (H256(k.to_big_endian()), *v))
285 .collect(),
286 }
287 }
288}
289
290pub fn code_hash(code: &Bytes, crypto: &dyn Crypto) -> H256 {
291 H256(crypto.keccak256(code.as_ref()))
292}
293
294pub const EIP7702_DELEGATION_PREFIX: [u8; 3] = [0xef, 0x01, 0x00];
297pub const EIP7702_DELEGATED_CODE_LEN: usize = 23;
300
301pub fn is_eip7702_delegation(code: &[u8]) -> bool {
304 code.len() == EIP7702_DELEGATED_CODE_LEN && code.starts_with(&EIP7702_DELEGATION_PREFIX)
305}
306
307impl RLPEncode for AccountInfo {
308 fn encode(&self, buf: &mut dyn bytes::BufMut) {
309 Encoder::new(buf)
310 .encode_field(&self.code_hash)
311 .encode_field(&self.balance)
312 .encode_field(&self.nonce)
313 .finish();
314 }
315}
316
317impl RLPDecode for AccountInfo {
318 fn decode_unfinished(rlp: &[u8]) -> Result<(AccountInfo, &[u8]), RLPDecodeError> {
319 let decoder = Decoder::new(rlp)?;
320 let (code_hash, decoder) = decoder.decode_field("code_hash")?;
321 let (balance, decoder) = decoder.decode_field("balance")?;
322 let (nonce, decoder) = decoder.decode_field("nonce")?;
323 let account_info = AccountInfo {
324 code_hash,
325 balance,
326 nonce,
327 };
328 Ok((account_info, decoder.finish()?))
329 }
330}
331
332impl RLPEncode for AccountState {
333 fn encode(&self, buf: &mut dyn bytes::BufMut) {
334 Encoder::new(buf)
335 .encode_field(&self.nonce)
336 .encode_field(&self.balance)
337 .encode_field(&self.storage_root)
338 .encode_field(&self.code_hash)
339 .finish();
340 }
341}
342
343impl RLPDecode for AccountState {
344 fn decode_unfinished(rlp: &[u8]) -> Result<(AccountState, &[u8]), RLPDecodeError> {
345 let decoder = Decoder::new(rlp)?;
346 let (nonce, decoder) = decoder.decode_field("nonce")?;
347 let (balance, decoder) = decoder.decode_field("balance")?;
348 let (storage_root, decoder) = decoder.decode_field("storage_root")?;
349 let (code_hash, decoder) = decoder.decode_field("code_hash")?;
350 let state = AccountState {
351 nonce,
352 balance,
353 storage_root,
354 code_hash,
355 };
356 Ok((state, decoder.finish()?))
357 }
358}
359
360impl RLPEncode for AccountStateSlimCodec {
361 fn encode(&self, buf: &mut dyn BufMut) {
362 struct StorageRootCodec<'a>(&'a H256);
363 impl RLPEncode for StorageRootCodec<'_> {
364 fn encode(&self, buf: &mut dyn BufMut) {
365 let data = if *self.0 != *EMPTY_TRIE_HASH {
366 self.0.as_bytes()
367 } else {
368 &[]
369 };
370
371 data.encode(buf);
372 }
373 }
374
375 struct CodeHashCodec<'a>(&'a H256);
376 impl RLPEncode for CodeHashCodec<'_> {
377 fn encode(&self, buf: &mut dyn BufMut) {
378 let data = if *self.0 != *EMPTY_KECCAK_HASH {
379 self.0.as_bytes()
380 } else {
381 &[]
382 };
383
384 data.encode(buf);
385 }
386 }
387
388 Encoder::new(buf)
389 .encode_field(&self.0.nonce)
390 .encode_field(&self.0.balance)
391 .encode_field(&StorageRootCodec(&self.0.storage_root))
392 .encode_field(&CodeHashCodec(&self.0.code_hash))
393 .finish();
394 }
395}
396
397impl RLPDecode for AccountStateSlimCodec {
398 fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
399 struct StorageRootCodec(H256);
400 impl RLPDecode for StorageRootCodec {
401 fn decode_unfinished(mut rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
402 let value = match rlp.split_off_first() {
403 Some(0x80) => *EMPTY_TRIE_HASH,
404 Some(0xA0) => {
405 let data;
406 (data, rlp) = rlp
407 .split_first_chunk::<32>()
408 .ok_or(RLPDecodeError::InvalidLength)?;
409 H256(*data)
410 }
411 _ => return Err(RLPDecodeError::InvalidLength),
412 };
413
414 Ok((Self(value), rlp))
415 }
416 }
417
418 struct CodeHashCodec(H256);
419 impl RLPDecode for CodeHashCodec {
420 fn decode_unfinished(mut rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
421 let value = match rlp.split_off_first() {
422 Some(0x80) => *EMPTY_KECCAK_HASH,
423 Some(0xA0) => {
424 let data;
425 (data, rlp) = rlp
426 .split_first_chunk::<32>()
427 .ok_or(RLPDecodeError::InvalidLength)?;
428 H256(*data)
429 }
430 _ => return Err(RLPDecodeError::InvalidLength),
431 };
432
433 Ok((Self(value), rlp))
434 }
435 }
436
437 let decoder = Decoder::new(rlp)?;
438 let (nonce, decoder) = decoder.decode_field("nonce")?;
439 let (balance, decoder) = decoder.decode_field("balance")?;
440 let (StorageRootCodec(storage_root), decoder) = decoder.decode_field("storage_root")?;
441 let (CodeHashCodec(code_hash), decoder) = decoder.decode_field("code_hash")?;
442
443 Ok((
444 Self(AccountState {
445 nonce,
446 balance,
447 storage_root,
448 code_hash,
449 }),
450 decoder.finish()?,
451 ))
452 }
453}
454
455pub fn compute_storage_root(storage: &BTreeMap<U256, U256>, crypto: &dyn Crypto) -> H256 {
456 let iter = storage.iter().filter_map(|(k, v)| {
457 (!v.is_zero()).then_some((
458 crypto.keccak256(&k.to_big_endian()).to_vec(),
459 v.encode_to_vec(),
460 ))
461 });
462 Trie::compute_hash_from_unsorted_iter(iter, crypto)
463}
464
465impl From<&GenesisAccount> for AccountState {
466 fn from(value: &GenesisAccount) -> Self {
467 AccountState {
468 nonce: value.nonce,
469 balance: value.balance,
470 storage_root: compute_storage_root(&value.storage, &NativeCrypto),
471 code_hash: code_hash(&value.code, &NativeCrypto),
472 }
473 }
474}
475
476impl Account {
477 pub fn new(balance: U256, code: Code, nonce: u64, storage: FxHashMap<H256, U256>) -> Self {
478 Self {
479 info: AccountInfo {
480 balance,
481 code_hash: code.hash,
482 nonce,
483 },
484 code,
485 storage,
486 }
487 }
488}
489
490impl AccountInfo {
491 pub fn is_empty(&self) -> bool {
492 self.balance.is_zero() && self.nonce == 0 && self.code_hash == *EMPTY_KECCAK_HASH
493 }
494}
495
496#[cfg(test)]
497mod test {
498 use std::str::FromStr;
499
500 use super::*;
501
502 #[test]
503 fn test_code_hash() {
504 let empty_code = Bytes::new();
505 let hash = code_hash(&empty_code, &NativeCrypto);
506 assert_eq!(
507 hash,
508 H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
509 .unwrap()
510 )
511 }
512
513 #[test]
514 fn test_is_eip7702_delegation_valid() {
515 let mut code = Vec::with_capacity(23);
517 code.extend_from_slice(&EIP7702_DELEGATION_PREFIX);
518 code.extend_from_slice(&[0x42; 20]);
519 assert!(is_eip7702_delegation(&code));
520 }
521
522 #[test]
523 fn test_is_eip7702_delegation_rejects_empty() {
524 assert!(!is_eip7702_delegation(&[]));
525 }
526
527 #[test]
528 fn test_is_eip7702_delegation_rejects_short() {
529 assert!(!is_eip7702_delegation(&EIP7702_DELEGATION_PREFIX));
531 }
532
533 #[test]
534 fn test_is_eip7702_delegation_rejects_long() {
535 let mut code = Vec::with_capacity(24);
537 code.extend_from_slice(&EIP7702_DELEGATION_PREFIX);
538 code.extend_from_slice(&[0x42; 21]);
539 assert!(!is_eip7702_delegation(&code));
540 }
541
542 #[test]
543 fn test_is_eip7702_delegation_rejects_wrong_prefix() {
544 let mut code = Vec::with_capacity(23);
546 code.extend_from_slice(&[0xef, 0x01, 0x01]); code.extend_from_slice(&[0x42; 20]);
548 assert!(!is_eip7702_delegation(&code));
549 }
550
551 #[test]
552 fn test_is_eip7702_delegation_rejects_arbitrary_contract_code() {
553 let code = vec![0x60, 0x60, 0x60, 0x40, 0x52 ];
555 assert!(!is_eip7702_delegation(&code));
556 }
557}