def get_call_params(self, computation: BaseComputation) -> CallParams: gas = computation.stack_pop(type_hint=constants.UINT256) code_address = force_bytes_to_address( computation.stack_pop(type_hint=constants.BYTES)) ( memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, ) = computation.stack_pop(num_items=4, type_hint=constants.UINT256) to = computation.msg.storage_address sender = computation.msg.sender value = computation.msg.value return ( gas, value, to, sender, code_address, memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, False, # should_transfer_value, computation.msg.is_static, )
def mine_blocks_with_access_list_receipts( chain, num_blocks, num_tx_per_block, funded_address, funded_address_private_key): current_vm = chain.get_vm() if not isinstance(current_vm, BerlinVM): pytest.skip("{current_vm} does not support typed transactions") for _ in range(num_blocks): block_receipts = [] for _ in range(num_tx_per_block): tx = new_access_list_transaction( chain.get_vm(), from_=funded_address, to=force_bytes_to_address(b'\x10\x10'), private_key=funded_address_private_key, ) new_block, tx_receipt, computation = chain.apply_transaction(tx) block_receipts.append(tx_receipt) computation.raise_if_error() yield chain.mine_block(), block_receipts
def get_call_params(self, computation: BaseComputation) -> CallParams: gas = computation.stack_pop(type_hint=constants.UINT256) to = force_bytes_to_address( computation.stack_pop(type_hint=constants.BYTES)) ( memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, ) = computation.stack_pop(num_items=4, type_hint=constants.UINT256) return ( gas, 0, # value to, None, # sender None, # code_address memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, False, # should_transfer_value, True, # is_static )
def get_call_params(self, computation: ComputationAPI) -> CallParams: gas = computation.stack_pop1_int() to = force_bytes_to_address(computation.stack_pop1_bytes()) ( value, memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, ) = computation.stack_pop_ints(5) return ( gas, value, to, None, # sender None, # code_address memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, True, # should_transfer_value, computation.msg.is_static, )
def extcodecopy(computation: BaseComputation) -> None: account = force_bytes_to_address( computation.stack_pop(type_hint=constants.BYTES)) ( mem_start_position, code_start_position, size, ) = computation.stack_pop(num_items=3, type_hint=constants.UINT256) computation.extend_memory(mem_start_position, size) word_count = ceil32(size) // 32 copy_gas_cost = constants.GAS_COPY * word_count computation.consume_gas( copy_gas_cost, reason='EXTCODECOPY: word gas cost', ) code = computation.state.account_db.get_code(account) code_bytes = code[code_start_position:code_start_position + size] padded_code_bytes = code_bytes.ljust(size, b'\x00') computation.memory_write(mem_start_position, size, padded_code_bytes)
def get_call_params(self, computation: ComputationAPI) -> CallParams: gas = computation.stack_pop1_int() code_address = force_bytes_to_address(computation.stack_pop1_bytes()) ( memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, ) = computation.stack_pop_ints(4) to = computation.msg.storage_address sender = computation.msg.sender value = computation.msg.value return ( gas, value, to, sender, code_address, memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, False, # should_transfer_value, computation.msg.is_static, )
def selfdestruct_eip150(computation: ComputationAPI) -> None: beneficiary = force_bytes_to_address(computation.stack_pop1_bytes()) if not computation.state.account_exists(beneficiary): computation.consume_gas( constants.GAS_SELFDESTRUCT_NEWACCOUNT, reason=mnemonics.SELFDESTRUCT, ) _selfdestruct(computation, beneficiary)
def fuzz_extcodesize_opcode_fn(computation, opcode_fn) -> None: to = computation.stack_pop1_bytes() _to = to_normalized_address(to_hex(force_bytes_to_address(to))) if settings.ENVIRONMENTAL_INSTRUMENTATION and hasattr(computation.state, "fuzzed_extcodesize") and computation.state.fuzzed_extcodesize is not None\ and _to in computation.state.fuzzed_extcodesize and computation.state.fuzzed_extcodesize[_to] is not None: computation.stack_push_int(computation.state.fuzzed_extcodesize[_to]) else: computation.stack_push_bytes(to) opcode_fn(computation=computation)
def selfdestruct_eip2929(computation: ComputationAPI) -> None: beneficiary = force_bytes_to_address(computation.stack_pop1_bytes()) if _mark_address_warm(computation, beneficiary): gas_cost = berlin_constants.COLD_ACCOUNT_ACCESS_COST computation.consume_gas( gas_cost, reason=f"Implicit account load during {mnemonics.SELFDESTRUCT}", ) selfdestruct_eip161_on_address(computation, beneficiary)
def selfdestruct_eip161(computation: ComputationAPI) -> None: beneficiary = force_bytes_to_address(computation.stack_pop1_bytes()) is_dead = (not computation.state.account_exists(beneficiary) or computation.state.account_is_empty(beneficiary)) if is_dead and computation.state.get_balance( computation.msg.storage_address): computation.consume_gas( constants.GAS_SELFDESTRUCT_NEWACCOUNT, reason=mnemonics.SELFDESTRUCT, ) _selfdestruct(computation, beneficiary)
def create_random_tx(chain, private_key, is_valid=True): return chain.create_unsigned_transaction( nonce=0, gas_price=1, gas=2100000000000 if is_valid else 0, # For simplicity, both peers create tx with the same private key. # We rely on unique data to create truly unique txs data=uuid.uuid4().bytes, to=force_bytes_to_address(b'\x10\x10'), value=1, ).as_signed_transaction(private_key, chain_id=chain.chain_id)
def extcodehash(computation: BaseComputation) -> None: """ Return the code hash for a given address. EIP: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1052.md """ account = force_bytes_to_address(computation.stack_pop1_bytes()) state = computation.state if state.account_is_empty(account): computation.stack_push_bytes(constants.NULL_BYTE) else: computation.stack_push_bytes(state.get_code_hash(account))
def extcodehash(computation: BaseComputation) -> None: """ Return the code hash for a given address. EIP: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1052.md """ account = force_bytes_to_address(computation.stack_pop(type_hint=constants.BYTES)) account_db = computation.state.account_db if not account_db.account_exists(account): computation.stack_push(constants.NULL_BYTE) else: computation.stack_push(account_db.get_code_hash(account))
def extcodehash_eip2929(computation: ComputationAPI) -> None: """ Return the code hash for a given address. EIP: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1052.md """ address = force_bytes_to_address(computation.stack_pop1_bytes()) state = computation.state _consume_gas_for_account_load(computation, address, mnemonics.EXTCODEHASH) if state.account_is_empty(address): computation.stack_push_bytes(constants.NULL_BYTE) else: computation.stack_push_bytes(state.get_code_hash(address))
def mine_blocks_with_receipts(chain, num_blocks, num_tx_per_block, funded_address, funded_address_private_key): for _ in range(num_blocks): block_receipts = [] for _ in range(num_tx_per_block): tx = new_transaction( chain.get_vm(), from_=funded_address, to=force_bytes_to_address(b'\x10\x10'), private_key=funded_address_private_key, ) new_block, tx_receipt, computation = chain.apply_transaction(tx) block_receipts.append(tx_receipt) computation.raise_if_error() yield chain.mine_block(), block_receipts
def test_blake2b_f_compression(vm_class, input_hex, output_hex, expect_exception): comp = run_computation( setup_vm(vm_class), CANONICAL_ADDRESS_B, code=b'', gas=2**32 - 1, to=force_bytes_to_address(b'\x09'), data=to_bytes(hexstr=input_hex), ) if expect_exception: assert isinstance(comp.error, expect_exception) else: comp.raise_if_error() result = comp.output assert result.hex() == output_hex
def test_chaindb_get_receipt_by_index( chain, funded_address, funded_address_private_key): NUMBER_BLOCKS_IN_CHAIN = 5 TRANSACTIONS_IN_BLOCK = 10 REQUIRED_BLOCK_NUMBER = 2 REQUIRED_RECEIPT_INDEX = 3 for block_number in range(NUMBER_BLOCKS_IN_CHAIN): for tx_index in range(TRANSACTIONS_IN_BLOCK): tx = new_transaction( chain.get_vm(), from_=funded_address, to=force_bytes_to_address(b'\x10\x10'), private_key=funded_address_private_key, ) new_block, tx_receipt, computation = chain.apply_transaction(tx) computation.raise_if_error() if (block_number + 1) == REQUIRED_BLOCK_NUMBER and tx_index == REQUIRED_RECEIPT_INDEX: actual_receipt = tx_receipt chain.mine_block() # Check that the receipt retrieved is indeed the actual one chaindb_retrieved_receipt = chain.chaindb.get_receipt_by_index( REQUIRED_BLOCK_NUMBER, REQUIRED_RECEIPT_INDEX, ) assert chaindb_retrieved_receipt == actual_receipt # Raise error if block number is not found with pytest.raises(ReceiptNotFound): chain.chaindb.get_receipt_by_index( NUMBER_BLOCKS_IN_CHAIN + 1, REQUIRED_RECEIPT_INDEX, ) # Raise error if receipt index is out of range with pytest.raises(ReceiptNotFound): chain.chaindb.get_receipt_by_index( NUMBER_BLOCKS_IN_CHAIN, TRANSACTIONS_IN_BLOCK + 1, )
def fuzz_call_opcode_fn(computation, opcode_fn) -> None: gas = computation.stack_pop1_int() to = computation.stack_pop1_bytes() _to = to_normalized_address(to_hex(force_bytes_to_address(to))) if settings.ENVIRONMENTAL_INSTRUMENTATION and hasattr(computation.state, "fuzzed_call_return") and computation.state.fuzzed_call_return is not None\ and _to in computation.state.fuzzed_call_return and computation.state.fuzzed_call_return[_to] is not None: ( value, memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, ) = computation.stack_pop_ints(5) computation.stack_push_int(computation.state.fuzzed_call_return[_to]) else: computation.stack_push_bytes(to) computation.stack_push_int(gas) opcode_fn(computation=computation) return _to
def test_blake2b_f_compression(vm_class, input_hex, output_hex, expect_exception): computation = setup_computation( vm_class, CANONICAL_ADDRESS_B, code=b'', gas=2**32 - 1, to=force_bytes_to_address(b'\x09'), data=to_bytes(hexstr=input_hex), ) comp = computation.apply_message( computation.state, computation.msg, computation.transaction_context, ) if expect_exception: assert isinstance(comp.error, expect_exception) else: comp.raise_if_error() result = comp.output assert result.hex() == output_hex
def extcodecopy_execute(computation: ComputationAPI) -> Tuple[Address, int]: """ Runs the logical component of extcodecopy, without charging gas. :return (target_address, copy_size): useful for the caller to determine gas costs """ account = force_bytes_to_address(computation.stack_pop1_bytes()) ( mem_start_position, code_start_position, size, ) = computation.stack_pop_ints(3) computation.extend_memory(mem_start_position, size) code = computation.state.get_code(account) code_bytes = code[code_start_position:code_start_position + size] padded_code_bytes = code_bytes.ljust(size, b'\x00') computation.memory_write(mem_start_position, size, padded_code_bytes) return account, size
async def test_get_balance_works_for_block_number( chain_without_block_validation, ipc_request, funded_address, funded_address_initial_balance, funded_address_private_key): block_no_before_transfer = (await ipc_request('eth_blockNumber', []))['result'] transfer_eth(chain=chain_without_block_validation, sender_private_key=funded_address_private_key, value=1, to=force_bytes_to_address(b'\x10\x10')) balance_before = (await ipc_request( 'eth_getBalance', [funded_address.hex(), to_int(hexstr=block_no_before_transfer)]))['result'] assert balance_before == hex(funded_address_initial_balance) block_no_after_transfer = (await ipc_request('eth_blockNumber', []))['result'] balance_after = (await ipc_request( 'eth_getBalance', [funded_address.hex(), to_int(hexstr=block_no_after_transfer)]))['result'] assert to_int(hexstr=balance_after) < to_int(hexstr=balance_before)
def get_call_params(self, computation: BaseComputation) -> CallParams: gas = computation.stack_pop1_int() to = force_bytes_to_address(computation.stack_pop1_bytes()) ( memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, ) = computation.stack_pop_ints(4) return ( gas, 0, # value to, None, # sender None, # code_address memory_input_start_position, memory_input_size, memory_output_start_position, memory_output_size, False, # should_transfer_value, True, # is_static )
assemble( opcode_values.PUSH20, CANONICAL_ADDRESS_C, opcode_values.BALANCE, opcode_values.PUSH20, CANONICAL_ADDRESS_A, opcode_values.BALANCE, ), 3 + 2600 + 3 + 2600, ), # precompiles are exempt from cold cost ( BerlinVM, assemble( opcode_values.PUSH20, force_bytes_to_address(b'\x05'), opcode_values.BALANCE, ), 3 + 100, ), )) def test_gas_costs(vm_class, code, expect_gas_used): comp = run_computation(setup_vm(vm_class), CANONICAL_ADDRESS_B, code) assert comp.is_success assert comp.get_gas_used() == expect_gas_used @pytest.mark.parametrize( 'vm_class, code, expect_gas_used, access_list', ( # Empty access list does not affect account cache warmth
def extcodesize_eip2929(computation: ComputationAPI) -> None: address = force_bytes_to_address(computation.stack_pop1_bytes()) _consume_gas_for_account_load(computation, address, mnemonics.EXTCODEHASH) code_size = len(computation.state.get_code(address)) computation.stack_push_int(code_size)
def selfdestruct(computation: BaseComputation) -> None: beneficiary = force_bytes_to_address( computation.stack_pop(type_hint=constants.BYTES)) _selfdestruct(computation, beneficiary)
from typing import Iterable from eth_typing import Address from eth_utils import to_set from eth import constants from eth._utils.address import ( force_bytes_to_address, ) from eth.vm.computation import BaseComputation THREE = force_bytes_to_address(b'\x03') @to_set def collect_touched_accounts( computation: BaseComputation) -> Iterable[Address]: """ Collect all of the accounts that *may* need to be deleted based on `EIP-161 <https://eips.ethereum.org/EIPS/eip-161>`_. Checking whether they *do* need to be deleted happens in the caller. See also: https://github.com/ethereum/EIPs/issues/716 """ # collect the coinbase account if it was touched via zero-fee transfer if computation.is_origin_computation and computation.transaction_context.gas_price == 0: yield computation.state.coinbase
ComputationAPI, ) from eth.exceptions import ( OutOfGas, InsufficientFunds, StackDepthLimit, ) from eth.vm.computation import ( BaseComputation, ) from .opcodes import FRONTIER_OPCODES FRONTIER_PRECOMPILES = { force_bytes_to_address(b'\x01'): precompiles.ecrecover, force_bytes_to_address(b'\x02'): precompiles.sha256, force_bytes_to_address(b'\x03'): precompiles.ripemd160, force_bytes_to_address(b'\x04'): precompiles.identity, } class FrontierComputation(BaseComputation): """ A class for all execution computations in the ``Frontier`` fork. Inherits from :class:`~eth.vm.computation.BaseComputation` """ # Override opcodes = FRONTIER_OPCODES _precompiles = FRONTIER_PRECOMPILES # type: ignore # https://github.com/python/mypy/issues/708 # noqa: E501
def selfdestruct(computation: ComputationAPI) -> None: beneficiary = force_bytes_to_address(computation.stack_pop1_bytes()) _selfdestruct(computation, beneficiary)
import pytest from eth.estimators.gas import binary_gas_search_1000_tolerance from eth._utils.address import force_bytes_to_address from tests.core.helpers import ( fill_block, new_transaction, ) ADDRESS_2 = b'\0' * 19 + b'\x02' ADDR_1010 = force_bytes_to_address(b'\x10\x10') @pytest.fixture def chain(chain_without_block_validation): return chain_without_block_validation @pytest.mark.parametrize( 'should_sign_tx', (True, False), ) @pytest.mark.parametrize( 'data, gas_estimator, to, on_pending, expected', ( (b'', None, ADDR_1010, True, 21000), (b'', None, ADDR_1010, False, 21000), (b'\xff' * 10, None, ADDR_1010, True, 21680), (b'\xff' * 10, None, ADDR_1010, False, 21680),
merge, ) from eth import precompiles from eth._utils.address import ( force_bytes_to_address, ) from eth.vm.forks.frontier.computation import FRONTIER_PRECOMPILES from eth.vm.forks.spurious_dragon.computation import SpuriousDragonComputation from .opcodes import BYZANTIUM_OPCODES BYZANTIUM_PRECOMPILES = merge( FRONTIER_PRECOMPILES, { force_bytes_to_address(b'\x05'): precompiles.modexp, force_bytes_to_address(b'\x06'): precompiles.ecadd, force_bytes_to_address(b'\x07'): precompiles.ecmul, force_bytes_to_address(b'\x08'): precompiles.ecpairing, }, ) class ByzantiumComputation(SpuriousDragonComputation): """ A class for all execution computations in the ``Byzantium`` fork. Inherits from :class:`~eth.vm.forks.spurious_dragon.computation.SpuriousDragonComputation` """ # Override opcodes = BYZANTIUM_OPCODES _precompiles = BYZANTIUM_PRECOMPILES