2
2
Block Access List Builder for EIP-7928
3
3
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4
4
5
- This module implements the Block Access List builder that tracks all account and storage
6
- accesses during block execution and constructs the final BlockAccessList.
5
+ This module implements the Block Access List builder that tracks all account
6
+ and storage accesses during block execution and constructs the final
7
+ [`BlockAccessList`].
8
+
9
+ The builder follows a two-phase approach:
10
+
11
+ 1. **Collection Phase**: During transaction execution, all state accesses are
12
+ recorded via the tracking functions.
13
+ 2. **Build Phase**: After block execution, the accumulated data is sorted
14
+ and encoded into the final deterministic format.
15
+
16
+ [`BlockAccessList`]: ref:ethereum.osaka.ssz_types.BlockAccessList
7
17
"""
8
18
9
19
from dataclasses import dataclass , field
27
37
@dataclass
28
38
class AccountData :
29
39
"""
30
- Account data stored in the builder.
40
+ Account data stored in the builder during block execution.
41
+
42
+ This dataclass tracks all changes made to a single account throughout
43
+ the execution of a block, organized by the type of change and the
44
+ transaction index where it occurred.
31
45
"""
32
46
storage_changes : Dict [Bytes , List [StorageChange ]] = field (default_factory = dict )
47
+ """
48
+ Mapping from storage slot to list of changes made to that slot.
49
+ Each change includes the transaction index and new value.
50
+ """
51
+
33
52
storage_reads : Set [Bytes ] = field (default_factory = set )
53
+ """
54
+ Set of storage slots that were read but not modified.
55
+ """
56
+
34
57
balance_changes : List [BalanceChange ] = field (default_factory = list )
58
+ """
59
+ List of balance changes for this account, ordered by transaction index.
60
+ """
61
+
35
62
nonce_changes : List [NonceChange ] = field (default_factory = list )
63
+ """
64
+ List of nonce changes for this account, ordered by transaction index.
65
+ """
66
+
36
67
code_changes : List [CodeChange ] = field (default_factory = list )
68
+ """
69
+ List of code changes (contract deployments) for this account,
70
+ ordered by transaction index.
71
+ """
37
72
38
73
39
74
@dataclass
40
75
class BlockAccessListBuilder :
41
76
"""
42
- Builder for constructing `BlockAccessList` efficiently during transaction
77
+ Builder for constructing [ `BlockAccessList`] efficiently during transaction
43
78
execution.
44
79
45
80
The builder accumulates all account and storage accesses during block
46
- execution and constructs a deterministic access list following the pattern:
47
- address -> field -> tx_index -> change
81
+ execution and constructs a deterministic access list. Changes are tracked
82
+ by address, field type, and transaction index to enable efficient
83
+ reconstruction of state changes.
84
+
85
+ [`BlockAccessList`]: ref:ethereum.osaka.ssz_types.BlockAccessList
48
86
"""
49
87
accounts : Dict [Address , AccountData ] = field (default_factory = dict )
88
+ """
89
+ Mapping from account address to its tracked changes during block execution.
90
+ """
50
91
51
92
52
93
def ensure_account (builder : BlockAccessListBuilder , address : Address ) -> None :
53
94
"""
54
- Ensure account exists in builder.
95
+ Ensure an account exists in the builder's tracking structure.
96
+
97
+ Creates an empty [`AccountData`] entry for the given address if it
98
+ doesn't already exist. This function is idempotent and safe to call
99
+ multiple times for the same address.
55
100
56
- Creates an empty account entry if it doesn't already exist.
101
+ Parameters
102
+ ----------
103
+ builder :
104
+ The block access list builder instance.
105
+ address :
106
+ The account address to ensure exists.
107
+
108
+ [`AccountData`]: ref:ethereum.osaka.block_access_lists.builder.AccountData
57
109
"""
58
110
if address not in builder .accounts :
59
111
builder .accounts [address ] = AccountData ()
@@ -63,21 +115,35 @@ def add_storage_write(
63
115
builder : BlockAccessListBuilder ,
64
116
address : Address ,
65
117
slot : Bytes ,
66
- tx_index : int ,
118
+ tx_index : U32 ,
67
119
new_value : Bytes
68
120
) -> None :
69
121
"""
70
- Add storage write to the block access list.
122
+ Add a storage write operation to the block access list.
71
123
72
124
Records a storage slot modification for a given address at a specific
73
- transaction index.
125
+ transaction index. Multiple writes to the same slot are tracked
126
+ separately, maintaining the order and transaction index of each change.
127
+
128
+ Parameters
129
+ ----------
130
+ builder :
131
+ The block access list builder instance.
132
+ address :
133
+ The account address whose storage is being modified.
134
+ slot :
135
+ The storage slot being written to.
136
+ tx_index :
137
+ The index of the transaction making this change.
138
+ new_value :
139
+ The new value being written to the storage slot.
74
140
"""
75
141
ensure_account (builder , address )
76
142
77
143
if slot not in builder .accounts [address ].storage_changes :
78
144
builder .accounts [address ].storage_changes [slot ] = []
79
145
80
- change = StorageChange (tx_index = U32 ( tx_index ) , new_value = new_value )
146
+ change = StorageChange (tx_index = tx_index , new_value = new_value )
81
147
builder .accounts [address ].storage_changes [slot ].append (change )
82
148
83
149
@@ -87,10 +153,22 @@ def add_storage_read(
87
153
slot : Bytes
88
154
) -> None :
89
155
"""
90
- Add storage read to the block access list.
156
+ Add a storage read operation to the block access list.
91
157
92
- Records a storage slot read for a given address. Only slots that are
93
- not also written to will be included in the final access list.
158
+ Records that a storage slot was read during execution. Storage slots
159
+ that are both read and written will only appear in the storage changes
160
+ list, not in the storage reads list, as per [EIP-7928].
161
+
162
+ Parameters
163
+ ----------
164
+ builder :
165
+ The block access list builder instance.
166
+ address :
167
+ The account address whose storage is being read.
168
+ slot :
169
+ The storage slot being read.
170
+
171
+ [EIP-7928]: https://eips.ethereum.org/EIPS/eip-7928
94
172
"""
95
173
ensure_account (builder , address )
96
174
builder .accounts [address ].storage_reads .add (slot )
@@ -99,73 +177,147 @@ def add_storage_read(
99
177
def add_balance_change (
100
178
builder : BlockAccessListBuilder ,
101
179
address : Address ,
102
- tx_index : int ,
180
+ tx_index : U32 ,
103
181
post_balance : Bytes
104
182
) -> None :
105
183
"""
106
- Add balance change to the block access list.
184
+ Add a balance change to the block access list.
107
185
108
- Records a balance change for a given address at a specific transaction
109
- index.
186
+ Records the post-transaction balance for an account after it has been
187
+ modified. This includes changes from transfers, gas fees, block rewards,
188
+ and any other balance-affecting operations.
189
+
190
+ Parameters
191
+ ----------
192
+ builder :
193
+ The block access list builder instance.
194
+ address :
195
+ The account address whose balance changed.
196
+ tx_index :
197
+ The index of the transaction causing this change.
198
+ post_balance :
199
+ The account balance after the change, encoded as bytes.
110
200
"""
111
201
ensure_account (builder , address )
112
202
113
- change = BalanceChange (tx_index = U32 ( tx_index ) , post_balance = post_balance )
203
+ change = BalanceChange (tx_index = tx_index , post_balance = post_balance )
114
204
builder .accounts [address ].balance_changes .append (change )
115
205
116
206
117
207
def add_nonce_change (
118
208
builder : BlockAccessListBuilder ,
119
209
address : Address ,
120
- tx_index : int ,
121
- new_nonce : int
210
+ tx_index : U32 ,
211
+ new_nonce : U64
122
212
) -> None :
123
213
"""
124
- Add nonce change to the block access list.
214
+ Add a nonce change to the block access list.
215
+
216
+ Records a nonce increment for an account. This occurs when an EOA sends
217
+ a transaction or when a contract performs [`CREATE`] or [`CREATE2`]
218
+ operations.
125
219
126
- Records a nonce change for a given address at a specific transaction
127
- index.
220
+ Parameters
221
+ ----------
222
+ builder :
223
+ The block access list builder instance.
224
+ address :
225
+ The account address whose nonce changed.
226
+ tx_index :
227
+ The index of the transaction causing this change.
228
+ new_nonce :
229
+ The new nonce value after the change.
230
+
231
+ [`CREATE`]: ref:ethereum.osaka.vm.instructions.system.create
232
+ [`CREATE2`]: ref:ethereum.osaka.vm.instructions.system.create2
128
233
"""
129
234
ensure_account (builder , address )
130
235
131
- change = NonceChange (tx_index = U32 ( tx_index ) , new_nonce = U64 ( new_nonce ) )
236
+ change = NonceChange (tx_index = tx_index , new_nonce = new_nonce )
132
237
builder .accounts [address ].nonce_changes .append (change )
133
238
134
239
135
240
def add_code_change (
136
241
builder : BlockAccessListBuilder ,
137
242
address : Address ,
138
- tx_index : int ,
243
+ tx_index : U32 ,
139
244
new_code : Bytes
140
245
) -> None :
141
246
"""
142
- Add code change to the block access list.
247
+ Add a code change to the block access list.
248
+
249
+ Records contract code deployment or modification. This typically occurs
250
+ during contract creation via [`CREATE`], [`CREATE2`], or [`SETCODE`]
251
+ operations.
252
+
253
+ Parameters
254
+ ----------
255
+ builder :
256
+ The block access list builder instance.
257
+ address :
258
+ The account address receiving new code.
259
+ tx_index :
260
+ The index of the transaction deploying the code.
261
+ new_code :
262
+ The deployed contract bytecode.
143
263
144
- Records a code change for a given address at a specific transaction
145
- index.
264
+ [`CREATE`]: ref:ethereum.osaka.vm.instructions.system.create
265
+ [`CREATE2`]: ref:ethereum.osaka.vm.instructions.system.create2
266
+ [`SETCODE`]: ref:ethereum.osaka.vm.instructions.system.setcode
146
267
"""
147
268
ensure_account (builder , address )
148
269
149
- change = CodeChange (tx_index = U32 ( tx_index ) , new_code = new_code )
270
+ change = CodeChange (tx_index = tx_index , new_code = new_code )
150
271
builder .accounts [address ].code_changes .append (change )
151
272
152
273
153
274
def add_touched_account (builder : BlockAccessListBuilder , address : Address ) -> None :
154
275
"""
155
- Add an account that was touched but not changed.
276
+ Add an account that was accessed but not modified.
277
+
278
+ Records that an account was accessed during execution without any state
279
+ changes. This is used for operations like [`EXTCODEHASH`], [`BALANCE`],
280
+ [`EXTCODESIZE`], and [`EXTCODECOPY`] that read account data without
281
+ modifying it.
282
+
283
+ Parameters
284
+ ----------
285
+ builder :
286
+ The block access list builder instance.
287
+ address :
288
+ The account address that was accessed.
156
289
157
- Used for operations like EXTCODEHASH or BALANCE checks that access
158
- an account without modifying it.
290
+ [`EXTCODEHASH`]: ref:ethereum.osaka.vm.instructions.environment.extcodehash
291
+ [`BALANCE`]: ref:ethereum.osaka.vm.instructions.environment.balance
292
+ [`EXTCODESIZE`]: ref:ethereum.osaka.vm.instructions.environment.extcodesize
293
+ [`EXTCODECOPY`]: ref:ethereum.osaka.vm.instructions.environment.extcodecopy
159
294
"""
160
295
ensure_account (builder , address )
161
296
162
297
163
298
def build (builder : BlockAccessListBuilder ) -> BlockAccessList :
164
299
"""
165
- Build the final BlockAccessList.
300
+ Build the final [`BlockAccessList`] from accumulated changes.
301
+
302
+ Constructs a deterministic block access list by sorting all accumulated
303
+ changes. The resulting list is ordered by:
304
+
305
+ 1. Account addresses (lexicographically)
306
+ 2. Within each account:
307
+ - Storage slots (lexicographically)
308
+ - Transaction indices (numerically) for each change type
309
+
310
+ Parameters
311
+ ----------
312
+ builder :
313
+ The block access list builder containing all tracked changes.
314
+
315
+ Returns
316
+ -------
317
+ block_access_list :
318
+ The final sorted and encoded block access list.
166
319
167
- Constructs a sorted and deterministic block access list from all
168
- accumulated changes.
320
+ [`BlockAccessList`]: ref:ethereum.osaka.ssz_types.BlockAccessList
169
321
"""
170
322
account_changes_list = []
171
323
0 commit comments