ethereum.berlin.transactionsethereum.london.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 = Uint(21000)

TX_DATA_COST_PER_NON_ZERO

22
TX_DATA_COST_PER_NON_ZERO = Uint(16)

TX_DATA_COST_PER_ZERO

23
TX_DATA_COST_PER_ZERO = Uint(4)

TX_CREATE_COST

24
TX_CREATE_COST = Uint(32000)

TX_ACCESS_LIST_ADDRESS_COST

25
TX_ACCESS_LIST_ADDRESS_COST = Uint(2400)

TX_ACCESS_LIST_STORAGE_KEY_COST

26
TX_ACCESS_LIST_STORAGE_KEY_COST = Uint(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

Access

A mapping from account address to storage slots that are pre-warmed as part of a transaction.

47
@slotted_freezable
48
@dataclass
class Access:

account

55
    account: Address

slots

56
    slots: Tuple[Bytes32, ...]

AccessListTransaction

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

59
@slotted_freezable
60
@dataclass
class AccessListTransaction:

chain_id

66
    chain_id: U64

nonce

67
    nonce: U256

gas_price

68
    gas_price: Uint

gas

69
    gas: Uint

to

70
    to: Union[Bytes0, Address]

value

71
    value: U256

data

72
    data: Bytes

access_list

73
    access_list: Tuple[Access, ...]

y_parity

74
    y_parity: U256

r

75
    r: U256

s

76
    s: U256

FeeMarketTransaction

The transaction type added in EIP-1559.

79
@slotted_freezable
80
@dataclass
class FeeMarketTransaction:

chain_id

86
    chain_id: U64

nonce

87
    nonce: U256

max_priority_fee_per_gas

88
    max_priority_fee_per_gas: Uint

max_fee_per_gas

89
    max_fee_per_gas: Uint

gas

90
    gas: Uint

to

91
    to: Union[Bytes0, Address]

value

92
    value: U256

data

93
    data: Bytes

access_list

94
    access_list: Tuple[Access, ...]

y_parity

95
    y_parity: U256

r

96
    r: U256

s

97
    s: U256

Transaction

79
Transaction = Union[LegacyTransaction, AccessListTransaction]
100
Transaction = Union[
101
    LegacyTransaction, AccessListTransaction, FeeMarketTransaction
102
]

encode_transaction

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

def encode_transaction(tx: Transaction) -> Union[LegacyTransaction, Bytes]:
106
    """
107
    Encode a transaction. Needed because non-legacy transactions aren't RLP.
108
    """
109
    if isinstance(tx, LegacyTransaction):
110
        return tx
111
    elif isinstance(tx, AccessListTransaction):
112
        return b"\x01" + rlp.encode(tx)
90
    else:
91
        raise Exception(f"Unable to encode transaction of type {type(tx)}")
113
    elif isinstance(tx, FeeMarketTransaction):
114
        return b"\x02" + rlp.encode(tx)
115
    else:
116
        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:
120
    """
121
    Decode a transaction. Needed because non-legacy transactions aren't RLP.
122
    """
123
    if isinstance(tx, Bytes):
99
        if tx[0] != 1:
100
            raise TransactionTypeError(tx[0])
101
        return rlp.decode_to(AccessListTransaction, tx[1:])
124
        if tx[0] == 1:
125
            return rlp.decode_to(AccessListTransaction, tx[1:])
126
        elif tx[0] == 2:
127
            return rlp.decode_to(FeeMarketTransaction, tx[1:])
128
        else:
129
            raise TransactionTypeError(tx[0])
130
    else:
131
        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

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

Raises

InvalidTransaction : If the transaction is not valid.

def validate_transaction(tx: Transaction) -> Uint:
135
    """
136
    Verifies a transaction.
137
138
    The gas in a transaction gets used to pay for the intrinsic cost of
139
    operations, therefore if there is insufficient gas then it would not
140
    be possible to execute a transaction and it will be declared invalid.
141
142
    Additionally, the nonce of a transaction must not equal or exceed the
143
    limit defined in `EIP-2681 <https://eips.ethereum.org/EIPS/eip-2681>`_.
144
    In practice, defining the limit as ``2**64-1`` has no impact because
145
    sending ``2**64-1`` transactions is improbable. It's not strictly
146
    impossible though, ``2**64-1`` transactions is the entire capacity of the
147
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
148
149
    Parameters
150
    ----------
151
    tx :
152
        Transaction to validate.
153
154
    Returns
155
    -------
156
    intrinsic_gas : `ethereum.base_types.Uint`
157
        The intrinsic cost of the transaction.
158
159
    Raises
160
    ------
161
    InvalidTransaction :
162
        If the transaction is not valid.
163
    """
164
    intrinsic_gas = calculate_intrinsic_cost(tx)
165
    if intrinsic_gas > tx.gas:
166
        raise InvalidTransaction("Insufficient gas")
167
    if U256(tx.nonce) >= U256(U64.MAX_VALUE):
168
        raise InvalidTransaction("Nonce too high")
169
    return intrinsic_gas

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

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

def calculate_intrinsic_cost(tx: Transaction) -> Uint:
173
    """
174
    Calculates the gas that is charged before execution is started.
175
176
    The intrinsic cost of the transaction is charged before execution has
177
    begun. Functions/operations in the EVM cost money to execute so this
178
    intrinsic cost is for the operations that need to be paid for as part of
179
    the transaction. Data transfer, for example, is part of this intrinsic
180
    cost. It costs ether to send data over the wire and that ether is
181
    accounted for in the intrinsic cost calculated in this function. This
182
    intrinsic cost must be calculated and paid for before execution in order
183
    for all operations to be implemented.
184
185
    Parameters
186
    ----------
187
    tx :
188
        Transaction to compute the intrinsic cost of.
189
190
    Returns
191
    -------
192
    intrinsic_gas : `ethereum.base_types.Uint`
193
        The intrinsic cost of the transaction.
194
    """
195
    data_cost = Uint(0)
196
197
    for byte in tx.data:
198
        if byte == 0:
199
            data_cost += TX_DATA_COST_PER_ZERO
200
        else:
201
            data_cost += TX_DATA_COST_PER_NON_ZERO
202
203
    if tx.to == Bytes0(b""):
204
        create_cost = TX_CREATE_COST
205
    else:
206
        create_cost = Uint(0)
207
208
    access_list_cost = Uint(0)
181
    if isinstance(tx, AccessListTransaction):
209
    if isinstance(tx, (AccessListTransaction, FeeMarketTransaction)):
210
        for access in tx.access_list:
211
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
212
            access_list_cost += (
213
                ulen(access.slots) * TX_ACCESS_LIST_STORAGE_KEY_COST
214
            )
215
216
    return 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:
220
    """
221
    Extracts the sender address from a transaction.
222
223
    The v, r, and s values are the three parts that make up the signature
224
    of a transaction. In order to recover the sender of a transaction the two
225
    components needed are the signature (``v``, ``r``, and ``s``) and the
226
    signing hash of the transaction. The sender's public key can be obtained
227
    with these two values and therefore the sender address can be retrieved.
228
229
    Parameters
230
    ----------
231
    tx :
232
        Transaction of interest.
233
    chain_id :
234
        ID of the executing chain.
235
236
    Returns
237
    -------
238
    sender : `ethereum.fork_types.Address`
239
        The address of the account that signed the transaction.
240
    """
241
    r, s = tx.r, tx.s
242
    if U256(0) >= r or r >= SECP256K1N:
243
        raise InvalidSignatureError("bad r")
244
    if U256(0) >= s or s > SECP256K1N // U256(2):
245
        raise InvalidSignatureError("bad s")
246
247
    if isinstance(tx, LegacyTransaction):
248
        v = tx.v
249
        if v == 27 or v == 28:
250
            public_key = secp256k1_recover(
251
                r, s, v - U256(27), signing_hash_pre155(tx)
252
            )
253
        else:
254
            chain_id_x2 = U256(chain_id) * U256(2)
255
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
256
                raise InvalidSignatureError("bad v")
257
            public_key = secp256k1_recover(
258
                r,
259
                s,
260
                v - U256(35) - chain_id_x2,
261
                signing_hash_155(tx, chain_id),
262
            )
263
    elif isinstance(tx, AccessListTransaction):
264
        if tx.y_parity not in (U256(0), U256(1)):
265
            raise InvalidSignatureError("bad y_parity")
266
        public_key = secp256k1_recover(
267
            r, s, tx.y_parity, signing_hash_2930(tx)
240
        )
268
        )
