ethereum.forks.bpo5.trieethereum.forks.amsterdam.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

67
EMPTY_TRIE_ROOT = Root(
68
    hex_to_bytes(
69
        "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
70
    )
71
)

Node

73
Node = (
74
    Account
75
    | Bytes
76
    | LegacyTransaction
77
    | Receipt
78
    | Uint
79
    | U256
80
    | Withdrawal
81
    | None
82
)

K

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

V

84
V = TypeVar(
85
    "V",
86
    Optional[Account],
87
    Optional[Bytes],
88
    Bytes,
89
    Optional[LegacyTransaction | Bytes],
90
    Optional[Receipt | Bytes],
91
    Optional[Withdrawal | Bytes],
92
    Uint,
93
    U256,
94
)

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 object 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 : Extended The node encoded as RLP.

def encode_internal_node(node: Optional[InternalNodeInternalNode]) -> Extended:
98
    """
99
    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
100
    serialized into a `Bytes` object and hashed unless it is less than 32 bytes
101
    when serialized.
102
103
    This function also accepts `None`, representing the absence of a node,
104
    which is encoded to `b""`.
105
106
    Parameters
107
    ----------
108
    node : Optional[InternalNode]
109
        The node to encode.
110
111
    Returns
112
    -------
113
    encoded : `Extended`
114
        The node encoded as RLP.
115
116
    """
117
    unencoded: Extended
118
    if node is None:
119
        unencoded = b""
162
    elif isinstance(node, LeafNode):
120
    elif isinstance(node, LeafNode):
121
        unencoded = (
122
            nibble_list_to_compact(node.rest_of_key, True),
123
            node.value,
124
        )
167
    elif isinstance(node, ExtensionNode):
125
    elif isinstance(node, ExtensionNode):
126
        unencoded = (
127
            nibble_list_to_compact(node.key_segment, False),
128
            node.subnode,
129
        )
172
    elif isinstance(node, BranchNode):
130
    elif isinstance(node, BranchNode):
131
        unencoded = list(node.subnodes) + [node.value]
132
    else:
133
        raise AssertionError(f"Invalid internal node type {type(node)}!")
134
135
    encoded = rlp.encode(unencoded)
136
    if len(encoded) < 32:
137
        return unencoded
138
    else:
139
        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:
143
    """
144
    Encode a Node for storage in the Merkle Trie.
145
146
    Currently mostly an unimplemented stub.
147
    """
148
    if isinstance(node, Account):
149
        assert storage_root is not None
150
        return encode_account(node, storage_root)
151
    elif isinstance(node, (LegacyTransaction, Receipt, Withdrawal, U256)):
152
        return rlp.encode(node)
153
    elif isinstance(node, Bytes):
154
        return node
155
    else:
198
        return previous_trie.encode_node(node, storage_root)
156
        return previous_trie.encode_node(node, storage_root)

Trie

The Merkle Trie.

159
@dataclass
class Trie:

secured

165
    secured: bool

default

166
    default: V

_data

167
    _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]:
171
    """
172
    Create a copy of `trie`. Since only frozen objects may be stored in tries,
173
    the contents are reused.
174
175
    Parameters
176
    ----------
177
    trie: `Trie`
178
        Trie to copy.
179
180
    Returns
181
    -------
182
    new_trie : `Trie[K, V]`
183
        A copy of the trie.
184
185
    """
186
    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:
190
    """
191
    Stores an item in a Merkle Trie.
192
193
    This method deletes the key if `value == trie.default`, because the Merkle
194
    Trie represents the default value by omitting it from the trie.
195
196
    Parameters
197
    ----------
198
    trie: `Trie`
199
        Trie to store in.
200
    key : `Bytes`
201
        Key to lookup.
202
    value : `V`
203
        Node to insert at `key`.
204
205
    """
206
    if value == trie.default:
207
        if key in trie._data:
208
            del trie._data[key]
209
    else:
210
        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:
214
    """
215
    Gets an item from the Merkle Trie.
216
217
    This method returns `trie.default` if the key is missing.
218
219
    Parameters
220
    ----------
221
    trie:
222
        Trie to lookup in.
223
    key :
224
        Key to lookup.
225
226
    Returns
227
    -------
228
    node : `V`
229
        Node at `key` in the trie.
230
231
    """
232
    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:
236
    """
237
    Find the longest common prefix of two sequences.
238
    """
239
    for i in range(len(a)):
240
        if i >= len(b) or a[i] != b[i]:
241
            return i
242
    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:
246
    """
247
    Compresses nibble-list into a standard byte array with a flag.
248
249
    A nibble-list is a list of byte values no greater than `15`. The flag is
250
    encoded in high nibble of the highest byte. The flag nibble can be broken
251
    down into two two-bit flags.
252
253
    Highest nibble::
254
255
        +---+---+----------+--------+
256
        | _ | _ | is_leaf | parity |
257
        +---+---+----------+--------+
258
          3   2      1         0
259
260
261
    The lowest bit of the nibble encodes the parity of the length of the
262
    remaining nibbles -- `0` when even and `1` when odd. The second lowest bit
263
    is used to distinguish leaf and extension nodes. The other two bits are not
264
    used.
265
266
    Parameters
267
    ----------
268
    x :
269
        Array of nibbles.
270
    is_leaf :
271
        True if this is part of a leaf node, or false if it is an extension
272
        node.
273
274
    Returns
275
    -------
276
    compressed : `bytearray`
277
        Compact byte array.
278
279
    """
280
    compact = bytearray()
281
282
    if len(x) % 2 == 0:  # ie even length
