<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Edgar Luque - performance</title>
    <subtitle>Software Developer</subtitle>
    <link rel="self" type="application/atom+xml" href="https://edgl.dev/categories/performance/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://edgl.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-05-23T00:00:00+00:00</updated>
    <id>https://edgl.dev/categories/performance/atom.xml</id>
    <entry xml:lang="en">
        <title>How Block Access Lists are implemented in ethrex</title>
        <published>2026-05-23T00:00:00+00:00</published>
        <updated>2026-05-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://edgl.dev/blog/bal-in-ethrex/"/>
        <id>https://edgl.dev/blog/bal-in-ethrex/</id>
        
        <content type="html" xml:base="https://edgl.dev/blog/bal-in-ethrex/">&lt;p&gt;A &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eips.ethereum.org&#x2F;EIPS&#x2F;eip-7928&quot;&gt;Block Access List&lt;&#x2F;a&gt; is a structured, per-block record of every account and storage slot touched during execution, with the post-execution values. The top-level shape is &lt;code&gt;List[AccountChanges]&lt;&#x2F;code&gt;, one entry per touched address. It lives in two places: a new &lt;code&gt;block_access_list_hash&lt;&#x2F;code&gt; field in the block header (&lt;code&gt;keccak256(rlp.encode(bal))&lt;&#x2F;code&gt;), and the BAL itself transmitted alongside the block via the Engine API.&lt;&#x2F;p&gt;
