コード例 #1
0
    def create_account(
        self,
        balance=0,
        address=None,
        concrete_storage=False,
        dynamic_loader=None,
        creator=None,
    ) -> Account:
        """Create non-contract account.

        :param address: The account's address
        :param balance: Initial balance for the account
        :param concrete_storage: Interpret account storage as concrete
        :param dynamic_loader: used for dynamically loading storage from the block chain
        :return: The new account
        """
        address = (symbol_factory.BitVecVal(address, 256)
                   if address else self._generate_new_address(creator))

        new_account = Account(
            address=address,
            balances=self.balances,
            dynamic_loader=dynamic_loader,
            concrete_storage=concrete_storage,
        )
        if balance:
            new_account.add_balance(symbol_factory.BitVecVal(balance, 256))

        self.put_account(new_account)
        return new_account
コード例 #2
0
    def _add_external_call(global_state: GlobalState) -> None:
        gas = global_state.mstate.stack[-1]
        to = global_state.mstate.stack[-2]
        try:
            constraints = copy(global_state.mstate.constraints)
            solver.get_model(constraints + [
                UGT(gas, symbol_factory.BitVecVal(2300, 256)),
                Or(
                    to > symbol_factory.BitVecVal(16, 256),
                    to == symbol_factory.BitVecVal(0, 256),
                ),
            ])

            # Check whether we can also set the callee address
            try:
                constraints += [
                    to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
                ]
                solver.get_model(constraints)

                global_state.annotate(
                    StateChangeCallsAnnotation(global_state, True))
            except UnsatError:
                global_state.annotate(
                    StateChangeCallsAnnotation(global_state, False))
        except UnsatError:
            pass
コード例 #3
0
ファイル: memory.py プロジェクト: mygirl8893/mythril
    def get_word_at(self, index: int) -> Union[int, BitVec]:
        """Access a word from a specified memory index.

        :param index: integer representing the index to access
        :return: 32 byte word at the specified index
        """
        try:
            return symbol_factory.BitVecVal(
                util.concrete_int_from_bytes(
                    bytes([
                        util.get_concrete_int(b)
                        for b in self[index:index + 32]
                    ]),
                    0,
                ),
                256,
            )
        except TypeError:
            result = simplify(
                Concat([
                    b if isinstance(b, BitVec) else symbol_factory.BitVecVal(
                        b, 8)
                    for b in cast(List[Union[int,
                                             BitVec]], self[index:index + 32])
                ]))
            assert result.size() == 256
            return result
