Skip to content

Commit

Permalink
fix gas_used
Browse files Browse the repository at this point in the history
  • Loading branch information
nerolation committed Jun 19, 2024
1 parent fb1892b commit 2f77cd8
Showing 1 changed file with 77 additions and 171 deletions.
248 changes: 77 additions & 171 deletions src/ethereum/prague/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@
Log,
Receipt,
Withdrawal,
encode_receipt,
parse_deposit_requests_from_receipt,
parse_withdrawal_requests_from_system_tx,
validate_deposit_requests,
validate_requests,
)
from .bloom import logs_bloom
from .fork_types import Address, Bloom, Root, VersionedHash
Expand All @@ -49,12 +48,12 @@
state_root,
)
from .transactions import (
COST_FLOOR_PER_CALLDATA_TOKEN,
LEGACY_CALLDATA_TOKEN_COST,
TX_ACCESS_LIST_ADDRESS_COST,
TX_ACCESS_LIST_STORAGE_KEY_COST,
TX_BASE_COST,
TX_CREATE_COST,
LEGACY_CALLDATA_TOKEN_COST,
COST_FLOOR_PER_CALLDATA_TOKEN,
AccessListTransaction,
BlobTransaction,
FeeMarketTransaction,
Expand All @@ -74,11 +73,7 @@
calculate_total_blob_gas,
init_code_cost,
)
from .vm.interpreter import (
MAX_CODE_SIZE,
MessageCallOutput,
process_message_call,
)
from .vm.interpreter import MAX_CODE_SIZE, process_message_call

BASE_FEE_MAX_CHANGE_DENOMINATOR = 8
ELASTICITY_MULTIPLIER = 2
Expand All @@ -92,9 +87,6 @@
HISTORY_STORAGE_ADDRESS = hex_to_address(
"0x25a219378dad9b3503c8268c9ca836a52427a4fb"
)
WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS = hex_to_address(
"0x00A3ca265EBcb825B45F985A16CEFB49958cE017"
)
SYSTEM_TRANSACTION_GAS = Uint(30000000)
MAX_BLOB_GAS_PER_BLOCK = 786432
VERSIONED_HASH_VERSION_KZG = b"\x01"
Expand Down Expand Up @@ -220,8 +212,6 @@ def state_transition(chain: BlockChain, block: Block) -> None:
raise InvalidBlock
if apply_body_output.blob_gas_used != block.header.blob_gas_used:
raise InvalidBlock
if apply_body_output.requests_root != block.header.requests_root:
raise InvalidBlock

chain.blocks.append(block)
if len(chain.blocks) > 255:
Expand Down Expand Up @@ -469,7 +459,14 @@ def make_receipt(
logs=logs,
)

return encode_receipt(tx, receipt)
if isinstance(tx, AccessListTransaction):
return b"\x01" + rlp.encode(receipt)
elif isinstance(tx, FeeMarketTransaction):
return b"\x02" + rlp.encode(receipt)
elif isinstance(tx, BlobTransaction):
return b"\x03" + rlp.encode(receipt)
else:
return receipt


@dataclass
Expand Down Expand Up @@ -508,103 +505,6 @@ class ApplyBodyOutput:
requests_root: Root


def process_system_transaction(
target_address: Address,
data: Bytes,
coinbase: Address,
block_number: Uint,
base_fee_per_gas: Uint,
block_gas_limit: Uint,
block_time: U256,
prev_randao: Bytes32,
state: State,
chain_id: U64,
excess_blob_gas: U64,
) -> MessageCallOutput:
"""
Process a system transaction.
Parameters
----------
target_address :
Address of the contract to call.
data :
Data to pass to the contract.
coinbase :
Address of the block's coinbase.
block_number :
Block number.
base_fee_per_gas :
Base fee per gas.
block_gas_limit :
Gas limit of the block.
block_time :
Time the block was produced.
prev_randao :
Previous randao value.
state :
Current state.
chain_id :
ID of the chain.
excess_blob_gas :
Excess blob gas.
Returns
-------
system_tx_output : `MessageCallOutput`
Output of processing the system transaction.
"""
system_contract_code = get_account(state, target_address).code

system_tx_message = Message(
caller=SYSTEM_ADDRESS,
target=target_address,
gas=SYSTEM_TRANSACTION_GAS,
value=U256(0),
data=data,
code=system_contract_code,
depth=Uint(0),
current_target=target_address,
code_address=target_address,
should_transfer_value=False,
is_static=False,
accessed_addresses=set(),
accessed_storage_keys=set(),
parent_evm=None,
)

system_tx_env = vm.Environment(
caller=SYSTEM_ADDRESS,
origin=SYSTEM_ADDRESS,
coinbase=coinbase,
number=block_number,
gas_limit=block_gas_limit,
base_fee_per_gas=base_fee_per_gas,
gas_price=base_fee_per_gas,
time=block_time,
prev_randao=prev_randao,
state=state,
chain_id=chain_id,
traces=[],
excess_blob_gas=excess_blob_gas,
blob_versioned_hashes=(),
transient_storage=TransientStorage(),
)

system_tx_output = process_message_call(system_tx_message, system_tx_env)

# TODO: Empty accounts in post-merge forks are impossible
# see Ethereum Improvement Proposal 7523.
# This line is only included to support invalid tests in the test suite
# and will have to be removed in the future.
# See https://github.com/ethereum/execution-specs/issues/955
destroy_touched_empty_accounts(
system_tx_env.state, system_tx_output.touched_accounts
)

