From 4a3354173818fb4cdf52f6b0aa62df60535fb903 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 6 Nov 2023 19:07:01 +0100 Subject: [PATCH 01/10] Add support top level events --- slither/core/compilation_unit.py | 6 +++++ slither/core/declarations/__init__.py | 2 ++ slither/core/declarations/contract.py | 12 ++++----- slither/core/declarations/event.py | 24 ++--------------- slither/core/declarations/event_contract.py | 25 ++++++++++++++++++ slither/core/declarations/event_top_level.py | 13 +++++++++ slither/core/scope/scope.py | 7 ++++- slither/core/slither_core.py | 2 ++ slither/solc_parsing/declarations/contract.py | 8 +++--- slither/solc_parsing/declarations/event.py | 19 +++++++------ .../solc_parsing/expressions/find_variable.py | 3 +++ .../slither_compilation_unit_solc.py | 11 ++++++++ slither/tools/flattening/flattening.py | 1 + .../vyper_parsing/declarations/contract.py | 4 +-- tests/e2e/solc_parsing/test_ast_parsing.py | 1 + .../event-top-level.sol-0.8.22-compact.zip | Bin 0 -> 2022 bytes .../test_data/event-top-level.sol | 7 +++++ .../event-top-level.sol-0.8.22-compact.json | 5 ++++ 18 files changed, 105 insertions(+), 45 deletions(-) create mode 100644 slither/core/declarations/event_contract.py create mode 100644 slither/core/declarations/event_top_level.py create mode 100644 tests/e2e/solc_parsing/test_data/compile/event-top-level.sol-0.8.22-compact.zip create mode 100644 tests/e2e/solc_parsing/test_data/event-top-level.sol create mode 100644 tests/e2e/solc_parsing/test_data/expected/event-top-level.sol-0.8.22-compact.json diff --git a/slither/core/compilation_unit.py b/slither/core/compilation_unit.py index 87853aa34a..6221fd8bdc 100644 --- a/slither/core/compilation_unit.py +++ b/slither/core/compilation_unit.py @@ -16,6 +16,7 @@ ) from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel +from slither.core.declarations.event_top_level import EventTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel from slither.core.declarations.using_for_top_level import UsingForTopLevel @@ -57,6 +58,7 @@ def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit self.contracts: List[Contract] = [] self._structures_top_level: List[StructureTopLevel] = [] self._enums_top_level: List[EnumTopLevel] = [] + self._events_top_level: List[EventTopLevel] = [] self._variables_top_level: List[TopLevelVariable] = [] self._functions_top_level: List[FunctionTopLevel] = [] self._using_for_top_level: List[UsingForTopLevel] = [] @@ -234,6 +236,10 @@ def structures_top_level(self) -> List[StructureTopLevel]: def enums_top_level(self) -> List[EnumTopLevel]: return self._enums_top_level + @property + def events_top_level(self) -> List[EventTopLevel]: + return self._events_top_level + @property def variables_top_level(self) -> List[TopLevelVariable]: return self._variables_top_level diff --git a/slither/core/declarations/__init__.py b/slither/core/declarations/__init__.py index f6e902e06f..9d727da8e7 100644 --- a/slither/core/declarations/__init__.py +++ b/slither/core/declarations/__init__.py @@ -1,6 +1,8 @@ from .contract import Contract from .enum import Enum from .event import Event +from .event_contract import EventContract +from .event_top_level import EventTopLevel from .function import Function from .import_directive import Import from .modifier import Modifier diff --git a/slither/core/declarations/contract.py b/slither/core/declarations/contract.py index 458f951f56..5403d227ad 100644 --- a/slither/core/declarations/contract.py +++ b/slither/core/declarations/contract.py @@ -33,7 +33,7 @@ from slither.utils.type_helpers import LibraryCallType, HighLevelCallType, InternalCallType from slither.core.declarations import ( Enum, - Event, + EventContract, Modifier, EnumContract, StructureContract, @@ -73,7 +73,7 @@ def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope self._enums: Dict[str, "EnumContract"] = {} self._structures: Dict[str, "StructureContract"] = {} - self._events: Dict[str, "Event"] = {} + self._events: Dict[str, "EventContract"] = {} # map accessible variable from name -> variable # do not contain private variables inherited from contract self._variables: Dict[str, "StateVariable"] = {} @@ -278,28 +278,28 @@ def enums_as_dict(self) -> Dict[str, "EnumContract"]: ################################################################################### @property - def events(self) -> List["Event"]: + def events(self) -> List["EventContract"]: """ list(Event): List of the events """ return list(self._events.values()) @property - def events_inherited(self) -> List["Event"]: + def events_inherited(self) -> List["EventContract"]: """ list(Event): List of the inherited events """ return [e for e in self.events if e.contract != self] @property - def events_declared(self) -> List["Event"]: + def events_declared(self) -> List["EventContract"]: """ list(Event): List of the events declared within the contract (not inherited) """ return [e for e in self.events if e.contract == self] @property - def events_as_dict(self) -> Dict[str, "Event"]: + def events_as_dict(self) -> Dict[str, "EventContract"]: return self._events # endregion diff --git a/slither/core/declarations/event.py b/slither/core/declarations/event.py index 1b58ff63b0..7149e20c01 100644 --- a/slither/core/declarations/event.py +++ b/slither/core/declarations/event.py @@ -1,14 +1,10 @@ -from typing import List, Tuple, TYPE_CHECKING +from typing import List, Tuple -from slither.core.declarations.contract_level import ContractLevel from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.variables.event_variable import EventVariable -if TYPE_CHECKING: - from slither.core.declarations import Contract - -class Event(ContractLevel, SourceMapping): +class Event(SourceMapping): def __init__(self) -> None: super().__init__() self._name = None @@ -39,25 +35,9 @@ def full_name(self) -> str: name, parameters = self.signature return name + "(" + ",".join(parameters) + ")" - @property - def canonical_name(self) -> str: - """Return the function signature as a str - Returns: - str: contract.func_name(type1,type2) - """ - return self.contract.name + "." + self.full_name - @property def elems(self) -> List["EventVariable"]: return self._elems - def is_declared_by(self, contract: "Contract") -> bool: - """ - Check if the element is declared by the contract - :param contract: - :return: - """ - return self.contract == contract - def __str__(self) -> str: return self.name diff --git a/slither/core/declarations/event_contract.py b/slither/core/declarations/event_contract.py new file mode 100644 index 0000000000..652f8ca20c --- /dev/null +++ b/slither/core/declarations/event_contract.py @@ -0,0 +1,25 @@ +from typing import TYPE_CHECKING + +from slither.core.declarations.contract_level import ContractLevel +from slither.core.declarations import Event + +if TYPE_CHECKING: + from slither.core.declarations import Contract + + +class EventContract(Event, ContractLevel): + def is_declared_by(self, contract: "Contract") -> bool: + """ + Check if the element is declared by the contract + :param contract: + :return: + """ + return self.contract == contract + + @property + def canonical_name(self) -> str: + """Return the function signature as a str + Returns: + str: contract.func_name(type1,type2) + """ + return self.contract.name + "." + self.full_name diff --git a/slither/core/declarations/event_top_level.py b/slither/core/declarations/event_top_level.py new file mode 100644 index 0000000000..5f9f1774d1 --- /dev/null +++ b/slither/core/declarations/event_top_level.py @@ -0,0 +1,13 @@ +from typing import TYPE_CHECKING + +from slither.core.declarations import Event +from slither.core.declarations.top_level import TopLevel + +if TYPE_CHECKING: + from slither.core.scope.scope import FileScope + + +class EventTopLevel(Event, TopLevel): + def __init__(self, scope: "FileScope") -> None: + super().__init__() + self.file_scope: "FileScope" = scope diff --git a/slither/core/scope/scope.py b/slither/core/scope/scope.py index 937a051361..784b17cb20 100644 --- a/slither/core/scope/scope.py +++ b/slither/core/scope/scope.py @@ -7,6 +7,7 @@ from slither.core.declarations import Contract, Import, Pragma from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel +from slither.core.declarations.event_top_level import EventTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.using_for_top_level import UsingForTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel @@ -35,6 +36,7 @@ def __init__(self, filename: Filename) -> None: # So we simplify the logic and have the scope fields all populated self.custom_errors: Set[CustomErrorTopLevel] = set() self.enums: Dict[str, EnumTopLevel] = {} + self.events: Dict[str, EventTopLevel] = {} # Functions is a list instead of a dict # Because we parse the function signature later on # So we simplify the logic and have the scope fields all populated @@ -54,7 +56,7 @@ def __init__(self, filename: Filename) -> None: # Name -> type alias self.type_aliases: Dict[str, TypeAlias] = {} - def add_accesible_scopes(self) -> bool: + def add_accesible_scopes(self) -> bool: # pylint: disable=too-many-branches """ Add information from accessible scopes. Return true if new information was obtained @@ -74,6 +76,9 @@ def add_accesible_scopes(self) -> bool: if not _dict_contain(new_scope.enums, self.enums): self.enums.update(new_scope.enums) learn_something = True + if not _dict_contain(new_scope.events, self.events): + self.events.update(new_scope.events) + learn_something = True if not new_scope.functions.issubset(self.functions): self.functions |= new_scope.functions learn_something = True diff --git a/slither/core/slither_core.py b/slither/core/slither_core.py index 3535f2604d..b1bb7c66b8 100644 --- a/slither/core/slither_core.py +++ b/slither/core/slither_core.py @@ -269,6 +269,8 @@ def _compute_offsets_to_ref_impl_decl(self): # pylint: disable=too-many-branche self._compute_offsets_from_thing(event) for enum in compilation_unit.enums_top_level: self._compute_offsets_from_thing(enum) + for event in compilation_unit.events_top_level: + self._compute_offsets_from_thing(event) for function in compilation_unit.functions_top_level: self._compute_offsets_from_thing(function) for st in compilation_unit.structures_top_level: diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index 3dd6e2fd5d..34e2f24308 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -4,7 +4,7 @@ from slither.core.declarations import ( Modifier, - Event, + EventContract, EnumContract, StructureContract, Function, @@ -747,12 +747,12 @@ def analyze_events(self) -> None: self._contract.events_as_dict.update(father.events_as_dict) for event_to_parse in self._eventsNotParsed: - event = Event() + event = EventContract() event.set_contract(self._contract) event.set_offset(event_to_parse["src"], self._contract.compilation_unit) - event_parser = EventSolc(event, event_to_parse, self) # type: ignore - event_parser.analyze(self) # type: ignore + event_parser = EventSolc(event, event_to_parse, self._slither_parser) # type: ignore + event_parser.analyze() # type: ignore self._contract.events_as_dict[event.full_name] = event except (VariableNotFound, KeyError) as e: self.log_incorrect_parsing(f"Missing event {e}") diff --git a/slither/solc_parsing/declarations/event.py b/slither/solc_parsing/declarations/event.py index 6531e65365..4a7d62389d 100644 --- a/slither/solc_parsing/declarations/event.py +++ b/slither/solc_parsing/declarations/event.py @@ -8,7 +8,7 @@ from slither.core.declarations.event import Event if TYPE_CHECKING: - from slither.solc_parsing.declarations.contract import ContractSolc + from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc class EventSolc: @@ -16,11 +16,12 @@ class EventSolc: Event class """ - def __init__(self, event: Event, event_data: Dict, contract_parser: "ContractSolc") -> None: + def __init__( + self, event: Event, event_data: Dict, slither_parser: "SlitherCompilationUnitSolc" + ) -> None: self._event = event - event.set_contract(contract_parser.underlying_contract) - self._parser_contract = contract_parser + self._slither_parser = slither_parser if self.is_compact_ast: self._event.name = event_data["name"] @@ -41,18 +42,16 @@ def __init__(self, event: Event, event_data: Dict, contract_parser: "ContractSol @property def is_compact_ast(self) -> bool: - return self._parser_contract.is_compact_ast + return self._slither_parser.is_compact_ast - def analyze(self, contract: "ContractSolc") -> None: + def analyze(self) -> None: for elem_to_parse in self._elemsNotParsed: elem = EventVariable() # Todo: check if the source offset is always here if "src" in elem_to_parse: - elem.set_offset( - elem_to_parse["src"], self._parser_contract.underlying_contract.compilation_unit - ) + elem.set_offset(elem_to_parse["src"], self._slither_parser.compilation_unit) elem_parser = EventVariableSolc(elem, elem_to_parse) - elem_parser.analyze(contract) + elem_parser.analyze(self._slither_parser) self._event.elems.append(elem) diff --git a/slither/solc_parsing/expressions/find_variable.py b/slither/solc_parsing/expressions/find_variable.py index 2261350b4f..e7fa995215 100644 --- a/slither/solc_parsing/expressions/find_variable.py +++ b/slither/solc_parsing/expressions/find_variable.py @@ -134,6 +134,9 @@ def find_top_level( if var_name in scope.enums: return scope.enums[var_name], False + if var_name in scope.events: + return scope.events[var_name], False + for import_directive in scope.imports: if import_directive.alias == var_name: new_val = SolidityImportPlaceHolder(import_directive) diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 85921ce742..08ee62d804 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -10,6 +10,7 @@ from slither.core.declarations import Contract from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel +from slither.core.declarations.event_top_level import EventTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.import_directive import Import from slither.core.declarations.pragma_directive import Pragma @@ -23,6 +24,7 @@ from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.custom_error import CustomErrorSolc from slither.solc_parsing.declarations.function import FunctionSolc +from slither.solc_parsing.declarations.event import EventSolc from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc from slither.solc_parsing.declarations.using_for_top_level import UsingForTopLevelSolc from slither.solc_parsing.exceptions import VariableNotFound @@ -347,6 +349,15 @@ def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None: self._compilation_unit.type_aliases[alias] = type_alias scope.type_aliases[alias] = type_alias + elif top_level_data[self.get_key()] == "EventDefinition": + event = EventTopLevel(scope) + event.set_offset(top_level_data["src"], self._compilation_unit) + + event_parser = EventSolc(event, top_level_data, self) # type: ignore + event_parser.analyze() # type: ignore + scope.events[event.full_name] = event + self._compilation_unit.events_top_level.append(event) + else: raise SlitherException(f"Top level {top_level_data[self.get_key()]} not supported") diff --git a/slither/tools/flattening/flattening.py b/slither/tools/flattening/flattening.py index 55e1af21d3..9cb2abc3f1 100644 --- a/slither/tools/flattening/flattening.py +++ b/slither/tools/flattening/flattening.py @@ -77,6 +77,7 @@ def __init__( self._get_source_code_top_level(compilation_unit.structures_top_level) self._get_source_code_top_level(compilation_unit.enums_top_level) + self._get_source_code_top_level(compilation_unit.events_top_level) self._get_source_code_top_level(compilation_unit.custom_errors) self._get_source_code_top_level(compilation_unit.variables_top_level) self._get_source_code_top_level(compilation_unit.functions_top_level) diff --git a/slither/vyper_parsing/declarations/contract.py b/slither/vyper_parsing/declarations/contract.py index 6ca9c6557f..2acd43e0fa 100644 --- a/slither/vyper_parsing/declarations/contract.py +++ b/slither/vyper_parsing/declarations/contract.py @@ -24,7 +24,7 @@ from slither.vyper_parsing.variables.state_variable import StateVariableVyper from slither.vyper_parsing.declarations.function import FunctionVyper from slither.core.declarations.function_contract import FunctionContract -from slither.core.declarations import Contract, StructureContract, EnumContract, Event +from slither.core.declarations import Contract, StructureContract, EnumContract, EventContract from slither.core.variables.state_variable import StateVariable @@ -478,7 +478,7 @@ def parse_state_variables(self) -> None: def parse_events(self) -> None: for event_to_parse in self._eventsNotParsed: - event = Event() + event = EventContract() event.set_contract(self._contract) event.set_offset(event_to_parse.src, self._contract.compilation_unit) diff --git a/tests/e2e/solc_parsing/test_ast_parsing.py b/tests/e2e/solc_parsing/test_ast_parsing.py index bc57dc51b5..61250c5af0 100644 --- a/tests/e2e/solc_parsing/test_ast_parsing.py +++ b/tests/e2e/solc_parsing/test_ast_parsing.py @@ -462,6 +462,7 @@ def make_version(minor: int, patch_min: int, patch_max: int) -> List[str]: Test("aliasing/main.sol", ["0.8.19"]), Test("type-aliases.sol", ["0.8.19"]), Test("enum-max-min.sol", ["0.8.19"]), + Test("event-top-level.sol", ["0.8.22"]), ] # create the output folder if needed try: diff --git a/tests/e2e/solc_parsing/test_data/compile/event-top-level.sol-0.8.22-compact.zip b/tests/e2e/solc_parsing/test_data/compile/event-top-level.sol-0.8.22-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..ed82f32b17350e7c70788a8d84e0d02dcbdd0bba GIT binary patch literal 2022 zcma)-c{~#g1IIUHBvRzQkBl7kxX+C!SMey@=wMb@=4#_*Dw2uHk;r1sZ02mt$K)J^ zJaXo~>SbcC=2}zX>3RQuKcDCK`{Vojfd zXaN9#+mW|JaC*4VFg?ugiP6V~Vtj5#g@xY5`5^D20@0DT_3vOqLxcs60B!&PaR7jI zQc{57FT?Pn;r@C{QBr3JTC+`wkm4a{qdbmnkvg|~-X?Wg9(iJ6v0+ODmY=rkD7Q^B z@Yo<`JC=%1j^M)cLWElT-iH$~#WgRhfD>{y@wY5PR!$A6W#mR@5x?!{3n$Pf(q(ae zFZxWjJ0JXY?vd!jL!t`1j6Q;6GHAVqfy@SWXC{%qVRL7K^&AmqPH%+aRUZ6$HhQ-! z0#!ZnV@g86a;9kisRHacvMt$8YPz;?{yk@?hW)NV1X@V$ZU!d4i}dLidRv2t8xF%m z&~W{*KfzG;#CLnr73^S76S*1~Up7H`;XP$TZh|9(lhGq=kMO%%RsIZNy$Ck=VUkQ0 z@n$UiG=_O}j8U_?n2Z0;+EuD~w{5hrrzB+Dg8Evo&QM>y=AA?##NzJASxl2m``V$g z)Q5}Rm0jj<-FInXD=tj68+{eM$_}}@?i0Q{f{)&x)za?DoE3_@NPrfaUCNS-%wvjd z>Udv2@99SwJCY+rcaPna9I)oea`AjIYnqX-tHUc8!u?I4*RDT-*03VMijMhG9XWyF zjP6+Hn{6|9zB#3*n9VIsqsPK87WO zN|*I?x145$+l`7Ye^Ge4Y)6S3H)rT_6?t(g^s2xaz8xJH(rtmI2-z=cR3@5D;Jdsb@dk+>2veK1M68klnfl-FkQ&Oc9La`GDCS4>n2@ z*pMJ-R9~U)kp?K4Lzc@KpHGJVT+9#_bzz^17MM4L`fY{9Hg`(XqM||fwy-|U5$tH| zf)OwHF;X&T&$ae1h@-<0`b5%aP<$Dii}{*SnWo5DA@;j~NM_`0Y) z%4h9qHtT?{8Wt?aCbxF-*NfmrJ%Zo#?}{eIwxoRVag8hg zqm|Jtx35W?|B$NaS}h6=KaqEQ)M3B(eErpeH``zht4U}($)L~d^Tk^4m(EYCmrdt) z((S0|I;e5BqTyKwN{Q(e1xI%oLSX~s`0`}L!i3nmvgL(N3w(rp>ENVAm=eFUmK{6@ z?KR}DEpy$8^GI5|72J5#3zof`)}h`bIjZVdSn#C^%XBv_Ji4?Iz36yr(KarNx8)Tv ztRfSC8n)eFUdJ1{29dfN)68dCkV;;=XRj%Fp6eVB)kF_zy!{!$5OeP-OelCY{ z%>j<`y)XozR&dekLNE#4nIY3qcj#0L%h8E4f)rQ=!}cisL@-lbL@S_M*`sb z>3)VO{p%b=m)c7|2jhkbG7P>EC;kjq9R3V2>e!RBQvS7^!nbtMPU+px)GRJ{|1!Z0 z4UN0bD+L9uzl|58#(_JzOPC~7HjW@3QB1sIf=Xj|2ymu;J}F)_y}_o7^!MPaWsSe96{95a5R z`5pFM$H-Rp1$~_ciG77b{e< z-6*P8?qynzlHZhePUxkpDpLsqxl!mAkjXQT5_dc~c>M{!^HgeQ#RZL+w4&13ry9C9&cY$YpFh@5{i+eq(;T1~N-!^45| zi>&pP3h%|~0l$vG|B{3UoKh=TO#Sxm{srI(wm7BppwbJ0v0|HD9wVD8aofC2N#oH> zpoZG6h?wfx^IGq`aw5{fb_io!27jt$RY;Ehj`yTvY00EydFu!8Uch^MxUq4KEiVnr zAP3Q%x@W6AZv^59_8JKu+-?S0GsV7({UG6t>QJRDhd0=i9RAkd`8Coj!Fr$QORa?@ zYm4cx$8uh#3R0`orJ@FjFP^{d)+^FbK+zY(50ZT_yUaT|!!+WwsG#Ah*0^e>sXigGw(QRz4Q?Dr+TD6*Z8DpEH~` p-Cclu5dQx!-{1cIU*drO;9siP-Q|ejKX>5odj4k2Z<_-Ee*>9z)$#xU literal 0 HcmV?d00001 diff --git a/tests/e2e/solc_parsing/test_data/event-top-level.sol b/tests/e2e/solc_parsing/test_data/event-top-level.sol new file mode 100644 index 0000000000..fa64e1bf7c --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/event-top-level.sol @@ -0,0 +1,7 @@ +event MyEvent(uint256 a); + +contract T { + function a() public { + emit MyEvent(2); + } +} diff --git a/tests/e2e/solc_parsing/test_data/expected/event-top-level.sol-0.8.22-compact.json b/tests/e2e/solc_parsing/test_data/expected/event-top-level.sol-0.8.22-compact.json new file mode 100644 index 0000000000..58c6a3ab60 --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/expected/event-top-level.sol-0.8.22-compact.json @@ -0,0 +1,5 @@ +{ + "T": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + } +} \ No newline at end of file From 4f09d238236c971602a00ef8a9e7992f243ba7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 7 Feb 2024 18:02:15 -0300 Subject: [PATCH 02/10] Make triage database path customizable --- slither/__main__.py | 10 +++++++++- slither/slither.py | 2 ++ slither/utils/command_line.py | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/slither/__main__.py b/slither/__main__.py index d1b36d951b..3cd914a87a 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -528,12 +528,20 @@ def parse_args( group_misc.add_argument( "--triage-mode", - help="Run triage mode (save results in slither.db.json)", + help="Run triage mode (save results in triage database)", action="store_true", dest="triage_mode", default=False, ) + group_misc.add_argument( + "--triage-database", + help="File path to the triage database (default: slither.db.json)", + action="store", + dest="triage_database", + default=defaults_flag_in_config["triage_database"], + ) + group_misc.add_argument( "--config-file", help="Provide a config file (default: slither.config.json)", diff --git a/slither/slither.py b/slither/slither.py index 747d2207ef..a3cc644042 100644 --- a/slither/slither.py +++ b/slither/slither.py @@ -135,7 +135,9 @@ def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None: self._exclude_dependencies = kwargs.get("exclude_dependencies", False) triage_mode = kwargs.get("triage_mode", False) + triage_database = kwargs.get("triage_database", "slither.db.json") self._triage_mode = triage_mode + self._previous_results_filename = triage_database printers_to_run = kwargs.get("printers_to_run", "") if printers_to_run == "echidna": diff --git a/slither/utils/command_line.py b/slither/utils/command_line.py index 6c50fcab93..2432a21165 100644 --- a/slither/utils/command_line.py +++ b/slither/utils/command_line.py @@ -70,6 +70,7 @@ class FailOnLevel(enum.Enum): "no_fail": False, "sarif_input": "export.sarif", "sarif_triage": "export.sarif.sarifexplorer", + "triage_database": "slither.db.json", **DEFAULTS_FLAG_IN_CONFIG_CRYTIC_COMPILE, } From 9fd6128b94ef041b8c780ef9aa550693b2ebcec0 Mon Sep 17 00:00:00 2001 From: unknown <951161604@qq.com> Date: Thu, 15 Feb 2024 23:18:28 +0800 Subject: [PATCH 03/10] Changes to be committed: modified: examples/scripts/possible_paths.py --- examples/scripts/possible_paths.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/scripts/possible_paths.py b/examples/scripts/possible_paths.py index 06b68c2bcd..6f83e13f0b 100644 --- a/examples/scripts/possible_paths.py +++ b/examples/scripts/possible_paths.py @@ -19,7 +19,7 @@ def resolve_function(contract_name, function_name): contract = contracts[0] # Obtain the target function target_function = next( - (function for function in contract.functions if function.name == function_name), None + (function for function in contract.functions_declared if function.name == function_name), None ) # Verify we have resolved the function specified. From b66b3e091f3352c975937972f767ff5ee86f3fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 16 Feb 2024 16:26:28 -0300 Subject: [PATCH 04/10] slither: utils: respect colorization state when printing tables Closes #2229 --- slither/utils/myprettytable.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/slither/utils/myprettytable.py b/slither/utils/myprettytable.py index d67f570c0a..b33fb9c5f7 100644 --- a/slither/utils/myprettytable.py +++ b/slither/utils/myprettytable.py @@ -1,7 +1,10 @@ from typing import List, Dict, Union +from prettytable import PrettyTable from prettytable.colortable import ColorTable, Themes +from slither.utils.colors import Colors + class MyPrettyTable: def __init__(self, field_names: List[str], pretty_align: bool = True): # TODO: True by default? @@ -19,8 +22,12 @@ def __init__(self, field_names: List[str], pretty_align: bool = True): # TODO: def add_row(self, row: List[Union[str, List[str]]]) -> None: self._rows.append(row) - def to_pretty_table(self) -> ColorTable: - table = ColorTable(self._field_names, theme=Themes.OCEAN) + def to_pretty_table(self) -> PrettyTable: + if Colors.COLORIZATION_ENABLED: + table = ColorTable(self._field_names, theme=Themes.OCEAN) + else: + table = PrettyTable(self._field_names) + for row in self._rows: table.add_row(row) if len(self._options["set_alignment"]): From 3eebf49c1a3ec54c74ddeb1662df1ae6f9ddb05e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 22:41:00 +0000 Subject: [PATCH 05/10] Bump actions/download-artifact from 3 to 4 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/publish.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 72b002d1e7..234e2eb050 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -38,7 +38,7 @@ jobs: - build-release steps: - name: fetch dists - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: slither-dists path: dist/ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 68a32f80a9..d677218410 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -109,7 +109,7 @@ jobs: - run: pip install coverage[toml] - name: download coverage data - uses: actions/download-artifact@v3.0.2 + uses: actions/download-artifact@v4 with: name: coverage-data From b107e9e22cd79acce47c02a4aab70144e2e0186a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 16 Feb 2024 16:37:30 -0300 Subject: [PATCH 06/10] Bump actions/upload-artifact from 3 to 4 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... --- .github/actions/upload-coverage/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/upload-coverage/action.yml b/.github/actions/upload-coverage/action.yml index ac620c8e69..7895090805 100644 --- a/.github/actions/upload-coverage/action.yml +++ b/.github/actions/upload-coverage/action.yml @@ -21,7 +21,7 @@ runs: fi id: coverage-uuid shell: bash - - uses: actions/upload-artifact@v3.1.0 + - uses: actions/upload-artifact@v4 with: name: coverage-data path: | From 4a6920a2b5cfcce5b9f643e96e30280081e3028d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 16 Feb 2024 16:41:47 -0300 Subject: [PATCH 07/10] ci: test: adjust to new artifact merging behavior --- .github/actions/upload-coverage/action.yml | 4 ++-- .github/workflows/test.yml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/actions/upload-coverage/action.yml b/.github/actions/upload-coverage/action.yml index 7895090805..02fb82f65c 100644 --- a/.github/actions/upload-coverage/action.yml +++ b/.github/actions/upload-coverage/action.yml @@ -15,7 +15,7 @@ runs: # This method has the limitation of 1 coverage file per run, limiting some coverage between online/offline tests. - run: | COVERAGE_UUID=$(python3 -c "import uuid; print(uuid.uuid4())") - echo "COVERAGE_UUID=${COVERAGE_UUID}" >> $GITHUB_OUTPUT + echo "COVERAGE_UUID=${COVERAGE_UUID}" >> "$GITHUB_OUTPUT" if [ -f .coverage ]; then mv .coverage .coverage.${COVERAGE_UUID} fi @@ -23,7 +23,7 @@ runs: shell: bash - uses: actions/upload-artifact@v4 with: - name: coverage-data + name: coverage-data-${{ steps.coverage-uuid.outputs.COVERAGE_UUID }} path: | .coverage.* *.lcov diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d677218410..f91243cc7d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -111,7 +111,8 @@ jobs: - name: download coverage data uses: actions/download-artifact@v4 with: - name: coverage-data + pattern: coverage-data-* + merge-multiple: true - name: combine coverage data id: combinecoverage From 261182f34061caefe032170fa8ad6a42522f3d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 16 Feb 2024 21:44:01 -0300 Subject: [PATCH 08/10] tools: properties: correct tool description and usage Closes #568 --- slither/tools/properties/__main__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slither/tools/properties/__main__.py b/slither/tools/properties/__main__.py index 10837bb4b0..b5e5c911a3 100644 --- a/slither/tools/properties/__main__.py +++ b/slither/tools/properties/__main__.py @@ -68,13 +68,13 @@ def parse_args() -> argparse.Namespace: :return: Returns the arguments for the program. """ parser = argparse.ArgumentParser( - description="Demo", - usage="slither-demo filename", + description="Generates code properties (e.g., invariants) that can be tested with unit tests or Echidna, entirely automatically.", + usage="slither-prop filename", formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument( - "filename", help="The filename of the contract or truffle directory to analyze." + "filename", help="The filename of the contract or project directory to analyze." ) parser.add_argument("--contract", help="The targeted contract.") From 9996e4e56e2dbe7273bf213f28b56cbd9bf20397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 16 Feb 2024 22:03:49 -0300 Subject: [PATCH 09/10] tools: documentation: correct tool description --- slither/tools/documentation/__main__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py index 39b1eacdac..0244dd6c67 100644 --- a/slither/tools/documentation/__main__.py +++ b/slither/tools/documentation/__main__.py @@ -21,7 +21,10 @@ def parse_args() -> argparse.Namespace: Parse the underlying arguments for the program. :return: Returns the arguments for the program. """ - parser = argparse.ArgumentParser(description="Demo", usage="slither-documentation filename") + parser = argparse.ArgumentParser( + description="Auto-generate NatSpec documentation for every function using OpenAI Codex.", + usage="slither-documentation filename", + ) parser.add_argument("project", help="The target directory/Solidity file.") From f2f7598ccf2559a64ae8dd8f79ced7ae9e174c3d Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Sat, 17 Feb 2024 09:05:15 -0600 Subject: [PATCH 10/10] fmt --- examples/scripts/possible_paths.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/scripts/possible_paths.py b/examples/scripts/possible_paths.py index 6f83e13f0b..2057782a4b 100644 --- a/examples/scripts/possible_paths.py +++ b/examples/scripts/possible_paths.py @@ -19,7 +19,8 @@ def resolve_function(contract_name, function_name): contract = contracts[0] # Obtain the target function target_function = next( - (function for function in contract.functions_declared if function.name == function_name), None + (function for function in contract.functions_declared if function.name == function_name), + None, ) # Verify we have resolved the function specified.