ethereum.forks.paris.trieethereum.forks.shanghai.trie

State Trie.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

The state trie is the structure responsible for storing .fork_types.Account objects.

EMPTY_TRIE_ROOT

59
EMPTY_TRIE_ROOT = Root(
60
    hex_to_bytes(
61
        "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
62
    )
63
)

Node

65
Node = Account | Bytes | LegacyTransaction | Receipt | Uint | U256 | None
65
Node = (
66
    Account
67
    | Bytes
68
    | LegacyTransaction
69
    | Receipt
70
    | Uint
71
    | U256
72
    | Withdrawal
73
    | None
74
)

K

75
K = TypeVar("K", bound=Bytes)

V

76
V = TypeVar(
77
    "V",
78
    Optional[Account],
79
    Optional[Bytes],
80
    Bytes,
81
    Optional[LegacyTransaction | Bytes],
82
    Optional[Receipt | Bytes],
83
    Optional[Withdrawal | Bytes],
84
    Uint,
85
    U256,
86
)

LeafNode

Leaf node in the Merkle Trie.

89
@slotted_freezable
90
@dataclass
class LeafNode:

rest_of_key

94
    rest_of_key: Bytes

value

95
    value: Extended

ExtensionNode

Extension node in the Merkle Trie.

98
@slotted_freezable
99
@dataclass
class ExtensionNode:

key_segment

103
    key_segment: Bytes

subnode

104
    subnode: Extended

BranchSubnodes

107
BranchSubnodes = Tuple[
108
    Extended,
109
    Extended,
110
    Extended,
111
    Extended,
112
    Extended,
113
    Extended,
114
    Extended,
115
    Extended,
116
    Extended,
117
    Extended,
118
    Extended,
119
    Extended,
120
    Extended,
121
    Extended,
122
    Extended,
123
    Extended,
124
]

BranchNode

Branch node in the Merkle Trie.

127
@slotted_freezable
128
@dataclass
class BranchNode:

subnodes

132
    subnodes: BranchSubnodes

value

133
    value: Extended

InternalNode

136
InternalNode = LeafNode | ExtensionNode | BranchNode

encode_internal_node

Encodes a Merkle Trie node into its RLP form. The RLP will then be serialized into a Bytes and hashed unless it is less than 32 bytes when serialized.

This function also accepts None, representing the absence of a node, which is encoded to b"".

Parameters

node : Optional[InternalNode] The node to encode.

Returns

encoded : rlp.RLPExtended The node encoded as RLP.

def encode_internal_node(node: Optional[InternalNode]) -> Extended:
140
    """
141
    Encodes a Merkle Trie node into its RLP form. The RLP will then be
142
    serialized into a `Bytes` and hashed unless it is less than 32 bytes
143
    when serialized.
144
145
    This function also accepts `None`, representing the absence of a node,
146
    which is encoded to `b""`.
147
148
    Parameters
149
    ----------
150
    node : Optional[InternalNode]
151
        The node to encode.
152
153
    Returns
154
    -------
145
    encoded : `rlp.RLP`
155
    encoded : `Extended`
156
        The node encoded as RLP.
157
158
    """
159
    unencoded: Extended
160
    if node is None:
161
        unencoded = b""
162
    elif isinstance(node, LeafNode):
163
        unencoded = (
164
            nibble_list_to_compact(node.rest_of_key, True),
165
            node.value,
166
        )
167
    elif isinstance(node, ExtensionNode):
168
        unencoded = (
169
            nibble_list_to_compact(node.key_segment, False),
170
            node.subnode,
171
        )
172
    elif isinstance(node, BranchNode):
173
        unencoded = list(node.subnodes) + [node.value]
174
    else:
175
        raise AssertionError(f"Invalid internal node type {type(node)}!")
176
177
    encoded = rlp.encode(unencoded)
178
    if len(encoded) < 32:
179
        return unencoded
180
    else:
181
        return keccak256(encoded)

encode_node

Encode a Node for storage in the Merkle Trie.

Currently mostly an unimplemented stub.

def encode_node(node: Node, ​​storage_root: Optional[Bytes]) -> Bytes:
185
    """
186
    Encode a Node for storage in the Merkle Trie.
187
188
    Currently mostly an unimplemented stub.
189
    """
