예제 #1
0
    def __call__(self, computation):
        computation.consume_gas(self.gas_cost, reason=self.mnemonic)

        value, start_position, size = computation.stack_pop(
            num_items=3,
            type_hint=constants.UINT256,
        )

        computation.extend_memory(start_position, size)

        insufficient_funds = computation.state.account_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="CREATE")

        creation_nonce = computation.state.account_db.get_nonce(computation.msg.storage_address)
        computation.state.account_db.increment_nonce(computation.msg.storage_address)

        contract_address = generate_contract_address(
            computation.msg.storage_address,
            creation_nonce,
        )

        is_collision = computation.state.account_db.account_has_code_or_nonce(contract_address)

        if is_collision:
            self.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=constants.CREATE_CONTRACT_ADDRESS,
            value=value,
            data=b'',
            code=call_data,
            create_address=contract_address,
        )

        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())
예제 #2
0
    def __call__(self, computation):
        computation.gas_meter.consume_gas(self.gas_cost, reason=self.mnemonic)

        value, start_position, size = computation.stack.pop(
            num_items=3,
            type_hint=constants.UINT256,
        )

        computation.extend_memory(start_position, size)

        with computation.vm.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.gas_meter.gas_remaining)
        computation.gas_meter.consume_gas(create_msg_gas, reason="CREATE")

        with computation.vm.state_db(read_only=True) as state_db:
            creation_nonce = state_db.get_nonce(
                computation.msg.storage_address)
        contract_address = generate_contract_address(
            computation.msg.storage_address, creation_nonce)

        child_msg = computation.prepare_child_message(
            gas=create_msg_gas,
            to=constants.CREATE_CONTRACT_ADDRESS,
            value=value,
            data=b'',
            code=call_data,
            create_address=contract_address,
        )

        if child_msg.is_create:
            child_computation = computation.vm.apply_create_message(child_msg)
        else:
            child_computation = computation.vm.apply_message(child_msg)

        computation.children.append(child_computation)

        if child_computation.error:
            computation.stack.push(0)
        else:
            computation.gas_meter.return_gas(
                child_computation.gas_meter.gas_remaining)
            computation.stack.push(contract_address)
예제 #3
0
    def run_pre_computation(self, transaction):
        # Validate the transaction
        transaction.validate()

        self.validate_transaction(transaction)

        gas_fee = transaction.gas * transaction.gas_price
        with self.mutable_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)

        self.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)),
        )

        return Message(
            gas=message_gas,
            to=transaction.to,
            sender=transaction.sender,
            value=transaction.value,
            data=data,
            code=code,
            create_address=contract_address,
        )
예제 #4
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
예제 #5
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
예제 #6
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
예제 #7
0
파일: __init__.py 프로젝트: doetsch/py-evm
def _apply_frontier_transaction(evm, transaction):
    #
    # 1) Pre Computation
    #

    # Validate the transaction
    try:
        transaction.validate()
    except ValidationError as err:
        raise InvalidTransaction(str(err))

    evm.validate_transaction(transaction)

    gas_cost = transaction.gas * transaction.gas_price
    sender_balance = evm.state_db.get_balance(transaction.sender)

    # Buy Gas
    evm.state_db.set_balance(transaction.sender, sender_balance - gas_cost)

    # Increment Nonce
    evm.state_db.increment_nonce(transaction.sender)

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

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

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

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

    #
    # 2) Apply the message to the EVM.
    #
    if message.is_create:
        computation = evm.apply_create_message(message)
    else:
        computation = evm.apply_message(message)

    #
    # 2) Post Computation
    #
    if computation.error:
        # Miner Fees
        transaction_fee = transaction.gas * transaction.gas_price
        if evm.logger:
            evm.logger.debug('TRANSACTION FEE: %s', transaction_fee)
        coinbase_balance = evm.state_db.get_balance(evm.block.header.coinbase)
        evm.state_db.set_balance(
            evm.block.header.coinbase,
            coinbase_balance + transaction_fee,
        )
    else:
        # Suicide Refunds
        num_deletions = len(computation.get_accounts_for_deletion())
        if num_deletions:
            computation.gas_meter.refund_gas(constants.REFUND_SUICIDE *
                                             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:
            if evm.logger:
                evm.logger.debug(
                    'TRANSACTION REFUND: %s -> %s',
                    gas_refund_amount,
                    encode_hex(message.sender),
                )

            sender_balance = evm.state_db.get_balance(message.sender)
            evm.state_db.set_balance(message.sender,
                                     sender_balance + gas_refund_amount)

        # Miner Fees
        transaction_fee = (transaction.gas - gas_remaining -
                           gas_refund) * transaction.gas_price
        if evm.logger:
            evm.logger.debug(
                'TRANSACTION FEE: %s -> %s',
                transaction_fee,
                encode_hex(evm.block.header.coinbase),
            )
        coinbase_balance = evm.state_db.get_balance(evm.block.header.coinbase)
        evm.state_db.set_balance(
            evm.block.header.coinbase,
            coinbase_balance + transaction_fee,
        )

    # Suicides
    for account, beneficiary in computation.get_accounts_for_deletion():
        # TODO: need to figure out how we prevent multiple suicides from
        # the same account and if this is the right place to put this.
        if evm.logger is not None:
            evm.logger.debug('DELETING ACCOUNT: %s', encode_hex(account))

        evm.state_db.set_balance(account, 0)
        evm.state_db.delete_account(account)

    return computation
예제 #8
0
파일: system.py 프로젝트: firefox0x/py-evm
    def __call__(self, computation):
        computation.gas_meter.consume_gas(self.gas_cost, reason=self.mnemonic)

        value, start_position, size = computation.stack.pop(
            num_items=3,
            type_hint=constants.UINT256,
        )

        computation.extend_memory(start_position, size)

        with computation.vm_state.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.gas_meter.gas_remaining
        )
        computation.gas_meter.consume_gas(create_msg_gas, reason="CREATE")

        with computation.vm_state.state_db() as state_db:
            creation_nonce = state_db.get_nonce(computation.msg.storage_address)
            state_db.increment_nonce(computation.msg.storage_address)

            contract_address = generate_contract_address(
                computation.msg.storage_address,
                creation_nonce,
            )

            is_collision = state_db.account_has_code_or_nonce(contract_address)

        if is_collision:
            computation.vm_state.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=constants.CREATE_CONTRACT_ADDRESS,
            value=value,
            data=b'',
            code=call_data,
            create_address=contract_address,
        )

        child_computation = computation.apply_child_computation(child_msg)

        if child_computation.is_error:
            computation.stack.push(0)
        else:
            computation.stack.push(contract_address)
        computation.gas_meter.return_gas(child_computation.gas_meter.gas_remaining)