&lt;p&gt;A BAL exists because of what it lets a validator do: prefetch state without speculating, execute transactions in parallel with disjoint per-tx views, and merkleize the post-state root concurrently with the EVM. All three are possible because the BAL declares up front what the block will touch and what each touch will produce. This post is the anatomy of how ethrex implements both sides: producing a BAL while executing a block, and consuming a BAL to validate one in parallel.&lt;&#x2F;p&gt;
&lt;p&gt;Most of the code referenced below is in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&#x2F;blob&#x2F;main&#x2F;crates&#x2F;common&#x2F;types&#x2F;block_access_list.rs&quot;&gt;&lt;code&gt;crates&#x2F;common&#x2F;types&#x2F;block_access_list.rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&#x2F;blob&#x2F;main&#x2F;crates&#x2F;common&#x2F;validation.rs&quot;&gt;&lt;code&gt;crates&#x2F;common&#x2F;validation.rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, with the parallel execution wiring in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&#x2F;blob&#x2F;main&#x2F;crates&#x2F;vm&#x2F;backends&#x2F;levm&#x2F;mod.rs&quot;&gt;&lt;code&gt;crates&#x2F;vm&#x2F;backends&#x2F;levm&#x2F;mod.rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Pinned to ethrex &lt;code&gt;main&lt;&#x2F;code&gt; at commit &lt;code&gt;c0995b947&lt;&#x2F;code&gt; and bal-devnet-7. The EIP and ethrex are both in active development.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-data-structures&quot;&gt;The data structures&lt;&#x2F;h2&gt;
&lt;p&gt;Reading the types top-down is the fastest way in. The top of the tree is &lt;code&gt;BlockAccessList&lt;&#x2F;code&gt;, just a vector of per-address entries:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BlockAccessList&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;AccountChanges&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each &lt;code&gt;AccountChanges&lt;&#x2F;code&gt; is an address plus five vectors, one per kind of touch:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; AccountChanges&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; address&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; storage_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;SlotChange&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; storage_reads&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;U256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; balance_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;BalanceChange&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; nonce_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;NonceChange&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; code_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;CodeChange&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The split between &lt;code&gt;storage_changes&lt;&#x2F;code&gt; and &lt;code&gt;storage_reads&lt;&#x2F;code&gt; matters: a read is a slot that was loaded but not written, a change is a slot that was written. Same for everything else, except reads only exist for storage. Touching an address with no state change still puts the address in the BAL with empty vectors.&lt;&#x2F;p&gt;
&lt;p&gt;The leaf types are all &quot;block access index + post-state value&quot; pairs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; StorageChange&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; block_access_index&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; post_value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BalanceChange&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; block_access_index&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; post_balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; NonceChange&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; block_access_index&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; post_nonce&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; CodeChange&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; block_access_index&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; new_code&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Bytes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;SlotChange&lt;&#x2F;code&gt; groups changes by slot:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; SlotChange&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; slot&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; slot_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;StorageChange&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The recurring rule across all of them: post-state only. The EIP is explicit: &quot;If a storage slot&#x27;s value is changed but its post-transaction value is equal to its pre-transaction value, the slot MUST NOT be recorded as modified.&quot; That rule sounds simple. It isn&#x27;t.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-recorder&quot;&gt;The recorder&lt;&#x2F;h2&gt;
&lt;p&gt;The BAL is not built incrementally by executing the EVM and appending. It&#x27;s built by feeding execution events into a &lt;code&gt;BlockAccessListRecorder&lt;&#x2F;code&gt;, which accumulates everything, and consuming it at the end of the block:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BlockAccessListRecorder&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    current_index&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    touched_addresses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; IndexSet&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    storage_reads&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; IndexMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; IndexSet&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;U256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    storage_writes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;U256&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt;&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    initial_balances&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; IndexMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tx_initial_storage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tx_initial_code&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Bytes&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    balance_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    nonce_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    code_changes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Bytes&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    addresses_with_initial_code&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; IndexSet&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reads_promoted_to_writes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;U256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    in_system_call&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The choice of &lt;code&gt;IndexSet&lt;&#x2F;code&gt; and &lt;code&gt;IndexMap&lt;&#x2F;code&gt; over &lt;code&gt;BTreeMap&lt;&#x2F;code&gt; for some fields isn&#x27;t aesthetic. It&#x27;s for the revert mechanism below: those types let us snapshot a length and truncate back to it, instead of cloning the whole structure per call frame.&lt;&#x2F;p&gt;
&lt;p&gt;The lifecycle looks like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;new()&lt;&#x2F;code&gt; at the start of the block.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;set_block_access_index(0)&lt;&#x2F;code&gt; for the pre-execution system contracts (EIP-2935 history, EIP-4788 beacon root, etc.).&lt;&#x2F;li&gt;
&lt;li&gt;For each transaction &lt;code&gt;i&lt;&#x2F;code&gt; (1-indexed), &lt;code&gt;set_block_access_index(i)&lt;&#x2F;code&gt;, then execute the tx, with the EVM calling &lt;code&gt;record_storage_read&lt;&#x2F;code&gt;, &lt;code&gt;record_storage_write&lt;&#x2F;code&gt;, &lt;code&gt;record_balance_change&lt;&#x2F;code&gt;, etc.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;set_block_access_index(n+1)&lt;&#x2F;code&gt; for post-execution (withdrawals).&lt;&#x2F;li&gt;
&lt;li&gt;Consume the recorder into the final &lt;code&gt;BlockAccessList&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The EVM doesn&#x27;t care about BAL. It just emits access events. The recorder is the only thing that knows about block access indices, ordering, or filtering.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;revert-semantics-and-checkpoints&quot;&gt;Revert semantics and checkpoints&lt;&#x2F;h2&gt;
&lt;p&gt;The EIP says: &quot;State changes from reverted calls are discarded, but all accessed addresses must be included.&quot; This sounds like a footnote and is actually the most annoying part of the implementation.&lt;&#x2F;p&gt;
&lt;p&gt;The distinction is: &lt;em&gt;touches&lt;&#x2F;em&gt; persist across reverts, &lt;em&gt;state changes&lt;&#x2F;em&gt; don&#x27;t. If a &lt;code&gt;CALL&lt;&#x2F;code&gt; revert undoes a write, the slot still needs to appear in the BAL (because the SLOAD happened), but as a read, not a write. The recorder needs to be able to roll back exactly the state-change parts while keeping touched addresses and read sets intact.&lt;&#x2F;p&gt;
&lt;p&gt;ethrex uses two checkpoint types. The first is for inner-call reverts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BlockAccessListCheckpoint&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reads_promoted_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    storage_writes_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;U256&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    balance_changes_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    nonce_changes_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    code_changes_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BTreeMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice what&#x27;s missing: there&#x27;s no &lt;code&gt;touched_addresses_len&lt;&#x2F;code&gt; here, and no &lt;code&gt;storage_reads&lt;&#x2F;code&gt;. Both persist across the revert. The checkpoint only captures &lt;em&gt;lengths&lt;&#x2F;em&gt;, and restoring it truncates each vector back to its captured size. No cloning of the recorder, no copying of state. Take a checkpoint before a &lt;code&gt;CALL&lt;&#x2F;code&gt;, restore it on revert.&lt;&#x2F;p&gt;
&lt;p&gt;The second checkpoint is for a different case: a transaction during block building that fails validation entirely (gas underpriced after re-execution, etc.) and needs to be fully erased from the recorder:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; TxCheckpoint&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    inner&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BlockAccessListCheckpoint&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    current_index&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; u32&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    touched_addresses_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    storage_reads_lens&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; IndexMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    initial_balances_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    addresses_with_initial_code_len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This one &lt;em&gt;does&lt;&#x2F;em&gt; capture touched addresses and read lengths, because for a fully-rejected tx, those touches shouldn&#x27;t exist either. Same trick: lengths only, restore is &lt;code&gt;truncate()&lt;&#x2F;code&gt; and &lt;code&gt;Vec::resize()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The reason both are length-based and not copy-based: a tx can have hundreds of call frames. Cloning the recorder per frame would tip a state-heavy block into OOM. Lengths are O(addresses_changed) per checkpoint, restore is O(items_to_drop).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;net-zero-filtering&quot;&gt;Net-zero filtering&lt;&#x2F;h2&gt;
&lt;p&gt;Back to the EIP rule: &quot;If a storage slot&#x27;s value is changed but its post-transaction value is equal to its pre-transaction value, the slot MUST NOT be recorded as modified.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;This is a per-transaction rule, not per-call. You can write &lt;code&gt;slot[k] = 5&lt;&#x2F;code&gt; then &lt;code&gt;slot[k] = 0&lt;&#x2F;code&gt; (its original value) within the same tx and the BAL should show no storage change. You also can&#x27;t just suppress the write at write-time, because you don&#x27;t know the final value until the tx is done.&lt;&#x2F;p&gt;
&lt;p&gt;The recorder solves this with &lt;code&gt;tx_initial_storage&lt;&#x2F;code&gt;: a &lt;code&gt;BTreeMap&amp;lt;(Address, U256), U256&amp;gt;&lt;&#x2F;code&gt; capturing the pre-tx value of every slot first written during the current tx. When &lt;code&gt;set_block_access_index&lt;&#x2F;code&gt; is called to move to the next transaction, &lt;code&gt;filter_net_zero_storage&lt;&#x2F;code&gt; runs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; filter_net_zero_storage&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #39BAE6;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; current_idx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #39BAE6;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;current_index;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span&gt; slots_to_convert&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; ((addr, slot), pre_value)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #39BAE6;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;tx_initial_storage {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;        if let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span&gt;(slots)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #39BAE6;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;storage_writes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(addr)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;            &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt; let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span&gt;(changes)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; slots&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(slot)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;            let&lt;&#x2F;span&gt;&lt;span&gt; final_value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; changes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;filter&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt;(idx, _)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;| *&lt;&#x2F;span&gt;&lt;span&gt;idx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span&gt; current_idx)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;next_back&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt;(_, val)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;| *&lt;&#x2F;span&gt;&lt;span&gt;val);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;            if let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span&gt;(final_val)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; final_value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;                &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; final_val&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; == *&lt;&#x2F;span&gt;&lt;span&gt;pre_value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                slots_to_convert&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;addr,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt;slot));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; (addr, slot)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span&gt; slots_to_convert {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;        &#x2F;&#x2F; remove the write entries, undo any read-to-write promotion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;        &#x2F;&#x2F; and re-insert as a read&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;        &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #39BAE6;font-style: italic;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;storage_reads&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;entry&lt;&#x2F;span&gt;&lt;span&gt;(addr)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;or_default&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;insert&lt;&#x2F;span&gt;&lt;span&gt;(slot);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The subtle part is the last step: a net-zero write doesn&#x27;t disappear, it &lt;em&gt;downgrades&lt;&#x2F;em&gt; to a read. The slot was still touched. If the slot was already a read that got promoted to a write earlier in the tx (because of an SSTORE), we have to undo the promotion too. There&#x27;s a parallel &lt;code&gt;filter_net_zero_code&lt;&#x2F;code&gt; doing the same dance for code changes (delegate then reset in one tx should produce no code change).&lt;&#x2F;p&gt;
&lt;p&gt;This is one of those rules that is easy to read in the EIP and then takes three review rounds to get right in code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;block-access-index-semantics&quot;&gt;Block access index semantics&lt;&#x2F;h2&gt;
&lt;p&gt;Every change in the BAL has an index. The indices are not just transaction numbers; they encode the execution phase:&lt;&#x2F;p&gt;
&lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 680 160&quot; role=&quot;img&quot; aria-labelledby=&quot;bal-index-title bal-index-desc&quot; class=&quot;bal-index&quot;&gt;
  &lt;title id=&quot;bal-index-title&quot;&gt;Block access index timeline&lt;&#x2F;title&gt;
  &lt;desc id=&quot;bal-index-desc&quot;&gt;Horizontal timeline showing index 0 for pre-execution system contracts, indices 1 through n for transactions, and index n+1 for withdrawals.&lt;&#x2F;desc&gt;
  &lt;style&gt;
    .axis { stroke: #4d7577; stroke-width: 2; }
    .node-tx { fill: #14191F; stroke: #E6E1CF; stroke-width: 2; }
    .node-sys { fill: #14191F; stroke: #7abec2; stroke-width: 2; }
    .idx-label { fill: #7abec2; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 14px; font-weight: 600; text-anchor: middle; }
    .phase-label { fill: #E6E1CF; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 12px; text-anchor: middle; }
    .phase-sub { fill: #E6E1CF; opacity: 0.6; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 11px; text-anchor: middle; }
    .ellipsis { fill: #E6E1CF; opacity: 0.6; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 18px; text-anchor: middle; }
  &lt;&#x2F;style&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;80&quot; x2=&quot;620&quot; y2=&quot;80&quot; class=&quot;axis&quot; &#x2F;&gt;
  &lt;text x=&quot;80&quot;  y=&quot;50&quot; class=&quot;idx-label&quot;&gt;0&lt;&#x2F;text&gt;
  &lt;text x=&quot;200&quot; y=&quot;50&quot; class=&quot;idx-label&quot;&gt;1&lt;&#x2F;text&gt;
  &lt;text x=&quot;320&quot; y=&quot;50&quot; class=&quot;idx-label&quot;&gt;2&lt;&#x2F;text&gt;
  &lt;text x=&quot;500&quot; y=&quot;50&quot; class=&quot;idx-label&quot;&gt;n&lt;&#x2F;text&gt;
  &lt;text x=&quot;600&quot; y=&quot;50&quot; class=&quot;idx-label&quot;&gt;n+1&lt;&#x2F;text&gt;
  &lt;circle cx=&quot;80&quot;  cy=&quot;80&quot; r=&quot;10&quot; class=&quot;node-sys&quot; &#x2F;&gt;
  &lt;circle cx=&quot;200&quot; cy=&quot;80&quot; r=&quot;10&quot; class=&quot;node-tx&quot; &#x2F;&gt;
  &lt;circle cx=&quot;320&quot; cy=&quot;80&quot; r=&quot;10&quot; class=&quot;node-tx&quot; &#x2F;&gt;
  &lt;circle cx=&quot;500&quot; cy=&quot;80&quot; r=&quot;10&quot; class=&quot;node-tx&quot; &#x2F;&gt;
  &lt;circle cx=&quot;600&quot; cy=&quot;80&quot; r=&quot;10&quot; class=&quot;node-sys&quot; &#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;86&quot; class=&quot;ellipsis&quot;&gt;···&lt;&#x2F;text&gt;
  &lt;text x=&quot;80&quot;  y=&quot;110&quot; class=&quot;phase-label&quot;&gt;system&lt;&#x2F;text&gt;
  &lt;text x=&quot;80&quot;  y=&quot;128&quot; class=&quot;phase-sub&quot;&gt;pre-exec&lt;&#x2F;text&gt;
  &lt;text x=&quot;200&quot; y=&quot;110&quot; class=&quot;phase-label&quot;&gt;tx 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;320&quot; y=&quot;110&quot; class=&quot;phase-label&quot;&gt;tx 2&lt;&#x2F;text&gt;
  &lt;text x=&quot;500&quot; y=&quot;110&quot; class=&quot;phase-label&quot;&gt;tx n&lt;&#x2F;text&gt;
  &lt;text x=&quot;600&quot; y=&quot;110&quot; class=&quot;phase-label&quot;&gt;withdrawals&lt;&#x2F;text&gt;
  &lt;text x=&quot;600&quot; y=&quot;128&quot; class=&quot;phase-sub&quot;&gt;post-exec&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F;&#x2F; # Block Access Index Semantics&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F;&#x2F; - 0: System contracts (pre-execution phase)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F;&#x2F; - 1..n: Transaction indices (1-indexed)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;&#x2F;&#x2F;&#x2F; - n+1: Post-execution phase (withdrawals)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;System contract calls happen at index 0: EIP-2935 (historical block hashes), EIP-4788 (beacon block root). Withdrawals happen at index n+1, after all transactions. Validation rejects any BAL whose indices exceed &lt;code&gt;n+1&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This is also where &lt;code&gt;in_system_call&lt;&#x2F;code&gt; shows up in the recorder. System contracts touch &lt;code&gt;SYSTEM_ADDRESS&lt;&#x2F;code&gt; for their bookkeeping, but the spec says those touches shouldn&#x27;t appear in the BAL. The recorder filters them out while &lt;code&gt;in_system_call = true&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;two-execution-paths&quot;&gt;Two execution paths&lt;&#x2F;h2&gt;
&lt;p&gt;So far everything I&#x27;ve described, the recorder, the checkpoints, the net-zero filter, is the &lt;em&gt;builder&lt;&#x2F;em&gt; side: an execution flow that produces a BAL from scratch. ethrex has a second flow that doesn&#x27;t build a BAL at all, and that flow is the entire reason BAL exists.&lt;&#x2F;p&gt;
&lt;p&gt;The builder is sequential: execute transactions, record accesses through the recorder, consume the recorder, set the BAL hash in the produced header. The result is the canonical BAL for that block. Encoding is enforced through &lt;code&gt;encode_sorted_by&lt;&#x2F;code&gt; so two builders that observe the same accesses produce byte-identical RLP and therefore the same hash.&lt;&#x2F;p&gt;
&lt;p&gt;The validator path is different. When the consensus layer hands ethrex a block through &lt;code&gt;engine_newPayloadV5&lt;&#x2F;code&gt;, the BAL comes alongside as part of the execution payload. The validator then runs three things in parallel via &lt;code&gt;std::thread::scope&lt;&#x2F;code&gt;: a warmer that prefetches everything the BAL declares, the EVM executing transactions in parallel using the BAL to scope per-tx state, and a merkleizer that computes the post-state root from the BAL without waiting for execution to finish. There&#x27;s no &lt;code&gt;produced_bal&lt;&#x2F;code&gt; on this path; the input BAL is the ground truth.&lt;&#x2F;p&gt;
&lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 680 280&quot; role=&quot;img&quot; aria-labelledby=&quot;bal-scope-title bal-scope-desc&quot; class=&quot;bal-scope&quot;&gt;
  &lt;title id=&quot;bal-scope-title&quot;&gt;Parallel scope on the validator path&lt;&#x2F;title&gt;
  &lt;desc id=&quot;bal-scope-desc&quot;&gt;A single BAL input feeds three concurrent threads: warmer, EVM execution, and merkleizer. Their outputs converge into two gates: BAL access match and state root match.&lt;&#x2F;desc&gt;
  &lt;style&gt;
    .box-bal { fill: #0f1419; stroke: #7abec2; stroke-width: 2; }
    .box-lane { fill: #0f1419; stroke: #4d7577; stroke-width: 1.5; }
    .box-gate { fill: #0f1419; stroke: #E6E1CF; stroke-width: 1.5; }
    .arrow { stroke: #4d7577; stroke-width: 1.5; fill: none; }
    .label { fill: #E6E1CF; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 13px; }
    .label-bal { fill: #7abec2; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 15px; font-weight: 600; text-anchor: middle; }
    .label-fn { fill: #7abec2; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 11px; }
    .label-out { fill: #E6E1CF; opacity: 0.75; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 11px; }
    .label-gate { fill: #E6E1CF; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 12px; text-anchor: middle; }
    .scope-frame { fill: none; stroke: #4d7577; stroke-width: 1; stroke-dasharray: 4 4; opacity: 0.5; }
    .scope-label { fill: #E6E1CF; opacity: 0.5; font-family: &#x27;JetBrains Mono Variable&#x27;, &#x27;JetBrains Mono&#x27;, monospace; font-size: 11px; }
  &lt;&#x2F;style&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;bal-arr&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerUnits=&quot;strokeWidth&quot; markerWidth=&quot;8&quot; markerHeight=&quot;8&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#4d7577&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
  &lt;rect x=&quot;20&quot; y=&quot;105&quot; width=&quot;90&quot; height=&quot;70&quot; rx=&quot;6&quot; class=&quot;box-bal&quot; &#x2F;&gt;
  &lt;text x=&quot;65&quot; y=&quot;146&quot; class=&quot;label-bal&quot;&gt;BAL&lt;&#x2F;text&gt;
  &lt;rect x=&quot;170&quot; y=&quot;40&quot;  width=&quot;320&quot; height=&quot;44&quot; rx=&quot;6&quot; class=&quot;box-lane&quot; &#x2F;&gt;
  &lt;rect x=&quot;170&quot; y=&quot;118&quot; width=&quot;320&quot; height=&quot;44&quot; rx=&quot;6&quot; class=&quot;box-lane&quot; &#x2F;&gt;
  &lt;rect x=&quot;170&quot; y=&quot;196&quot; width=&quot;320&quot; height=&quot;44&quot; rx=&quot;6&quot; class=&quot;box-lane&quot; &#x2F;&gt;
  &lt;text x=&quot;184&quot; y=&quot;60&quot;  class=&quot;label&quot;&gt;Warmer&lt;&#x2F;text&gt;
  &lt;text x=&quot;184&quot; y=&quot;76&quot;  class=&quot;label-fn&quot;&gt;warm_block_from_bal&lt;&#x2F;text&gt;
  &lt;text x=&quot;184&quot; y=&quot;138&quot; class=&quot;label&quot;&gt;EVM&lt;&#x2F;text&gt;
  &lt;text x=&quot;184&quot; y=&quot;154&quot; class=&quot;label-fn&quot;&gt;LazyBalCursor (per tx, parallel)&lt;&#x2F;text&gt;
  &lt;text x=&quot;184&quot; y=&quot;216&quot; class=&quot;label&quot;&gt;Merkleizer&lt;&#x2F;text&gt;
  &lt;text x=&quot;184&quot; y=&quot;232&quot; class=&quot;label-fn&quot;&gt;synthesize_bal_updates → trie&lt;&#x2F;text&gt;
  &lt;rect x=&quot;155&quot; y=&quot;20&quot; width=&quot;350&quot; height=&quot;240&quot; rx=&quot;8&quot; class=&quot;scope-frame&quot; &#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;34&quot; class=&quot;scope-label&quot;&gt;std::thread::scope&lt;&#x2F;text&gt;
  &lt;path d=&quot;M 110 130 C 140 130, 140 62, 168 62&quot;  class=&quot;arrow lane-in lane-in-warmer&quot;    marker-end=&quot;url(#bal-arr)&quot; &#x2F;&gt;
  &lt;path d=&quot;M 110 140 L 168 140&quot;                  class=&quot;arrow lane-in lane-in-evm&quot;       marker-end=&quot;url(#bal-arr)&quot; &#x2F;&gt;
  &lt;path d=&quot;M 110 150 C 140 150, 140 218, 168 218&quot; class=&quot;arrow lane-in lane-in-merkleize&quot; marker-end=&quot;url(#bal-arr)&quot; &#x2F;&gt;
  &lt;path d=&quot;M 490 62  C 540 62, 540 110, 568 110&quot; class=&quot;arrow lane-out lane-out-warmer&quot;    marker-end=&quot;url(#bal-arr)&quot; &#x2F;&gt;
  &lt;path d=&quot;M 490 140 L 568 140&quot;                  class=&quot;arrow lane-out lane-out-evm&quot;       marker-end=&quot;url(#bal-arr)&quot; &#x2F;&gt;
  &lt;path d=&quot;M 490 218 C 540 218, 540 170, 568 170&quot; class=&quot;arrow lane-out lane-out-merkleize&quot; marker-end=&quot;url(#bal-arr)&quot; &#x2F;&gt;
  &lt;text x=&quot;495&quot; y=&quot;58&quot;  class=&quot;label-out&quot;&gt;caches&lt;&#x2F;text&gt;
  &lt;text x=&quot;495&quot; y=&quot;136&quot; class=&quot;label-out&quot;&gt;unread sets&lt;&#x2F;text&gt;
  &lt;text x=&quot;495&quot; y=&quot;214&quot; class=&quot;label-out&quot;&gt;state root&lt;&#x2F;text&gt;
  &lt;rect x=&quot;568&quot; y=&quot;95&quot;  width=&quot;100&quot; height=&quot;32&quot; rx=&quot;6&quot; class=&quot;box-gate gate-hash&quot; &#x2F;&gt;
  &lt;text x=&quot;618&quot; y=&quot;115&quot; class=&quot;label-gate&quot;&gt;hash gate&lt;&#x2F;text&gt;
  &lt;rect x=&quot;568&quot; y=&quot;153&quot; width=&quot;100&quot; height=&quot;32&quot; rx=&quot;6&quot; class=&quot;box-gate gate-root&quot; &#x2F;&gt;
  &lt;text x=&quot;618&quot; y=&quot;173&quot; class=&quot;label-gate&quot;&gt;root gate&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;h3 id=&quot;deterministic-prewarm&quot;&gt;Deterministic prewarm&lt;&#x2F;h3&gt;
&lt;p&gt;Without a BAL, the only way to prewarm state is to guess what the EVM will touch. ethrex&#x27;s fallback warmer does this by speculatively re-executing transactions in parallel, grouped by sender (Nethermind&#x27;s trick: same-sender txs sequentially, different senders in parallel). It&#x27;s an educated guess. Sometimes wrong, often wasteful.&lt;&#x2F;p&gt;
&lt;p&gt;With a BAL, the guess is replaced by a list. &lt;code&gt;warm_block_from_bal&lt;&#x2F;code&gt; walks the BAL and prefetches in two phases: every account first (which warms the trie layer cache), then every storage slot and bytecode (which benefit from the trie nodes already cached in phase one). No re-execution, no speculation, exact set.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; warm_block_from_bal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;BlockAccessList&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Arc&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;dyn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Database&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cancelled&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;AtomicBool&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; EvmError&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; account_addresses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; bal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;accounts&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt;ac&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; ac&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;address)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    store&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt;prefetch_accounts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;account_addresses)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;    &#x2F;&#x2F; phase 2: parallel per-slot storage + per-account code prefetch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The warmer runs on its own thread inside the scope. If it falls behind the EVM, the EVM does the IO itself; the prewarm is opportunistic, not a barrier.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;parallel-transaction-execution&quot;&gt;Parallel transaction execution&lt;&#x2F;h3&gt;
&lt;p&gt;The BAL declares exactly what each transaction will touch, so each transaction can execute against a database view that contains only its declared subset. The mechanism is &lt;code&gt;LazyBalCursor&lt;&#x2F;code&gt;: each per-tx database holds a cursor into the BAL scoped to that tx&#x27;s &lt;code&gt;block_access_index&lt;&#x2F;code&gt;. When the EVM calls &lt;code&gt;get_storage_value&lt;&#x2F;code&gt; or &lt;code&gt;load_account&lt;&#x2F;code&gt;, the cursor lazily materializes that single slot or account from the BAL overlay, not the whole tx&#x27;s slice.&lt;&#x2F;p&gt;
&lt;p&gt;That keeps per-tx seeding cost at O(touched-by-this-tx) instead of O(BAL). It also means cross-tx interference is impossible by construction: if two txs touch the same slot, the later tx&#x27;s cursor resolves to the earlier tx&#x27;s post-value, copied into its scoped view; there&#x27;s no shared mutable reference.&lt;&#x2F;p&gt;
&lt;p&gt;While the txs run in parallel, a shadow recorder per tx notes which addresses and slots the EVM actually touched. Two block-wide sets, &lt;code&gt;unread_storage_reads&lt;&#x2F;code&gt; and &lt;code&gt;unaccessed_pure_accounts&lt;&#x2F;code&gt;, are seeded from the BAL up front. Each tx&#x27;s shadow recorder removes the entries it satisfied. After all txs, withdrawals, and request extraction have run, both sets must be empty. If they aren&#x27;t, the BAL claimed something that didn&#x27;t happen, and the block is rejected. The reverse direction is enforced by construction: an EVM access for a slot the BAL didn&#x27;t list can&#x27;t be satisfied by the scoped view, so the block fails as soon as the missing access surfaces.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;optimistic-merkleization&quot;&gt;Optimistic merkleization&lt;&#x2F;h3&gt;
&lt;p&gt;Computing the post-state root is usually the dominant cost after EVM execution finishes. With a BAL, you don&#x27;t need to wait. The BAL declares every post-state value: last &lt;code&gt;BalanceChange.post_balance&lt;&#x2F;code&gt;, last &lt;code&gt;NonceChange.post_nonce&lt;&#x2F;code&gt;, last &lt;code&gt;CodeChange.new_code&lt;&#x2F;code&gt;, last &lt;code&gt;StorageChange.post_value&lt;&#x2F;code&gt; per slot. That&#x27;s enough to drive trie updates.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;synthesize_bal_updates&lt;&#x2F;code&gt; collapses the BAL into a per-account map of field-level deltas:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #BFBDB6; background-color: #0D1017;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BalSynthesisItem&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;U256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; nonce&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; code_hash&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;H256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; code&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Code&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;    pub&lt;&#x2F;span&gt;&lt;span&gt; added_storage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; FxHashMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;H256&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; U256&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF8F40;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFB454;&quot;&gt; synthesize_bal_updates&lt;&#x2F;span&gt;&lt;span&gt;(bal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;BlockAccessList&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F29668;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; FxHashMap&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #59C2FF;&quot;&gt; BalSynthesisItem&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5A6673;font-style: italic;&quot;&gt;    &#x2F;&#x2F; ... last() of each change vector, per account&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The merkleizer thread takes this map and starts trie work the moment block execution begins, in parallel with the EVM. Two gates guard the result: (1) every BAL entry must be accessed (the &lt;code&gt;unread_storage_reads&lt;&#x2F;code&gt; + &lt;code&gt;unaccessed_pure_accounts&lt;&#x2F;code&gt; check above), and (2) the computed state root must equal &lt;code&gt;header.state_root&lt;&#x2F;code&gt;. If either fails, the optimistic merkle output is discarded.&lt;&#x2F;p&gt;
&lt;p&gt;Accounts that appear in the BAL only via &lt;code&gt;storage_reads&lt;&#x2F;code&gt; (no actual changes) are skipped: their trie state is unchanged, so there&#x27;s nothing for the merkleizer to do for them.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-cheap-checks-both-paths-share&quot;&gt;The cheap checks both paths share&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;validate_header_bal_indices&lt;&#x2F;code&gt; rejects any BAL with an index &amp;gt; &lt;code&gt;n+1&lt;&#x2F;code&gt;. &lt;code&gt;BAL_ITEM_COST = 2000&lt;&#x2F;code&gt; caps total items at &lt;code&gt;gas_limit &#x2F; 2000&lt;&#x2F;code&gt; (15,000 for a 30M gas block) as a DoS bound. These run early on both paths so a bogus BAL fails fast.&lt;&#x2F;p&gt;
&lt;p&gt;The split is the architectural point: building a BAL is sequential and easy to reason about; validating one parallelizes three expensive things at once (prefetch, execution, merkleization) because the BAL itself tells each of them what to do.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to read the source: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&#x2F;blob&#x2F;main&#x2F;crates&#x2F;common&#x2F;types&#x2F;block_access_list.rs&quot;&gt;&lt;code&gt;block_access_list.rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&#x2F;blob&#x2F;main&#x2F;crates&#x2F;common&#x2F;validation.rs&quot;&gt;&lt;code&gt;validation.rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&#x2F;blob&#x2F;main&#x2F;crates&#x2F;vm&#x2F;backends&#x2F;levm&#x2F;mod.rs&quot;&gt;&lt;code&gt;vm&#x2F;backends&#x2F;levm&#x2F;mod.rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&quot;&gt;ethrex&lt;&#x2F;a&gt;, and the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eips.ethereum.org&#x2F;EIPS&#x2F;eip-7928&quot;&gt;EIP&lt;&#x2F;a&gt; itself.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
