ethereum.muir_glacier.transactionsethereum.berlin.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

Base cost of a transaction in gas units. This is the minimum amount of gas required to execute a transaction.

21
TX_BASE_COST = Uint(21000)

TX_DATA_COST_PER_NON_ZERO

Gas cost per non-zero byte in the transaction data.

27
TX_DATA_COST_PER_NON_ZERO = Uint(16)

TX_DATA_COST_PER_ZERO

Gas cost per zero byte in the transaction data.

32
TX_DATA_COST_PER_ZERO = Uint(4)

TX_CREATE_COST

Additional gas cost for creating a new contract.

37
TX_CREATE_COST = Uint(32000)

TX_ACCESS_LIST_ADDRESS_COST

Gas cost for including an address in the access list of a transaction.

42
TX_ACCESS_LIST_ADDRESS_COST = Uint(2400)

TX_ACCESS_LIST_STORAGE_KEY_COST

Gas cost for including a storage key in the access list of a transaction.

47
TX_ACCESS_LIST_STORAGE_KEY_COST = Uint(1900)

LegacyTransaction

Atomic operation performed on the block chain. This represents the original transaction format used before EIP-2930.

53
@slotted_freezable
54
@dataclass
class LegacyTransaction:

nonce

63
    nonce: U256

gas_price

68
    gas_price: Uint

gas

73
    gas: Uint

to

78
    to: Union[Bytes0, Address]

value

84
    value: U256

data

89
    data: Bytes

v

95
    v: U256

r

100
    r: U256

s

105
    s: U256

Access

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

111
@slotted_freezable
112
@dataclass
class Access:

account

119
    account: Address

slots

124
    slots: Tuple[Bytes32, ...]

AccessListTransaction

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

This transaction type extends the legacy transaction with an access list and chain ID. The access list specifies which addresses and storage slots the transaction will access.

130
@slotted_freezable
131
@dataclass
class AccessListTransaction:

chain_id

143
    chain_id: U64

nonce

148
    nonce: U256

gas_price

153
    gas_price: Uint

gas

158
    gas: Uint

to

163
    to: Union[Bytes0, Address]

value

169
    value: U256

data

174
    data: Bytes

access_list

180
    access_list: Tuple[Access, ...]

y_parity

186
    y_parity: U256

r

191
    r: U256

s

196
    s: U256

Transaction

Atomic operation performed on the block chain.

42
@slotted_freezable
43
@dataclass
class Transaction:

nonce

49
    nonce: U256

gas_price

54
    gas_price: Uint

gas

59
    gas: Uint

to

64
    to: Union[Bytes0, Address]

value

70
    value: U256

data

75
    data: Bytes

v

81
    v: U256

r

86
    r: U256

s

91
    s: U256

Transaction

Union type representing any valid transaction type.

202
Transaction = Union[LegacyTransaction, AccessListTransaction]

encode_transaction

Encode a transaction into its RLP or typed transaction format. Needed because non-legacy transactions aren't RLP.

Legacy transactions are returned as-is, while other transaction types are prefixed with their type identifier and RLP encoded.

def encode_transaction(tx: Transaction) -> Union[LegacyTransaction, Bytes]:
209
    """
210
    Encode a transaction into its RLP or typed transaction format.
211
    Needed because non-legacy transactions aren't RLP.
212
213
    Legacy transactions are returned as-is, while other transaction types
214
    are prefixed with their type identifier and RLP encoded.
215
    """
216
    if isinstance(tx, LegacyTransaction):
217
        return tx
218
    elif isinstance(tx, AccessListTransaction):
219
        return b"\x01" + rlp.encode(tx)
220
    else:
221
        raise Exception(f"Unable to encode transaction of type {type(tx)}")

decode_transaction

Decode a transaction from its RLP or typed transaction format. Needed because non-legacy transactions aren't RLP.

Legacy transactions are returned as-is, while other transaction types are decoded based on their type identifier prefix.

def decode_transaction(tx: Union[LegacyTransaction, Bytes]) -> Transaction:
225
    """
226
    Decode a transaction from its RLP or typed transaction format.
227
    Needed because non-legacy transactions aren't RLP.
228
229
    Legacy transactions are returned as-is, while other transaction types
230
    are decoded based on their type identifier prefix.
231
    """
232
    if isinstance(tx, Bytes):
233
        if tx[0] != 1:
234
            raise TransactionTypeError(tx[0])
235
        return rlp.decode_to(AccessListTransaction, tx[1:])
236
    else:
237
        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. 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.

This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an InvalidTransaction exception if the transaction is invalid.

