ethereum.gray_glacier.transactionsethereum.paris.transactions

Transactions are atomic units of work created externally to Ethereum and submitted to be executed. If Ethereum is viewed as a state machine, transactions are the events that move between states.

TX_BASE_COST

21
TX_BASE_COST = 21000

TX_DATA_COST_PER_NON_ZERO

22
TX_DATA_COST_PER_NON_ZERO = 16

TX_DATA_COST_PER_ZERO

23
TX_DATA_COST_PER_ZERO = 4

TX_CREATE_COST

24
TX_CREATE_COST = 32000

TX_ACCESS_LIST_ADDRESS_COST

25
TX_ACCESS_LIST_ADDRESS_COST = 2400

TX_ACCESS_LIST_STORAGE_KEY_COST

26
TX_ACCESS_LIST_STORAGE_KEY_COST = 1900

LegacyTransaction

Atomic operation performed on the block chain.

29
@slotted_freezable
30
@dataclass
class LegacyTransaction:

nonce

36
    nonce: U256

gas_price

37
    gas_price: Uint

gas

38
    gas: Uint

to

39
    to: Union[Bytes0, Address]

value

40
    value: U256

data

41
    data: Bytes

v

42
    v: U256

r

43
    r: U256

s

44
    s: U256

AccessListTransaction

The transaction type added in EIP-2930 to support access lists.

47
@slotted_freezable
48
@dataclass
class AccessListTransaction:

chain_id

54
    chain_id: U64

nonce

55
    nonce: U256

gas_price

56
    gas_price: Uint

gas

57
    gas: Uint

to

58
    to: Union[Bytes0, Address]

value

59
    value: U256

data

60
    data: Bytes

access_list

61
    access_list: Tuple[Tuple[Address, Tuple[Bytes32, ...]], ...]

y_parity

62
    y_parity: U256

r

63
    r: U256

s

64
    s: U256

FeeMarketTransaction

The transaction type added in EIP-1559.

67
@slotted_freezable
68
@dataclass
class FeeMarketTransaction:

chain_id

74
    chain_id: U64

nonce

75
    nonce: U256

max_priority_fee_per_gas

76
    max_priority_fee_per_gas: Uint

max_fee_per_gas

77
    max_fee_per_gas: Uint

gas

78
    gas: Uint

to

79
    to: Union[Bytes0, Address]

value

80
    value: U256

data

81
    data: Bytes

access_list

82
    access_list: Tuple[Tuple[Address, Tuple[Bytes32, ...]], ...]

y_parity

83
    y_parity: U256

r

84
    r: U256

s

85
    s: U256

Transaction

88
Transaction = Union[
89
    LegacyTransaction, AccessListTransaction, FeeMarketTransaction
90
]

encode_transaction

Encode a transaction. Needed because non-legacy transactions aren't RLP.

def encode_transaction(tx: Transaction) -> Union[LegacyTransaction, Bytes]:
94
    """
95
    Encode a transaction. Needed because non-legacy transactions aren't RLP.
96
    """
97
    if isinstance(tx, LegacyTransaction):
98
        return tx
99
    elif isinstance(tx, AccessListTransaction):
100
        return b"\x01" + rlp.encode(tx)
101
    elif isinstance(tx, FeeMarketTransaction):
102
        return b"\x02" + rlp.encode(tx)
103
    else:
104
        raise Exception(f"Unable to encode transaction of type {type(tx)}")

decode_transaction

Decode a transaction. Needed because non-legacy transactions aren't RLP.

def decode_transaction(tx: Union[LegacyTransaction, Bytes]) -> Transaction:
108
    """
109
    Decode a transaction. Needed because non-legacy transactions aren't RLP.
110
    """
111
    if isinstance(tx, Bytes):
112
        if tx[0] == 1:
113
            return rlp.decode_to(AccessListTransaction, tx[1:])
114
        elif tx[0] == 2:
115
            return rlp.decode_to(FeeMarketTransaction, tx[1:])
116
        else:
117
            raise TransactionTypeError(tx[0])
118
    else:
119
        return tx

validate_transaction

Verifies a transaction.

The gas in a transaction gets used to pay for the intrinsic cost of operations, therefore if there is insufficient gas then it would not be possible to execute a transaction and it will be declared invalid.

Additionally, the nonce of a transaction must not equal or exceed the limit defined in EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>_. In practice, defining the limit as 2**64-1 has no impact because sending 2**64-1 transactions is improbable. It's not strictly impossible though, 2**64-1 transactions is the entire capacity of the Ethereum blockchain at 2022 gas limits for a little over 22 years.

Parameters

tx : Transaction to validate.