283
        compact.append(16 * (2 * is_leaf))
284
        for i in range(0, len(x), 2):
285
            compact.append(16 * x[i] + x[i + 1])
286
    else:
287
        compact.append(16 * ((2 * is_leaf) + 1) + x[0])
288
        for i in range(1, len(x), 2):
289
            compact.append(16 * x[i] + x[i + 1])
290
291
    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:
295
    """
296
    Converts a `Bytes` into to a sequence of nibbles (bytes with value < 16).
297
298
    Parameters
299
    ----------
300
    bytes_:
301
        The `Bytes` to convert.
302
303
    Returns
304
    -------
305
    nibble_list : `Bytes`
306
        The `Bytes` in nibble-list format.
307
308
    """
309
    nibble_list = bytearray(2 * len(bytes_))
310
    for byte_index, byte in enumerate(bytes_):
311
        nibble_list[byte_index * 2] = (byte & 0xF0) >> 4
312
        nibble_list[byte_index * 2 + 1] = byte & 0x0F
313
    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]:
320
    """
321
    Prepares the trie for root calculation. Removes values that are empty,
322
    hashes the keys (if `secured == True`) and encodes all the nodes.
323
324
    Parameters
325
    ----------
326
    trie :
327
        The `Trie` to prepare.
328
    get_storage_root :
329
        Function to get the storage root of an account. Needed to encode
330
        `Account` objects.
331
332
    Returns
333
    -------
334
    out : `Mapping[ethereum.base_types.Bytes, Node]`
335
        Object with keys mapped to nibble-byte form.
336
337
    """
338
    mapped: MutableMapping[Bytes, Bytes] = {}
339
340
    for preimage, value in trie._data.items():
341
        if isinstance(value, Account):
342
            assert get_storage_root is not None
343
            address = Address(preimage)
344
            encoded_value = encode_node(value, get_storage_root(address))
345
        else:
346
            encoded_value = encode_node(value)
347
        if encoded_value == b"":
348
            raise AssertionError
349
        key: Bytes
350
        if trie.secured:
351
            # "secure" tries hash keys once before construction
352
            key = keccak256(preimage)
353
        else:
354
            key = preimage
355
        mapped[bytes_to_nibble_list(key)] = encoded_value
356
357
    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:
364
    """
365
    Computes the root of a modified merkle patricia trie (MPT).
366
367
    Parameters
368
    ----------
369
    trie :
370
        `Trie` to get the root of.
371
    get_storage_root :
372
        Function to get the storage root of an account. Needed to encode
373
        `Account` objects.
374
375
376
    Returns
377
    -------
378
    root : `.fork_types.Root`
379
        MPT root of the underlying key-value pairs.
380
381
    """
382
    obj = _prepare_trie(trie, get_storage_root)
383
384
    root_node = encode_internal_node(patricialize(obj, Uint(0)))
385
    if len(rlp.encode(root_node)) < 32:
386
        return keccak256(rlp.encode(root_node))
387
    else:
388
        assert isinstance(root_node, Bytes)
389
        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[InternalNodeInternalNode]:
395
    """
396
    Structural composition function.
397
398
    Used to recursively patricialize and merkleize a dictionary. Includes
399
    memoization of the tree structure and hashes.
400
401
    Parameters
402
    ----------
403
    obj :
404
        Underlying trie key-value pairs, with keys in nibble-list format.
405
    level :
406
        Current trie level.
407
408
    Returns
409
    -------
410
    node : `ethereum.base_types.Bytes`
411
        Root node of `obj`.
412
413
    """
414
    if len(obj) == 0:
415
        return None
416
417
    arbitrary_key = next(iter(obj))
418
419
    # if leaf node
420
    if len(obj) == 1:
463
        leaf = LeafNode(arbitrary_key[level:], obj[arbitrary_key])
421
        leaf = LeafNode(arbitrary_key[level:], obj[arbitrary_key])
422
        return leaf
423
424
    # prepare for extension node check by finding max j such that all keys in
425
    # obj have the same key[i:j]
426
    substring = arbitrary_key[level:]
427
    prefix_length = len(substring)
428
    for key in obj:
429
        prefix_length = min(
430
            prefix_length, common_prefix_length(substring, key[level:])
431
        )
432
433
        # finished searching, found another key at the current level
434
        if prefix_length == 0:
435
            break
436
437
    # if extension node
438
    if prefix_length > 0:
439
        prefix = arbitrary_key[int(level) : int(level) + prefix_length]
482
        return ExtensionNode(
440
        return ExtensionNode(
441
            prefix,
442
            encode_internal_node(
443
                patricialize(obj, level + Uint(prefix_length))
444
            ),
445
        )
446
447
    branches: List[MutableMapping[Bytes, Bytes]] = []
448
    for _ in range(16):
449
        branches.append({})
450
    value = b""
451
    for key in obj:
452
        if len(key) == level:
453
            # shouldn't ever have an account or receipt in an internal node
454
            if isinstance(obj[key], (Account, Receipt, Uint)):
455
                raise AssertionError
456
            value = obj[key]
457
        else:
458
            branches[key[level]][key] = obj[key]
459
460
    subnodes = tuple(
461
        encode_internal_node(patricialize(branches[k], level + Uint(1)))
462
        for k in range(16)
463
    )
506
    return BranchNode(
507
        cast(BranchSubnodes, assert_type(subnodes, Tuple[Extended, ...])),
464
    return BranchNode(
465
        cast(BranchSubnodes, assert_type(subnodes, Tuple[Extended, ...])),
466
        value,
467
    )