@ -1,12 +1,12 @@
import binascii
import binascii
import rlp
import rlp
from mythril . leveldb . accountindexing import CountableList
from mythril . ethereum . interface . leveldb . accountindexing import CountableList
from mythril . leveldb . accountindexing import ReceiptForStorage , AccountIndexer
from mythril . ethereum . interface . leveldb . accountindexing import ReceiptForStorage , AccountIndexer
import logging
import logging
from ethereum import utils
from ethereum import utils
from ethereum . block import BlockHeader , Block
from ethereum . block import BlockHeader , Block
from mythril . leveldb . state import State
from mythril . ethereum . interface . leveldb . state import State
from mythril . leveldb . eth_db import ETH_DB
from mythril . ethereum . interface . leveldb . eth_db import ETH_DB
from mythril . ether . ethcontract import ETHContract
from mythril . ether . ethcontract import ETHContract
from mythril . exceptions import AddressNotFoundError
from mythril . exceptions import AddressNotFoundError
@ -26,23 +26,23 @@ address_mapping_head_key = b'accountMapping' # head (latest) number of indexed
def _format_block_number ( number ) :
def _format_block_number ( number ) :
'''
"""
formats block number to uint64 big endian
formats block number to uint64 big endian
'''
"""
return utils . zpad ( utils . int_to_big_endian ( number ) , 8 )
return utils . zpad ( utils . int_to_big_endian ( number ) , 8 )
def _encode_hex ( v ) :
def _encode_hex ( v ) :
'''
"""
encodes hash as hex
encodes hash as hex
'''
"""
return ' 0x ' + utils . encode_hex ( v )
return ' 0x ' + utils . encode_hex ( v )
class LevelDBReader ( object ) :
class LevelDBReader ( object ) :
'''
"""
level db reading interface , can be used with snapshot
level db reading interface , can be used with snapshot
'''
"""
def __init__ ( self , db ) :
def __init__ ( self , db ) :
self . db = db
self . db = db
@ -50,34 +50,34 @@ class LevelDBReader(object):
self . head_state = None
self . head_state = None
def _get_head_state ( self ) :
def _get_head_state ( self ) :
'''
"""
gets head state
gets head state
'''
"""
if not self . head_state :
if not self . head_state :
root = self . _get_head_block ( ) . state_root
root = self . _get_head_block ( ) . state_root
self . head_state = State ( self . db , root )
self . head_state = State ( self . db , root )
return self . head_state
return self . head_state
def _get_account ( self , address ) :
def _get_account ( self , address ) :
'''
"""
gets account by address
gets account by address
'''
"""
state = self . _get_head_state ( )
state = self . _get_head_state ( )
account_address = binascii . a2b_hex ( utils . remove_0x_head ( address ) )
account_address = binascii . a2b_hex ( utils . remove_0x_head ( address ) )
return state . get_and_cache_account ( account_address )
return state . get_and_cache_account ( account_address )
def _get_block_hash ( self , number ) :
def _get_block_hash ( self , number ) :
'''
"""
gets block hash by block number
gets block hash by block number
'''
"""
num = _format_block_number ( number )
num = _format_block_number ( number )
hash_key = header_prefix + num + num_suffix
hash_key = header_prefix + num + num_suffix
return self . db . get ( hash_key )
return self . db . get ( hash_key )
def _get_head_block ( self ) :
def _get_head_block ( self ) :
'''
"""
gets head block header
gets head block header
'''
"""
if not self . head_block_header :
if not self . head_block_header :
hash = self . db . get ( head_header_key )
hash = self . db . get ( head_header_key )
num = self . _get_block_number ( hash )
num = self . _get_block_number ( hash )
@ -91,38 +91,38 @@ class LevelDBReader(object):
return self . head_block_header
return self . head_block_header
def _get_block_number ( self , hash ) :
def _get_block_number ( self , hash ) :
'''
"""
gets block number by hash
gets block number by hash
'''
"""
number_key = block_hash_prefix + hash
number_key = block_hash_prefix + hash
return self . db . get ( number_key )
return self . db . get ( number_key )
def _get_block_header ( self , hash , num ) :
def _get_block_header ( self , hash , num ) :
'''
"""
get block header by block header hash & number
get block header by block header hash & number
'''
"""
header_key = header_prefix + num + hash
header_key = header_prefix + num + hash
block_header_data = self . db . get ( header_key )
block_header_data = self . db . get ( header_key )
header = rlp . decode ( block_header_data , sedes = BlockHeader )
header = rlp . decode ( block_header_data , sedes = BlockHeader )
return header
return header
def _get_address_by_hash ( self , hash ) :
def _get_address_by_hash ( self , hash ) :
'''
"""
get mapped address by its hash
get mapped address by its hash
'''
"""
address_key = address_prefix + hash
address_key = address_prefix + hash
return self . db . get ( address_key )
return self . db . get ( address_key )
def _get_last_indexed_number ( self ) :
def _get_last_indexed_number ( self ) :
'''
"""
latest indexed block number
latest indexed block number
'''
"""
return self . db . get ( address_mapping_head_key )
return self . db . get ( address_mapping_head_key )
def _get_block_receipts ( self , hash , num ) :
def _get_block_receipts ( self , hash , num ) :
'''
"""
get block transaction receipts by block header hash & number
get block transaction receipts by block header hash & number
'''
"""
number = _format_block_number ( num )
number = _format_block_number ( num )
receipts_key = block_receipts_prefix + number + hash
receipts_key = block_receipts_prefix + number + hash
receipts_data = self . db . get ( receipts_key )
receipts_data = self . db . get ( receipts_key )
@ -131,44 +131,44 @@ class LevelDBReader(object):
class LevelDBWriter ( object ) :
class LevelDBWriter ( object ) :
'''
"""
level db writing interface
level db writing interface
'''
"""
def __init__ ( self , db ) :
def __init__ ( self , db ) :
self . db = db
self . db = db
self . wb = None
self . wb = None
def _set_last_indexed_number ( self , number ) :
def _set_last_indexed_number ( self , number ) :
'''
"""
sets latest indexed block number
sets latest indexed block number
'''
"""
return self . db . put ( address_mapping_head_key , _format_block_number ( number ) )
return self . db . put ( address_mapping_head_key , _format_block_number ( number ) )
def _start_writing ( self ) :
def _start_writing ( self ) :
'''
"""
start writing a batch
start writing a batch
'''
"""
self . wb = self . db . write_batch ( )
self . wb = self . db . write_batch ( )
def _commit_batch ( self ) :
def _commit_batch ( self ) :
'''
"""
commit batch
commit batch
'''
"""
self . wb . write ( )
self . wb . write ( )
def _store_account_address ( self , address ) :
def _store_account_address ( self , address ) :
'''
"""
get block transaction receipts by block header hash & number
get block transaction receipts by block header hash & number
'''
"""
address_key = address_prefix + utils . sha3 ( address )
address_key = address_prefix + utils . sha3 ( address )
self . wb . put ( address_key , address )
self . wb . put ( address_key , address )
class EthLevelDB ( object ) :
class EthLevelDB ( object ) :
'''
"""
Go - Ethereum LevelDB client class
Go - Ethereum LevelDB client class
'''
"""
def __init__ ( self , path ) :
def __init__ ( self , path ) :
self . path = path
self . path = path
@ -177,9 +177,9 @@ class EthLevelDB(object):
self . writer = LevelDBWriter ( self . db )
self . writer = LevelDBWriter ( self . db )
def get_contracts ( self ) :
def get_contracts ( self ) :
'''
"""
iterate through all contracts
iterate through all contracts
'''
"""
for account in self . reader . _get_head_state ( ) . get_all_accounts ( ) :
for account in self . reader . _get_head_state ( ) . get_all_accounts ( ) :
if account . code is not None :
if account . code is not None :
code = _encode_hex ( account . code )
code = _encode_hex ( account . code )
@ -188,9 +188,9 @@ class EthLevelDB(object):
yield contract , account . address , account . balance
yield contract , account . address , account . balance
def search ( self , expression , callback_func ) :
def search ( self , expression , callback_func ) :
'''
"""
searches through all contract accounts
searches through all contract accounts
'''
"""
cnt = 0
cnt = 0
indexer = AccountIndexer ( self )
indexer = AccountIndexer ( self )
@ -217,9 +217,9 @@ class EthLevelDB(object):
logging . info ( " Searched %d contracts " % cnt )
logging . info ( " Searched %d contracts " % cnt )
def contract_hash_to_address ( self , hash ) :
def contract_hash_to_address ( self , hash ) :
'''
"""
tries to find corresponding account address
tries to find corresponding account address
'''
"""
address_hash = binascii . a2b_hex ( utils . remove_0x_head ( hash ) )
address_hash = binascii . a2b_hex ( utils . remove_0x_head ( hash ) )
indexer = AccountIndexer ( self )
indexer = AccountIndexer ( self )
@ -227,17 +227,17 @@ class EthLevelDB(object):
return _encode_hex ( indexer . get_contract_by_hash ( address_hash ) )
return _encode_hex ( indexer . get_contract_by_hash ( address_hash ) )
def eth_getBlockHeaderByNumber ( self , number ) :
def eth_getBlockHeaderByNumber ( self , number ) :
'''
"""
gets block header by block number
gets block header by block number
'''
"""
hash = self . reader . _get_block_hash ( number )
hash = self . reader . _get_block_hash ( number )
block_number = _format_block_number ( number )
block_number = _format_block_number ( number )
return self . reader . _get_block_header ( hash , block_number )
return self . reader . _get_block_header ( hash , block_number )
def eth_getBlockByNumber ( self , number ) :
def eth_getBlockByNumber ( self , number ) :
'''
"""
gets block body by block number
gets block body by block number
'''
"""
block_hash = self . reader . _get_block_hash ( number )
block_hash = self . reader . _get_block_hash ( number )
block_number = _format_block_number ( number )
block_number = _format_block_number ( number )
body_key = body_prefix + block_number + block_hash
body_key = body_prefix + block_number + block_hash
@ -246,22 +246,22 @@ class EthLevelDB(object):
return body
return body
def eth_getCode ( self , address ) :
def eth_getCode ( self , address ) :
'''
"""
gets account code
gets account code
'''
"""
account = self . reader . _get_account ( address )
account = self . reader . _get_account ( address )
return _encode_hex ( account . code )
return _encode_hex ( account . code )
def eth_getBalance ( self , address ) :
def eth_getBalance ( self , address ) :
'''
"""
gets account balance
gets account balance
'''
"""
account = self . reader . _get_account ( address )
account = self . reader . _get_account ( address )
return account . balance
return account . balance
def eth_getStorageAt ( self , address , position ) :
def eth_getStorageAt ( self , address , position ) :
'''
"""
gets account storage data at position
gets account storage data at position
'''
"""
account = self . reader . _get_account ( address )
account = self . reader . _get_account ( address )
return _encode_hex ( utils . zpad ( utils . encode_int ( account . get_storage_data ( position ) ) , 32 ) )
return _encode_hex ( utils . zpad ( utils . encode_int ( account . get_storage_data ( position ) ) , 32 ) )