示例#1
0
def prepare_computation(vm_class):

    message = Message(
        to=CANONICAL_ADDRESS_A,
        sender=CANONICAL_ADDRESS_B,
        value=100,
        data=b'',
        code=b'',
        gas=800,
    )

    tx_context = vm_class._state_class.transaction_context_class(
        gas_price=1,
        origin=CANONICAL_ADDRESS_B,
    )

    vm = vm_class(GENESIS_HEADER, ChainDB(AtomicDB()))

    computation = vm_class._state_class.computation_class(
        state=vm.state,
        message=message,
        transaction_context=tx_context,
    )

    computation.state.account_db.touch_account(
        decode_hex(EMPTY_ADDRESS_IN_STATE))
    computation.state.account_db.set_code(decode_hex(ADDRESS_WITH_CODE[0]),
                                          ADDRESS_WITH_CODE[1])

    return computation
示例#2
0
def message():
    message = Message(
        to=CANONICAL_ADDRESS_A,
        sender=CANONICAL_ADDRESS_B,
        value=100,
        data=b'',
        code=b'',
        gas=100,
    )
    return message
示例#3
0
    def build_evm_message(self, transaction):

        transaction_context = self.get_transaction_context(transaction)
        gas_fee = transaction.gas * transaction_context.gas_price

        # Buy Gas
        self.vm_state.account_db.delta_balance(transaction.sender, -1 * gas_fee)

        # Increment Nonce
        self.vm_state.account_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,
                self.vm_state.account_db.get_nonce(transaction.sender) - 1,
            )
            data = b''
            code = transaction.data
        else:
            contract_address = None
            data = transaction.data
            code = self.vm_state.account_db.get_code(transaction.to)

        self.vm_state.logger.debug(
            (
                "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,
        )
        return message
示例#4
0
def _create_message(gas=1,
                    to=ADDRESS_A,
                    sender=ADDRESS_B,
                    value=0,
                    data=b"",
                    code=b"",
                    **kwargs):
    return Message(gas=gas,
                   to=to,
                   sender=sender,
                   value=value,
                   data=data,
                   code=code,
                   **kwargs)
示例#5
0
def test_is_origin_computation(computation, transaction_context):
    assert computation.is_origin_computation
    message2 = Message(
        to=CANONICAL_ADDRESS_A,
        # Different sender than the tx context origin
        sender=CANONICAL_ADDRESS_A,
        value=100,
        data=b'',
        code=b'',
        gas=100,
    )
    computation2 = DummyComputation(
        state=None,
        message=message2,
        transaction_context=transaction_context,
    )
    assert not computation2.is_origin_computation
示例#6
0
    def execute_bytecode(
        self,
        origin,
        gas_price,
        gas,
        to,
        sender,
        value,
        data,
        code,
        code_address=None,
    ):
        exit("NOT IMPLEMENTED YET")
        """
        Execute raw bytecode in the context of the current state of
        the virtual machine.
        """
        if origin is None:
            origin = sender

        # Construct a message
        message = Message(
            gas=gas,
            to=to,
            sender=sender,
            value=value,
            data=data,
            code=code,
            code_address=code_address,
        )

        # Construction a tx context
        transaction_context = self.state.get_transaction_context_class()(
            gas_price=gas_price,
            origin=origin,
        )

        # Execute it in the VM
        return self.state.get_computation(
            message, transaction_context).apply_computation(
                self.state,
                message,
                transaction_context,
            )
def fixture_to_computation(fixture, code, vm):
    message = Message(
        to=fixture['exec']['address'],
        sender=fixture['exec']['caller'],
        value=fixture['exec']['value'],
        data=fixture['exec']['data'],
        code=code,
        gas=fixture['exec']['gas'],
    )
    transaction_context = BaseTransactionContext(
        origin=fixture['exec']['origin'],
        gas_price=fixture['exec']['gasPrice'],
    )
    return vm.state.get_computation(message,
                                    transaction_context).apply_computation(
                                        vm.state,
                                        message,
                                        transaction_context,
                                    )
示例#8
0
    def prepare_child_message(self,
                              gas: int,
                              to: bytes,
                              value: int,
                              data: bytes,
                              code: bytes,
                              **kwargs: Any) -> Message:
        """
        Helper method for creating a child computation.
        """
        kwargs.setdefault('sender', self.msg.storage_address)

        child_message = Message(
            gas=gas,
            to=to,
            value=value,
            data=data,
            code=code,
            depth=self.msg.depth + 1,
            **kwargs
        )
        return child_message
def test_vm_fixtures(fixture, vm_class, computation_getter):
    chaindb = ChainDB(get_db_backend())
    header = BlockHeader(
        coinbase=fixture['env']['currentCoinbase'],
        difficulty=fixture['env']['currentDifficulty'],
        block_number=fixture['env']['currentNumber'],
        gas_limit=fixture['env']['currentGasLimit'],
        timestamp=fixture['env']['currentTimestamp'],
    )
    vm = vm_class(header=header, chaindb=chaindb)
    state = vm.state
    setup_account_db(fixture['pre'], state.account_db)
    code = state.account_db.get_code(fixture['exec']['address'])
    # Update state_root manually
    vm.block = vm.block.copy(header=vm.block.header.copy(
        state_root=state.state_root))

    message = Message(
        to=fixture['exec']['address'],
        sender=fixture['exec']['caller'],
        value=fixture['exec']['value'],
        data=fixture['exec']['data'],
        code=code,
        gas=fixture['exec']['gas'],
    )
    transaction_context = BaseTransactionContext(
        origin=fixture['exec']['origin'],
        gas_price=fixture['exec']['gasPrice'],
    )
    computation = vm.state.get_computation(
        message, transaction_context).apply_computation(
            vm.state,
            message,
            transaction_context,
        )
    # Update state_root manually
    vm.block = vm.block.copy(
        header=vm.block.header.copy(state_root=computation.state.state_root), )

    if 'post' in fixture:
        #
        # Success checks
        #
        assert not computation.is_error

        log_entries = computation.get_log_entries()
        if 'logs' in fixture:
            actual_logs_hash = hash_log_entries(log_entries)
            expected_logs_hash = fixture['logs']
            assert expected_logs_hash == actual_logs_hash
        elif log_entries:
            raise AssertionError("Got log entries: {0}".format(log_entries))

        expected_output = fixture['out']
        assert computation.output == expected_output

        gas_meter = computation._gas_meter

        expected_gas_remaining = fixture['gas']
        actual_gas_remaining = gas_meter.gas_remaining
        gas_delta = actual_gas_remaining - expected_gas_remaining
        assert gas_delta == 0, "Gas difference: {0}".format(gas_delta)

        call_creates = fixture.get('callcreates', [])
        assert len(computation.children) == len(call_creates)

        call_creates = fixture.get('callcreates', [])
        for child_computation, created_call in zip(computation.children,
                                                   call_creates):
            to_address = created_call['destination']
            data = created_call['data']
            gas_limit = created_call['gasLimit']
            value = created_call['value']

            assert child_computation.msg.to == to_address
            assert data == child_computation.msg.data or child_computation.msg.code
            assert gas_limit == child_computation.msg.gas
            assert value == child_computation.msg.value
        expected_account_db = fixture['post']
    else:
        #
        # Error checks
        #
        assert computation.is_error
        assert isinstance(computation._error, VMError)
        expected_account_db = fixture['pre']

    verify_account_db(expected_account_db, vm.state.account_db)
示例#10
0
    def build_evm_message(
            self,
            send_transaction: BaseTransaction,
            transaction_context: BaseTransactionContext,
            receive_transaction: BaseReceiveTransaction = None) -> Message:
        if transaction_context.is_refund == True:

            # Setup VM Message
            message_gas = 0

            refund_amount = receive_transaction.remaining_refund

            contract_address = None
            data = b''
            code = b''

            self.vm_state.logger.debug(
                ("REFUND TRANSACTION: sender: %s | refund amount: %s "),
                encode_hex(send_transaction.sender),
                refund_amount,
            )

        elif transaction_context.is_receive == True:
            # this is a receive transaction - now we get to execute any code or data
            # transaction_context = self.get_transaction_context(send_transaction)
            # gas_fee = transaction.transaction.gas * transaction_context.gas_price

            # TODO:
            # fail niceley here so we can put a failed tx. the failed tx can be seen in the receipt status_code
            # we will have to refund the sender the money if this is the case.
            # so the amount of gas the send tx paid is saved as transaction.transaction.gas
            # Setup VM Message
            # message_gas = transaction.transaction.gas - transaction.transaction.intrinsic_gas -1 * gas_fee
            # I tested this, if this tx uses more gas than what was charged to the send tx it will fail.

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

            refund_amount = 0

            if send_transaction.to == constants.CREATE_CONTRACT_ADDRESS:
                # the contract address was already chosen on the send transaction. It is now the caller chain address
                contract_address = transaction_context.caller_chain_address
                data = b''
                code = send_transaction.data
            else:
                contract_address = None
                data = send_transaction.data
                code = self.vm_state.account_db.get_code(send_transaction.to)

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

        else:
            # this is a send transaction

            #transaction_context = self.get_transaction_context(send_transaction, receive_transaction)
            gas_fee = send_transaction.gas * transaction_context.gas_price

            #this is the default gas fee for the send tx that needs to be subtracted on the receive of a smart contract
            # Buy Gas
            self.vm_state.account_db.delta_balance(send_transaction.sender,
                                                   -1 * gas_fee)

            # Increment Nonce
            self.vm_state.account_db.increment_nonce(send_transaction.sender)

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

            refund_amount = 0

            #when a contract is created with a send transaction, do no computation.
            #we have to put the computation back. because it needs to charge computation
            #gas on the send. We just have to make sure it doesnt execute the transaction...
            #TODO: make sure the computation is not executed
            #temporarily we will just do no computation. This means interactions with
            #smart contracts will cost no gas until we finish this.

            if send_transaction.to == constants.CREATE_CONTRACT_ADDRESS:
                contract_address = generate_contract_address(
                    send_transaction.sender,
                    self.vm_state.account_db.get_nonce(send_transaction.sender)
                    - 1,
                )
                data = b''
                code = send_transaction.data
            else:
                contract_address = None
                data = send_transaction.data
                code = self.vm_state.account_db.get_code(send_transaction.to)

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

        message = Message(
            gas=message_gas,
            to=send_transaction.to,
            sender=send_transaction.sender,
            value=send_transaction.value,
            data=data,
            code=code,
            create_address=contract_address,
            refund_amount=refund_amount,
        )
        return message