def validate_transaction(tx: Transaction) -> Uint:
241
    """
242
    Verifies a transaction.
243
244
    The gas in a transaction gets used to pay for the intrinsic cost of
245
    operations, therefore if there is insufficient gas then it would not
246
    be possible to execute a transaction and it will be declared invalid.
247
248
    Additionally, the nonce of a transaction must not equal or exceed the
249
    limit defined in [EIP-2681].
250
    In practice, defining the limit as ``2**64-1`` has no impact because
251
    sending ``2**64-1`` transactions is improbable. It's not strictly
252
    impossible though, ``2**64-1`` transactions is the entire capacity of the
253
    Ethereum blockchain at 2022 gas limits for a little over 22 years.
254
255
    This function takes a transaction as a parameter and returns the intrinsic
256
    gas cost of the transaction after validation. It throws an
257
    `InvalidTransaction` exception if the transaction is invalid.
258
259
    [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681
260
    """
261
    intrinsic_gas = calculate_intrinsic_cost(tx)
262
    if intrinsic_gas > tx.gas:
263
        raise InvalidTransaction("Insufficient gas")
264
    if U256(tx.nonce) >= U256(U64.MAX_VALUE):
265
        raise InvalidTransaction("Nonce too high")
266
    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.

The intrinsic cost includes:

  1. Base cost (TX_BASE_COST)

  2. Cost for data (zero and non-zero bytes)

  3. Cost for contract creation (if applicable)

  4. Cost for access list entries (if applicable)

This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction.

def calculate_intrinsic_cost(tx: Transaction) -> Uint:
270
    """
271
    Calculates the gas that is charged before execution is started.
272
273
    The intrinsic cost of the transaction is charged before execution has
274
    begun. Functions/operations in the EVM cost money to execute so this
275
    intrinsic cost is for the operations that need to be paid for as part of
276
    the transaction. Data transfer, for example, is part of this intrinsic
277
    cost. It costs ether to send data over the wire and that ether is
278
    accounted for in the intrinsic cost calculated in this function. This
279
    intrinsic cost must be calculated and paid for before execution in order
280
    for all operations to be implemented.
281
282
    The intrinsic cost includes:
283
    1. Base cost (`TX_BASE_COST`)
284
    2. Cost for data (zero and non-zero bytes)
285
    3. Cost for contract creation (if applicable)
286
    4. Cost for access list entries (if applicable)
287
288
    This function takes a transaction as a parameter and returns the intrinsic
289
    gas cost of the transaction.
290
    """
291
    data_cost = Uint(0)
292
293
    for byte in tx.data:
294
        if byte == 0:
295
            data_cost += TX_DATA_COST_PER_ZERO
296
        else:
297
            data_cost += TX_DATA_COST_PER_NON_ZERO
298
299
    if tx.to == Bytes0(b""):
300
        create_cost = TX_CREATE_COST
301
    else:
302
        create_cost = Uint(0)
303
160
    return TX_BASE_COST + data_cost + create_cost
304
    access_list_cost = Uint(0)
305
    if isinstance(tx, AccessListTransaction):
306
        for access in tx.access_list:
307
            access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
308
            access_list_cost += (
309
                ulen(access.slots) * TX_ACCESS_LIST_STORAGE_KEY_COST
310
            )
311
312
    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.

This function takes chain_id and a transaction as parameters and returns the address of the sender of the transaction. It raises an InvalidSignatureError if the signature values (r, s, v) are invalid.

def recover_sender(chain_id: U64, ​​tx: Transaction) -> Address:
316
    """
317
    Extracts the sender address from a transaction.
318
319
    The v, r, and s values are the three parts that make up the signature
320
    of a transaction. In order to recover the sender of a transaction the two
321
    components needed are the signature (``v``, ``r``, and ``s``) and the
322
    signing hash of the transaction. The sender's public key can be obtained
323
    with these two values and therefore the sender address can be retrieved.
324
325
    This function takes chain_id and a transaction as parameters and returns
326
    the address of the sender of the transaction. It raises an
327
    `InvalidSignatureError` if the signature values (r, s, v) are invalid.
328
    """
177
    v, r, s = tx.v, tx.r, tx.s
329
    r, s = tx.r, tx.s
330
    if U256(0) >= r or r >= SECP256K1N:
331
        raise InvalidSignatureError("bad r")
332
    if U256(0) >= s or s > SECP256K1N // U256(2):
333
        raise InvalidSignatureError("bad s")
334
183
    if v == 27 or v == 28:
184
        public_key = secp256k1_recover(
185
            r, s, v - U256(27), signing_hash_pre155(tx)
186
        )
187
    else:
188
        chain_id_x2 = U256(chain_id) * U256(2)
