示例#1
0
文件: call.py 项目: ygdmxy/py-evm
def compute_eip150_msg_gas(*, computation: ComputationAPI, gas: int,
                           extra_gas: int, value: int, mnemonic: str,
                           callstipend: int) -> Tuple[int, int]:
    if computation.get_gas_remaining() < extra_gas:
        # It feels wrong to raise an OutOfGas exception outside of GasMeter,
        # but I don't see an easy way around it.
        raise OutOfGas(f"Out of gas: Needed {extra_gas}"
                       f" - Remaining {computation.get_gas_remaining()}"
                       f" - Reason: {mnemonic}")
    gas = min(
        gas, max_child_gas_eip150(computation.get_gas_remaining() - extra_gas))
    total_fee = gas + extra_gas
    child_msg_gas = gas + (callstipend if value else 0)
    return child_msg_gas, total_fee
示例#2
0
    def __call__(self, computation: ComputationAPI) -> None:

        stack_data = self.get_stack_data(computation)

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

        computation.extend_memory(stack_data.memory_start, stack_data.memory_length)

        storage_address_balance = computation.state.get_balance(computation.msg.storage_address)

        insufficient_funds = storage_address_balance < stack_data.endowment
        stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT

        if insufficient_funds or stack_too_deep:
            computation.stack_push_int(0)
            computation.return_data = b''
            if insufficient_funds:
                self.logger.debug2(
                    "%s failure: %s",
                    self.mnemonic,
                    f"Insufficient Funds: {storage_address_balance} < {stack_data.endowment}"
                )
            elif stack_too_deep:
                self.logger.debug2("%s failure: %s", self.mnemonic, "Stack limit reached")
            else:
                raise RuntimeError("Invariant: error must be insufficient funds or stack too deep")
            return

        call_data = computation.memory_read_bytes(
            stack_data.memory_start, stack_data.memory_length
        )

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

        contract_address = self.generate_contract_address(stack_data, call_data, computation)

        is_collision = computation.state.has_code_or_nonce(contract_address)

        if is_collision:
            computation.stack_push_int(0)
            computation.return_data = b''
            self.logger.debug2(
                "Address collision while creating contract: %s",
                encode_hex(contract_address),
            )
            return

        child_msg = computation.prepare_child_message(
            gas=create_msg_gas,
            to=constants.CREATE_CONTRACT_ADDRESS,
            value=stack_data.endowment,
            data=b'',
            code=call_data,
            create_address=contract_address,
        )
        self.apply_create_message(computation, child_msg)
示例#3
0
def make_frontier_receipt(base_header: BlockHeaderAPI,
                          transaction: SignedTransactionAPI,
                          computation: ComputationAPI) -> ReceiptAPI:
    # Reusable for other forks
    # This skips setting the state root (set to 0 instead). The logic for making a state root
    # lives in the FrontierVM, so that state merkelization at each receipt is skipped at Byzantium+.

    logs = [
        Log(address, topics, data)
        for address, topics, data in computation.get_log_entries()
    ]

    gas_remaining = computation.get_gas_remaining()
    gas_refund = computation.get_gas_refund()
    tx_gas_used = (transaction.gas - gas_remaining) - min(
        gas_refund,
        (transaction.gas - gas_remaining) // 2,
    )
    gas_used = base_header.gas_used + tx_gas_used

    receipt = Receipt(
        state_root=ZERO_HASH32,
        gas_used=gas_used,
        logs=logs,
    )

    return receipt
示例#4
0
    def finalize_gas_used(cls, transaction: SignedTransactionAPI,
                          computation: ComputationAPI) -> int:

        gas_remaining = computation.get_gas_remaining()
        consumed_gas = transaction.gas - gas_remaining

        gross_refund = computation.get_gas_refund()
        net_refund = cls.calculate_net_gas_refund(consumed_gas, gross_refund)

        return consumed_gas - net_refund