269
    elif isinstance(tx, FeeMarketTransaction):
270
        if tx.y_parity not in (U256(0), U256(1)):
271
            raise InvalidSignatureError("bad y_parity")
272
        public_key = secp256k1_recover(
273
            r, s, tx.y_parity, signing_hash_1559(tx)
274
        )
275
276
    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: TransactionLegacyTransaction) -> Hash32:
280
    """
281
    Compute the hash of a transaction used in a legacy (pre EIP 155) signature.
282
283
    Parameters
284
    ----------
285
    tx :
286
        Transaction of interest.
287
288
    Returns
289
    -------
290
    hash : `ethereum.crypto.hash.Hash32`
291
        Hash of the transaction.
292
    """
293
    return keccak256(
294
        rlp.encode(
295
            (
296
                tx.nonce,
297
                tx.gas_price,
298
                tx.gas,
299
                tx.to,
300
                tx.value,
301
                tx.data,
302
            )
303
        )
304
    )

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: TransactionLegacyTransaction, ​​chain_id: U64) -> Hash32:
308
    """
309
    Compute the hash of a transaction used in a EIP 155 signature.
310
311
    Parameters
312
    ----------
313
    tx :
314
        Transaction of interest.
315
    chain_id :
316
        The id of the current chain.
317
318
    Returns
319
    -------
320
    hash : `ethereum.crypto.hash.Hash32`
321
        Hash of the transaction.
322
    """