190
    if isinstance(node, Account):
191
        assert storage_root is not None
192
        return encode_account(node, storage_root)
183
    elif isinstance(node, (LegacyTransaction, Receipt, U256)):
193
    elif isinstance(node, (LegacyTransaction, Receipt, Withdrawal, U256)):
194
        return rlp.encode(node)
195
    elif isinstance(node, Bytes):
196
        return node
197
    else:
188
        return previous_trie.encode_node(node, storage_root)
198
        return previous_trie.encode_node(node, storage_root)

Trie

The Merkle Trie.

201
@dataclass
class Trie:

secured

207
    secured: bool

default

208
    default: V

_data

209
    _data: Dict[K, V] = field(default_factory=dict)

copy_trie

Create a copy of trie. Since only frozen objects may be stored in tries, the contents are reused.

Parameters

trie: Trie Trie to copy.

Returns

new_trie : Trie[K, V] A copy of the trie.

def copy_trie(trie: Trie[K, V]) -> Trie[K, V]:
213
    """
214
    Create a copy of `trie`. Since only frozen objects may be stored in tries,
215
    the contents are reused.
216
217
    Parameters
218
    ----------
219
    trie: `Trie`
220
        Trie to copy.
221
222
    Returns
223
    -------
224
    new_trie : `Trie[K, V]`
225
        A copy of the trie.
226
227
    """
228
    return Trie(trie.secured, trie.default, copy.copy(trie._data))

trie_set

Stores an item in a Merkle Trie.

This method deletes the key if value == trie.default, because the Merkle Trie represents the default value by omitting it from the trie.

Parameters

trie: Trie Trie to store in. key : Bytes Key to lookup. value : V Node to insert at key.

def trie_set(trie: Trie[K, V], ​​key: K, ​​value: V) -> None:
232
    """
233
    Stores an item in a Merkle Trie.
234
235
    This method deletes the key if `value == trie.default`, because the Merkle
236
    Trie represents the default value by omitting it from the trie.
237
238
    Parameters
239
    ----------
240
    trie: `Trie`
241
        Trie to store in.
242
    key : `Bytes`
243
        Key to lookup.
244
    value : `V`
245
        Node to insert at `key`.
246
247
    """
248
    if value == trie.default:
249
        if key in trie._data:
250
            del trie._data[key]
251
    else:
252
        trie._data[key] = value

trie_get

Gets an item from the Merkle Trie.

This method returns trie.default if the key is missing.

Parameters

trie: Trie to lookup in. key : Key to lookup.

Returns

node : V Node at key in the trie.

def trie_get(trie: Trie[K, V], ​​key: K) -> V:
256
    """
257
    Gets an item from the Merkle Trie.
258
259
    This method returns `trie.default` if the key is missing.
260
261
    Parameters
262
    ----------
263
    trie:
264
        Trie to lookup in.
265
    key :
266
        Key to lookup.
267
268
    Returns
269
    -------
270
    node : `V`
271
        Node at `key` in the trie.
272
273
    """
274
    return trie._data.get(key, trie.default)

common_prefix_length

Find the longest common prefix of two sequences.

def common_prefix_length(a: Sequence, ​​b: Sequence) -> int:
278
    """
279
    Find the longest common prefix of two sequences.
280
    """
281
    for i in range(len(a)):
282
        if i >= len(b) or a[i] != b[i]:
283
            return i
284
    return len(a)

nibble_list_to_compact

Compresses nibble-list into a standard byte array with a flag.

A nibble-list is a list of byte values no greater than 15. The flag is encoded in high nibble of the highest byte. The flag nibble can be broken down into two two-bit flags.

Highest nibble::

+---+---+----------+--------+
| _ | _ | is_leaf | parity |
+---+---+----------+--------+
  3   2      1         0

The lowest bit of the nibble encodes the parity of the length of the remaining nibbles -- 0 when even and 1 when odd. The second lowest bit is used to distinguish leaf and extension nodes. The other two bits are not used.

Parameters

x : Array of nibbles. is_leaf : True if this is part of a leaf node, or false if it is an extension node.

