Esempio n. 1
0
    def execute_state(self, global_state):
        instructions = global_state.environment.code.instruction_list
        op_code = instructions[global_state.mstate.pc]['opcode']

        # Only count coverage for the main contract
        if len(global_state.transaction_stack) == 0:
            self.instructions_covered[global_state.mstate.pc] = True

        self._execute_pre_hook(op_code, global_state)
        try:
            new_global_states = Instruction(
                op_code, self.dynamic_loader).evaluate(global_state)

        except TransactionStartSignal as e:
            # Setup new global state
            new_global_state = e.transaction.initial_global_state()

            new_global_state.transaction_stack = copy(
                global_state.transaction_stack) + [
                    (e.transaction, global_state)
                ]
            new_global_state.node = global_state.node
            new_global_state.mstate.constraints = global_state.mstate.constraints

            return [new_global_state], op_code

        except TransactionEndSignal as e:
            transaction, return_global_state = e.global_state.transaction_stack.pop(
            )

            if return_global_state is None:
                self.open_states.append(e.global_state)
                new_global_states = []
            else:
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [e.global_state])

                # Resume execution of the transaction initializing instruction
                op_code = return_global_state.environment.code.instruction_list[
                    return_global_state.mstate.pc]['opcode']

                # Set execution result in the return_state
                return_global_state.last_return_data = transaction.return_data
                return_global_state.world_state = copy(
                    global_state.world_state)
                return_global_state.environment.active_account =\
                    global_state.accounts[return_global_state.environment.active_account.address]

                # Execute the post instruction handler
                new_global_states = Instruction(op_code,
                                                self.dynamic_loader).evaluate(
                                                    return_global_state, True)

                # In order to get a nice call graph we need to set the nodes here
                for state in new_global_states:
                    state.node = global_state.node

        self._execute_post_hook(op_code, new_global_states)

        return new_global_states, op_code
Esempio n. 2
0
def test_staticness(input):
    # Arrange
    state = get_global_state()
    state.environment.static = True
    state.mstate.stack = []
    instruction = Instruction(input, dynamic_loader=None)

    # Act and Assert
    with pytest.raises(WriteProtection):
        instruction.evaluate(state)
