コード例 #1
0
def test_CREATE2_deploy_contract_edge_cases(
        unvalidated_shard_chain):  # noqa: F811
    CREATE2_contracts = json.load(
        open(os.path.join(DIR, '../contract_fixtures/CREATE2_contracts.json')))
    simple_transfer_contract = CREATE2_contracts["simple_transfer_contract"]

    # First case: computed contract address not the same as provided in `transaction.to`
    chain = unvalidated_shard_chain
    code = "0xf3"
    computed_address = generate_CREATE2_contract_address(b"", decode_hex(code))
    first_failed_deploy_tx = new_sharding_transaction(
        tx_initiator=decode_hex(simple_transfer_contract['address']),
        data_destination=b'',
        data_value=0,
        data_msgdata=b'',
        data_vrs=b'',
        code=code,
        access_list=[[decode_hex(simple_transfer_contract['address'])],
                     [computed_address]])

    vm = chain.get_vm()
    computation, _ = vm.apply_transaction(first_failed_deploy_tx)
    assert isinstance(computation._error, IncorrectContractCreationAddress)
    gas_used = vm.block.header.gas_used
    assert gas_used > first_failed_deploy_tx.intrinsic_gas
    last_gas_used = gas_used

    # Next, complete deploying the contract
    successful_deploy_tx = new_sharding_transaction(
        tx_initiator=decode_hex(simple_transfer_contract['address']),
        data_destination=b'',
        data_value=0,
        data_msgdata=b'',
        data_vrs=b'',
        code=simple_transfer_contract['bytecode'],
    )
    computation, _ = vm.apply_transaction(successful_deploy_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > successful_deploy_tx.intrinsic_gas
    last_gas_used = gas_used

    # Second case: deploy to existing account
    second_failed_deploy_tx = successful_deploy_tx
    computation, _ = vm.apply_transaction(second_failed_deploy_tx)
    assert isinstance(computation._error, ContractCreationCollision)
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > second_failed_deploy_tx.intrinsic_gas
コード例 #2
0
ファイル: system.py プロジェクト: theresume/py-evm
    def __call__(self, computation):
        if computation.msg.is_static:
            raise WriteProtection(
                "Cannot modify state while inside of a STATICCALL context")

        computation.consume_gas(self.gas_cost, reason=self.mnemonic)

        value = computation.stack_pop(type_hint=constants.UINT256, )
        salt = computation.stack_pop(type_hint=constants.BYTES, )
        start_position, size = computation.stack_pop(
            num_items=2,
            type_hint=constants.UINT256,
        )

        computation.extend_memory(start_position, size)

        with computation.state_db(read_only=True) as state_db:
            insufficient_funds = state_db.get_balance(
                computation.msg.storage_address) < value
        stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT

        if insufficient_funds or stack_too_deep:
            computation.stack_push(0)
            return

        call_data = computation.memory_read(start_position, size)

        create_msg_gas = self.max_child_gas_modifier(
            computation.get_gas_remaining())
        computation.consume_gas(create_msg_gas, reason="CREATE2")

        contract_address = generate_CREATE2_contract_address(
            salt,
            call_data,
        )

        with computation.state_db(read_only=True) as state_db:
            is_collision = state_db.account_has_code(contract_address)

        if is_collision:
            computation.vm.logger.debug(
                "Address collision while creating contract: %s",
                encode_hex(contract_address),
            )
            computation.stack_push(0)
            return

        child_msg = computation.prepare_child_message(
            gas=create_msg_gas,
            to=contract_address,
            value=value,
            data=b'',
            code=call_data,
            is_create=True,
        )

        child_computation = computation.apply_child_computation(child_msg)

        if child_computation.is_error:
            computation.stack_push(0)
        else:
            computation.stack_push(contract_address)
        computation.return_gas(child_computation.get_gas_remaining())
コード例 #3
0
ファイル: vm_state.py プロジェクト: cburgdorf/py-evm
    def run_computation(self, transaction, message):
        """Apply the message to the VM."""

        state_db_cm = functools.partial(self.state_db,
                                        access_list=transaction.prefix_list)

        if transaction.code:
            contract_address = generate_CREATE2_contract_address(
                transaction.salt,
                transaction.code,
            )
        else:
            contract_address = None

        transaction_context = self.get_transaction_context_class()(
            origin=transaction.to,
            sig_hash=transaction.sig_hash,
            transaction_gas_limit=transaction.gas,
        )

        if message.is_create:
            with state_db_cm(read_only=True) as state_db:
                is_collision = state_db.account_has_code(contract_address)

            # Check if contract address provided by transaction is correct
            if contract_address != transaction.to:
                computation = self.get_computation(message,
                                                   transaction_context)
                computation._error = IncorrectContractCreationAddress(
                    "Contract address calculated: {0} but {1} is provided".
                    format(
                        encode_hex(contract_address),
                        encode_hex(transaction.to),
                    ))
                self.logger.debug(
                    "Contract address calculated: %s but %s is provided",
                    encode_hex(contract_address),
                    encode_hex(transaction.to),
                )
            elif is_collision:
                # The address of the newly created contract has collided
                # with an existing contract address.
                computation = self.get_computation(message,
                                                   transaction_context)
                computation._error = ContractCreationCollision(
                    "Address collision while creating contract: {0}".format(
                        encode_hex(contract_address), ))
                self.logger.debug(
                    "Address collision while creating contract: %s",
                    encode_hex(contract_address),
                )
            else:
                computation = self.get_computation(
                    message,
                    transaction_context,
                ).apply_create_message()
        else:
            computation = self.get_computation(
                message, transaction_context).apply_message()

        return computation
コード例 #4
0
    def execute_transaction(self, transaction):
        # state_db ontext manager that restricts access as specified in the transacion
        state_db_cm = functools.partial(self.state_db,
                                        access_list=transaction.prefix_list)

        #
        # 1) Pre Computation
        #

        # Validate the transaction
        transaction.validate()

        self.validate_transaction(transaction)

        with state_db_cm() as state_db:
            # Setup VM Message
            message_gas = transaction.gas - transaction.intrinsic_gas

            if transaction.code:
                contract_address = generate_CREATE2_contract_address(
                    transaction.salt,
                    transaction.code,
                )
                data = b''
                code = transaction.code
                is_create = True
            else:
                contract_address = None
                data = transaction.data
                code = state_db.get_code(transaction.to)
                is_create = False

        self.logger.info(
            ("TRANSACTION: to: %s | gas: %s | "
             "data-hash: %s | code-hash: %s | salt: %s"),
            encode_hex(transaction.to),
            transaction.gas,
            encode_hex(keccak(transaction.data)),
            encode_hex(keccak(transaction.code)),
            encode_hex(transaction.salt),
        )

        message = ShardingMessage(
            gas=message_gas,
            to=transaction.to,
            sender=ENTRY_POINT,
            value=0,
            data=data,
            code=code,
            is_create=is_create,
            access_list=transaction.prefix_list,
        )
        transaction_context = self.get_transaction_context_class()(
            origin=transaction.to,
            sig_hash=transaction.sig_hash,
            transaction_gas_limit=transaction.gas,
        )

        #
        # 2) Apply the message to the VM.
        #
        if message.is_create:
            with state_db_cm(read_only=True) as state_db:
                is_collision = state_db.account_has_code(contract_address)

            # Check if contract address provided by transaction is correct
            if contract_address != transaction.to:
                computation = self.get_computation(message,
                                                   transaction_context)
                computation._error = IncorrectContractCreationAddress(
                    "Contract address calculated: {0} but {1} is provided".
                    format(
                        encode_hex(contract_address),
                        encode_hex(transaction.to),
                    ))
                self.logger.debug(
                    "Contract address calculated: %s but %s is provided",
                    encode_hex(contract_address),
                    encode_hex(transaction.to),
                )
            elif is_collision:
                # The address of the newly created contract has collided
                # with an existing contract address.
                computation = self.get_computation(message,
                                                   transaction_context)
                computation._error = ContractCreationCollision(
                    "Address collision while creating contract: {0}".format(
                        encode_hex(contract_address), ))
                self.logger.debug(
                    "Address collision while creating contract: %s",
                    encode_hex(contract_address),
                )
            else:
                computation = self.get_computation(
                    message,
                    transaction_context,
                ).apply_create_message()
        else:
            computation = self.get_computation(
                message, transaction_context).apply_message()

        #
        # 2) Post Computation
        #
        # Self Destruct Refunds
        num_deletions = len(computation.get_accounts_for_deletion())
        if num_deletions:
            computation.refund_gas(REFUND_SELFDESTRUCT * num_deletions)

        # Gas Refunds
        transaction_fee, gas_refund_amount = computation.compute_transaction_fee_and_refund(
        )

        if gas_refund_amount:
            self.logger.debug(
                'TRANSACTION REFUND: %s -> %s',
                gas_refund_amount,
                encode_hex(message.to),
            )

            with state_db_cm() as state_db:
                state_db.delta_balance(message.to, gas_refund_amount)

        # Miner Fees
        self.logger.debug(
            'TRANSACTION FEE: %s',
            transaction_fee,
        )

        # Process Self Destructs
        with state_db_cm() as state_db:
            for account, beneficiary in computation.get_accounts_for_deletion(
            ):
                # TODO: need to figure out how we prevent multiple selfdestructs from
                # the same account and if this is the right place to put this.
                self.logger.debug('DELETING ACCOUNT: %s', encode_hex(account))

                # TODO: this balance setting is likely superflous and can be
                # removed since `delete_account` does this.
                state_db.set_balance(account, 0)
                state_db.delete_account(account)

        return computation
コード例 #5
0
from evm.auxiliary.user_account_contract.transaction import (
    UserAccountTransaction,
    UnsignedUserAccountTransaction,
)
from evm.auxiliary.user_account_contract.contract import (
    generate_account_bytecode,
    NONCE_GETTER_ID,
    ECRECOVER_ADDRESS as ECRECOVER_ADDRESS_INT,
)

PRIVATE_KEY = keys.PrivateKey(b"\x33" * 32)

ACCOUNT_CODE = generate_account_bytecode(
    PRIVATE_KEY.public_key.to_canonical_address())
ACCOUNT_ADDRESS = generate_CREATE2_contract_address(b"", ACCOUNT_CODE)
INITIAL_BALANCE = 10000000000

# contract that does nothing
NOOP_CONTRACT_CODE = b""
NOOP_CONTRACT_ADDRESS = generate_CREATE2_contract_address(
    b"", NOOP_CONTRACT_CODE)

# contract that reverts without returning data
FAILING_CONTRACT_CODE = b"\x61\x00\x00\xfd"  # PUSH2 0 0 REVERT
FAILING_CONTRACT_ADDRESS = generate_CREATE2_contract_address(
    b"", FAILING_CONTRACT_CODE)

# contract that logs available gas
# GAS PUSH1 0 MSTORE PUSH1 32 PUSH1 0 LOG0
GAS_LOGGING_CONTRACT_CODE = b"\x5a\x60\x00\x52\x60\x20\x60\x00\xa0"
コード例 #6
0
DIR = os.path.dirname(__file__)

simple_transfer_contract_bytecode = assembly_to_evm(
    compile_to_assembly(LLLnode.from_list(simple_transfer_contract_lll_code)))

CREATE2_contract_bytecode = assembly_to_evm(
    compile_to_assembly(LLLnode.from_list(CREATE2_contract_lll_code)))

CREATE2_json = {
    "simple_transfer_contract": {
        "bytecode":
        encode_hex(simple_transfer_contract_bytecode),
        "address":
        encode_hex(
            generate_CREATE2_contract_address(
                b'', simple_transfer_contract_bytecode)),
    },
    "CREATE2_contract": {
        "bytecode":
        encode_hex(CREATE2_contract_bytecode),
        "address":
        encode_hex(
            generate_CREATE2_contract_address(b'', CREATE2_contract_bytecode)),
    },
    "simple_factory_contract": {
        "bytecode": encode_hex(simple_factory_contract_bytecode),
    }
}

with open(os.path.join(DIR, 'CREATE2_contracts.json'), 'w') as f:
    json.dump(CREATE2_json, f, indent=4, sort_keys=True)
コード例 #7
0
def test_sharding_apply_transaction(unvalidated_shard_chain):  # noqa: F811
    chain = unvalidated_shard_chain

    CREATE2_contracts = json.load(
        open(os.path.join(DIR, '../contract_fixtures/CREATE2_contracts.json')))
    simple_transfer_contract = CREATE2_contracts["simple_transfer_contract"]
    CREATE2_contract = CREATE2_contracts["CREATE2_contract"]
    simple_factory_contract_bytecode = CREATE2_contracts[
        "simple_factory_contract"]["bytecode"]

    # First test: simple ether transfer contract
    first_deploy_tx = new_sharding_transaction(
        tx_initiator=decode_hex(simple_transfer_contract['address']),
        data_destination=b'',
        data_value=0,
        data_msgdata=b'',
        data_vrs=b'',
        code=simple_transfer_contract['bytecode'],
    )

    vm = chain.get_vm()
    computation, _ = vm.apply_transaction(first_deploy_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used
    assert gas_used > first_deploy_tx.intrinsic_gas
    last_gas_used = gas_used

    # Transfer ether to recipient
    recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c')
    amount = 100
    tx_initiator = decode_hex(simple_transfer_contract['address'])
    transfer_tx = new_sharding_transaction(tx_initiator, recipient, amount,
                                           b'', b'')

    computation, _ = vm.apply_transaction(transfer_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > transfer_tx.intrinsic_gas
    last_gas_used = vm.block.header.gas_used
    with vm.state.state_db(read_only=True) as state_db:
        assert state_db.get_balance(recipient) == amount

    # Second test: contract that deploy new contract with CREATE2
    second_deploy_tx = new_sharding_transaction(
        tx_initiator=decode_hex(CREATE2_contract['address']),
        data_destination=b'',
        data_value=0,
        data_msgdata=b'',
        data_vrs=b'',
        code=CREATE2_contract['bytecode'],
    )

    computation, _ = vm.apply_transaction(second_deploy_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > second_deploy_tx.intrinsic_gas
    last_gas_used = vm.block.header.gas_used

    # Invoke the contract to deploy new contract
    tx_initiator = decode_hex(CREATE2_contract['address'])
    newly_deployed_contract_address = generate_CREATE2_contract_address(
        int_to_big_endian(0), decode_hex(simple_factory_contract_bytecode))
    invoke_tx = new_sharding_transaction(
        tx_initiator,
        b'',
        0,
        b'',
        b'',
        access_list=[[tx_initiator, pad32(b'')],
                     [newly_deployed_contract_address]])

    computation, _ = vm.apply_transaction(invoke_tx)
    assert not computation.is_error
    gas_used = vm.block.header.gas_used - last_gas_used
    assert gas_used > invoke_tx.intrinsic_gas
    with vm.state.state_db(read_only=True) as state_db:
        newly_deployed_contract_address = generate_CREATE2_contract_address(
            int_to_big_endian(0), decode_hex(simple_factory_contract_bytecode))
        assert state_db.get_code(
            newly_deployed_contract_address) == b'\xbe\xef'
        assert state_db.get_storage(decode_hex(CREATE2_contract['address']),
                                    0) == 1