Fix bug #1168 by checking eth is not None in the loader. Refactor the loader. (#1169)

* Fix bug #1168 by checking eth is not None in the loader.

Also refactor the loader quite a bit:
 - remove the cache dictionary, and use functools.lru_cache instead
 - also use lru_cache for caching contract code
 - add type annotations, now mypy would be complaining if we didn't
   "self.eth" for None.
 - use log.debug() with %s, it's good pratice and allow advanced logging
   to group by log messages / parameters if needed.

* Fix type annotation.

* Exception -> ValueError in loader.py

* Remove unused import.
jinja-print-initial-state
palkeo 5 years ago committed by Nikhil Parasaram
parent 2c591a2b14
commit 79307c4a09
  1. 52
      mythril/support/loader.py

@ -3,6 +3,11 @@ and dependencies."""
from mythril.disassembler.disassembly import Disassembly
import logging
import re
import functools
from mythril.ethereum.interface.rpc.client import EthJsonRpc
from typing import Optional
LRU_CACHE_SIZE = 4096
log = logging.getLogger(__name__)
@ -10,7 +15,9 @@ log = logging.getLogger(__name__)
class DynLoader:
"""The dynamic loader class."""
def __init__(self, eth, contract_loading=True, storage_loading=True):
def __init__(
self, eth: Optional[EthJsonRpc], contract_loading=True, storage_loading=True
):
"""
:param eth:
@ -18,11 +25,11 @@ class DynLoader:
:param storage_loading:
"""
self.eth = eth
self.storage_cache = {}
self.contract_loading = contract_loading
self.storage_loading = storage_loading
def read_storage(self, contract_address: str, index: int):
@functools.lru_cache(LRU_CACHE_SIZE)
def read_storage(self, contract_address: str, index: int) -> str:
"""
:param contract_address:
@ -30,43 +37,28 @@ class DynLoader:
:return:
"""
if not self.storage_loading:
raise Exception(
raise ValueError(
"Cannot load from the storage when the storage_loading flag is false"
)
if not self.eth:
raise ValueError("Cannot load from the storage when eth is None")
try:
contract_ref = self.storage_cache[contract_address]
data = contract_ref[index]
except KeyError:
self.storage_cache[contract_address] = {}
data = self.eth.eth_getStorageAt(
contract_address, position=index, block="latest"
)
self.storage_cache[contract_address][index] = data
except IndexError:
data = self.eth.eth_getStorageAt(
contract_address, position=index, block="latest"
)
self.storage_cache[contract_address][index] = data
return data
return self.eth.eth_getStorageAt(
contract_address, position=index, block="latest"
)
def dynld(self, dependency_address):
@functools.lru_cache(LRU_CACHE_SIZE)
def dynld(self, dependency_address: str) -> Optional[Disassembly]:
"""
:param dependency_address:
:return:
"""
if not self.contract_loading:
raise ValueError("Cannot load contract when contract_loading flag is false")
if not self.eth:
raise ValueError("Cannot load from the storage when eth is None")
log.debug("Dynld at contract " + dependency_address)
log.debug("Dynld at contract %s", dependency_address)
# Ensure that dependency_address is the correct length, with 0s prepended as needed.
dependency_address = (
@ -81,7 +73,7 @@ class DynLoader:
else:
return None
log.debug("Dependency address: " + dependency_address)
log.debug("Dependency address: %s", dependency_address)
code = self.eth.eth_getCode(dependency_address)

Loading…
Cancel
Save