Esempio n. 3
0
def test_concrete_shr(val1, val2, expected):
    state = get_state()
    state.mstate.stack = [BVV(int(val1, 16), 256), BVV(int(val2, 16), 256)]
    expected = BVV(int(expected, 16), 256)
    instruction = Instruction("shr", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(state)[0]

    # Assert
    assert simplify(new_state.mstate.stack[-1]) == expected
Esempio n. 4
0
def test_staticcall(f1):
    # Arrange
    state = get_global_state()
    state.mstate.stack = [10, 10, 10, 10, 10, 10, 10, 10, 0]
    instruction = Instruction("staticcall", dynamic_loader=None)

    # Act and Assert
    with pytest.raises(TransactionStartSignal) as ts:
        instruction.evaluate(state)
    assert ts.value.transaction.static
    assert ts.value.transaction.initial_global_state().environment.static
Esempio n. 5
0
def test_shr(inputs, output):
    # Arrange
    state = get_state()

    state.mstate.stack = inputs
    instruction = Instruction("shr", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(state)[0]

    # Assert
    assert simplify(new_state.mstate.stack[-1]) == output
Esempio n. 6
0
def test_codecopy_concrete():
    # Arrange
    active_account = Account("0x0", code=Disassembly("60606040"))
    environment = Environment(active_account, None, None, None, None, None)
    og_state = GlobalState(None, environment, None, MachineState(gas=10000000))

    og_state.mstate.stack = [2, 2, 2]
    instruction = Instruction("codecopy", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(og_state)[0]

    # Assert
    assert new_state.mstate.memory[2] == 96
    assert new_state.mstate.memory[3] == 64
Esempio n. 7
0
    def _end_message_call(
        self,
        return_global_state: GlobalState,
        global_state: GlobalState,
        revert_changes=False,
        return_data=None,
    ) -> List[GlobalState]:
        # Resume execution of the transaction initializing instruction
        op_code = return_global_state.environment.code.instruction_list[
            return_global_state.mstate.pc]["opcode"]

        # Set execution result in the return_state
        return_global_state.last_return_data = return_data
        if not revert_changes:
            return_global_state.world_state = copy(global_state.world_state)
            return_global_state.environment.active_account = global_state.accounts[
                return_global_state.environment.active_account.address]

        # Execute the post instruction handler
        new_global_states = Instruction(op_code, self.dynamic_loader).evaluate(
            return_global_state, True)

        # In order to get a nice call graph we need to set the nodes here
        for state in new_global_states:
            state.node = global_state.node

        return new_global_states
Esempio n. 8
0
def test_staticness_call_symbolic(f1):
    # Arrange
    state = get_global_state()
    state.environment.static = True
    state.mstate.stack = []
    call_value = symbol_factory.BitVecSym("x", 256)
    code = Disassembly(code="616263")
    f1.return_value = ("0", Account(code=code,
                                    address="0x19"), 0, call_value, 0, 0, 0)
    instruction = Instruction("call", dynamic_loader=None)

    # Act and Assert
    with pytest.raises(TransactionStartSignal) as ts:
        instruction.evaluate(state)

    assert ts.value.transaction.static
    assert ts.value.global_state.mstate.constraints[-1] == (call_value == 0)
Esempio n. 9
0
File: svm.py Progetto: p0n1/mythril
    def execute_state(self, global_state):
        instructions = global_state.environment.code.instruction_list
        try:
            op_code = instructions[global_state.mstate.pc]['opcode']
        except IndexError:
            self.open_states.append(global_state.world_state)
            return [], None

        self._execute_pre_hook(op_code, global_state)
        try:
            self._measure_coverage(global_state)
            new_global_states = Instruction(op_code, self.dynamic_loader).evaluate(global_state)

        except VmException as e:
            transaction, return_global_state = global_state.transaction_stack.pop()

            if return_global_state is None:
                # In this case we don't put an unmodified world state in the open_states list Since in the case of an
                #  exceptional halt all changes should be discarded, and this world state would not provide us with a
                #  previously unseen world state
                logging.debug("Encountered a VmException, ending path: `{}`".format(str(e)))
                new_global_states = []
            else:
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [global_state])
                new_global_states = self._end_message_call(return_global_state, global_state,
                                                           revert_changes=True, return_data=None)

        except TransactionStartSignal as e:
            # Setup new global state
            new_global_state = e.transaction.initial_global_state()

            new_global_state.transaction_stack = copy(global_state.transaction_stack) + [(e.transaction, global_state)]
            new_global_state.node = global_state.node
            new_global_state.mstate.constraints = global_state.mstate.constraints

            return [new_global_state], op_code

        except TransactionEndSignal as e:
            transaction, return_global_state = e.global_state.transaction_stack.pop()

            if return_global_state is None:
                if not isinstance(transaction, ContractCreationTransaction) or transaction.return_data:
                    e.global_state.world_state.node = global_state.node
                    self.open_states.append(e.global_state.world_state)
                new_global_states = []
            else:
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [e.global_state])

                new_global_states = self._end_message_call(return_global_state, global_state,
                                                           revert_changes=False, return_data=transaction.return_data)

        self._execute_post_hook(op_code, new_global_states)

        return new_global_states, op_code
Esempio n. 10
0
def test_codecopy_concrete():
    # Arrange
    active_account = Account("0x0", code=Disassembly("60606040"))
    environment = Environment(active_account, None, None, None, None, None)
    og_state = GlobalState(None, environment, None,
                           MachineState(gas_limit=8000000))
    og_state.transaction_stack.append(
        (MessageCallTransaction(world_state=WorldState(),
                                gas_limit=8000000), None))

    og_state.mstate.stack = [2, 2, 2]
    instruction = Instruction("codecopy", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(og_state)[0]

    # Assert
    assert new_state.mstate.memory[2] == 96
    assert new_state.mstate.memory[3] == 64
Esempio n. 11
0
    def execute_state(self, global_state):
        instructions = global_state.environment.code.instruction_list
        op_code = instructions[global_state.mstate.pc]['opcode']
        self.instructions_covered[global_state.mstate.pc] = True

        self._execute_pre_hook(op_code, global_state)
        new_global_states = Instruction(
            op_code, self.dynamic_loader).evaluate(global_state)
        self._execute_post_hook(op_code, new_global_states)

        return new_global_states, op_code
Esempio n. 12
0
def test_extcodecopy_fail():
    # Arrange
    new_world_state = WorldState()
    new_account = new_world_state.create_account(balance=10, address=101)
    new_account.code = Disassembly("60616240")
    new_environment = Environment(new_account, None, None, None, None, None)
    state = GlobalState(
        new_world_state, new_environment, None, MachineState(gas_limit=8000000)
    )
    state.transaction_stack.append(
        (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None)
    )

    state.mstate.stack = [2, 2, 2, symbol_factory.BitVecSym("FAIL", 256)]
    instruction = Instruction("extcodecopy", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(state)[0]

    # Assert
    assert new_state.mstate.stack == []
    assert new_state.mstate.memory._memory == state.mstate.memory._memory
Esempio n. 13
0
def test_extcodecopy():
    # Arrange
    new_world_state = WorldState()
    new_account = new_world_state.create_account(balance=10, address=101)
    new_account.code = Disassembly("60616240")
    ext_account = new_world_state.create_account(balance=1000, address=121)
    ext_account.code = Disassembly("6040404040")

    new_environment = Environment(new_account, None, None, None, None, None)
    state = GlobalState(
        new_world_state, new_environment, None, MachineState(gas_limit=8000000)
    )
    state.transaction_stack.append(
        (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None)
    )

    state.mstate.stack = [3, 0, 0, 121]
    instruction = Instruction("extcodecopy", dynamic_loader=None)

    # Act
    new_state = instruction.evaluate(state)[0]
    # Assert
    assert new_state.mstate.memory[0:3] == [96, 64, 64]
Esempio n. 14
0
    def execute_state(self, global_state):
        instructions = global_state.environment.code.instruction_list
        op_code = instructions[global_state.mstate.pc]['opcode']

        # Only count coverage for the main contract
        if len(global_state.call_stack) == 0:
            self.instructions_covered[global_state.mstate.pc] = True

        self._execute_pre_hook(op_code, global_state)
        new_global_states = Instruction(
            op_code, self.dynamic_loader).evaluate(global_state)
        self._execute_post_hook(op_code, new_global_states)

        return new_global_states, op_code
Esempio n. 15
0
    def _end_message_call(
        self,
        return_global_state: GlobalState,
        global_state: GlobalState,
        revert_changes=False,
        return_data=None,
    ) -> List[GlobalState]:
        """

        :param return_global_state:
        :param global_state:
        :param revert_changes:
        :param return_data:
        :return:
        """

        return_global_state.mstate.constraints += global_state.mstate.constraints
        # Resume execution of the transaction initializing instruction
        op_code = return_global_state.environment.code.instruction_list[
            return_global_state.mstate.pc]["opcode"]

        # Set execution result in the return_state
        return_global_state.last_return_data = return_data
        if not revert_changes:
            return_global_state.world_state = copy(global_state.world_state)
            return_global_state.environment.active_account = global_state.accounts[
                return_global_state.environment.active_account.address.value]
            if isinstance(global_state.current_transaction,
                          ContractCreationTransaction):
                return_global_state.mstate.min_gas_used += (
                    global_state.mstate.min_gas_used)
                return_global_state.mstate.max_gas_used += (
                    global_state.mstate.max_gas_used)

        # Execute the post instruction handler
        new_global_states = Instruction(op_code, self.dynamic_loader,
                                        self.iprof).evaluate(
                                            return_global_state, True)

        # In order to get a nice call graph we need to set the nodes here
        for state in new_global_states:
            state.node = global_state.node

        return new_global_states
Esempio n. 16
0
def test_staticness_call_concrete(f1, input, success):
    # Arrange
    state = get_global_state()
    state.environment.static = True
    state.mstate.stack = []
    code = Disassembly(code="616263")
    f1.return_value = ("0", Account(code=code,
                                    address="0x19"), 0, input, 0, 0, 0)
    instruction = Instruction("call", dynamic_loader=None)

    # Act and Assert
    if success:
        with pytest.raises(TransactionStartSignal) as ts:
            instruction.evaluate(state)
        assert ts.value.transaction.static
    else:
        with pytest.raises(WriteProtection):
            instruction.evaluate(state)
Esempio n. 17
0
    def execute_state(
            self, global_state: GlobalState
    ) -> Tuple[List[GlobalState], Optional[str]]:
        """Execute a single instruction in global_state.

        :param global_state:
        :return: A list of successor states.
        """
        # Execute hooks
        for hook in self._execute_state_hooks:
            hook(global_state)

        instructions = global_state.environment.code.instruction_list

        try:
            op_code = instructions[global_state.mstate.pc]["opcode"]
        except IndexError:
            self._add_world_state(global_state)
            return [], None
        if len(global_state.mstate.stack) < get_required_stack_elements(
                op_code):
            error_msg = ("Stack Underflow Exception due to insufficient "
                         "stack elements for the address {}".format(
                             instructions[global_state.mstate.pc]["address"]))
            new_global_states = self.handle_vm_exception(
                global_state, op_code, error_msg)
            self._execute_post_hook(op_code, new_global_states)
            return new_global_states, op_code

        try:
            self._execute_pre_hook(op_code, global_state)
        except PluginSkipState:
            self._add_world_state(global_state)
            return [], None

        try:
            new_global_states = Instruction(op_code, self.dynamic_loader,
                                            self.iprof).evaluate(global_state)

        except VmException as e:
            new_global_states = self.handle_vm_exception(
                global_state, op_code, str(e))

        except TransactionStartSignal as start_signal:
            # Setup new global state
            new_global_state = start_signal.transaction.initial_global_state()

            new_global_state.transaction_stack = copy(
                global_state.transaction_stack) + [
                    (start_signal.transaction, global_state)
                ]
            new_global_state.node = global_state.node
            new_global_state.mstate.constraints = (
                start_signal.global_state.mstate.constraints)

            log.debug("Starting new transaction %s", start_signal.transaction)

            return [new_global_state], op_code

        except TransactionEndSignal as end_signal:
            transaction, return_global_state = end_signal.global_state.transaction_stack[
                -1]

            log.debug("Ending transaction %s.", transaction)

            if return_global_state is None:
                if (not isinstance(transaction, ContractCreationTransaction)
                        or transaction.return_data) and not end_signal.revert:
                    check_potential_issues(global_state)

                    end_signal.global_state.world_state.node = global_state.node
                    self._add_world_state(end_signal.global_state)
                new_global_states = []
            else:
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [end_signal.global_state])

                # Propogate codecall based annotations
                if return_global_state.get_current_instruction()["opcode"] in (
                        "DELEGATECALL",
                        "CALLCODE",
                ):
                    new_annotations = [
                        annotation for annotation in
                        global_state.get_annotations(MutationAnnotation)
                    ]
                    return_global_state.add_annotations(new_annotations)

                new_global_states = self._end_message_call(
                    copy(return_global_state),
                    global_state,
                    revert_changes=False or end_signal.revert,
                    return_data=transaction.return_data,
                )

        self._execute_post_hook(op_code, new_global_states)

        return new_global_states, op_code
Esempio n. 18
0
 def execute_state(self, global_state):
     instructions = global_state.environment.code.instruction_list
     op_code = instructions[global_state.mstate.pc]['opcode']
     return Instruction(op_code,
                        self.dynamic_loader).evaluate(global_state), op_code
Esempio n. 19
0
    def execute_state(self, global_state):
        instructions = global_state.environment.code.instruction_list
        try:
            op_code = instructions[global_state.mstate.pc]['opcode']
        except IndexError:
            self.open_states.append(global_state.world_state)
            return [], None

        self._execute_pre_hook(op_code, global_state)
        try:
            self._measure_coverage(global_state)

            if self.prepostprocessor:
                global_state = self.prepostprocessor.preprocess(global_state)
                op_code = global_state.get_current_instruction()['opcode']

            new_global_states = Instruction(op_code, self.dynamic_loader).evaluate(global_state)

            if self.prepostprocessor:
                new_global_states = self.prepostprocessor.postprocess(global_state, new_global_states)

        except CreateNewContractSignal as c:
            laser_evm = LaserEVM(self.accounts, self.dynamic_loader, self.max_depth, self.execution_timeout, self.create_timeout,
                 strategy=DepthFirstSearchStrategy, prepostprocessor=self.prepostprocessor)

            laser_evm.open_states = [self.world_state]
            printd("Start subconstruction")
            code_extension = SymbolicCodeExtension("calldata", "Subcontract", c.extension_byte_size, c.predefined_map)
            created_account = execute_contract_creation(laser_evm, c.bytecode, contract_name="Subcontract",
                        code_extension=code_extension, callvalue=c.callvalue)

            if laser_evm.open_states:
                created_account = laser_evm.open_states[0].accounts[created_account.address]

            paused_state = c.paused_state
            paused_state.accounts[created_account.address] = created_account

            # Computing address from hex str returned to z3 BitVec representation
            address_as_int = 0
            new_address = created_account.address.replace("0x", "")
            i = 0
            while i < len(new_address):
                address_as_int *= 256
                address_as_int += int(new_address[i:i + 2], 16)
                i += 2


            paused_state.mstate.stack.append(BitVecVal(address_as_int, 256))
            paused_state.mstate.pc += 1 # Because the post code of instruction wrapper was not executed after Signal
            new_global_states = [paused_state]

            if self.prepostprocessor:
                new_global_states = self.prepostprocessor.postprocess(global_state, new_global_states)
            printd("End subcontruction")

        except TransactionStartSignal as e:
            printd("Transaction start")
            # Setup new global state
            new_global_state = e.transaction.initial_global_state()


            new_global_state.transaction_stack = copy(global_state.transaction_stack) + [(e.transaction, global_state)]
            new_global_state.node = global_state.node
            new_global_state.mstate.constraints = global_state.mstate.constraints

            return [new_global_state], op_code

        except TransactionEndSignal as e:
            printd("Transaction end")
            transaction, return_global_state = e.global_state.transaction_stack.pop()

            if return_global_state is None:
                if not isinstance(transaction, ContractCreationTransaction) or transaction.return_data:
                    e.global_state.world_state.node = global_state.node
                    self.open_states.append(e.global_state.world_state)
                new_global_states = []
            else: 
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [e.global_state])

                # Resume execution of the transaction initializing instruction
                op_code = return_global_state.environment.code.instruction_list[return_global_state.mstate.pc]['opcode']

                # Set execution result in the return_state
                return_global_state.last_return_data = transaction.return_data
                return_global_state.world_state = copy(global_state.world_state)
                return_global_state.environment.active_account = \
                    global_state.accounts[return_global_state.environment.active_account.address]
		
                #if self.prepostprocessor:
                #    global_state = self.prepostprocessor.preprocess(global_state)
                #    op_code = global_state.get_current_instruction()['opcode']

                # Execute the post instruction handler
                new_global_states = Instruction(op_code, self.dynamic_loader).evaluate(return_global_state, True)

                #if self.prepostprocessor:
                #    new_global_states = self.prepostprocessor.postprocess(global_state, new_global_states)

                # In order to get a nice call graph we need to set the nodes here
                for state in new_global_states:
                    state.node = global_state.node

        self._execute_post_hook(op_code, new_global_states) # Todo Maybe also filter here

        return new_global_states, op_code
Esempio n. 20
0
    def execute_state(
        self, global_state: GlobalState
    ) -> Tuple[List[GlobalState], Union[str, None]]:
        """

        :param global_state:
        :return:
        """
        # Execute hooks
        for hook in self._execute_state_hooks:
            hook(global_state)

        instructions = global_state.environment.code.instruction_list

        try:
            op_code = instructions[global_state.mstate.pc]["opcode"]
        except IndexError:
            self._add_world_state(global_state)
            return [], None

        self._execute_pre_hook(op_code, global_state)
        try:
            self._measure_coverage(global_state)
            new_global_states = Instruction(
                op_code, self.dynamic_loader, self.iprof
            ).evaluate(global_state)

        except VmException as e:
            transaction, return_global_state = global_state.transaction_stack.pop()

            if return_global_state is None:
                # In this case we don't put an unmodified world state in the open_states list Since in the case of an
                #  exceptional halt all changes should be discarded, and this world state would not provide us with a
                #  previously unseen world state
                log.debug("Encountered a VmException, ending path: `{}`".format(str(e)))
                new_global_states = []
            else:
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [global_state])
                new_global_states = self._end_message_call(
                    return_global_state,
                    global_state,
                    revert_changes=True,
                    return_data=None,
                )

        except TransactionStartSignal as start_signal:
            # Setup new global state
            new_global_state = start_signal.transaction.initial_global_state()

            new_global_state.transaction_stack = copy(
                global_state.transaction_stack
            ) + [(start_signal.transaction, global_state)]
            new_global_state.node = global_state.node
            new_global_state.mstate.constraints = global_state.mstate.constraints

            return [new_global_state], op_code

        except TransactionEndSignal as end_signal:
            transaction, return_global_state = end_signal.global_state.transaction_stack[
                -1
            ]

            if return_global_state is None:
                if (
                    not isinstance(transaction, ContractCreationTransaction)
                    or transaction.return_data
                ) and not end_signal.revert:
                    end_signal.global_state.world_state.node = global_state.node
                    self._add_world_state(end_signal.global_state)
                new_global_states = []
            else:
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [end_signal.global_state])

                new_global_states = self._end_message_call(
                    copy(return_global_state),
                    global_state,
                    revert_changes=False or end_signal.revert,
                    return_data=transaction.return_data,
                )

        self._execute_post_hook(op_code, new_global_states)

        return new_global_states, op_code