示例#5
0
文件: state.py 项目: ggs134/py-evm
    def finalize_computation(self, transaction: SignedTransactionAPI,
                             computation: ComputationAPI) -> ComputationAPI:

        # Self Destruct Refunds
        num_deletions = len(computation.get_accounts_for_deletion())
        if num_deletions:
            computation.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:
            self.vm_state.logger.debug2(
                'TRANSACTION REFUND: %s -> %s',
                gas_refund_amount,
                encode_hex(computation.msg.sender),
            )

            # self.vm_state.delta_balance(computation.msg.sender, gas_refund_amount)

        ### DAEJUN changed ###
        # Miner Fees
        # transaction_fee = \
        #     (transaction.gas - gas_remaining - gas_refund) * transaction.gas_price
        transaction_fee = 0
        self.vm_state.logger.debug2(
            'TRANSACTION FEE: %s -> %s',
            transaction_fee,
            encode_hex(self.vm_state.coinbase),
        )
        self.vm_state.delta_balance(self.vm_state.coinbase, transaction_fee)

        # Process Self Destructs
        for account, _ 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.vm_state.logger.debug2('DELETING ACCOUNT: %s',
                                        encode_hex(account))

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

        return computation
示例#6
0
    def __call__(self, computation: ComputationAPI) -> None:

        stack_data = self.get_stack_data(computation)

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

        computation.extend_memory(stack_data.memory_start,
                                  stack_data.memory_length)

        insufficient_funds = computation.state.get_balance(
            computation.msg.storage_address) < stack_data.endowment
        stack_too_deep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT

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

        call_data = computation.memory_read_bytes(stack_data.memory_start,
                                                  stack_data.memory_length)

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

        contract_address = self.generate_contract_address(
            stack_data, call_data, computation)

        is_collision = computation.state.has_code_or_nonce(contract_address)

        if is_collision:
            self.logger.debug2(
                "Address collision while creating contract: %s",
                encode_hex(contract_address),
            )
            computation.stack_push_int(0)
            return

        child_msg = computation.prepare_child_message(
            gas=create_msg_gas,
            to=constants.CREATE_CONTRACT_ADDRESS,
            value=stack_data.endowment,
            data=b'',
            code=call_data,
            create_address=contract_address,
        )
        self.apply_create_message(computation, child_msg)
示例#7
0
    def finalize_computation(self,
                             transaction: SignedTransactionAPI,
                             computation: ComputationAPI) -> ComputationAPI:
        transaction_context = self.vm_state.get_transaction_context(transaction)

        gas_remaining = computation.get_gas_remaining()
        gas_used = transaction.gas - gas_remaining
        gas_refund = self.calculate_gas_refund(computation, gas_used)
        gas_refund_amount = (gas_refund + gas_remaining) * transaction_context.gas_price

        if gas_refund_amount:
            self.vm_state.logger.debug2(
                'TRANSACTION REFUND: %s -> %s',
                gas_refund_amount,
                encode_hex(computation.msg.sender),
            )

            self.vm_state.delta_balance(computation.msg.sender, gas_refund_amount)

        # Miner Fees
        gas_used = transaction.gas - gas_remaining - gas_refund
        transaction_fee = gas_used * self.vm_state.get_tip(transaction)
        self.vm_state.logger.debug2(
            'TRANSACTION FEE: %s -> %s',
            transaction_fee,
            encode_hex(self.vm_state.coinbase),
        )
        self.vm_state.delta_balance(self.vm_state.coinbase, transaction_fee)

        # Process Self Destructs
        for account, _ 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.vm_state.logger.debug2('DELETING ACCOUNT: %s', encode_hex(account))

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

        return computation