Returns

compressed : bytearray Compact byte array.

def nibble_list_to_compact(x: Bytes, ​​is_leaf: bool) -> Bytes:
288
    """
289
    Compresses nibble-list into a standard byte array with a flag.
290
291
    A nibble-list is a list of byte values no greater than `15`. The flag is
292
    encoded in high nibble of the highest byte. The flag nibble can be broken
293
    down into two two-bit flags.
294
295
    Highest nibble::
296
297
        +---+---+----------+--------+
298
        | _ | _ | is_leaf | parity |
299
        +---+---+----------+--------+
300
          3   2      1         0
301
302
303
    The lowest bit of the nibble encodes the parity of the length of the
304
    remaining nibbles -- `0` when even and `1` when odd. The second lowest bit
305
    is used to distinguish leaf and extension nodes. The other two bits are not
306
    used.
307
308
    Parameters
309
    ----------
310
    x :
311
        Array of nibbles.
312
    is_leaf :
313
        True if this is part of a leaf node, or false if it is an extension
314
        node.
315
316
    Returns
317
    -------
318
    compressed : `bytearray`
319
        Compact byte array.
320
321
    """
322
    compact = bytearray()
323
324
    if len(x) % 2 == 0:  # ie even length
325
        compact.append(16 * (2 * is_leaf))
326
        for i in range(0, len(x), 2):
327
            compact.append(16 * x[i] + x[i + 1])
328
    else:
329
        compact.append(16 * ((2 * is_leaf) + 1) + x[0])
330
        for i in range(1, len(x), 2):
331
            compact.append(16 * x[i] + x[i + 1])
332
333
    return Bytes(compact)

bytes_to_nibble_list

Converts a Bytes into to a sequence of nibbles (bytes with value < 16).

Parameters

bytes_: The Bytes to convert.

Returns

nibble_list : Bytes The Bytes in nibble-list format.

def bytes_to_nibble_list(bytes_: Bytes) -> Bytes:
337
    """
338
    Converts a `Bytes` into to a sequence of nibbles (bytes with value < 16).
339
340
    Parameters
341
    ----------
342
    bytes_:
343
        The `Bytes` to convert.
344
345
    Returns
346
    -------
347
    nibble_list : `Bytes`
348
        The `Bytes` in nibble-list format.
349
350
    """
351
    nibble_list = bytearray(2 * len(bytes_))
352
    for byte_index, byte in enumerate(bytes_):
353
        nibble_list[byte_index * 2] = (byte & 0xF0) >> 4
354
        nibble_list[byte_index * 2 + 1] = byte & 0x0F
355
    return Bytes(nibble_list)

_prepare_trie

Prepares the trie for root calculation. Removes values that are empty, hashes the keys (if secured == True) and encodes all the nodes.

Parameters

trie : The Trie to prepare. get_storage_root : Function to get the storage root of an account. Needed to encode Account objects.

Returns

out : Mapping[ethereum.base_types.Bytes, Node] Object with keys mapped to nibble-byte form.

def _prepare_trie(trie: Trie[K, V], ​​get_storage_root: Optional[Callable[[Address], Root]]) -> Mapping[Bytes, Bytes]:
362
    """
363
    Prepares the trie for root calculation. Removes values that are empty,
364
    hashes the keys (if `secured == True`) and encodes all the nodes.
365
366
    Parameters
367
    ----------
368
    trie :
369
        The `Trie` to prepare.
370
    get_storage_root :
371
        Function to get the storage root of an account. Needed to encode
372
        `Account` objects.
373
374
    Returns
375
    -------
376
    out : `Mapping[ethereum.base_types.Bytes, Node]`
377
        Object with keys mapped to nibble-byte form.
378
379
    """
380
    mapped: MutableMapping[Bytes, Bytes] = {}
381
382
    for preimage, value in trie._data.items():
383
        if isinstance(value, Account):
384
            assert get_storage_root is not None
385
            address = Address(preimage)
386
            encoded_value = encode_node(value, get_storage_root(address))
387
        else:
388
            encoded_value = encode_node(value)
389
        if encoded_value == b"":
