Beispiel #1
0
def test_call_checks_signature(vm, v, r, s):
    transaction = UserAccountTransaction(**merge(DEFAULT_TX_PARAMS, {
        "v": v,
        "r": r,
        "s": s
    }))
    message_params = {
        "gas": transaction.gas,
        "to": transaction.to,
        "sender": ENTRY_POINT,
        "value": 0,
        "code": ACCOUNT_CODE,
        "is_create": False,
        "access_list": transaction.prefix_list,
    }
    message = ShardingMessage(
        **assoc(message_params, "data", transaction.data))
    transaction_context = ShardingTransactionContext(
        origin=ENTRY_POINT,
        sig_hash=transaction.sig_hash,
        transaction_gas_limit=transaction.gas,
    )
    computation = vm.state.get_computation(message, transaction_context)
    computation = computation.apply_message()
    assert computation.is_error

    # error is due to bad signature, so with tx should pass with original one
    message = ShardingMessage(
        **assoc(message_params, "data", SIGNED_DEFAULT_TRANSACTION.data))
    computation = vm.state.get_computation(message, transaction_context)
    computation = computation.apply_message()
    assert computation.is_success
Beispiel #2
0
    def prepare_child_message(self, gas, to, value, data, code, **kwargs):
        kwargs.setdefault('sender', self.msg.storage_address)

        child_message = ShardingMessage(gas=gas,
                                        to=to,
                                        value=value,
                                        data=data,
                                        code=code,
                                        depth=self.msg.depth + 1,
                                        access_list=self.msg.access_list,
                                        **kwargs)
        return child_message
Beispiel #3
0
    def run_pre_computation(self, transaction):
        state_db_cm = functools.partial(self.state_db,
                                        access_list=transaction.prefix_list)

        # 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:
                data = b''
                code = transaction.code
                is_create = True
            else:
                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),
        )

        return 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,
        )
Beispiel #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