return system_tx_output


def apply_body(
state: State,
coinbase: Address,
Expand Down Expand Up @@ -682,20 +582,51 @@ def apply_body(
secured=False, default=None
)
block_logs: Tuple[Log, ...] = ()
requests_from_execution: Tuple[Bytes, ...] = ()

process_system_transaction(
BEACON_ROOTS_ADDRESS,
parent_beacon_block_root,
coinbase,
block_number,
base_fee_per_gas,
block_gas_limit,
block_time,
prev_randao,
state,
chain_id,
excess_blob_gas,
receipts: Tuple[Receipt, ...] = ()

beacon_block_roots_contract_code = get_account(
state, BEACON_ROOTS_ADDRESS
).code

system_tx_message = Message(
caller=SYSTEM_ADDRESS,
target=BEACON_ROOTS_ADDRESS,
gas=SYSTEM_TRANSACTION_GAS,
value=U256(0),
data=parent_beacon_block_root,
code=beacon_block_roots_contract_code,
depth=Uint(0),
current_target=BEACON_ROOTS_ADDRESS,
code_address=BEACON_ROOTS_ADDRESS,
should_transfer_value=False,
is_static=False,
accessed_addresses=set(),
accessed_storage_keys=set(),
parent_evm=None,
)

system_tx_env = vm.Environment(
caller=SYSTEM_ADDRESS,
origin=SYSTEM_ADDRESS,
coinbase=coinbase,
number=block_number,
gas_limit=block_gas_limit,
base_fee_per_gas=base_fee_per_gas,
gas_price=base_fee_per_gas,
time=block_time,
prev_randao=prev_randao,
state=state,
chain_id=chain_id,
traces=[],
excess_blob_gas=excess_blob_gas,
blob_versioned_hashes=(),
transient_storage=TransientStorage(),
)

system_tx_output = process_message_call(system_tx_message, system_tx_env)

destroy_touched_empty_accounts(
system_tx_env.state, system_tx_output.touched_accounts
)

for i, tx in enumerate(map(decode_transaction, transactions)):
Expand Down Expand Up @@ -746,9 +677,8 @@ def apply_body(
rlp.encode(Uint(i)),
receipt,
)

deposit_requests = parse_deposit_requests_from_receipt(receipt)
requests_from_execution += deposit_requests
if isinstance(receipt, Receipt):
receipts += (receipt,)

block_logs += logs
blob_gas_used += calculate_total_blob_gas(tx)
Expand All @@ -767,31 +697,10 @@ def apply_body(
destroy_account(state, wd.address)

# Requests are to be in ascending order of request type
validate_requests(requests)

system_withdrawal_tx_output = process_system_transaction(
WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
b"",
coinbase,
block_number,
base_fee_per_gas,
block_gas_limit,
block_time,
prev_randao,
state,
chain_id,
excess_blob_gas,
)

withdrawal_requests = parse_withdrawal_requests_from_system_tx(
system_withdrawal_tx_output.return_data
)

requests_from_execution += withdrawal_requests

if requests_from_execution != requests:
raise InvalidBlock

for i, request in enumerate(requests_from_execution):
validate_deposit_requests(receipts, requests)
for i, request in enumerate(requests):
trie_set(requests_trie, rlp.encode(Uint(i)), request)

return ApplyBodyOutput(
Expand Down Expand Up @@ -877,19 +786,17 @@ def process_transaction(
)

output = process_message_call(message, env)

floor = Uint(
tokens_in_calldata * COST_FLOOR_PER_CALLDATA_TOKEN + TX_BASE_COST
)

legacy_cost = Uint(gas_used + tokens_in_calldata * LEGACY_TOKEN_COST)

gas_used = tx.gas - output.gas_left

floor = Uint(tokens_in_calldata * COST_FLOOR_PER_CALLDATA_TOKEN + TX_BASE_COST)
legacy_cost = Uint(gas_used - tokens_in_calldata * (COST_FLOOR_PER_CALLDATA_TOKEN - LEGACY_TOKEN_COST))
if legacy_cost < floor:
output.gas_left -= floor - gas_used
gas_used = floor
else:
gas_used = tx.gas - output.gas_left


gas_refund = min(gas_used // 5, output.refund_counter)
gas_refund_amount = (output.gas_left + gas_refund) * env.gas_price

Expand Down Expand Up @@ -948,18 +855,18 @@ def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]:
-------
verified : `ethereum.base_types.Uint`
The intrinsic cost of the transaction.
verified : `ethereum.base_types.Uint`
tokens_in_calldata : `ethereum.base_types.Uint`
The eip-7623 calldata tokens used by the transaction.
"""
data_cost = 0

zerobytes = 0
for byte in tx.data:
if byte == 0:
zerobytes += 1

tokens_in_calldata = zerobytes + (len(tx.data) - zerobytes) * 4

data_cost = tokens_in_calldata * COST_FLOOR_PER_CALLDATA_TOKEN

if tx.to == Bytes0(b""):
Expand All @@ -975,10 +882,9 @@ def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]:
access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST

return (
Uint(TX_BASE_COST + data_cost + create_cost + access_list_cost),
tokens_in_calldata,
)
return Uint(TX_BASE_COST +
data_cost +
create_cost + access_list_cost), tokens_in_calldata


def recover_sender(chain_id: U64, tx: Transaction) -> Address:
Expand Down

0 comments on commit 2f77cd8

Please sign in to comment.