Esempio n. 21
0
    def execute_state(self, global_state):
        instructions = global_state.environment.code.instruction_list
        try:
            op_code = instructions[global_state.mstate.pc]['opcode']
        except IndexError:
            self.open_states.append(global_state.world_state)
            return [], None

        self._execute_pre_hook(op_code, global_state)
        try:
            self._measure_coverage(global_state)
            new_global_states = Instruction(
                op_code, self.dynamic_loader).evaluate(global_state)

        except VmException as e:
            logging.debug(
                "Encountered a VmException, ending path: `{}`".format(str(e)))
            new_global_states = []

        except TransactionStartSignal as e:
            # Setup new global state
            new_global_state = e.transaction.initial_global_state()

            new_global_state.transaction_stack = copy(
                global_state.transaction_stack) + [
                    (e.transaction, global_state)
                ]
            new_global_state.node = global_state.node
            new_global_state.mstate.constraints = global_state.mstate.constraints

            return [new_global_state], op_code

        except TransactionEndSignal as e:
            transaction, return_global_state = e.global_state.transaction_stack.pop(
            )

            if return_global_state is None:
                if not isinstance(transaction, ContractCreationTransaction
                                  ) or transaction.return_data:
                    e.global_state.world_state.node = global_state.node
                    self.open_states.append(e.global_state.world_state)
                new_global_states = []
            else:
                # First execute the post hook for the transaction ending instruction
                self._execute_post_hook(op_code, [e.global_state])

                # Resume execution of the transaction initializing instruction
                op_code = return_global_state.environment.code.instruction_list[
                    return_global_state.mstate.pc]['opcode']

                # Set execution result in the return_state
                return_global_state.last_return_data = transaction.return_data
                return_global_state.world_state = copy(
                    global_state.world_state)
                return_global_state.environment.active_account = \
                    global_state.accounts[return_global_state.environment.active_account.address]

                # Execute the post instruction handler
                new_global_states = Instruction(op_code,
                                                self.dynamic_loader).evaluate(
                                                    return_global_state, True)

                # In order to get a nice call graph we need to set the nodes here
                for state in new_global_states:
                    state.node = global_state.node

        self._execute_post_hook(op_code, new_global_states)

        return new_global_states, op_code
Esempio n. 22
0
from mythril.laser.smt import symbol_factory

# Arrange
world_state = WorldState()
account = world_state.create_account(balance=10, address=101)
account.code = Disassembly("60606040")
world_state.create_account(balance=10, address=1000)
environment = Environment(account, None, None, None, None, None)
og_state = GlobalState(world_state, environment, None,
                       MachineState(gas_limit=8000000))
og_state.transaction_stack.append(
    (MessageCallTransaction(world_state=WorldState(),
                            gas_limit=8000000), None))

instruction = Instruction("extcodehash", dynamic_loader=None)


def test_extcodehash_no_account():

    # If account does not exist, return 0
    og_state.mstate.stack = [symbol_factory.BitVecVal(1, 256)]
    new_state = instruction.evaluate(og_state)[0]
    assert new_state.mstate.stack[-1] == 0


def test_extcodehash_no_code():

    # If account code does not exist, return hash of empty set.
    og_state.mstate.stack = [symbol_factory.BitVecVal(1000, 256)]
    new_state = instruction.evaluate(og_state)[0]