From 70c5d290272b3a49f2d7a736e5d7da1b3a04bfcc Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Thu, 17 Jan 2019 23:17:06 +0530 Subject: [PATCH] Add more type hints from analysis modules --- .../modules/dependence_on_predictable_vars.py | 5 ++--- mythril/analysis/modules/integer.py | 4 +++- mythril/analysis/modules/multiple_sends.py | 15 +++++++++++---- mythril/analysis/modules/unchecked_retval.py | 12 +++++++++--- mythril/laser/ethereum/state/calldata.py | 6 +++--- mythril/laser/ethereum/state/global_state.py | 5 ++++- .../ethereum/transaction/transaction_models.py | 12 ++++++------ 7 files changed, 38 insertions(+), 21 deletions(-) diff --git a/mythril/analysis/modules/dependence_on_predictable_vars.py b/mythril/analysis/modules/dependence_on_predictable_vars.py index fc965307..1450f93a 100644 --- a/mythril/analysis/modules/dependence_on_predictable_vars.py +++ b/mythril/analysis/modules/dependence_on_predictable_vars.py @@ -118,10 +118,9 @@ def _analyze_states(state: GlobalState) -> list: m = re.search(r"blockhash\w+(\s-\s(\d+))*", str(constraint)) if m and solve(call): - found = m.group(1) - print(type(found)) + found_item = m.group(1) - if found: # block.blockhash(block.number - N) + if found_item: # block.blockhash(block.number - N) description = ( "The predictable expression 'block.blockhash(block.number - " + m.group(2) diff --git a/mythril/analysis/modules/integer.py b/mythril/analysis/modules/integer.py index ae0a12d3..6cbfd5ac 100644 --- a/mythril/analysis/modules/integer.py +++ b/mythril/analysis/modules/integer.py @@ -27,7 +27,9 @@ log = logging.getLogger(__name__) class OverUnderflowAnnotation: - def __init__(self, overflowing_state: GlobalState, operator: str, constraint) -> None: + def __init__( + self, overflowing_state: GlobalState, operator: str, constraint + ) -> None: self.overflowing_state = overflowing_state self.operator = operator self.constraint = constraint diff --git a/mythril/analysis/modules/multiple_sends.py b/mythril/analysis/modules/multiple_sends.py index 1e6881f5..e7ae0055 100644 --- a/mythril/analysis/modules/multiple_sends.py +++ b/mythril/analysis/modules/multiple_sends.py @@ -1,8 +1,9 @@ """This module contains the detection code to find multiple sends occurring in a single transaction.""" from copy import copy -from typing import List +from typing import cast, List, Union +from mythril.analysis.ops import Call from mythril.analysis.report import Issue from mythril.analysis.swc_data import MULTIPLE_SENDS from mythril.analysis.modules.base import DetectionModule @@ -16,7 +17,7 @@ log = logging.getLogger(__name__) class MultipleSendsAnnotation(StateAnnotation): def __init__(self) -> None: - self.calls = [] + self.calls = [] # type: List[Union[Call, None]] def __copy__(self): result = MultipleSendsAnnotation() @@ -57,11 +58,17 @@ def _analyze_state(state: GlobalState): node = state.node instruction = state.get_current_instruction() - annotations = [a for a in state.get_annotations(MultipleSendsAnnotation)] # type: List[MultipleSendsAnnotation] + annotations = cast( + List[MultipleSendsAnnotation], + [a for a in state.get_annotations(MultipleSendsAnnotation)], + ) if len(annotations) == 0: log.debug("Creating annotation for state") state.annotate(MultipleSendsAnnotation()) - annotations = [a for a in state.get_annotations(MultipleSendsAnnotation)] + annotations = cast( + List[MultipleSendsAnnotation], + [a for a in state.get_annotations(MultipleSendsAnnotation)], + ) calls = annotations[0].calls diff --git a/mythril/analysis/modules/unchecked_retval.py b/mythril/analysis/modules/unchecked_retval.py index 8034b4e5..ba05bb96 100644 --- a/mythril/analysis/modules/unchecked_retval.py +++ b/mythril/analysis/modules/unchecked_retval.py @@ -1,7 +1,7 @@ """This module contains detection code to find occurrences of calls whose return value remains unchecked.""" from copy import copy -from typing import Dict, List +from typing import cast, Dict, List, Union from mythril.analysis import solver from mythril.analysis.report import Issue @@ -63,10 +63,16 @@ def _analyze_state(state: GlobalState) -> list: instruction = state.get_current_instruction() node = state.node - annotations = [a for a in state.get_annotations(UncheckedRetvalAnnotation)] # type: List[UncheckedRetvalAnnotation] + annotations = cast( + List[UncheckedRetvalAnnotation], + [a for a in state.get_annotations(UncheckedRetvalAnnotation)], + ) if len(annotations) == 0: state.annotate(UncheckedRetvalAnnotation()) - annotations = [a for a in state.get_annotations(UncheckedRetvalAnnotation)] + annotations = cast( + List[UncheckedRetvalAnnotation], + [a for a in state.get_annotations(UncheckedRetvalAnnotation)], + ) retvals = annotations[0].retvals diff --git a/mythril/laser/ethereum/state/calldata.py b/mythril/laser/ethereum/state/calldata.py index b2ea15a0..3901a158 100644 --- a/mythril/laser/ethereum/state/calldata.py +++ b/mythril/laser/ethereum/state/calldata.py @@ -114,7 +114,7 @@ class BaseCalldata: class ConcreteCalldata(BaseCalldata): """A concrete call data representation.""" - def __init__(self, tx_id: int, calldata: list): + def __init__(self, tx_id: str, calldata: list): """Initializes the ConcreteCalldata object. :param tx_id: Id of the transaction that the calldata is for. @@ -161,7 +161,7 @@ class ConcreteCalldata(BaseCalldata): class BasicConcreteCalldata(BaseCalldata): """A base class to represent concrete call data.""" - def __init__(self, tx_id: int, calldata: list): + def __init__(self, tx_id: str, calldata: list): """Initializes the ConcreteCalldata object, that doesn't use z3 arrays. :param tx_id: Id of the transaction that the calldata is for. @@ -207,7 +207,7 @@ class BasicConcreteCalldata(BaseCalldata): class SymbolicCalldata(BaseCalldata): """A class for representing symbolic call data.""" - def __init__(self, tx_id: int): + def __init__(self, tx_id: str): """Initializes the SymbolicCalldata object. :param tx_id: Id of the transaction that the calldata is for. diff --git a/mythril/laser/ethereum/state/global_state.py b/mythril/laser/ethereum/state/global_state.py index 2730fffc..aa931606 100644 --- a/mythril/laser/ethereum/state/global_state.py +++ b/mythril/laser/ethereum/state/global_state.py @@ -12,7 +12,10 @@ from mythril.laser.ethereum.state.annotation import StateAnnotation if TYPE_CHECKING: from mythril.laser.ethereum.state.world_state import WorldState - from mythril.laser.ethereum.transaction.transaction_models import MessageCallTransaction, ContractCreationTransaction + from mythril.laser.ethereum.transaction.transaction_models import ( + MessageCallTransaction, + ContractCreationTransaction, + ) class GlobalState: diff --git a/mythril/laser/ethereum/transaction/transaction_models.py b/mythril/laser/ethereum/transaction/transaction_models.py index a915c0e3..c22ba5a6 100644 --- a/mythril/laser/ethereum/transaction/transaction_models.py +++ b/mythril/laser/ethereum/transaction/transaction_models.py @@ -30,7 +30,7 @@ def get_next_transaction_id() -> int: class TransactionEndSignal(Exception): """Exception raised when a transaction is finalized.""" - def __init__(self, global_state: GlobalState, revert=False): + def __init__(self, global_state: GlobalState, revert=False) -> None: self.global_state = global_state self.revert = revert @@ -42,7 +42,7 @@ class TransactionStartSignal(Exception): self, transaction: Union["MessageCallTransaction", "ContractCreationTransaction"], op_code: str, - ): + ) -> None: self.transaction = transaction self.op_code = op_code @@ -63,7 +63,7 @@ class BaseTransaction: code=None, call_value=None, init_call_data=True, - ): + ) -> None: assert isinstance(world_state, WorldState) self.world_state = world_state self.id = identifier or get_next_transaction_id() @@ -99,7 +99,7 @@ class BaseTransaction: else symbol_factory.BitVecSym("callvalue{}".format(identifier), 256) ) - self.return_data = None + self.return_data = None # type: str def initial_global_state_from_environment(self, environment, active_function): """ @@ -117,7 +117,7 @@ class BaseTransaction: class MessageCallTransaction(BaseTransaction): """Transaction object models an transaction.""" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) def initial_global_state(self) -> GlobalState: @@ -149,7 +149,7 @@ class MessageCallTransaction(BaseTransaction): class ContractCreationTransaction(BaseTransaction): """Transaction object models an transaction.""" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs, init_call_data=False) # TODO: set correct balance for new account self.callee_account = self.callee_account or self.world_state.create_account(