コード例 #4
0
ファイル: memory.py プロジェクト: mygirl8893/mythril
    def write_word_at(self, index: int, value: Union[int, BitVec, bool,
                                                     Bool]) -> None:
        """Writes a 32 byte word to memory at the specified index`

        :param index: index to write to
        :param value: the value to write to memory
        """
        try:
            # Attempt to concretize value
            if isinstance(value, bool):
                _bytes = (int(1).to_bytes(32, byteorder="big")
                          if value else int(0).to_bytes(32, byteorder="big"))
            else:
                _bytes = util.concrete_int_to_bytes(value)
            assert len(_bytes) == 32
            self[index:index + 32] = list(bytearray(_bytes))
        except (Z3Exception, AttributeError):  # BitVector or BoolRef
            value = cast(Union[BitVec, Bool], value)
            if isinstance(value, Bool):
                value_to_write = If(
                    value,
                    symbol_factory.BitVecVal(1, 256),
                    symbol_factory.BitVecVal(0, 256),
                )
            else:
                value_to_write = value
            assert value_to_write.size() == 256

            for i in range(0, value_to_write.size(), 8):
                self[index + 31 - (i // 8)] = Extract(i + 7, i, value_to_write)
コード例 #5
0
ファイル: account.py プロジェクト: mygirl8893/mythril
    def __getitem__(self, item: Union[str, int]) -> Any:
        try:
            return self._storage[item]
        except KeyError:
            if (self.address and self.address.value != 0
                    and (self.dynld and self.dynld.storage_loading)):
                try:
                    self._storage[item] = symbol_factory.BitVecVal(
                        int(
                            self.dynld.read_storage(
                                contract_address=hex(self.address.value),
                                index=int(item),
                            ),
                            16,
                        ),
                        256,
                    )
                    return self._storage[item]
                except ValueError:
                    pass

        if self.concrete:
            return symbol_factory.BitVecVal(0, 256)

        self._storage[item] = symbol_factory.BitVecSym(
            "storage_{}_{}".format(str(item), str(self.address)), 256)
        return self._storage[item]
コード例 #6
0
 def _handle_exp(self, state):
     op0, op1 = self._get_args(state)
     if op0.symbolic and op1.symbolic:
         constraint = And(
             op1 > symbol_factory.BitVecVal(256, 256),
             op0 > symbol_factory.BitVecVal(1, 256),
         )
     elif op1.symbolic:
         if op0.value < 2:
             return
         constraint = op1 >= symbol_factory.BitVecVal(
             ceil(256 / log2(op0.value)), 256)
     elif op0.symbolic:
         if op1.value == 0:
             return
         constraint = op0 >= symbol_factory.BitVecVal(
             2**ceil(256 / op1.value), 256)
     else:
         constraint = op0.value**op1.value >= 2**256
     model = self._try_constraints(state.mstate.constraints, [constraint])
     if model is None:
         return
     annotation = OverUnderflowAnnotation(state, "exponentiation",
                                          constraint)
     op0.annotate(annotation)
コード例 #7
0
ファイル: create_test.py プロジェクト: xahiru/mythril
def test_create_has_storage():
    last_state, created_contract_account = execute_create()
    storage = created_contract_account.storage
    # From contract, val = 10.
    assert storage[symbol_factory.BitVecVal(0,
                                            256)] == symbol_factory.BitVecVal(
                                                10, 256)
コード例 #8
0
    def __getitem__(self, item: Union[int, slice, BitVec]) -> Any:
        """

        :param item:
        :return:
        """
        if isinstance(item, int) or isinstance(item, Expression):
            return self._load(item)

        if isinstance(item, slice):
            start = 0 if item.start is None else item.start
            step = 1 if item.step is None else item.step
            stop = self.size if item.stop is None else item.stop

            try:
                current_index = (
                    start
                    if isinstance(start, Expression)
                    else symbol_factory.BitVecVal(start, 256)
                )
                parts = []
                while simplify(current_index != stop):
                    element = self._load(current_index)
                    if not isinstance(element, Expression):
                        element = symbol_factory.BitVecVal(element, 8)

                    parts.append(element)
                    current_index = simplify(current_index + step)
            except Z3Exception:
                raise IndexError("Invalid Calldata Slice")

            return parts

        raise ValueError
コード例 #9
0
ファイル: call.py プロジェクト: xahiru/mythril
def get_call_data(
    global_state: GlobalState,
    memory_start: Union[int, BitVec],
    memory_size: Union[int, BitVec],
):
    """Gets call_data from the global_state.

    :param global_state: state to look in
    :param memory_start: Start index
    :param memory_size: Size
    :return: Tuple containing: call_data array from memory or empty array if symbolic, type found
    """
    state = global_state.mstate
    transaction_id = "{}_internalcall".format(global_state.current_transaction.id)

    memory_start = cast(
        BitVec,
        (
            symbol_factory.BitVecVal(memory_start, 256)
            if isinstance(memory_start, int)
            else memory_start
        ),
    )
    memory_size = cast(
        BitVec,
        (
            symbol_factory.BitVecVal(memory_size, 256)
            if isinstance(memory_size, int)
            else memory_size
        ),
    )

    uses_entire_calldata = simplify(
        memory_size == global_state.environment.calldata.calldatasize
    )

    if is_true(uses_entire_calldata):
        return global_state.environment.calldata

    try:
        calldata_from_mem = state.memory[
            util.get_concrete_int(memory_start) : util.get_concrete_int(
                memory_start + memory_size
            )
        ]
        return ConcreteCalldata(transaction_id, calldata_from_mem)
    except TypeError:
        log.debug(
            "Unsupported symbolic memory offset %s size %s", memory_start, memory_size
        )
        return SymbolicCalldata(transaction_id)
コード例 #10
0
    def get_issue(
        self, global_state: GlobalState, detector: DetectionModule
    ) -> Optional[PotentialIssue]:
        if not self.state_change_states:
            return None
        constraints = Constraints()
        gas = self.call_state.mstate.stack[-1]
        to = self.call_state.mstate.stack[-2]
        constraints += [
            UGT(gas, symbol_factory.BitVecVal(2300, 256)),
            Or(
                to > symbol_factory.BitVecVal(16, 256),
                to == symbol_factory.BitVecVal(0, 256),
            ),
        ]
        if self.user_defined_address:
            constraints += [to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF]

        try:
            solver.get_transaction_sequence(
                global_state, constraints + global_state.mstate.constraints
            )
        except UnsatError:
            return None

        severity = "Medium" if self.user_defined_address else "Low"
        address = global_state.get_current_instruction()["address"]
        logging.debug(
            "[EXTERNAL_CALLS] Detected state changes at addresses: {}".format(address)
        )
        description_head = (
            "The contract account state is changed after an external call. "
        )
        description_tail = (
            "Consider that the called contract could re-enter the function before this "
            "state change takes place. This can lead to business logic vulnerabilities."
        )

        return PotentialIssue(
            contract=global_state.environment.active_account.contract_name,
            function_name=global_state.environment.active_function_name,
            address=address,
            title="State change after external call",
            severity=severity,
            description_head=description_head,
            description_tail=description_tail,
            swc_id=REENTRANCY,
            bytecode=global_state.environment.code.bytecode,
            constraints=constraints,
            detector=detector,
        )
コード例 #11
0
    def _generate_new_address(self, creator=None) -> BitVec:
        """Generates a new address for the global state.

        :return:
        """
        if creator:
            # TODO: Use nounce
            address = "0x" + str(mk_contract_address(creator, 0).hex())
            return symbol_factory.BitVecVal(int(address, 16), 256)
        while True:
            address = "0x" + "".join(
                [str(hex(randint(0, 16)))[-1] for _ in range(40)])
            if address not in self._accounts.keys():
                return symbol_factory.BitVecVal(int(address, 16), 256)
コード例 #12
0
ファイル: calldata.py プロジェクト: xahiru/mythril
    def __init__(self, tx_id: str, calldata: list) -> None:
        """Initializes the ConcreteCalldata object.

        :param tx_id: Id of the transaction that the calldata is for.
        :param calldata: The concrete calldata content
        """
        self._concrete_calldata = calldata
        self._calldata = K(256, 8, 0)
        for i, element in enumerate(calldata, 0):
            element = (symbol_factory.BitVecVal(element, 8) if isinstance(
                element, int) else element)
            self._calldata[symbol_factory.BitVecVal(i, 256)] = element

        super().__init__(tx_id)
コード例 #13
0
    def _load(self, item: Union[int, BitVec]) -> Any:
        """

        :param item:
        :return:
        """
        item = symbol_factory.BitVecVal(item, 256) if isinstance(item, int) else item
        return simplify(
            If(
                item < self._size,
                simplify(self._calldata[cast(BitVec, item)]),
                symbol_factory.BitVecVal(0, 8),
            )
        )
コード例 #14
0
def _is_precompile_call(global_state: GlobalState):
    to = global_state.mstate.stack[-2]  # type: BitVec
    constraints = copy(global_state.mstate.constraints)
    constraints += [
        Or(
            to < symbol_factory.BitVecVal(1, 256),
            to > symbol_factory.BitVecVal(16, 256),
        )
    ]

    try:
        solver.get_model(constraints)
        return False
    except UnsatError:
        return True
コード例 #15
0
    def __getitem__(self, item: BitVec) -> BitVec:
        storage, is_keccak_storage = self._get_corresponding_storage(item)
        if is_keccak_storage:
            item = self._sanitize(cast(BitVecFunc, item).input_)
        value = storage[item]
        if (value.value == 0 and self.address and item.symbolic is False
                and self.address.value != 0
                and (self.dynld and self.dynld.storage_loading)):
            try:
                storage[item] = symbol_factory.BitVecVal(
                    int(
                        self.dynld.read_storage(
                            contract_address=hex(self.address.value),
                            index=int(item.value),
                        ),
                        16,
                    ),
                    256,
                )
                self.printable_storage[item] = storage[item]
                return storage[item]
            except ValueError:
                pass

        return simplify(storage[item])
コード例 #16
0
    def __init__(
        self,
        address: Union[BitVec, str],
        code=None,
        contract_name="unknown",
        balances: Array = None,
        concrete_storage=False,
        dynamic_loader=None,
    ) -> None:
        """Constructor for account.

        :param address: Address of the account
        :param code: The contract code of the account
        :param contract_name: The name associated with the account
        :param balance: The balance for the account
        :param concrete_storage: Interpret storage as concrete
        """
        self.nonce = 0
        self.code = code or Disassembly("")
        self.address = (address if isinstance(address, BitVec) else
                        symbol_factory.BitVecVal(int(address, 16), 256))

        self.storage = Storage(concrete_storage,
                               address=self.address,
                               dynamic_loader=dynamic_loader)

        # Metadata
        self.contract_name = contract_name

        self.deleted = False

        self._balances = balances
        self.balance = lambda: self._balances[self.address]
コード例 #17
0
def execute_message_call(laser_evm, callee_address: str) -> None:
    """Executes a message call transaction from all open states.

    :param laser_evm:
    :param callee_address:
    """
    # TODO: Resolve circular import between .transaction and ..svm to import LaserEVM here
    open_states = laser_evm.open_states[:]
    del laser_evm.open_states[:]

    for open_world_state in open_states:
        if open_world_state[callee_address].deleted:
            log.debug("Can not execute dead contract, skipping.")
            continue

        next_transaction_id = get_next_transaction_id()
        transaction = MessageCallTransaction(
            world_state=open_world_state,
            identifier=next_transaction_id,
            gas_price=symbol_factory.BitVecSym(
                "gas_price{}".format(next_transaction_id), 256),
            gas_limit=8000000,  # block gas limit
            origin=symbol_factory.BitVecSym(
                "origin{}".format(next_transaction_id), 256),
            caller=symbol_factory.BitVecVal(ATTACKER_ADDRESS, 256),
            callee_account=open_world_state[callee_address],
            call_data=SymbolicCalldata(next_transaction_id),
            call_value=symbol_factory.BitVecSym(
                "call_value{}".format(next_transaction_id), 256),
        )
        _setup_global_state_for_execution(laser_evm, transaction)

    laser_evm.exec()
コード例 #18
0
def _set_minimisation_constraints(transaction_sequence, constraints, minimize,
                                  max_size):
    """ Set constraints that minimise key transaction values

    Constraints generated:
    - Upper bound on calldata size
    - Minimisation of call value's and calldata sizes

    :param transaction_sequence: Transaction for which the constraints should be applied
    :param constraints: The constraints array which should contain any added constraints
    :param minimize: The minimisation array which should contain any variables that should be minimised
    :param max_size: The max size of the calldata array
    :return: updated constraints, minimize
    """
    for transaction in transaction_sequence:
        # Set upper bound on calldata size
        max_calldata_size = symbol_factory.BitVecVal(max_size, 256)
        constraints.append(
            UGE(max_calldata_size, transaction.call_data.calldatasize))

        # Minimize
        minimize.append(transaction.call_data.calldatasize)
        minimize.append(transaction.call_value)

    return constraints, minimize
コード例 #19
0
 def _sanitize(input_: BitVec) -> BitVec:
     if input_.size() == 512:
         return input_
     if input_.size() > 512:
         return Extract(511, 0, input_)
     else:
         return Concat(symbol_factory.BitVecVal(0, 512 - input_.size()), input_)
コード例 #20
0
    def __getitem__(self, item: BitVec) -> BitVec:
        storage, is_keccak_storage = self._get_corresponding_storage(item)
        if is_keccak_storage:
            sanitized_item = self._sanitize(cast(BitVecFunc, item).input_)
        else:
            sanitized_item = item
        if (
            self.address
            and self.address.value != 0
            and item.symbolic is False
            and int(item.value) not in self.storage_keys_loaded
            and (self.dynld and self.dynld.storage_loading)
        ):
            try:
                storage[sanitized_item] = symbol_factory.BitVecVal(
                    int(
                        self.dynld.read_storage(
                            contract_address="0x{:040X}".format(self.address.value),
                            index=int(item.value),
                        ),
                        16,
                    ),
                    256,
                )
                self.storage_keys_loaded.add(int(item.value))
                self.printable_storage[item] = storage[sanitized_item]
            except ValueError as e:
                log.debug("Couldn't read storage at %s: %s", item, e)

        return simplify(storage[sanitized_item])
コード例 #21
0
    def _load(self, item: Union[int, BitVec]) -> BitVec:
        """

        :param item:
        :return:
        """
        item = symbol_factory.BitVecVal(item, 256) if isinstance(item, int) else item
        return simplify(self._calldata[item])
コード例 #22
0
    def add_balance(self, balance: Union[int, BitVec]) -> None:
        """

        :param balance:
        """
        balance = (symbol_factory.BitVecVal(balance, 256) if isinstance(
            balance, int) else balance)
        self._balances[self.address] += balance
コード例 #23
0
ファイル: calldata.py プロジェクト: xahiru/mythril
    def _load(self, item: Union[int, BitVec], clean=False) -> Any:
        expr_item = (symbol_factory.BitVecVal(item, 256) if isinstance(
            item, int) else item)  # type: BitVec

        symbolic_base_value = If(
            expr_item >= self._size,
            symbol_factory.BitVecVal(0, 8),
            BitVec(
                symbol_factory.BitVecSym(
                    "{}_calldata_{}".format(self.tx_id, str(item)), 8)),
        )
        return_value = symbolic_base_value
        for r_index, r_value in self._reads:
            return_value = If(r_index == expr_item, r_value, return_value)
        if not clean:
            self._reads.append((expr_item, symbolic_base_value))
        return simplify(return_value)
コード例 #24
0
    def _analyze_state(state) -> List[Issue]:
        instruction = state.get_current_instruction()
        address, value = state.mstate.stack[-1], state.mstate.stack[-2]

        target_slot = 0
        target_offset = 0

        # In the following array we'll describe all the conditions that need to hold for a take over of ownership
        vulnerable_conditions = [
            # Lets check that we're writing to address 0 (where the owner variable is located
            address == target_slot,
            # There is only a vulnerability if before the writing to the owner variable: owner != attacker
            Extract(
                20*8 + target_offset,
                0 + target_offset,
                state.environment.active_account.storage[symbol_factory.BitVecVal(0, 256)]
            ) != ACTORS.attacker,
            # There IS a vulnerability if the value being written to owner is the attacker address
            Extract(
                20*8 + target_offset,
                0 + target_offset,
                value,
            ) == ACTORS.attacker,
            # Lets only look for cases where the attacker makes themselves the owner by saying that the attacker
            # is the sender of this transaction
            state.environment.sender == ACTORS.attacker,
        ]

        try:
            # vulnerable_conditions describes when there is a vulnerability
            # lets check if the conditions are actually satisfiable by running the following command:
            # This will raise an UnsatError if the vulnerable_conditions are not satisfiable (i.e. not possible)
            transaction_sequence = solver.get_transaction_sequence(
                state,
                state.world_state.constraints
                + vulnerable_conditions,
            )
            # Note that get_transaction_sequence also gives us `transaction_sequence` which gives us a concrete
            # transaction trace that can be used to exploit/demonstrate the vulnerability.

            # Lets register an issue with Mythril so that the vulnerability is reported to the user!
            return [Issue(
                contract=state.environment.active_account.contract_name,
                function_name=state.environment.active_function_name,
                address=instruction["address"],
                swc_id='000',
                bytecode=state.environment.code.bytecode,
                title="Ownership Takeover",
                severity="High",
                description_head="An attacker can take over ownership of this contract.",
                description_tail="",
                transaction_sequence=transaction_sequence,
                gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
            )]
        except UnsatError:
            # Sadly (or happily), no vulnerabilities were found here.
            log.debug("Vulnerable conditions were not satisfiable")
            return list()
コード例 #25
0
    def set_balance(self, balance: Union[int, BitVec]) -> None:
        """

        :param balance:
        """
        balance = (symbol_factory.BitVecVal(balance, 256) if isinstance(
            balance, int) else balance)
        assert self._balances is not None
        self._balances[self.address] = balance
コード例 #26
0
    def calldatasize(self) -> BitVec:
        """

        :return: Calldata size for this calldata object
        """
        result = self.size
        if isinstance(result, int):
            return symbol_factory.BitVecVal(result, 256)
        return result
コード例 #27
0
ファイル: solver.py プロジェクト: yxliang01/mythril-classic
def get_transaction_sequence(global_state, constraints):
    """Generate concrete transaction sequence.

    :param global_state: GlobalState to generate transaction sequence for
    :param constraints: list of constraints used to generate transaction sequence
    """

    transaction_sequence = global_state.world_state.transaction_sequence

    # gaslimit & gasprice don't exist yet
    tx_template = {
        "calldata": None,
        "call_value": None,
        "caller": "0xCA11EDEADBEEF37E636E6CA11EDEADBEEFCA11ED",
    }

    concrete_transactions = {}
    creation_tx_ids = []
    tx_constraints = constraints.copy()
    minimize = []

    transactions = []
    for transaction in transaction_sequence:
        tx_id = str(transaction.id)
        if not isinstance(transaction, ContractCreationTransaction):
            transactions.append(transaction)
            # Constrain calldatasize
            max_calldatasize = symbol_factory.BitVecVal(5000, 256)
            tx_constraints.append(
                UGE(max_calldatasize, transaction.call_data.calldatasize))

            minimize.append(transaction.call_data.calldatasize)
            minimize.append(transaction.call_value)

            concrete_transactions[tx_id] = tx_template.copy()

        else:
            creation_tx_ids.append(tx_id)

    model = get_model(tx_constraints, minimize=minimize)

    for transaction in transactions:
        tx_id = str(transaction.id)

        concrete_transactions[tx_id]["calldata"] = "0x" + "".join([
            hex(b)[2:] if len(hex(b)) % 2 == 0 else "0" + hex(b)[2:]
            for b in transaction.call_data.concrete(model)
        ])

        concrete_transactions[tx_id]["call_value"] = ("0x%x" % model.eval(
            transaction.call_value.raw, model_completion=True).as_long())
        concrete_transactions[tx_id]["caller"] = "0x" + ("%x" % model.eval(
            transaction.caller.raw, model_completion=True).as_long()).zfill(40)

    return concrete_transactions
コード例 #28
0
def _set_minimisation_constraints(
    transaction_sequence, constraints, minimize, max_size, world_state
) -> Tuple[Constraints, tuple]:
    """ Set constraints that minimise key transaction values

    Constraints generated:
    - Upper bound on calldata size
    - Minimisation of call value's and calldata sizes

    :param transaction_sequence: Transaction for which the constraints should be applied
    :param constraints: The constraints array which should contain any added constraints
    :param minimize: The minimisation array which should contain any variables that should be minimised
    :param max_size: The max size of the calldata array
    :return: updated constraints, minimize
    """
    for transaction in transaction_sequence:
        # Set upper bound on calldata size
        max_calldata_size = symbol_factory.BitVecVal(max_size, 256)
        constraints.append(UGE(max_calldata_size, transaction.call_data.calldatasize))

        # Minimize
        minimize.append(transaction.call_data.calldatasize)
        minimize.append(transaction.call_value)
        constraints.append(
            UGE(
                symbol_factory.BitVecVal(1000000000000000000000, 256),
                world_state.starting_balances[transaction.caller],
            )
        )

    for account in world_state.accounts.values():
        # Lazy way to prevent overflows and to ensure "reasonable" balances
        # Each account starts with less than 100 ETH
        constraints.append(
            UGE(
                symbol_factory.BitVecVal(100000000000000000000, 256),
                world_state.starting_balances[account.address],
            )
        )

    return constraints, tuple(minimize)
コード例 #29
0
 def append(self, element: Union[int, Expression]) -> None:
     """
     :param element: element to be appended to the list
     :function: appends the element to list if the size is less than STACK_LIMIT, else throws an error
     """
     if isinstance(element, int):
         element = symbol_factory.BitVecVal(element, 256)
     if super(MachineStack, self).__len__() >= self.STACK_LIMIT:
         raise StackOverflowException(
             "Reached the EVM stack limit of {}, you can't append more "
             "elements".format(self.STACK_LIMIT))
     super(MachineStack, self).append(element)
コード例 #30
0
 def world_state_filter_hook(global_state: GlobalState):
     if And(*global_state.mstate.constraints[:] + [
             global_state.environment.callvalue >
             symbol_factory.BitVecVal(0, 256)
     ]).is_false:
         return
     if isinstance(global_state.current_transaction,
                   ContractCreationTransaction):
         return
     if len(list(
             global_state.get_annotations(MutationAnnotation))) == 0:
         raise PluginSkipWorldState