Skip to main content

ethrex_common/types/
account.rs

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
21/// Shared empty jumpdest bitmap. `Code::default()` and any bytecode without a
22/// `JUMPDEST` clone this (a refcount bump) instead of allocating a fresh empty
23/// `Arc` header each time. This matters because the per-tx `Code::default()`
24/// placeholder and every EOA / empty-code load would otherwise each allocate.
25static EMPTY_JUMPDESTS: LazyLock<Arc<[u8]>> = LazyLock::new(|| Arc::from(Vec::new()));
26
27/// Trailing STOP bytes appended to every bytecode so the dispatch loop can read
28/// the next opcode without a bounds check. 33 is the widest single-opcode advance
29/// (PUSH32: 1 opcode byte + 32 immediate bytes), so `pc` can never step past the
30/// padding regardless of which opcode sits at the last real byte.
31pub const BYTECODE_PADDING: usize = 33;
32
33#[derive(Clone, Debug, PartialEq, Eq, Hash)]
34pub struct Code {
35    // hash is only used for bytecodes stored in the DB, either for reading it from the DB
36    // or with the CODEHASH opcode, which needs an account address as argument and
37    // thus only accessed persisted bytecodes.
38    // We use a bogus H256::zero() value for initcodes as there is no way for the VM or
39    // endpoints to access that hash, saving one expensive Keccak hash.
40    pub hash: H256,
41    /// bytecode padded with 33 zeroes (STOP opcodes, due to PUSH32) to avoid checks on the hot path.
42    bytecode: Bytes,
43    /// The real bytecode length, needed for some opcodes, `bytecode` is padded with 33 STOPs to avoid checked adds on hot loop.
44    bytecode_len: usize,
45    /// One bit per bytecode byte, set when that offset holds a `JUMPDEST` that is not
46    /// part of a `PUSH` immediate. Costs `ceil(len / 8)` bytes regardless of how dense
47    /// the jump destinations are, and validating a jump is a bit test rather than a
48    /// search.
49    ///
50    /// Bytecode with no jump destination stores a zero-length bitmap ([`EMPTY_JUMPDESTS`])
51    /// rather than an all-zero one, so this is not always `ceil(len / 8)` bytes long;
52    /// [`Code::is_valid_jumpdest`] reads a missing byte as "no jump destination".
53    //
54    // `Arc<[u8]>` so cloning `Code` (hot: every message-call resolves and clones
55    // the callee's code) is a refcount bump instead of deep-copying the bitmap.
56    // Serializes via serde's `rc` feature (enabled workspace-wide).
57    jumpdests: Arc<[u8]>,
58}
59
60impl Code {
61    // SAFETY: hash will be stored as-is, so it either needs to match
62    // the real code hash (i.e. it was precomputed and we're reusing)
63    // or never be read (e.g. for initcode).
64    //
65    // `code` is the logical, unpadded bytecode; `BYTECODE_PADDING` STOP bytes are
66    // appended internally by `from_parts_unchecked`.
67    pub fn from_bytecode_unchecked(code: Bytes, hash: H256) -> Self {
68        let jumpdests = Self::compute_jumpdests(&code);
69        Self::from_parts_unchecked(hash, &code, jumpdests)
70    }
71
72    /// `code` is the logical, unpadded bytecode; `BYTECODE_PADDING` STOP bytes are
73    /// appended internally by `from_parts_unchecked`.
74    pub fn from_bytecode(code: Bytes, crypto: &dyn Crypto) -> Self {
75        let jumpdests = Self::compute_jumpdests(&code);
76        let hash = H256(crypto.keccak256(code.as_ref()));
77        Self::from_parts_unchecked(hash, &code, jumpdests)
78    }
79
80    /// Builds a `Code` from precomputed parts. The caller must guarantee `hash`
81    /// and `jumpdests` correspond to `code`; neither is recomputed or validated.
82    ///
83    /// `code` is the logical, unpadded bytecode: this function appends
84    /// `BYTECODE_PADDING` STOP bytes and records the original length in
85    /// `bytecode_len`. Never pass a pre-padded buffer, or the logical length and
86    /// every `JUMPDEST`/`PUSH` offset derived from it would be wrong.
87    pub fn from_parts_unchecked(hash: H256, code: &[u8], jumpdests: Arc<[u8]>) -> Self {
88        let bytecode_len = code.len();
89        let mut padded_code = Vec::with_capacity(bytecode_len + BYTECODE_PADDING);
90        padded_code.extend_from_slice(code);
91        padded_code.extend_from_slice(&[0u8; BYTECODE_PADDING]);
92        Self {
93            hash,
94            bytecode: Bytes::from_owner(padded_code),
95            bytecode_len,
96            jumpdests,
97        }
98    }
99
100    /// Builds the [`Code::jumpdests`] bitmap: the bit of every `JUMPDEST` that is not a
101    /// `PUSH` immediate.
102    ///
103    /// On aarch64, and on x86_64 with SSSE3, this runs without a data-dependent branch
104    /// (see `by_block`), because a scan that branches on each opcode stalls on every
105    /// misprediction, and random bytecode mispredicts on most bytes. execution-specs#3631
106    /// builds such initcode on purpose. Other targets are mostly the zkVM guests, which
107    /// have no branch predictor and would only pay for the extra instructions, so they
108    /// keep the plain scan (`jumpdests_by_opcode`).
109    pub fn compute_jumpdests(code: &[u8]) -> Arc<[u8]> {
110        let mut bitmap = vec![0u8; code.len().div_ceil(8)];
111        #[cfg(any(
112            target_arch = "aarch64",
113            all(target_arch = "x86_64", target_feature = "ssse3")
114        ))]
115        let any = by_block::jumpdests(code, &mut bitmap);
116        #[cfg(not(any(
117            target_arch = "aarch64",
118            all(target_arch = "x86_64", target_feature = "ssse3")
119        )))]
120        let any = jumpdests_by_opcode(code, &mut bitmap);
121        // Share the single empty bitmap for jumpless bytecode (very common: EOAs,
122        // tiny contracts) so we don't allocate for an all-zero map; `is_valid_jumpdest`
123        // reads a missing byte as "no jump destination".
124        if any {
125            Arc::from(bitmap)
126        } else {
127            EMPTY_JUMPDESTS.clone()
128        }
129    }
130
131    /// Whether `offset` is a valid jump destination, i.e. it holds a `JUMPDEST` that is
132    /// not part of a `PUSH` immediate. Offsets past the bytecode are not valid.
133    #[inline]
134    pub fn is_valid_jumpdest(&self, offset: usize) -> bool {
135        self.jumpdests
136            .get(offset / 8)
137            .is_some_and(|byte| byte & (1 << (offset % 8)) != 0)
138    }
139
140    /// The raw [`Code::jumpdests`] bitmap, for persisting it alongside the bytecode.
141    #[inline]
142    pub fn jumpdests(&self) -> &[u8] {
143        &self.jumpdests
144    }
145
146    #[inline]
147    pub fn code(&self) -> &[u8] {
148        self.bytecode.get(..self.bytecode_len).unwrap_or_default()
149    }
150
151    #[inline]
152    pub fn code_bytes(&self) -> Bytes {
153        self.bytecode.slice(..self.bytecode_len)
154    }
155
156    #[inline]
157    pub fn len(&self) -> usize {
158        self.bytecode_len
159    }
160
161    #[inline]
162    pub fn is_empty(&self) -> bool {
163        self.bytecode_len == 0
164    }
165
166    /// Returns the padded bytecode buffer (real code + [`BYTECODE_PADDING`] trailing
167    /// STOPs) used by the opcode dispatch loop to read opcodes without bounds checks.
168    /// Use [`Code::code`] for the real, unpadded bytecode.
169    #[inline]
170    pub fn dispatch_buf(&self) -> &[u8] {
171        &self.bytecode
172    }
173
174    /// Estimates the size of the Code struct in bytes
175    /// (including stack size and heap allocation).
176    ///
177    /// Note: an estimate. It ignores allocator overhead and the `Arc`/`Bytes` control
178    /// blocks, so it slightly under-counts, and a shared allocation is attributed in
179    /// full to every entry holding it.
180    ///
181    /// # Returns
182    ///
183    /// usize - Estimated size in bytes
184    pub fn size(&self) -> usize {
185        let hash_size = size_of::<H256>();
186        let bytes_size = size_of::<Bytes>() + self.bytecode.len();
187        let bitmap_size = size_of::<Arc<[u8]>>() + self.jumpdests.len();
188        hash_size + bytes_size + bitmap_size
189    }
190}
191
192// Opcodes the jump destination analysis needs. The vm module defines them too, but
193// depending on it here would be circular.
194const OP_JUMPDEST: u8 = 0x5B;
195const OP_PUSH1: u8 = 0x60;
196const OP_PUSH32: u8 = 0x7F;
197
198/// Fills `bitmap` for `code` one opcode at a time and returns whether any bit is set.
199///
200/// The bits of a byte are accumulated in a register and written once the scan leaves
201/// that byte, which the monotonic `i` makes safe. Reading the bitmap back inside the
202/// loop instead would turn each `JUMPDEST` into a read-modify-write, and indexing it
203/// would put a bounds-check panic path in the loop body, which inhibits optimization
204/// of every iteration rather than only the ones that find a destination.
205#[cfg_attr(
206    any(
207        target_arch = "aarch64",
208        all(target_arch = "x86_64", target_feature = "ssse3")
209    ),
210    allow(dead_code)
211)]
212fn jumpdests_by_opcode(code: &[u8], bitmap: &mut [u8]) -> bool {
213    let mut any = false;
214    let mut current_byte = usize::MAX;
215    let mut bits = 0u8;
216    let mut i = 0;
217    while i < code.len() {
218        match code[i] {
219            OP_JUMPDEST => {
220                if i / 8 != current_byte {
221                    if let Some(byte) = bitmap.get_mut(current_byte) {
222                        *byte = bits;
223                    }
224                    current_byte = i / 8;
225                    bits = 0;
226                }
227                bits |= 1 << (i % 8);
228                any = true;
229            }
230            // PUSH1..PUSH32 are followed by 1..32 immediate bytes.
231            c @ OP_PUSH1..=OP_PUSH32 => i += usize::from(c - OP_PUSH1) + 1,
232            _ => (),
233        }
234        i += 1;
235    }
236    if let Some(byte) = bitmap.get_mut(current_byte) {
237        *byte = bits;
238    }
239    any
240}
241
242/// The jump destination analysis without a data-dependent branch, 64 bytes at a time.
243///
244/// Whether a byte is an opcode depends on every `PUSH` before it, so the natural scan
245/// branches on each opcode, and on random bytecode that branch mispredicts on most bytes.
246/// Here the work per block is the same whatever its bytes are:
247///
248/// 1. In each 16-byte group, the walks from all 16 bytes, each as if its byte were an
249///    opcode, advance at once until they leave the group (see [`group_walks`]).
250/// 2. The real walk enters the block where the previous block's walk left it. Where it
251///    leaves a group is where it enters the next one, so four dependent loads pick the
252///    walk of each group, and give where the walk enters the next block.
253#[cfg(any(
254    target_arch = "aarch64",
255    all(target_arch = "x86_64", target_feature = "ssse3")
256))]
257mod by_block {
258    use super::{OP_JUMPDEST, OP_PUSH1};
259    use lanes::Lanes;
260
261    /// Bytes per block, one `u64` of bitmap.
262    const BLOCK: usize = 64;
263    /// Bytes per group, one SIMD register.
264    const GROUP: usize = 16;
265
266    /// Fills `bitmap` for `code` and returns whether any bit is set.
267    pub(super) fn jumpdests(code: &[u8], bitmap: &mut [u8]) -> bool {
268        let mut walks = Walks::new();
269        let (blocks, tail) = code.as_chunks::<BLOCK>();
270        let mut carry = 0;
271        let mut any = 0;
272        // A full block fills exactly one 8-byte word of the bitmap.
273        for (block, word) in blocks.iter().zip(bitmap.as_chunks_mut::<8>().0) {
274            let valid = block_jumpdests(block, &mut carry, &mut walks);
275            *word = valid.to_le_bytes();
276            any |= valid;
277        }
278        if !tail.is_empty() {
279            // Zeros are STOPs, which are neither destinations nor PUSHes.
280            let mut padded = [0; BLOCK];
281            padded[..tail.len()].copy_from_slice(tail);
282            let valid = block_jumpdests(&padded, &mut carry, &mut walks);
283            let rest = &mut bitmap[blocks.len() * 8..];
284            rest.copy_from_slice(&valid.to_le_bytes()[..rest.len()]);
285            any |= valid;
286        }
287        any != 0
288    }
289
290    /// The walks of one block's bytes (see [`group_walks`]), by position in the block:
291    /// where each leaves its group, and which bytes of the group it lands on, the lower
292    /// 8 in `low_stops` and the upper 8 in `high_stops`.
293    ///
294    /// Positions from 64 on stand for the next block: they lead to themselves and land on
295    /// nothing, so a walk that has left the block stays where it is.
296    struct Walks {
297        exits: [u8; 2 * BLOCK],
298        low_stops: [u8; 2 * BLOCK],
299        high_stops: [u8; 2 * BLOCK],
300    }
301
302    impl Walks {
303        fn new() -> Self {
304            Self {
305                exits: core::array::from_fn(|i| i as u8),
306                low_stops: [0; 2 * BLOCK],
307                high_stops: [0; 2 * BLOCK],
308            }
309        }
310    }
311
312    /// The valid jump destinations of one block, bit `i` for byte `i`.
313    ///
314    /// `carry` is how many leading bytes of the block are immediates of a `PUSH` in the
315    /// previous block, and is updated for the next one.
316    #[inline(always)]
317    fn block_jumpdests(block: &[u8; BLOCK], carry: &mut usize, walks: &mut Walks) -> u64 {
318        let groups = block.as_chunks::<GROUP>().0;
319        let groups: [Lanes; BLOCK / GROUP] = core::array::from_fn(|g| Lanes::load(&groups[g]));
320        let jumpdests = Lanes::bits(groups.map(|bytes| bytes.eq(Lanes::splat(OP_JUMPDEST))));
321        for (g, bytes) in groups.into_iter().enumerate() {
322            let (exits, low_stops, high_stops) = group_walks(bytes);
323            // From here on, positions are relative to the block instead of the group.
324            let exits = exits.add(Lanes::splat((g * GROUP) as u8));
325            exits.store(&mut walks.exits.as_chunks_mut::<GROUP>().0[g]);
326            low_stops.store(&mut walks.low_stops.as_chunks_mut::<GROUP>().0[g]);
327            high_stops.store(&mut walks.high_stops.as_chunks_mut::<GROUP>().0[g]);
328        }
329        let mut at = *carry;
330        let mut opcodes = 0;
331        for _ in 0..BLOCK / GROUP {
332            // At most 96, 32 immediates past the block; the modulo drops the bounds checks.
333            let i = at % (2 * BLOCK);
334            let stops = u64::from(walks.low_stops[i]) | (u64::from(walks.high_stops[i]) << 8);
335            // Past the block there are no stops, so the shift only matters inside it.
336            let group_start = i & (BLOCK - GROUP);
337            opcodes |= stops << group_start;
338            at = usize::from(walks.exits[i]);
339        }
340        // Each load moves the walk past at least one more group, so it is now past the
341        // block, by as many bytes as the next block starts with immediates.
342        *carry = at - BLOCK;
343        jumpdests & opcodes
344    }
345
346    /// For each byte of a 16-byte group, the walk that starts if that byte is an opcode,
347    /// up to where it leaves the group: the position it leaves to, relative to the group
348    /// (16 to 48), and the bytes it lands on, bits 0 to 7 in the first mask and bits 8 to
349    /// 15 in the second.
350    ///
351    /// All 16 walks advance together by pointer doubling: each round, a walk that is still
352    /// in the group takes as many steps again by continuing with the walk of the byte it
353    /// is at, which a table lookup of every lane (TBL on aarch64, PSHUFB on x86_64) reads.
354    /// A step moves at least one byte, so four rounds (16 steps) take every walk out of
355    /// the group.
356    #[inline(always)]
357    fn group_walks(bytes: Lanes) -> (Lanes, Lanes, Lanes) {
358        const POSITIONS_PLUS_ONE: [u8; GROUP] =
359            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
360        const LOW_POSITION_BITS: [u8; GROUP] =
361            [1, 2, 4, 8, 16, 32, 64, 128, 0, 0, 0, 0, 0, 0, 0, 0];
362        const HIGH_POSITION_BITS: [u8; GROUP] =
363            [0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 8, 16, 32, 64, 128];
364        // PUSH1..PUSH32 are exactly the bytes 0b011x_xxxx, with `byte - PUSH1 + 1`
365        // immediates.
366        let is_push = bytes.and(Lanes::splat(0xE0)).eq(Lanes::splat(OP_PUSH1));
367        let immediates = is_push.and(bytes.sub(Lanes::splat(OP_PUSH1 - 1)));
368        // One step, past the opcode and its immediates.
369        let mut exits = Lanes::load(&POSITIONS_PLUS_ONE).add(immediates);
370        let mut low_stops = Lanes::load(&LOW_POSITION_BITS);
371        let mut high_stops = Lanes::load(&HIGH_POSITION_BITS);
372        // The lookups read zero for a walk that has left the group, so its stops stay as
373        // they are, and `max` keeps its exit, while a walk still inside moves ahead.
374        // Stops in the lower 8 bytes are a walk's first 8 at most, so the last round can
375        // skip them.
376        for round in 0..4 {
377            if round < 3 {
378                low_stops = low_stops.or(low_stops.lookup(exits));
379            }
380            high_stops = high_stops.or(high_stops.lookup(exits));
381            exits = exits.max(exits.lookup(exits));
382        }
383        (exits, low_stops, high_stops)
384    }
385
386    #[cfg(target_arch = "aarch64")]
387    mod lanes {
388        use core::arch::aarch64::*;
389
390        /// 16 bytes in a NEON register.
391        #[derive(Clone, Copy)]
392        pub(super) struct Lanes(uint8x16_t);
393
394        // SAFETY (every `unsafe` below): NEON is part of the aarch64 baseline, and the
395        // loads and stores go through a reference to exactly 16 bytes, with no alignment
396        // requirement.
397        impl Lanes {
398            #[inline(always)]
399            pub(super) fn load(bytes: &[u8; 16]) -> Self {
400                unsafe { Self(vld1q_u8(bytes.as_ptr())) }
401            }
402
403            #[inline(always)]
404            pub(super) fn store(self, out: &mut [u8; 16]) {
405                unsafe { vst1q_u8(out.as_mut_ptr(), self.0) }
406            }
407
408            #[inline(always)]
409            pub(super) fn splat(byte: u8) -> Self {
410                unsafe { Self(vdupq_n_u8(byte)) }
411            }
412
413            #[inline(always)]
414            pub(super) fn and(self, other: Self) -> Self {
415                unsafe { Self(vandq_u8(self.0, other.0)) }
416            }
417
418            #[inline(always)]
419            pub(super) fn or(self, other: Self) -> Self {
420                unsafe { Self(vorrq_u8(self.0, other.0)) }
421            }
422
423            #[inline(always)]
424            pub(super) fn add(self, other: Self) -> Self {
425                unsafe { Self(vaddq_u8(self.0, other.0)) }
426            }
427
428            #[inline(always)]
429            pub(super) fn sub(self, other: Self) -> Self {
430                unsafe { Self(vsubq_u8(self.0, other.0)) }
431            }
432
433            /// All ones in the lanes that are equal, zero in the others.
434            #[inline(always)]
435            pub(super) fn eq(self, other: Self) -> Self {
436                unsafe { Self(vceqq_u8(self.0, other.0)) }
437            }
438
439            #[inline(always)]
440            pub(super) fn max(self, other: Self) -> Self {
441                unsafe { Self(vmaxq_u8(self.0, other.0)) }
442            }
443
444            /// Lane `i` of `self` for each lane `i` of `indices` below 16, zero for the rest.
445            #[inline(always)]
446            pub(super) fn lookup(self, indices: Self) -> Self {
447                unsafe { Self(vqtbl1q_u8(self.0, indices.0)) }
448            }
449
450            /// The top bit of every lane of four registers of all-ones or zero lanes.
451            ///
452            /// NEON has no instruction that gathers one bit per byte, so each lane keeps
453            /// the bit of its position within 8 bytes, and three rounds of pairwise adds
454            /// pack them into one `u64`.
455            #[inline(always)]
456            pub(super) fn bits(masks: [Self; 4]) -> u64 {
457                unsafe {
458                    let position_bits = vreinterpretq_u8_u64(vdupq_n_u64(0x8040_2010_0804_0201));
459                    let [a, b, c, d] = masks.map(|m| vandq_u8(m.0, position_bits));
460                    let quarters = vpaddq_u8(vpaddq_u8(a, b), vpaddq_u8(c, d));
461                    vgetq_lane_u64::<0>(vreinterpretq_u64_u8(vpaddq_u8(quarters, quarters)))
462                }
463            }
464        }
465    }
466
467    #[cfg(target_arch = "x86_64")]
468    mod lanes {
469        use core::arch::x86_64::*;
470
471        /// 16 bytes in an SSE register.
472        #[derive(Clone, Copy)]
473        pub(super) struct Lanes(__m128i);
474
475        // SAFETY (every `unsafe` below): SSE2 is part of the x86_64 baseline, SSSE3 is
476        // enabled for this build (see the `cfg` on `by_block`), and the loads and stores
477        // go through a reference to exactly 16 bytes, with no alignment requirement.
478        impl Lanes {
479            #[inline(always)]
480            pub(super) fn load(bytes: &[u8; 16]) -> Self {
481                unsafe { Self(_mm_loadu_si128(bytes.as_ptr().cast())) }
482            }
483
484            #[inline(always)]
485            pub(super) fn store(self, out: &mut [u8; 16]) {
486                unsafe { _mm_storeu_si128(out.as_mut_ptr().cast(), self.0) }
487            }
488
489            #[inline(always)]
490            pub(super) fn splat(byte: u8) -> Self {
491                unsafe { Self(_mm_set1_epi8(byte as i8)) }
492            }
493
494            #[inline(always)]
495            pub(super) fn and(self, other: Self) -> Self {
496                unsafe { Self(_mm_and_si128(self.0, other.0)) }
497            }
498
499            #[inline(always)]
500            pub(super) fn or(self, other: Self) -> Self {
501                unsafe { Self(_mm_or_si128(self.0, other.0)) }
502            }
503
504            #[inline(always)]
505            pub(super) fn add(self, other: Self) -> Self {
506                unsafe { Self(_mm_add_epi8(self.0, other.0)) }
507            }
508
509            #[inline(always)]
510            pub(super) fn sub(self, other: Self) -> Self {
511                unsafe { Self(_mm_sub_epi8(self.0, other.0)) }
512            }
513
514            /// All ones in the lanes that are equal, zero in the others.
515            #[inline(always)]
516            pub(super) fn eq(self, other: Self) -> Self {
517                unsafe { Self(_mm_cmpeq_epi8(self.0, other.0)) }
518            }
519
520            #[inline(always)]
521            pub(super) fn max(self, other: Self) -> Self {
522                unsafe { Self(_mm_max_epu8(self.0, other.0)) }
523            }
524
525            /// Lane `i` of `self` for each lane `i` of `indices` below 16, zero for the rest
526            /// up to 143.
527            #[inline(always)]
528            pub(super) fn lookup(self, indices: Self) -> Self {
529                // PSHUFB zeroes the lanes whose index has its top bit set and otherwise
530                // uses the index's low 4 bits. Adding 0x70 sets the top bit of 16..=143
531                // and keeps the low 4 bits of 0..=15.
532                unsafe {
533                    let indices = _mm_add_epi8(indices.0, _mm_set1_epi8(0x70));
534                    Self(_mm_shuffle_epi8(self.0, indices))
535                }
536            }
537
538            /// The top bit of every lane of four registers of all-ones or zero lanes.
539            #[inline(always)]
540            pub(super) fn bits(masks: [Self; 4]) -> u64 {
541                masks.iter().enumerate().fold(0, |bits, (i, m)| {
542                    let lanes = unsafe { _mm_movemask_epi8(m.0) } as u16;
543                    bits | (u64::from(lanes) << (16 * i))
544                })
545            }
546        }
547    }
548}
549
550/// Serde shadow for [`Code`]. Stores the *logical* (unpadded) bytecode so the
551/// padding is never part of the serialized form. Deserialization re-pads through
552/// [`Code::from_parts_unchecked`], which keeps the dispatch-loop invariant (every
553/// `Code` is padded with [`BYTECODE_PADDING`] trailing STOPs) sound regardless of
554/// where the bytes came from. Deserializing the padded buffer directly would
555/// otherwise let unpadded input through and cause OOB reads during execution.
556/// The jump destinations are deliberately absent: they are a pure function of the
557/// bytecode, so carrying them would put a derived value in the wire format of everything
558/// that embeds a `Code` (notably `AccountUpdate`, which the L2 rollup store persists with
559/// bincode) and couple that format to how they happen to be represented.
560/// Wire form of [`Code`]. Jump destinations are recomputed from `code` on
561/// deserialize, never read from here — but the `jump_targets` field is kept so
562/// the layout stays byte-identical to the pre-bitmap `Code` serialization.
563/// `Code` is embedded in `AccountUpdate`, which is persisted with bincode (a
564/// non-self-describing, positional codec) in the L2 rollup store; dropping the
565/// field would shift every following field and make existing rows undecodable.
566/// It is always serialized empty and ignored on read.
567#[derive(Serialize, Deserialize)]
568struct CodeSerde {
569    hash: H256,
570    code: Bytes,
571    jump_targets: Arc<[u32]>,
572}
573
574impl Serialize for Code {
575    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
576        CodeSerde {
577            hash: self.hash,
578            code: self.code_bytes(),
579            jump_targets: Arc::from([]),
580        }
581        .serialize(serializer)
582    }
583}
584
585impl<'de> Deserialize<'de> for Code {
586    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
587        // `jump_targets` is read only to consume its bytes (layout compatibility);
588        // the bitmap is always recomputed from `code`.
589        let CodeSerde {
590            hash,
591            code,
592            jump_targets: _,
593        } = CodeSerde::deserialize(deserializer)?;
594        Ok(Self::from_parts_unchecked(
595            hash,
596            &code,
597            Self::compute_jumpdests(&code),
598        ))
599    }
600}
601
602#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
603pub struct CodeMetadata {
604    pub length: u64,
605}
606
607#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
608pub struct Account {
609    pub info: AccountInfo,
610    pub code: Code,
611    pub storage: FxHashMap<H256, U256>,
612}
613
614#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
615pub struct AccountInfo {
616    pub code_hash: H256,
617    pub balance: U256,
618    pub nonce: u64,
619}
620
621#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
622pub struct AccountState {
623    pub nonce: u64,
624    pub balance: U256,
625    pub storage_root: H256,
626    pub code_hash: H256,
627}
628
629/// A slim codec for an [`AccountState`].
630///
631/// The slim codec will optimize both the [storage root](AccountState::storage_root) and the
632/// [code hash](AccountState::code_hash)'s encoding so that it does not take space when empty.
633///
634/// The correct way to use it is to wrap the [`AccountState`] and encode it using this codec, and
635/// not to store the codec as a field in a struct.
636#[derive(Clone, Copy, Debug, Default, PartialEq)]
637pub struct AccountStateSlimCodec(pub AccountState);
638
639impl Default for AccountInfo {
640    fn default() -> Self {
641        Self {
642            code_hash: *EMPTY_KECCAK_HASH,
643            balance: Default::default(),
644            nonce: Default::default(),
645        }
646    }
647}
648
649impl Default for AccountState {
650    fn default() -> Self {
651        Self {
652            nonce: Default::default(),
653            balance: Default::default(),
654            storage_root: *EMPTY_TRIE_HASH,
655            code_hash: *EMPTY_KECCAK_HASH,
656        }
657    }
658}
659
660impl Default for Code {
661    fn default() -> Self {
662        Self {
663            bytecode: Bytes::from_static(&[0u8; BYTECODE_PADDING]),
664            bytecode_len: 0,
665            hash: *EMPTY_KECCAK_HASH,
666            jumpdests: EMPTY_JUMPDESTS.clone(),
667        }
668    }
669}
670
671impl From<GenesisAccount> for Account {
672    fn from(genesis: GenesisAccount) -> Self {
673        let code = Code::from_bytecode(genesis.code, &NativeCrypto);
674        Self {
675            info: AccountInfo {
676                code_hash: code.hash,
677                balance: genesis.balance,
678                nonce: genesis.nonce,
679            },
680            code,
681            storage: genesis
682                .storage
683                .iter()
684                .map(|(k, v)| (H256(k.to_big_endian()), *v))
685                .collect(),
686        }
687    }
688}
689
690pub fn code_hash(code: &Bytes, crypto: &dyn Crypto) -> H256 {
691    H256(crypto.keccak256(code.as_ref()))
692}
693
694/// EIP-7702 delegation designation: an EOA whose code is `0xef0100 || address`.
695/// See <https://eips.ethereum.org/EIPS/eip-7702>.
696pub const EIP7702_DELEGATION_PREFIX: [u8; 3] = [0xef, 0x01, 0x00];
697/// Total byte length of an EIP-7702 delegation designation: 3-byte prefix
698/// plus the 20-byte target address.
699pub const EIP7702_DELEGATED_CODE_LEN: usize = 23;
700
701/// Returns true iff `code` is a valid EIP-7702 delegation designation
702/// (exactly 23 bytes, prefixed with `0xef0100`).
703pub fn is_eip7702_delegation(code: &[u8]) -> bool {
704    code.len() == EIP7702_DELEGATED_CODE_LEN && code.starts_with(&EIP7702_DELEGATION_PREFIX)
705}
706
707impl RLPEncode for AccountInfo {
708    fn encode(&self, buf: &mut dyn bytes::BufMut) {
709        Encoder::new(buf)
710            .encode_field(&self.code_hash)
711            .encode_field(&self.balance)
712            .encode_field(&self.nonce)
713            .finish();
714    }
715}
716
717impl RLPDecode for AccountInfo {
718    fn decode_unfinished(rlp: &[u8]) -> Result<(AccountInfo, &[u8]), RLPDecodeError> {
719        let decoder = Decoder::new(rlp)?;
720        let (code_hash, decoder) = decoder.decode_field("code_hash")?;
721        let (balance, decoder) = decoder.decode_field("balance")?;
722        let (nonce, decoder) = decoder.decode_field("nonce")?;
723        let account_info = AccountInfo {
724            code_hash,
725            balance,
726            nonce,
727        };
728        Ok((account_info, decoder.finish()?))
729    }
730}
731
732impl RLPEncode for AccountState {
733    fn encode(&self, buf: &mut dyn bytes::BufMut) {
734        Encoder::new(buf)
735            .encode_field(&self.nonce)
736            .encode_field(&self.balance)
737            .encode_field(&self.storage_root)
738            .encode_field(&self.code_hash)
739            .finish();
740    }
741}
742
743impl RLPDecode for AccountState {
744    fn decode_unfinished(rlp: &[u8]) -> Result<(AccountState, &[u8]), RLPDecodeError> {
745        let decoder = Decoder::new(rlp)?;
746        let (nonce, decoder) = decoder.decode_field("nonce")?;
747        let (balance, decoder) = decoder.decode_field("balance")?;
748        let (storage_root, decoder) = decoder.decode_field("storage_root")?;
749        let (code_hash, decoder) = decoder.decode_field("code_hash")?;
750        let state = AccountState {
751            nonce,
752            balance,
753            storage_root,
754            code_hash,
755        };
756        Ok((state, decoder.finish()?))
757    }
758}
759
760impl RLPEncode for AccountStateSlimCodec {
761    fn encode(&self, buf: &mut dyn BufMut) {
762        struct StorageRootCodec<'a>(&'a H256);
763        impl RLPEncode for StorageRootCodec<'_> {
764            fn encode(&self, buf: &mut dyn BufMut) {
765                let data = if *self.0 != *EMPTY_TRIE_HASH {
766                    self.0.as_bytes()
767                } else {
768                    &[]
769                };
770
771                data.encode(buf);
772            }
773        }
774
775        struct CodeHashCodec<'a>(&'a H256);
776        impl RLPEncode for CodeHashCodec<'_> {
777            fn encode(&self, buf: &mut dyn BufMut) {
778                let data = if *self.0 != *EMPTY_KECCAK_HASH {
779                    self.0.as_bytes()
780                } else {
781                    &[]
782                };
783
784                data.encode(buf);
785            }
786        }
787
788        Encoder::new(buf)
789            .encode_field(&self.0.nonce)
790            .encode_field(&self.0.balance)
791            .encode_field(&StorageRootCodec(&self.0.storage_root))
792            .encode_field(&CodeHashCodec(&self.0.code_hash))
793            .finish();
794    }
795}
796
797impl RLPDecode for AccountStateSlimCodec {
798    fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
799        struct StorageRootCodec(H256);
800        impl RLPDecode for StorageRootCodec {
801            fn decode_unfinished(mut rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
802                let value = match rlp.split_off_first() {
803                    Some(0x80) => *EMPTY_TRIE_HASH,
804                    Some(0xA0) => {
805                        let data;
806                        (data, rlp) = rlp
807                            .split_first_chunk::<32>()
808                            .ok_or(RLPDecodeError::InvalidLength)?;
809                        H256(*data)
810                    }
811                    _ => return Err(RLPDecodeError::InvalidLength),
812                };
813
814                Ok((Self(value), rlp))
815            }
816        }
817
818        struct CodeHashCodec(H256);
819        impl RLPDecode for CodeHashCodec {
820            fn decode_unfinished(mut rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
821                let value = match rlp.split_off_first() {
822                    Some(0x80) => *EMPTY_KECCAK_HASH,
823                    Some(0xA0) => {
824                        let data;
825                        (data, rlp) = rlp
826                            .split_first_chunk::<32>()
827                            .ok_or(RLPDecodeError::InvalidLength)?;
828                        H256(*data)
829                    }
830                    _ => return Err(RLPDecodeError::InvalidLength),
831                };
832
833                Ok((Self(value), rlp))
834            }
835        }
836
837        let decoder = Decoder::new(rlp)?;
838        let (nonce, decoder) = decoder.decode_field("nonce")?;
839        let (balance, decoder) = decoder.decode_field("balance")?;
840        let (StorageRootCodec(storage_root), decoder) = decoder.decode_field("storage_root")?;
841        let (CodeHashCodec(code_hash), decoder) = decoder.decode_field("code_hash")?;
842
843        Ok((
844            Self(AccountState {
845                nonce,
846                balance,
847                storage_root,
848                code_hash,
849            }),
850            decoder.finish()?,
851        ))
852    }
853}
854
855pub fn compute_storage_root(storage: &BTreeMap<U256, U256>, crypto: &dyn Crypto) -> H256 {
856    let iter = storage.iter().filter_map(|(k, v)| {
857        (!v.is_zero()).then_some((
858            crypto.keccak256(&k.to_big_endian()).to_vec(),
859            v.encode_to_vec(),
860        ))
861    });
862    Trie::compute_hash_from_unsorted_iter(iter, crypto)
863}
864
865impl From<&GenesisAccount> for AccountState {
866    fn from(value: &GenesisAccount) -> Self {
867        AccountState {
868            nonce: value.nonce,
869            balance: value.balance,
870            storage_root: compute_storage_root(&value.storage, &NativeCrypto),
871            code_hash: code_hash(&value.code, &NativeCrypto),
872        }
873    }
874}
875
876impl Account {
877    pub fn new(balance: U256, code: Code, nonce: u64, storage: FxHashMap<H256, U256>) -> Self {
878        Self {
879            info: AccountInfo {
880                balance,
881                code_hash: code.hash,
882                nonce,
883            },
884            code,
885            storage,
886        }
887    }
888}
889
890impl AccountInfo {
891    pub fn is_empty(&self) -> bool {
892        self.balance.is_zero() && self.nonce == 0 && self.code_hash == *EMPTY_KECCAK_HASH
893    }
894}
895
896#[cfg(test)]
897mod test {
898    use std::str::FromStr;
899
900    use super::*;
901
902    // Pre-bitmap on-wire layout of `Code`: `{hash, code, jump_targets}`. `AccountUpdate`
903    // embeds `Code` and is persisted with bincode (positional) in the L2 rollup store,
904    // so a row written before the bitmap change carries a non-empty `jump_targets`.
905    #[derive(serde::Serialize)]
906    struct OldCodeSerde {
907        hash: H256,
908        code: Bytes,
909        jump_targets: Vec<u32>,
910    }
911
912    // `Code` is never persisted alone — it sits inside `AccountUpdate`, which has fields
913    // AFTER `code`. These wrappers mirror that: a field following the code. A standalone
914    // `Code` would tolerate trailing bytes, hiding the bug; only an embedded field
915    // exposes the positional shift.
916    #[derive(serde::Serialize)]
917    struct OldWrap {
918        code: OldCodeSerde,
919        tail: u64,
920    }
921    #[derive(serde::Deserialize)]
922    struct NewWrap {
923        code: Code,
924        tail: u64,
925    }
926
927    // A row serialized under the old three-field layout must still decode with the field
928    // following `code` intact: the current `Code` deserializer reads and discards
929    // `jump_targets`, keeping the layout aligned. Without the retained field, bincode
930    // reads `tail` from the `jump_targets` bytes and every following field is corrupt —
931    // exactly the `store_account_updates_by_block_number` break.
932    #[test]
933    fn embedded_code_decodes_an_old_layout_bincode_row() {
934        // PUSH1 0x00 JUMPDEST STOP — offset 2 is a real JUMPDEST, offset 1 a PUSH immediate.
935        let bytecode = Bytes::from(vec![0x60, 0x00, 0x5b, 0x00]);
936        let hash = H256::from_low_u64_be(0xabc);
937        const SENTINEL: u64 = 0x0123_4567_89ab_cdef;
938        let old = OldWrap {
939            code: OldCodeSerde {
940                hash,
941                code: bytecode.clone(),
942                jump_targets: vec![2], // non-empty, as an old row would hold
943            },
944            tail: SENTINEL,
945        };
946        let bytes = bincode::serialize(&old).expect("serialize old layout");
947
948        let decoded: NewWrap = bincode::deserialize(&bytes).expect("decode old row under new Code");
949        assert_eq!(decoded.code.hash, hash);
950        assert_eq!(decoded.code.code_bytes(), bytecode);
951        // The field after `code` must survive — this is what breaks if the layout shifts.
952        assert_eq!(
953            decoded.tail, SENTINEL,
954            "field after Code corrupted by layout shift"
955        );
956        // Jump destinations recomputed from code, not read from the row.
957        assert!(decoded.code.is_valid_jumpdest(2));
958        assert!(!decoded.code.is_valid_jumpdest(1));
959    }
960
961    #[test]
962    fn test_code_hash() {
963        let empty_code = Bytes::new();
964        let hash = code_hash(&empty_code, &NativeCrypto);
965        assert_eq!(
966            hash,
967            H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
968                .unwrap()
969        )
970    }
971
972    #[test]
973    fn test_is_eip7702_delegation_valid() {
974        // 0xef0100 || 20-byte address
975        let mut code = Vec::with_capacity(23);
976        code.extend_from_slice(&EIP7702_DELEGATION_PREFIX);
977        code.extend_from_slice(&[0x42; 20]);
978        assert!(is_eip7702_delegation(&code));
979    }
980
981    #[test]
982    fn test_is_eip7702_delegation_rejects_empty() {
983        assert!(!is_eip7702_delegation(&[]));
984    }
985
986    #[test]
987    fn test_is_eip7702_delegation_rejects_short() {
988        // Prefix only, no address.
989        assert!(!is_eip7702_delegation(&EIP7702_DELEGATION_PREFIX));
990    }
991
992    #[test]
993    fn test_is_eip7702_delegation_rejects_long() {
994        // Correct prefix but 24 bytes total.
995        let mut code = Vec::with_capacity(24);
996        code.extend_from_slice(&EIP7702_DELEGATION_PREFIX);
997        code.extend_from_slice(&[0x42; 21]);
998        assert!(!is_eip7702_delegation(&code));
999    }
1000
1001    #[test]
1002    fn test_is_eip7702_delegation_rejects_wrong_prefix() {
1003        // Right length, wrong magic.
1004        let mut code = Vec::with_capacity(23);
1005        code.extend_from_slice(&[0xef, 0x01, 0x01]); // off by one in the last prefix byte
1006        code.extend_from_slice(&[0x42; 20]);
1007        assert!(!is_eip7702_delegation(&code));
1008    }
1009
1010    #[test]
1011    fn test_is_eip7702_delegation_rejects_arbitrary_contract_code() {
1012        // Real contract code starting with anything else.
1013        let code = vec![0x60, 0x60, 0x60, 0x40, 0x52 /* ... */];
1014        assert!(!is_eip7702_delegation(&code));
1015    }
1016
1017    // On these targets `compute_jumpdests` runs `by_block`, so the scan it replaces only
1018    // runs here, as the reference: both must give the same bitmap.
1019    #[cfg(any(
1020        target_arch = "aarch64",
1021        all(target_arch = "x86_64", target_feature = "ssse3")
1022    ))]
1023    mod by_block_against_the_scan {
1024        use super::*;
1025
1026        fn assert_same_jumpdests(code: &[u8]) {
1027            let mut want = vec![0; code.len().div_ceil(8)];
1028            let mut got = want.clone();
1029            let want_any = jumpdests_by_opcode(code, &mut want);
1030            let got_any = by_block::jumpdests(code, &mut got);
1031            assert_eq!((got_any, got), (want_any, want), "code {code:02x?}");
1032        }
1033
1034        /// One or two bytes at every offset of codes whose lengths straddle the 16-byte
1035        /// groups and 64-byte blocks, so every PUSH below crosses each boundary, and is cut
1036        /// short by the end of the code.
1037        #[test]
1038        fn matches_around_group_and_block_boundaries() {
1039            // STOP, JUMPDEST, the shortest PUSHes, the ones that fill a group with their
1040            // immediates or come a byte short or over, and the longest ones.
1041            const BYTES: [u8; 9] = [
1042                0x00,
1043                OP_JUMPDEST,
1044                OP_PUSH1,
1045                OP_PUSH1 + 1,
1046                OP_PUSH1 + 14,
1047                OP_PUSH1 + 15,
1048                OP_PUSH1 + 16,
1049                OP_PUSH32 - 1,
1050                OP_PUSH32,
1051            ];
1052            let lengths = [
1053                1, 15, 16, 17, 31, 32, 33, 63, 64, 65, 96, 127, 128, 129, 193,
1054            ];
1055            // A JUMPDEST filler exposes any immediate taken for an opcode or the other way
1056            // round. A PUSH1 filler makes where each block's walk starts depend on every
1057            // byte before it.
1058            for filler in [OP_JUMPDEST, OP_PUSH1] {
1059                for len in lengths {
1060                    for at in 0..len {
1061                        for first in BYTES {
1062                            for second in [None].into_iter().chain(BYTES.map(Some)) {
1063                                let mut code = vec![filler; len];
1064                                code[at] = first;
1065                                if let (Some(second), Some(byte)) = (second, code.get_mut(at + 1)) {
1066                                    *byte = second;
1067                                }
1068                                assert_same_jumpdests(&code);
1069                            }
1070                        }
1071                    }
1072                }
1073            }
1074        }
1075
1076        /// Random code up to 4 KiB long, over byte mixes that make the scan's branches
1077        /// unpredictable.
1078        #[test]
1079        fn matches_on_random_code() {
1080            // xorshift64, so every run checks the same inputs.
1081            let mut state = 0x9E37_79B9_7F4A_7C15_u64;
1082            let mut next = move || {
1083                state ^= state << 13;
1084                state ^= state >> 7;
1085                state ^= state << 17;
1086                state
1087            };
1088            let jumpdest_and_pushes: Vec<u8> = std::iter::once(OP_JUMPDEST)
1089                .chain(OP_PUSH1..=OP_PUSH32)
1090                .collect();
1091            let all_bytes: Vec<u8> = (0..=u8::MAX).collect();
1092            let mixes: [&[u8]; 4] = [
1093                &[0x00, OP_JUMPDEST, OP_PUSH1],
1094                &[OP_JUMPDEST, OP_PUSH1, OP_PUSH1 + 1],
1095                &jumpdest_and_pushes,
1096                &all_bytes,
1097            ];
1098            for mix in mixes {
1099                for _ in 0..200 {
1100                    let len = (next() % 4096) as usize;
1101                    let code: Vec<u8> = (0..len)
1102                        .map(|_| mix[(next() % mix.len() as u64) as usize])
1103                        .collect();
1104                    assert_same_jumpdests(&code);
1105                }
1106            }
1107        }
1108    }
1109}