Returns

verified : bool True if the transaction can be executed, or False otherwise.

def validate_transaction(tx: Transaction) -> bool:
123
    """
124
    Verifies a transaction.
125
126
    The gas in a transaction gets used to pay for the intrinsic cost of
127
    operations, therefore if there is insufficient gas then it would not
128
    be possible to execute a transaction and it will be declared invalid.
129
130
    Additionally, the nonce of a transaction must not equal or exceed the
131
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
132
    In practice, defining the limit as ``2**64-1`` has no impact because
133
    sending ``2**64-1`` transactions is improbable. It's not strictly
134
    impossible though, ``2**64-1`` transactions is the entire capacity of the
135
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
136
137
    Parameters
138
    ----------
139
    tx :
140
        Transaction to validate.
141
142
    Returns
143
    -------
144
    verified : `bool`
145
        True if the transaction can be executed, or False otherwise.
146
    """
147
    if calculate_intrinsic_cost(tx) > Uint(tx.gas):
147
    if calculate_intrinsic_cost(tx) > tx.gas:
148
        return False
149
    if tx.nonce >= U256(U64.MAX_VALUE):
150
        return False
151
    return True

calculate_intrinsic_cost

Calculates the gas that is charged before execution is started.

The intrinsic cost of the transaction is charged before execution has begun. Functions/operations in the EVM cost money to execute so this intrinsic cost is for the operations that need to be paid for as part of the transaction. Data transfer, for example, is part of this intrinsic cost. It costs ether to send data over the wire and that ether is accounted for in the intrinsic cost calculated in this function. This intrinsic cost must be calculated and paid for before execution in order for all operations to be implemented.

Parameters

tx : Transaction to compute the intrinsic cost of.

Returns

verified : ethereum.base_types.Uint The intrinsic cost of the transaction.

def calculate_intrinsic_cost(tx: Transaction) -> Uint:
155
    """
156
    Calculates the gas that is charged before execution is started.
157
158
    The intrinsic cost of the transaction is charged before execution has
159
    begun. Functions/operations in the EVM cost money to execute so this
160
    intrinsic cost is for the operations that need to be paid for as part of
161
    the transaction. Data transfer, for example, is part of this intrinsic
162
    cost. It costs ether to send data over the wire and that ether is
163
    accounted for in the intrinsic cost calculated in this function. This
164
    intrinsic cost must be calculated and paid for before execution in order
165
    for all operations to be implemented.
166
167
    Parameters
168
    ----------
169
    tx :
170
        Transaction to compute the intrinsic cost of.
171
172
    Returns
173
    -------
174
    verified : `ethereum.base_types.Uint`
175
        The intrinsic cost of the transaction.
176
    """
177
    data_cost = 0
178
179
    for byte in tx.data:
180
        if byte == 0:
181
            data_cost += TX_DATA_COST_PER_ZERO
182
        else:
183
            data_cost += TX_DATA_COST_PER_NON_ZERO
184
185
    if tx.to == Bytes0(b""):
186
        create_cost = TX_CREATE_COST
187
    else:
188
        create_cost = 0
189
190
    access_list_cost = 0
191
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
192
        for _address, keys in tx.access_list:
193
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
194
            access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
195
196
    return Uint(TX_BASE_COST + data_cost + create_cost + access_list_cost)

recover_sender

Extracts the sender address from a transaction.

The v, r, and s values are the three parts that make up the signature of a transaction. In order to recover the sender of a transaction the two components needed are the signature (v, r, and s) and the signing hash of the transaction. The sender's public key can be obtained with these two values and therefore the sender address can be retrieved.

Parameters

tx : Transaction of interest. chain_id : ID of the executing chain.

Returns

sender : ethereum.fork_types.Address The address of the account that signed the transaction.

def recover_sender(chain_id: U64, ​​tx: Transaction) -> Address:
200
    """
201
    Extracts the sender address from a transaction.
202
203
    The v, r, and s values are the three parts that make up the signature
204
    of a transaction. In order to recover the sender of a transaction the two
205
    components needed are the signature (``v``, ``r``, and ``s``) and the
206
    signing hash of the transaction. The sender's public key can be obtained
207
    with these two values and therefore the sender address can be retrieved.
208
209
    Parameters
210
    ----------
211
    tx :
212
        Transaction of interest.
213
    chain_id :
214
        ID of the executing chain.
215
216
    Returns
217
    -------
218
    sender : `ethereum.fork_types.Address`
219
        The address of the account that signed the transaction.
220
    """
221
    r, s = tx.r, tx.s
222
    if U256(0) >= r or r >= SECP256K1N:
223
        raise InvalidSignatureError("bad r")
224
    if U256(0) >= s or s > SECP256K1N // U256(2):
225
        raise InvalidSignatureError("bad s")
226
227
    if isinstance(tx, LegacyTransaction):
228
        v = tx.v
229
        if v == 27 or v == 28:
230
            public_key = secp256k1_recover(
231
                r, s, v - U256(27), signing_hash_pre155(tx)
232
            )
233
        else:
234
            chain_id_x2 = U256(chain_id) * U256(2)
235
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
236
                raise InvalidSignatureError("bad v")
237
            public_key = secp256k1_recover(
238
                r,
239
                s,
240
                v - U256(35) - chain_id_x2,
241
                signing_hash_155(tx, chain_id),
242
            )
243
    elif isinstance(tx, AccessListTransaction):
244
        public_key = secp256k1_recover(
245
            r, s, tx.y_parity, signing_hash_2930(tx)
246
        )
247
    elif isinstance(tx, FeeMarketTransaction):
248
        public_key = secp256k1_recover(
249
            r, s, tx.y_parity, signing_hash_1559(tx)
250
        )
251
252
    return Address(keccak256(public_key)[12:32])

signing_hash_pre155

Compute the hash of a transaction used in a legacy (pre EIP 155) signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_pre155(tx: LegacyTransaction) -> Hash32:
256
    """
257
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
258
259
    Parameters
260
    ----------
261
    tx :
262
        Transaction of interest.
263
264
    Returns
265
    -------
266
    hash : `ethereum.crypto.hash.Hash32`
267
        Hash of the transaction.
268
    """
269
    return keccak256(
270
        rlp.encode(
271
            (
272
                tx.nonce,
273
                tx.gas_price,
274
                tx.gas,
275
                tx.to,
276
                tx.value,
277
                tx.data,
278
            )
279
        )
280
    )

signing_hash_155

Compute the hash of a transaction used in a EIP 155 signature.

Parameters

tx : Transaction of interest. chain_id : The id of the current chain.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_155(tx: LegacyTransaction, ​​chain_id: U64) -> Hash32:
284
    """
285
    Compute the hash of a transaction used in a EIP 155 signature.
286
287
    Parameters
288
    ----------
289
    tx :
290
        Transaction of interest.
291
    chain_id :
292
        The id of the current chain.
293
294
    Returns
295
    -------
296
    hash : `ethereum.crypto.hash.Hash32`
297
        Hash of the transaction.
298
    """
299
    return keccak256(
300
        rlp.encode(
301
            (
302
                tx.nonce,
303
                tx.gas_price,
304
                tx.gas,
305
                tx.to,
306
                tx.value,
307
                tx.data,
308
                chain_id,
309
                Uint(0),
310
                Uint(0),
311
            )
312
        )
313
    )

signing_hash_2930

Compute the hash of a transaction used in a EIP 2930 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_2930(tx: AccessListTransaction) -> Hash32:
317
    """
318
    Compute the hash of a transaction used in a EIP 2930 signature.
319
320
    Parameters
321
    ----------
322
    tx :
323
        Transaction of interest.
324
325
    Returns
326
    -------
327
    hash : `ethereum.crypto.hash.Hash32`
328
        Hash of the transaction.
329
    """
330
    return keccak256(
331
        b"\x01"
332
        + rlp.encode(
333
            (
334
                tx.chain_id,
335
                tx.nonce,
336
                tx.gas_price,
337
                tx.gas,
338
                tx.to,
339
                tx.value,
340
                tx.data,
341
                tx.access_list,
342
            )
343
        )
344
    )

signing_hash_1559

Compute the hash of a transaction used in a EIP 1559 signature.

Parameters

tx : Transaction of interest.

Returns

hash : ethereum.crypto.hash.Hash32 Hash of the transaction.

def signing_hash_1559(tx: FeeMarketTransaction) -> Hash32:
348
    """
349
    Compute the hash of a transaction used in a EIP 1559 signature.
350
351
    Parameters
352
    ----------
353
    tx :
354
        Transaction of interest.
355
356
    Returns
357
    -------
358
    hash : `ethereum.crypto.hash.Hash32`
359
        Hash of the transaction.
360
    """
361
    return keccak256(
362
        b"\x02"
363
        + rlp.encode(
364
            (
365
                tx.chain_id,
366
                tx.nonce,
367
                tx.max_priority_fee_per_gas,
368
                tx.max_fee_per_gas,
369
                tx.gas,
370
                tx.to,
371
                tx.value,
372
                tx.data,
373
                tx.access_list,
374
            )
375
        )
376
    )