189
        if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
190
            raise InvalidSignatureError("bad v")
191
        public_key = secp256k1_recover(
192
            r, s, v - U256(35) - chain_id_x2, signing_hash_155(tx, chain_id)
193
        )
335
    if isinstance(tx, LegacyTransaction):
336
        v = tx.v
337
        if v == 27 or v == 28:
338
            public_key = secp256k1_recover(
339
                r, s, v - U256(27), signing_hash_pre155(tx)
340
            )
341
        else:
342
            chain_id_x2 = U256(chain_id) * U256(2)
343
            if v != U256(35) + chain_id_x2 and v != U256(36) + chain_id_x2:
344
                raise InvalidSignatureError("bad v")
345
            public_key = secp256k1_recover(
346
                r,
347
                s,
348
                v - U256(35) - chain_id_x2,
349
                signing_hash_155(tx, chain_id),
350
            )
351
    elif isinstance(tx, AccessListTransaction):
352
        if tx.y_parity not in (U256(0), U256(1)):
353
            raise InvalidSignatureError("bad y_parity")
354
        public_key = secp256k1_recover(
355
            r, s, tx.y_parity, signing_hash_2930(tx)
356
        )
357
358
    return Address(keccak256(public_key)[12:32])

signing_hash_pre155

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

This function takes a transaction as a parameter and returns the signing hash of the transaction.hash of the transaction used in a legacy signature.

def signing_hash_pre155(tx: Transaction) -> Hash32:
362
    """
363
    Compute the hash of a transaction used in a legacy (pre [EIP-155])
364
    signature.
365
366
    This function takes a transaction as a parameter and returns the
204
    signing hash of the transaction.
367
    hash of the transaction used in a legacy signature.
368
369
    [EIP-155]: https://eips.ethereum.org/EIPS/eip-155
370
    """
371
    return keccak256(
372
        rlp.encode(
373
            (
374
                tx.nonce,
375
                tx.gas_price,
376
                tx.gas,
377
                tx.to,
378
                tx.value,
379
                tx.data,
380
            )
381
        )
382
    )

signing_hash_155

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

This function takes a transaction and chain ID as parameters and returns the hash of the transaction used in a EIP-155 signature.

def signing_hash_155(tx: Transaction, ​​chain_id: U64) -> Hash32:
386
    """
387
    Compute the hash of a transaction used in a [EIP-155] signature.
388
389
    This function takes a transaction and chain ID as parameters and returns
390
    the hash of the transaction used in a [EIP-155] signature.
391
392
    [EIP-155]: https://eips.ethereum.org/EIPS/eip-155
393
    """
394
    return keccak256(
395
        rlp.encode(
396
            (
397
                tx.nonce,
398
                tx.gas_price,
399
                tx.gas,
400
                tx.to,
401
                tx.value,
402
                tx.data,
403
                chain_id,
404
                Uint(0),
405
                Uint(0),
406
            )
407
        )
408
    )

signing_hash_2930

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

This function takes an access list transaction as a parameter and returns the hash of the transaction used in an EIP-2930 signature.

def signing_hash_2930(tx: AccessListTransaction) -> Hash32:
412
    """
413
    Compute the hash of a transaction used in a [EIP-2930] signature.
414
415
    This function takes an access list transaction as a parameter
416
    and returns the hash of the transaction used in an [EIP-2930] signature.
417
418
    [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930
419
    """
420
    return keccak256(
421
        b"\x01"
422
        + rlp.encode(
423
            (
424
                tx.chain_id,
425
                tx.nonce,
426
                tx.gas_price,
427
                tx.gas,
428
                tx.to,
429
                tx.value,
430
                tx.data,
431
                tx.access_list,
432
            )
433
        )
434
    )

get_transaction_hash

Compute the hash of a transaction.

This function takes a transaction as a parameter and returns the hash of the transaction.keccak256 hash of the transaction. It can handle both legacy transactions and typed transactions (eg. AccessListTransaction).

def get_transaction_hash(tx: TransactionUnion[Bytes, LegacyTransaction]) -> Hash32:
438
    """
439
    Compute the hash of a transaction.
440
441
    This function takes a transaction as a parameter and returns the
253
    hash of the transaction.
442
    keccak256 hash of the transaction. It can handle both legacy transactions
443
    and typed transactions (eg. `AccessListTransaction`).
444
    """
255
    return keccak256(rlp.encode(tx))
445
    assert isinstance(tx, (LegacyTransaction, Bytes))
446
    if isinstance(tx, LegacyTransaction):
447
        return keccak256(rlp.encode(tx))
448
    else:
449
        return keccak256(tx)