示例#8
0
    def before_computation(cls, computation: ComputationAPI, next_opcode: int, next_opcode_fn: Any):
        logger.info("Entering pre_computation with opcode {o}".format(o=next_opcode_fn.mnemonic))
        head = ChangeChainLink(TableWidgetEnum.OPCODES, pre_computation=[computation.code.pc - 1], post_computation=[])
        chain = ChangeChain(head)

        chain.add_link(stack_effects.get(next_opcode))
        stack = computation._stack.values
        lkp = cls.storage_lookup.get(computation.msg.storage_address)

        # Big if construct that determines which opcode has which causer and has which effect. This could be
        # simplified a bit, however it was not possible to determine the effects statically like in stack effects,
        # since the changes in memory and storage are dependent on the varying contents of memory, stack and storage,
        # instead of the only the opcode as it is the case with the stack.
        if next_opcode == SSTORE:
            slot = get_stack_content(stack, 1)[0]
            if lkp is None:
                index = 0
            else:
                index = lkp.get(slot)
                if index is None:
                    index = len(lkp)
            chain.add_link(ChangeChainLink(TableWidgetEnum.STORAGE, [], [index]))
        elif next_opcode == SLOAD:
            slot = get_stack_content(stack, 1)[0]
            if lkp is None or lkp.get(slot) is None:
                cls.set_storage.emit(computation.msg.storage_address, slot, "0x00")
                cls.storage_lock.acquire(True)
                # refresh because the main storage should have set this in the meantime
                lkp = cls.storage_lookup.get(computation.msg.storage_address)
            logger.info("Trying to SLOAD storage key -> index: {k} -> {i}".format(k=slot, i=lkp.get(slot)))
            chain.add_link(ChangeChainLink(TableWidgetEnum.STORAGE, [lkp.get(slot)], []))
        elif next_opcode == MSTORE or next_opcode == MSTORE8:
            offset = get_stack_content(stack, 1)[0]
            chain.add_link(
                ChangeChainLink(TableWidgetEnum.MEMORY, [], [int(offset, 16) / 32])
            )
        elif next_opcode == MLOAD:
            offset = get_stack_content(stack, 1)[0]
            chain.add_link(
                ChangeChainLink(TableWidgetEnum.MEMORY, [int(offset, 16) / 32], [])
            )
        elif next_opcode == SHA3 or (LOG0 <= next_opcode <= LOG4) \
                or next_opcode == RETURN or next_opcode == REVERT:
            arr = get_stack_content(stack, 2)
            print(arr)

            offset = arr[0]
            length = arr[1]
            chain.add_link(ChangeChainLink(TableWidgetEnum.MEMORY,
                                           list(range(int(int(offset, 16) / 32), int(int(length, 16) / 32) + 1)), [])
                           )

        elif next_opcode == CALLDATACOPY or next_opcode == CODECOPY \
                or next_opcode == RETURNDATACOPY:
            arr = get_stack_content(stack, 3)
            offset = arr[0]
            length = arr[2]
            chain.add_link(ChangeChainLink(TableWidgetEnum.MEMORY, [],
                                           [] if "0x" == length or "0x" == offset else list(
                                               range(int(int(offset, 16) / 32), int(int(length, 16) / 32) + 1)))
                           )
        elif next_opcode == EXTCODECOPY:
            arr = get_stack_content(stack, 4)
            offset = arr[1]
            length = arr[3]
            chain.add_link(ChangeChainLink(TableWidgetEnum.MEMORY, [],
                                           list(range(int(int(offset, 16) / 32), int(int(length, 16) / 32) + 1)))
                           )
        elif next_opcode == CREATE or next_opcode == CREATE2:
            arr = get_stack_content(stack, 3)
            print(f"CREATE {arr}")
            offset = arr[1]
            length = arr[2]
            chain.add_link(ChangeChainLink(TableWidgetEnum.MEMORY,
                                           list(range(int(int(offset, 16) / 32), int(int(length, 16) / 32) + 1)), [])
                           )
        elif next_opcode == CALL or next_opcode == CALLCODE:
            arr = get_stack_content(stack, 7)
            print(f"CALL {arr}")
            argoffset = arr[3]
            arglength = arr[4]
            retOffset = arr[5]
            retLength = arr[6]
            chain.add_link(
                ChangeChainLink(TableWidgetEnum.MEMORY,
                                list(range(int(int(argoffset, 16) / 32), int(int(arglength, 16) / 32) + 1)),
                                list(range(int(int(retOffset, 16) / 32), int(int(retLength, 16) / 32) + 1)))
            )
        elif next_opcode == DELEGATECALL or next_opcode == STATICCALL:
            arr = get_stack_content(stack, 6)
            print(f"DELEGATECALL {arr}")
            argoffset = arr[2]
            arglength = arr[3]
            retOffset = arr[4]
            retLength = arr[5]
            chain.add_link(
                ChangeChainLink(TableWidgetEnum.MEMORY,
                                list(range(int(int(argoffset, 16) / 32), int(int(arglength, 16) / 32) + 1)),
                                list(range(int(int(retOffset, 16) / 32), int(int(retLength, 16) / 32) + 1)))
            )

        cls.add_chain.emit(chain)
        cls.pre_computation.emit(computation.get_gas_remaining(), computation.code.pc)
        if cls.debug_mode:
            cls.step_lock.acquire(True)