From 8cee05d5e7166f92a30e87e885291a8febc03288 Mon Sep 17 00:00:00 2001 From: webthethird Date: Mon, 17 Apr 2023 12:07:43 -0500 Subject: [PATCH 01/24] Native support for POA networks in read_storage --- slither/tools/read_storage/read_storage.py | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index 387aa619a2..11a3145f04 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -8,6 +8,8 @@ from eth_typing.evm import ChecksumAddress from eth_utils import keccak from web3 import Web3 +from web3.exceptions import ExtraDataLengthError +from web3.middleware import geth_poa_middleware from slither.core.declarations import Contract, Structure from slither.core.solidity_types import ArrayType, ElementaryType, MappingType, UserDefinedType @@ -52,7 +54,7 @@ def __init__(self, contracts: List[Contract], max_depth: int) -> None: self._slot_info: Dict[str, SlotInfo] = {} self._target_variables: List[Tuple[Contract, StateVariable]] = [] self._web3: Optional[Web3] = None - self.block: Union[str, int] = "latest" + self._block: Optional[int] = None self.rpc: Optional[str] = None self.storage_address: Optional[str] = None self.table: Optional[MyPrettyTable] = None @@ -73,6 +75,26 @@ def log(self) -> str: def log(self, log: str) -> None: self._log = log + @property + def block(self) -> int: + """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" + if not self._block: + try: + self._block = self.web3.eth.get_block("latest")["number"] + except ExtraDataLengthError: + self.web3.middleware_onion.inject(geth_poa_middleware, layer=0) + self._block = self.web3.eth.get_block("latest")["number"] + return self._block + + @block.setter + def block(self, block) -> None: + """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" + try: + self._block = self.web3.eth.get_block(block)["number"] + except ExtraDataLengthError: + self.web3.middleware_onion.inject(geth_poa_middleware, layer=0) + self._block = self.web3.eth.get_block(block)["number"] + @property def web3(self) -> Web3: if not self._web3: From c4bb804a89ab625dd7f61679a895ccdfacf27b6c Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 27 Apr 2023 09:43:12 -0500 Subject: [PATCH 02/24] Set `srs.rpc` before `srs.block` --- slither/tools/read_storage/__main__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 1a8901321d..0402a654ec 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -128,11 +128,6 @@ def main() -> None: srs = SlitherReadStorage(contracts, args.max_depth) - try: - srs.block = int(args.block) - except ValueError: - srs.block = str(args.block or "latest") - if args.rpc_url: # Remove target prefix e.g. rinkeby:0x0 -> 0x0. address = target[target.find(":") + 1 :] @@ -143,6 +138,11 @@ def main() -> None: srs.rpc = args.rpc_url + try: + srs.block = int(args.block) + except ValueError: + srs.block = str(args.block or "latest") + if args.variable_name: # Use a lambda func to only return variables that have same name as target. # x is a tuple (`Contract`, `StateVariable`). From b490c54b9296f123a80360163e41c9ef3fc4f85c Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 27 Apr 2023 09:50:05 -0500 Subject: [PATCH 03/24] Type hint --- slither/tools/read_storage/read_storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index 11a3145f04..73691fba86 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -87,7 +87,7 @@ def block(self) -> int: return self._block @block.setter - def block(self, block) -> None: + def block(self, block: Union[str, int]) -> None: """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" try: self._block = self.web3.eth.get_block(block)["number"] From 5bcaf4186d69ce300aa62979150154fe4f1f01f9 Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 27 Apr 2023 11:22:04 -0500 Subject: [PATCH 04/24] New RpcInfo class w/ RpcInfo.web3 and RpcInfo.block In SlitherReadStorage, self.rpc_info: Optional[RpcInfo] replaces self.rpc, self._block, self._web3 --- slither/tools/read_storage/__main__.py | 15 +++-- slither/tools/read_storage/read_storage.py | 67 ++++++++++------------ 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 0402a654ec..8da021cfed 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -7,7 +7,7 @@ from crytic_compile import cryticparser from slither import Slither -from slither.tools.read_storage.read_storage import SlitherReadStorage +from slither.tools.read_storage.read_storage import SlitherReadStorage, RpcInfo def parse_args() -> argparse.Namespace: @@ -129,6 +129,12 @@ def main() -> None: srs = SlitherReadStorage(contracts, args.max_depth) if args.rpc_url: + try: + block = int(args.block) + except ValueError: + block = "latest" + rpc_info = RpcInfo(args.rpc_url, block) + srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) # Remove target prefix e.g. rinkeby:0x0 -> 0x0. address = target[target.find(":") + 1 :] # Default to implementation address unless a storage address is given. @@ -136,13 +142,6 @@ def main() -> None: args.storage_address = address srs.storage_address = args.storage_address - srs.rpc = args.rpc_url - - try: - srs.block = int(args.block) - except ValueError: - srs.block = str(args.block or "latest") - if args.variable_name: # Use a lambda func to only return variables that have same name as target. # x is a tuple (`Contract`, `StateVariable`). diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index 73691fba86..7e6c811339 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -6,7 +6,7 @@ from eth_abi import decode, encode from eth_typing.evm import ChecksumAddress -from eth_utils import keccak +from eth_utils import keccak, to_checksum_address from web3 import Web3 from web3.exceptions import ExtraDataLengthError from web3.middleware import geth_poa_middleware @@ -44,18 +44,36 @@ class SlitherReadStorageException(Exception): pass +class RpcInfo: + def __init__(self, rpc_url: str, block: Union[int, str] = "latest") -> None: + assert(isinstance(block, int) or block.isnumeric() or block == "latest") + self.rpc: str = rpc_url + self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) + try: + self._block: int = self.web3.eth.get_block(block)["number"] + except ExtraDataLengthError: + self._web3.middleware_onion.inject(geth_poa_middleware, layer=0) + self._block: int = self.web3.eth.get_block(block)["number"] + + @property + def web3(self) -> Web3: + return self._web3 + + @property + def block(self) -> int: + return self._block + + # pylint: disable=too-many-instance-attributes class SlitherReadStorage: - def __init__(self, contracts: List[Contract], max_depth: int) -> None: + def __init__(self, contracts: List[Contract], max_depth: int, rpc_info: RpcInfo = None) -> None: self._checksum_address: Optional[ChecksumAddress] = None self._contracts: List[Contract] = contracts self._log: str = "" self._max_depth: int = max_depth self._slot_info: Dict[str, SlotInfo] = {} self._target_variables: List[Tuple[Contract, StateVariable]] = [] - self._web3: Optional[Web3] = None - self._block: Optional[int] = None - self.rpc: Optional[str] = None + self.rpc_info: Optional[RpcInfo] = rpc_info self.storage_address: Optional[str] = None self.table: Optional[MyPrettyTable] = None @@ -75,38 +93,12 @@ def log(self) -> str: def log(self, log: str) -> None: self._log = log - @property - def block(self) -> int: - """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" - if not self._block: - try: - self._block = self.web3.eth.get_block("latest")["number"] - except ExtraDataLengthError: - self.web3.middleware_onion.inject(geth_poa_middleware, layer=0) - self._block = self.web3.eth.get_block("latest")["number"] - return self._block - - @block.setter - def block(self, block: Union[str, int]) -> None: - """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" - try: - self._block = self.web3.eth.get_block(block)["number"] - except ExtraDataLengthError: - self.web3.middleware_onion.inject(geth_poa_middleware, layer=0) - self._block = self.web3.eth.get_block(block)["number"] - - @property - def web3(self) -> Web3: - if not self._web3: - self._web3 = Web3(Web3.HTTPProvider(self.rpc)) - return self._web3 - @property def checksum_address(self) -> ChecksumAddress: if not self.storage_address: raise ValueError if not self._checksum_address: - self._checksum_address = self.web3.to_checksum_address(self.storage_address) + self._checksum_address = to_checksum_address(self.storage_address) return self._checksum_address @property @@ -245,11 +237,12 @@ def get_slot_values(self, slot_info: SlotInfo) -> None: """Fetches the slot value of `SlotInfo` object :param slot_info: """ + assert self.rpc_info is not None hex_bytes = get_storage_data( - self.web3, + self.rpc_info.web3, self.checksum_address, int.to_bytes(slot_info.slot, 32, byteorder="big"), - self.block, + self.rpc_info.block, ) slot_info.value = self.convert_value_to_type( hex_bytes, slot_info.size, slot_info.offset, slot_info.type_string @@ -622,15 +615,15 @@ def _get_array_length(self, type_: Type, slot: int) -> int: (int): The length of the array. """ val = 0 - if self.rpc: + if self.rpc_info: # The length of dynamic arrays is stored at the starting slot. # Convert from hexadecimal to decimal. val = int( get_storage_data( - self.web3, + self.rpc_info.web3, self.checksum_address, int.to_bytes(slot, 32, byteorder="big"), - self.block, + self.rpc_info.block, ).hex(), 16, ) From e900e79a641a101f8da2e3b44b43aedfd711f633 Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 27 Apr 2023 11:29:35 -0500 Subject: [PATCH 05/24] Black --- slither/tools/read_storage/read_storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index 7e6c811339..fc8c848795 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -46,7 +46,7 @@ class SlitherReadStorageException(Exception): class RpcInfo: def __init__(self, rpc_url: str, block: Union[int, str] = "latest") -> None: - assert(isinstance(block, int) or block.isnumeric() or block == "latest") + assert isinstance(block, int) or block.isnumeric() or block == "latest" self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) try: From 5b90a52d14780ea27dea465f90ac4bf6efd15c16 Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 27 Apr 2023 11:36:34 -0500 Subject: [PATCH 06/24] Update test_read_storage.py --- tests/tools/read-storage/test_read_storage.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tools/read-storage/test_read_storage.py b/tests/tools/read-storage/test_read_storage.py index 38d909bf88..673d6a6df6 100644 --- a/tests/tools/read-storage/test_read_storage.py +++ b/tests/tools/read-storage/test_read_storage.py @@ -12,7 +12,7 @@ from web3.contract import Contract from slither import Slither -from slither.tools.read_storage import SlitherReadStorage +from slither.tools.read_storage import SlitherReadStorage, RpcInfo TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" @@ -103,8 +103,8 @@ def test_read_storage(web3, ganache) -> None: sl = Slither(Path(TEST_DATA_DIR, "storage_layout-0.8.10.sol").as_posix()) contracts = sl.contracts - srs = SlitherReadStorage(contracts, 100) - srs.rpc = ganache.provider + rpc_info: RpcInfo = RpcInfo(ganache.provider) + srs = SlitherReadStorage(contracts, 100, rpc_info) srs.storage_address = address srs.get_all_storage_variables() srs.get_storage_layout() From 55817ab65875ef0b13686c899df08de63dae474e Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 27 Apr 2023 11:36:46 -0500 Subject: [PATCH 07/24] Add import in __init__.py --- slither/tools/read_storage/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/__init__.py b/slither/tools/read_storage/__init__.py index dbc1e5bc0e..df9b8280d8 100644 --- a/slither/tools/read_storage/__init__.py +++ b/slither/tools/read_storage/__init__.py @@ -1 +1 @@ -from .read_storage import SlitherReadStorage +from .read_storage import SlitherReadStorage, RpcInfo From b28e350da02f6eb7979afedc3454d830880bc37e Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 28 Apr 2023 08:25:56 -0500 Subject: [PATCH 08/24] Avoid instantiating SRS twice --- slither/tools/read_storage/__main__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 8da021cfed..63a42ec766 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -126,20 +126,20 @@ def main() -> None: else: contracts = slither.contracts - srs = SlitherReadStorage(contracts, args.max_depth) - + rpc_info = None if args.rpc_url: try: block = int(args.block) except ValueError: block = "latest" rpc_info = RpcInfo(args.rpc_url, block) - srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) # Remove target prefix e.g. rinkeby:0x0 -> 0x0. - address = target[target.find(":") + 1 :] + address = target[target.find(":") + 1:] # Default to implementation address unless a storage address is given. if not args.storage_address: args.storage_address = address + srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) + if args.storage_address: srs.storage_address = args.storage_address if args.variable_name: From 2645d5ee31df82f0cd70e1ff815d9449babcbc32 Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 28 Apr 2023 08:29:48 -0500 Subject: [PATCH 09/24] Add comment about `get_block` for POA networks --- slither/tools/read_storage/read_storage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index fc8c848795..9a6923936d 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -49,6 +49,7 @@ def __init__(self, rpc_url: str, block: Union[int, str] = "latest") -> None: assert isinstance(block, int) or block.isnumeric() or block == "latest" self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) + """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" try: self._block: int = self.web3.eth.get_block(block)["number"] except ExtraDataLengthError: From 71e13aa8fa567bd9a54adbedb9383be7a7bf80f7 Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 28 Apr 2023 08:33:51 -0500 Subject: [PATCH 10/24] Pylint --- slither/tools/read_storage/__main__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 63a42ec766..b1eec31927 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -133,14 +133,14 @@ def main() -> None: except ValueError: block = "latest" rpc_info = RpcInfo(args.rpc_url, block) - # Remove target prefix e.g. rinkeby:0x0 -> 0x0. - address = target[target.find(":") + 1:] - # Default to implementation address unless a storage address is given. - if not args.storage_address: - args.storage_address = address + srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) - if args.storage_address: - srs.storage_address = args.storage_address + # Remove target prefix e.g. rinkeby:0x0 -> 0x0. + address = target[target.find(":") + 1:] + # Default to implementation address unless a storage address is given. + if not args.storage_address: + args.storage_address = address + srs.storage_address = args.storage_address if args.variable_name: # Use a lambda func to only return variables that have same name as target. From 4fbbfffb5f49576b47f2f2efdcd6024db7b7edbc Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 28 Apr 2023 08:34:13 -0500 Subject: [PATCH 11/24] Black --- slither/tools/read_storage/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index b1eec31927..438fcc9271 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -136,7 +136,7 @@ def main() -> None: srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) # Remove target prefix e.g. rinkeby:0x0 -> 0x0. - address = target[target.find(":") + 1:] + address = target[target.find(":") + 1 :] # Default to implementation address unless a storage address is given. if not args.storage_address: args.storage_address = address From b6bc23484ce2d29e434262b50c08b6be9c855d1e Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 28 Apr 2023 14:52:07 -0500 Subject: [PATCH 12/24] Allow other valid block string arguments ["latest", "earliest", "pending", "safe", "finalized"] --- slither/tools/read_storage/read_storage.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index 9a6923936d..bece1b2ca9 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -46,7 +46,11 @@ class SlitherReadStorageException(Exception): class RpcInfo: def __init__(self, rpc_url: str, block: Union[int, str] = "latest") -> None: - assert isinstance(block, int) or block.isnumeric() or block == "latest" + assert ( + isinstance(block, int) + or block.isnumeric() + or block in ["latest", "earliest", "pending", "safe", "finalized"] + ) self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" From 610052d381c40d098f51894e70f53e616cd2997d Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 4 May 2023 11:51:24 -0500 Subject: [PATCH 13/24] `args.block` can be in ["latest", "earliest", "pending", "safe", "finalized"] --- slither/tools/read_storage/__main__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 438fcc9271..8c62d25416 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -128,10 +128,13 @@ def main() -> None: rpc_info = None if args.rpc_url: - try: - block = int(args.block) - except ValueError: - block = "latest" + if args.block in ["latest", "earliest", "pending", "safe", "finalized"]: + block = args.block + else: + try: + block = int(args.block) + except ValueError: + block = "latest" rpc_info = RpcInfo(args.rpc_url, block) srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) From 034d12d85d8d25fd91e1a921bdb8ee56dd6afa99 Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 4 May 2023 12:17:27 -0500 Subject: [PATCH 14/24] Use BlockTag enum class for valid `str` arguments --- slither/tools/read_storage/__main__.py | 13 +++++------ slither/tools/read_storage/read_storage.py | 25 +++++++++++++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 8c62d25416..a5414babff 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -7,7 +7,7 @@ from crytic_compile import cryticparser from slither import Slither -from slither.tools.read_storage.read_storage import SlitherReadStorage, RpcInfo +from slither.tools.read_storage.read_storage import SlitherReadStorage, RpcInfo, BlockTag def parse_args() -> argparse.Namespace: @@ -128,13 +128,10 @@ def main() -> None: rpc_info = None if args.rpc_url: - if args.block in ["latest", "earliest", "pending", "safe", "finalized"]: - block = args.block - else: - try: - block = int(args.block) - except ValueError: - block = "latest" + try: + block = int(args.block) + except ValueError: + block = BlockTag(args.block) or "latest" rpc_info = RpcInfo(args.rpc_url, block) srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index bece1b2ca9..f6f54d102e 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -1,5 +1,6 @@ import logging from math import floor +from enum import Enum, EnumMeta from typing import Any, Callable, Dict, List, Optional, Tuple, Union import dataclasses @@ -44,13 +45,27 @@ class SlitherReadStorageException(Exception): pass +# pylint: disable=no-value-for-parameter +class MetaEnum(EnumMeta): + def __contains__(cls, item): + try: + cls(item) + except ValueError: + return False + return True + + +class BlockTag(Enum, metaclass=MetaEnum): + LATEST = "latest" + EARLIEST = "earliest" + PENDING = "pending" + SAFE = "safe" + FINALIZED = "finalized" + + class RpcInfo: def __init__(self, rpc_url: str, block: Union[int, str] = "latest") -> None: - assert ( - isinstance(block, int) - or block.isnumeric() - or block in ["latest", "earliest", "pending", "safe", "finalized"] - ) + assert isinstance(block, int) or block in BlockTag self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" From 87f94b413fc59c77151ddbbc2b9e0baa70eee3c5 Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 4 May 2023 12:29:36 -0500 Subject: [PATCH 15/24] Tweak `RpcInfo.__init__()` signature --- slither/tools/read_storage/read_storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index f6f54d102e..e956d77ca3 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -64,7 +64,7 @@ class BlockTag(Enum, metaclass=MetaEnum): class RpcInfo: - def __init__(self, rpc_url: str, block: Union[int, str] = "latest") -> None: + def __init__(self, rpc_url: str, block: Union[int, BlockTag] = "latest") -> None: assert isinstance(block, int) or block in BlockTag self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) From ee42026c75082f3a9bf646062410a62ee0460f1d Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 4 May 2023 13:11:08 -0500 Subject: [PATCH 16/24] get rid of `or "latest"` --- slither/tools/read_storage/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index a5414babff..0d8e6c7d43 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -131,7 +131,7 @@ def main() -> None: try: block = int(args.block) except ValueError: - block = BlockTag(args.block) or "latest" + block = BlockTag(args.block) rpc_info = RpcInfo(args.rpc_url, block) srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) From 80b688d547595744fe6cec083fe8585149cebefe Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 4 May 2023 13:11:29 -0500 Subject: [PATCH 17/24] Import BlockTag --- slither/tools/read_storage/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/__init__.py b/slither/tools/read_storage/__init__.py index df9b8280d8..d1025dd830 100644 --- a/slither/tools/read_storage/__init__.py +++ b/slither/tools/read_storage/__init__.py @@ -1 +1 @@ -from .read_storage import SlitherReadStorage, RpcInfo +from .read_storage import SlitherReadStorage, RpcInfo, BlockTag From 24813cc31f4995270e1a66190bf7a5eeacbea274 Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 4 May 2023 13:12:22 -0500 Subject: [PATCH 18/24] Use `web3.types.BlockIdentifier` --- slither/tools/read_storage/read_storage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index e956d77ca3..b86673cdce 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -9,6 +9,7 @@ from eth_typing.evm import ChecksumAddress from eth_utils import keccak, to_checksum_address from web3 import Web3 +from web3.types import BlockIdentifier from web3.exceptions import ExtraDataLengthError from web3.middleware import geth_poa_middleware @@ -64,7 +65,7 @@ class BlockTag(Enum, metaclass=MetaEnum): class RpcInfo: - def __init__(self, rpc_url: str, block: Union[int, BlockTag] = "latest") -> None: + def __init__(self, rpc_url: str, block: BlockIdentifier = "latest") -> None: assert isinstance(block, int) or block in BlockTag self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) From d462c12b6bf13217b7915f77db96929806f2aaaf Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 11 May 2023 15:35:26 -0500 Subject: [PATCH 19/24] Revert BlockTag enum --- slither/tools/read_storage/__init__.py | 2 +- slither/tools/read_storage/__main__.py | 5 +++-- slither/tools/read_storage/read_storage.py | 20 +------------------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/slither/tools/read_storage/__init__.py b/slither/tools/read_storage/__init__.py index d1025dd830..93b74938b5 100644 --- a/slither/tools/read_storage/__init__.py +++ b/slither/tools/read_storage/__init__.py @@ -1 +1 @@ -from .read_storage import SlitherReadStorage, RpcInfo, BlockTag +from .read_storage import SlitherReadStorage, RpcInfo \ No newline at end of file diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 0d8e6c7d43..c6064235c2 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -7,7 +7,7 @@ from crytic_compile import cryticparser from slither import Slither -from slither.tools.read_storage.read_storage import SlitherReadStorage, RpcInfo, BlockTag +from slither.tools.read_storage.read_storage import SlitherReadStorage, RpcInfo def parse_args() -> argparse.Namespace: @@ -131,7 +131,8 @@ def main() -> None: try: block = int(args.block) except ValueError: - block = BlockTag(args.block) + valid = ["latest", "earliest", "pending", "safe", "finalized"] + block = next((v for v in valid if v == args.block), "latest") rpc_info = RpcInfo(args.rpc_url, block) srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index b86673cdce..3b81b61d17 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -46,27 +46,9 @@ class SlitherReadStorageException(Exception): pass -# pylint: disable=no-value-for-parameter -class MetaEnum(EnumMeta): - def __contains__(cls, item): - try: - cls(item) - except ValueError: - return False - return True - - -class BlockTag(Enum, metaclass=MetaEnum): - LATEST = "latest" - EARLIEST = "earliest" - PENDING = "pending" - SAFE = "safe" - FINALIZED = "finalized" - - class RpcInfo: def __init__(self, rpc_url: str, block: BlockIdentifier = "latest") -> None: - assert isinstance(block, int) or block in BlockTag + assert isinstance(block, int) or block in ["latest", "earliest", "pending", "safe", "finalized"] self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" From c4cec4cf300f12d4aa7fc5420a742c50cd44bb4b Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 11 May 2023 15:36:56 -0500 Subject: [PATCH 20/24] Pylint and black --- slither/tools/read_storage/read_storage.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/slither/tools/read_storage/read_storage.py b/slither/tools/read_storage/read_storage.py index 3b81b61d17..0d2a97bc65 100644 --- a/slither/tools/read_storage/read_storage.py +++ b/slither/tools/read_storage/read_storage.py @@ -1,6 +1,5 @@ import logging from math import floor -from enum import Enum, EnumMeta from typing import Any, Callable, Dict, List, Optional, Tuple, Union import dataclasses @@ -48,7 +47,13 @@ class SlitherReadStorageException(Exception): class RpcInfo: def __init__(self, rpc_url: str, block: BlockIdentifier = "latest") -> None: - assert isinstance(block, int) or block in ["latest", "earliest", "pending", "safe", "finalized"] + assert isinstance(block, int) or block in [ + "latest", + "earliest", + "pending", + "safe", + "finalized", + ] self.rpc: str = rpc_url self._web3: Web3 = Web3(Web3.HTTPProvider(self.rpc)) """If the RPC is for a POA network, the first call to get_block fails, so we inject geth_poa_middleware""" From 5e335194170aa2cc6bdd86a922dce7d96069f16f Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 11 May 2023 15:51:01 -0500 Subject: [PATCH 21/24] Replace missing newline --- slither/tools/read_storage/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/__init__.py b/slither/tools/read_storage/__init__.py index 93b74938b5..df9b8280d8 100644 --- a/slither/tools/read_storage/__init__.py +++ b/slither/tools/read_storage/__init__.py @@ -1 +1 @@ -from .read_storage import SlitherReadStorage, RpcInfo \ No newline at end of file +from .read_storage import SlitherReadStorage, RpcInfo From a1f6235c5193000f7456b8ba148daf197a31edca Mon Sep 17 00:00:00 2001 From: William E Bodell III Date: Thu, 11 May 2023 20:20:12 -0500 Subject: [PATCH 22/24] Update slither/tools/read_storage/__main__.py Better, cleaner python Co-authored-by: alpharush <0xalpharush@protonmail.com> --- slither/tools/read_storage/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index c6064235c2..ec40c5f9bb 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -132,7 +132,7 @@ def main() -> None: block = int(args.block) except ValueError: valid = ["latest", "earliest", "pending", "safe", "finalized"] - block = next((v for v in valid if v == args.block), "latest") + block = args.block if args.block in valid else "latest" rpc_info = RpcInfo(args.rpc_url, block) srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) From f38eabe5f2402b9b0d2bffa57b707bc031b152eb Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 12 May 2023 08:42:03 -0500 Subject: [PATCH 23/24] Drop try/except around args.block parsing allow ValueError if user provides invalid block arg --- slither/tools/read_storage/__main__.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index ec40c5f9bb..31df764b1d 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -7,6 +7,7 @@ from crytic_compile import cryticparser from slither import Slither +from slither.exceptions import SlitherError from slither.tools.read_storage.read_storage import SlitherReadStorage, RpcInfo @@ -128,11 +129,8 @@ def main() -> None: rpc_info = None if args.rpc_url: - try: - block = int(args.block) - except ValueError: - valid = ["latest", "earliest", "pending", "safe", "finalized"] - block = args.block if args.block in valid else "latest" + valid = ["latest", "earliest", "pending", "safe", "finalized"] + block = args.block if args.block in valid else int(args.block) rpc_info = RpcInfo(args.rpc_url, block) srs = SlitherReadStorage(contracts, args.max_depth, rpc_info) From a86ee8fbb8e95c435f3c817c699f5898f5743d8a Mon Sep 17 00:00:00 2001 From: webthethird Date: Thu, 18 May 2023 11:58:56 -0500 Subject: [PATCH 24/24] Remove unused import --- slither/tools/read_storage/__main__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/slither/tools/read_storage/__main__.py b/slither/tools/read_storage/__main__.py index 31df764b1d..f6635ab4be 100644 --- a/slither/tools/read_storage/__main__.py +++ b/slither/tools/read_storage/__main__.py @@ -7,7 +7,6 @@ from crytic_compile import cryticparser from slither import Slither -from slither.exceptions import SlitherError from slither.tools.read_storage.read_storage import SlitherReadStorage, RpcInfo