Exemple #1
0
    def run_computation(self, transaction, message):
        """Apply the message to the VM."""
        transaction_context = self.get_transaction_context_class()(
            gas_price=transaction.gas_price,
            origin=transaction.sender,
        )
        if message.is_create:
            is_collision = self.read_only_state_db.account_has_code_or_nonce(
                message.storage_address)

            if is_collision:
                # The address of the newly created contract has *somehow* 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(message.storage_address), ))
                self.logger.debug(
                    "Address collision while creating contract: %s",
                    encode_hex(message.storage_address),
                )
            else:
                computation = self.get_computation(
                    message,
                    transaction_context,
                ).apply_create_message()
        else:
            computation = self.get_computation(
                message, transaction_context).apply_message()

        return computation
Exemple #2
0
    def build_computation(self, message, transaction):
        """Apply the message to the VM."""
        transaction_context = self.get_transaction_context(transaction)
        if message.is_create:
            is_collision = self.vm_state.account_db.account_has_code_or_nonce(
                message.storage_address)

            if is_collision:
                # The address of the newly created contract has *somehow* collided
                # with an existing contract address.
                computation = self.vm_state.get_computation(
                    message, transaction_context)
                computation._error = ContractCreationCollision(
                    "Address collision while creating contract: {0}".format(
                        encode_hex(message.storage_address), ))
                self.vm_state.logger.debug(
                    "Address collision while creating contract: %s",
                    encode_hex(message.storage_address),
                )
            else:
                computation = self.vm_state.get_computation(
                    message,
                    transaction_context,
                ).apply_create_message()
        else:
            computation = self.vm_state.get_computation(
                message, transaction_context).apply_message()

        return computation
Exemple #3
0
    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
Exemple #4
0
def _execute_frontier_transaction(vm_state, transaction):
    # Reusable for other forks

    #
    # 1) Pre Computation
    #

    # Validate the transaction
    transaction.validate()

    vm_state.validate_transaction(transaction)

    gas_fee = transaction.gas * transaction.gas_price
    with vm_state.state_db() as state_db:
        # Buy Gas
        state_db.delta_balance(transaction.sender, -1 * gas_fee)

        # Increment Nonce
        state_db.increment_nonce(transaction.sender)

        # Setup VM Message
        message_gas = transaction.gas - transaction.intrinsic_gas

        if transaction.to == constants.CREATE_CONTRACT_ADDRESS:
            contract_address = generate_contract_address(
                transaction.sender,
                state_db.get_nonce(transaction.sender) - 1,
            )
            data = b''
            code = transaction.data
        else:
            contract_address = None
            data = transaction.data
            code = state_db.get_code(transaction.to)

    vm_state.logger.info(
        ("TRANSACTION: sender: %s | to: %s | value: %s | gas: %s | "
         "gas-price: %s | s: %s | r: %s | v: %s | data-hash: %s"),
        encode_hex(transaction.sender),
        encode_hex(transaction.to),
        transaction.value,
        transaction.gas,
        transaction.gas_price,
        transaction.s,
        transaction.r,
        transaction.v,
        encode_hex(keccak(transaction.data)),
    )

    message = Message(
        gas=message_gas,
        to=transaction.to,
        sender=transaction.sender,
        value=transaction.value,
        data=data,
        code=code,
        create_address=contract_address,
    )
    transaction_context = vm_state.get_transaction_context_class()(
        gas_price=transaction.gas_price,
        origin=transaction.sender,
    )

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

        if is_collision:
            # The address of the newly created contract has *somehow* collided
            # with an existing contract address.
            computation = vm_state.get_computation(message,
                                                   transaction_context)
            computation._error = ContractCreationCollision(
                "Address collision while creating contract: {0}".format(
                    encode_hex(contract_address), ))
            vm_state.logger.debug(
                "Address collision while creating contract: %s",
                encode_hex(contract_address),
            )
        else:
            computation = vm_state.get_computation(
                message,
                transaction_context,
            ).apply_create_message()
    else:
        computation = vm_state.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.gas_meter.refund_gas(REFUND_SELFDESTRUCT * num_deletions)

    # Gas Refunds
    gas_remaining = computation.get_gas_remaining()
    gas_refunded = computation.get_gas_refund()
    gas_used = transaction.gas - gas_remaining
    gas_refund = min(gas_refunded, gas_used // 2)
    gas_refund_amount = (gas_refund + gas_remaining) * transaction.gas_price

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

        with vm_state.state_db() as state_db:
            state_db.delta_balance(message.sender, gas_refund_amount)

    # Miner Fees
    transaction_fee = (transaction.gas - gas_remaining -
                       gas_refund) * transaction.gas_price
    vm_state.logger.debug(
        'TRANSACTION FEE: %s -> %s',
        transaction_fee,
        encode_hex(vm_state.coinbase),
    )
    with vm_state.state_db() as state_db:
        state_db.delta_balance(vm_state.coinbase, transaction_fee)

    # Process Self Destructs
    with vm_state.state_db() 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.
            vm_state.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
Exemple #5
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