390
            raise AssertionError
391
        key: Bytes
392
        if trie.secured:
393
            # "secure" tries hash keys once before construction
394
            key = keccak256(preimage)
395
        else:
396
            key = preimage
397
        mapped[bytes_to_nibble_list(key)] = encoded_value
398
399
    return mapped

root

Computes the root of a modified merkle patricia trie (MPT).

Parameters

trie : Trie to get the root of. get_storage_root : Function to get the storage root of an account. Needed to encode Account objects.

Returns

root : .fork_types.Root MPT root of the underlying key-value pairs.

def root(trie: Trie[K, V], ​​get_storage_root: Optional[Callable[[Address], Root]]) -> Root:
406
    """
407
    Computes the root of a modified merkle patricia trie (MPT).
408
409
    Parameters
410
    ----------
411
    trie :
412
        `Trie` to get the root of.
413
    get_storage_root :
414
        Function to get the storage root of an account. Needed to encode
415
        `Account` objects.
416
417
418
    Returns
419
    -------
420
    root : `.fork_types.Root`
421
        MPT root of the underlying key-value pairs.
422
423
    """
424
    obj = _prepare_trie(trie, get_storage_root)
425
426
    root_node = encode_internal_node(patricialize(obj, Uint(0)))
427
    if len(rlp.encode(root_node)) < 32:
428
        return keccak256(rlp.encode(root_node))
429
    else:
430
        assert isinstance(root_node, Bytes)
431
        return Root(root_node)

patricialize

Structural composition function.

Used to recursively patricialize and merkleize a dictionary. Includes memoization of the tree structure and hashes.

Parameters

obj : Underlying trie key-value pairs, with keys in nibble-list format. level : Current trie level.

Returns

node : ethereum.base_types.Bytes Root node of obj.

def patricialize(obj: Mapping[Bytes, Bytes], ​​level: Uint) -> Optional[InternalNode]:
437
    """
438
    Structural composition function.
439
440
    Used to recursively patricialize and merkleize a dictionary. Includes
441
    memoization of the tree structure and hashes.
442
443
    Parameters
444
    ----------
445
    obj :
446
        Underlying trie key-value pairs, with keys in nibble-list format.
447
    level :
448
        Current trie level.
449
450
    Returns
451
    -------
452
    node : `ethereum.base_types.Bytes`
453
        Root node of `obj`.
454
455
    """
456
    if len(obj) == 0:
457
        return None
458
459
    arbitrary_key = next(iter(obj))
460
461
    # if leaf node
462
    if len(obj) == 1:
463
        leaf = LeafNode(arbitrary_key[level:], obj[arbitrary_key])
464
        return leaf
465
466
    # prepare for extension node check by finding max j such that all keys in
467
    # obj have the same key[i:j]
468
    substring = arbitrary_key[level:]
469
    prefix_length = len(substring)
470
    for key in obj:
471
        prefix_length = min(
472
            prefix_length, common_prefix_length(substring, key[level:])
473
        )
474
475
        # finished searching, found another key at the current level
476
        if prefix_length == 0:
477
            break
478
479
    # if extension node
480
    if prefix_length > 0:
481
        prefix = arbitrary_key[int(level) : int(level) + prefix_length]
482
        return ExtensionNode(
483
            prefix,
484
            encode_internal_node(
485
                patricialize(obj, level + Uint(prefix_length))
486
            ),
487
        )
488
489
    branches: List[MutableMapping[Bytes, Bytes]] = []
490
    for _ in range(16):
491
        branches.append({})
492
    value = b""
493
    for key in obj:
494
        if len(key) == level:
495
            # shouldn't ever have an account or receipt in an internal node
496
            if isinstance(obj[key], (Account, Receipt, Uint)):
497
                raise AssertionError
498
            value = obj[key]
499
        else:
500
            branches[key[level]][key] = obj[key]
501
502
    subnodes = tuple(
503
        encode_internal_node(patricialize(branches[k], level + Uint(1)))
504
        for k in range(16)
505
    )
506
    return BranchNode(
507
        cast(BranchSubnodes, assert_type(subnodes, Tuple[Extended, ...])),
508
        value,
509
    )