323
    return keccak256(
324
        rlp.encode(
325
            (
326
                tx.nonce,
327
                tx.gas_price,
328
                tx.gas,
329
                tx.to,
330
                tx.value,
331
                tx.data,
332
                chain_id,
333
                Uint(0),
334
                Uint(0),
335
            )
336
        )
337
    )

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:
341
    """
342
    Compute the hash of a transaction used in a EIP 2930 signature.
343
344
    Parameters
345
    ----------
346
    tx :
347
        Transaction of interest.
348
349
    Returns
350
    -------
351
    hash : `ethereum.crypto.hash.Hash32`
352
        Hash of the transaction.
353
    """
354
    return keccak256(
355
        b"\x01"
356
        + rlp.encode(
357
            (
358
                tx.chain_id,
359
                tx.nonce,
360
                tx.gas_price,
361
                tx.gas,
362
                tx.to,
363
                tx.value,
364
                tx.data,
365
                tx.access_list,
366
            )
367
        )
368
    )

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:
372
    """
373
    Compute the hash of a transaction used in a EIP 1559 signature.
374
375
    Parameters
376
    ----------
377
    tx :
378
        Transaction of interest.
379
380
    Returns
381
    -------
382
    hash : `ethereum.crypto.hash.Hash32`
383
        Hash of the transaction.
384
    """
385
    return keccak256(
386
        b"\x02"
387
        + rlp.encode(
388
            (
389
                tx.chain_id,
390
                tx.nonce,
391
                tx.max_priority_fee_per_gas,
392
                tx.max_fee_per_gas,
393
                tx.gas,
394
                tx.to,
395
                tx.value,
396
                tx.data,
397
                tx.access_list,
398
            )
399
        )
400
    )

get_transaction_hash

Parameters

tx : Transaction of interest.

Returns

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

def get_transaction_hash(tx: Union[Bytes, LegacyTransaction]) -> Hash32:
404
    """
405
    Parameters
406
    ----------
407
    tx :
408
        Transaction of interest.
409
410
    Returns
411
    -------
412
    hash : `ethereum.crypto.hash.Hash32`
413
        Hash of the transaction.
414
    """
415
    assert isinstance(tx, (LegacyTransaction, Bytes))
416
    if isinstance(tx, LegacyTransaction):
417
        return keccak256(rlp.encode(tx))
418
    else:
419
        return keccak256(tx)