|
|
|
@ -11,21 +11,21 @@ from mythril.ether.ethcontract import ETHContract |
|
|
|
|
|
|
|
|
|
# Per https://github.com/ethereum/go-ethereum/blob/master/core/database_util.go |
|
|
|
|
# prefixes and suffixes for keys in geth |
|
|
|
|
headerPrefix = b'h' # headerPrefix + num (uint64 big endian) + hash -> header |
|
|
|
|
bodyPrefix = b'b' # bodyPrefix + num (uint64 big endian) + hash -> block body |
|
|
|
|
numSuffix = b'n' # headerPrefix + num (uint64 big endian) + numSuffix -> hash |
|
|
|
|
blockHashPrefix = b'H' # blockHashPrefix + hash -> num (uint64 big endian) |
|
|
|
|
blockReceiptsPrefix = b'r' # blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts |
|
|
|
|
header_prefix = b'h' # header_prefix + num (uint64 big endian) + hash -> header |
|
|
|
|
body_prefix = b'b' # body_prefix + num (uint64 big endian) + hash -> block body |
|
|
|
|
num_suffix = b'n' # header_prefix + num (uint64 big endian) + num_suffix -> hash |
|
|
|
|
block_hash_prefix = b'H' # block_hash_prefix + hash -> num (uint64 big endian) |
|
|
|
|
block_receipts_prefix = b'r' # block_receipts_prefix + num (uint64 big endian) + hash -> block receipts |
|
|
|
|
# known geth keys |
|
|
|
|
headHeaderKey = b'LastBlock' # head (latest) header hash |
|
|
|
|
head_header_key = b'last_block' # head (latest) header hash |
|
|
|
|
# custom prefixes |
|
|
|
|
addressPrefix = b'AM' # addressPrefix + hash -> address |
|
|
|
|
address_prefix = b'AM' # address_prefix + hash -> address |
|
|
|
|
# custom keys |
|
|
|
|
addressMappingHeadKey = b'accountMapping' # head (latest) number of indexed block |
|
|
|
|
headHeaderKey = b'LastBlock' # head (latest) header hash |
|
|
|
|
address_mapping_head_key = b'account_mapping' # head (latest) number of indexed block |
|
|
|
|
head_header_key = b'last_block' # head (latest) header hash |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _formatBlockNumber(number): |
|
|
|
|
def _format_block_number(number): |
|
|
|
|
''' |
|
|
|
|
formats block number to uint64 big endian |
|
|
|
|
''' |
|
|
|
@ -46,87 +46,87 @@ class LevelDBReader(object): |
|
|
|
|
|
|
|
|
|
def __init__(self, db): |
|
|
|
|
self.db = db |
|
|
|
|
self.headBlockHeader = None |
|
|
|
|
self.headState = None |
|
|
|
|
self.head_block_header = None |
|
|
|
|
self.head_state = None |
|
|
|
|
|
|
|
|
|
def _get_head_state(self): |
|
|
|
|
''' |
|
|
|
|
gets head state |
|
|
|
|
''' |
|
|
|
|
if not self.headState: |
|
|
|
|
if not self.head_state: |
|
|
|
|
root = self._get_head_block().state_root |
|
|
|
|
self.headState = State(self.db, root) |
|
|
|
|
return self.headState |
|
|
|
|
self.head_state = State(self.db, root) |
|
|
|
|
return self.head_state |
|
|
|
|
|
|
|
|
|
def _get_account(self, address): |
|
|
|
|
''' |
|
|
|
|
gets account by address |
|
|
|
|
''' |
|
|
|
|
state = self._get_head_state() |
|
|
|
|
accountAddress = binascii.a2b_hex(utils.remove_0x_head(address)) |
|
|
|
|
return state.get_and_cache_account(accountAddress) |
|
|
|
|
account_address = binascii.a2b_hex(utils.remove_0x_head(address)) |
|
|
|
|
return state.get_and_cache_account(account_address) |
|
|
|
|
|
|
|
|
|
def _get_block_hash(self, number): |
|
|
|
|
''' |
|
|
|
|
gets block hash by block number |
|
|
|
|
''' |
|
|
|
|
num = _formatBlockNumber(number) |
|
|
|
|
hashKey = headerPrefix + num + numSuffix |
|
|
|
|
return self.db.get(hashKey) |
|
|
|
|
num = _format_block_number(number) |
|
|
|
|
hash_key = header_prefix + num + num_suffix |
|
|
|
|
return self.db.get(hash_key) |
|
|
|
|
|
|
|
|
|
def _get_head_block(self): |
|
|
|
|
''' |
|
|
|
|
gets head block header |
|
|
|
|
''' |
|
|
|
|
if not self.headBlockHeader: |
|
|
|
|
hash = self.db.get(headHeaderKey) |
|
|
|
|
if not self.head_block_header: |
|
|
|
|
hash = self.db.get(head_header_key) |
|
|
|
|
num = self._get_block_number(hash) |
|
|
|
|
self.headBlockHeader = self._get_block_header(hash, num) |
|
|
|
|
self.head_block_header = self._get_block_header(hash, num) |
|
|
|
|
# find header with valid state |
|
|
|
|
while not self.db.get(self.headBlockHeader.state_root) and self.headBlockHeader.prevhash is not None: |
|
|
|
|
hash = self.headBlockHeader.prevhash |
|
|
|
|
while not self.db.get(self.head_block_header.state_root) and self.head_block_header.prevhash is not None: |
|
|
|
|
hash = self.head_block_header.prevhash |
|
|
|
|
num = self._get_block_number(hash) |
|
|
|
|
self.headBlockHeader = self._get_block_header(hash, num) |
|
|
|
|
self.head_block_header = self._get_block_header(hash, num) |
|
|
|
|
|
|
|
|
|
return self.headBlockHeader |
|
|
|
|
return self.head_block_header |
|
|
|
|
|
|
|
|
|
def _get_block_number(self, hash): |
|
|
|
|
''' |
|
|
|
|
gets block number by hash |
|
|
|
|
''' |
|
|
|
|
numberKey = blockHashPrefix + hash |
|
|
|
|
return self.db.get(numberKey) |
|
|
|
|
number_key = block_hash_prefix + hash |
|
|
|
|
return self.db.get(number_key) |
|
|
|
|
|
|
|
|
|
def _get_block_header(self, hash, num): |
|
|
|
|
''' |
|
|
|
|
get block header by block header hash & number |
|
|
|
|
''' |
|
|
|
|
headerKey = headerPrefix + num + hash |
|
|
|
|
blockHeaderData = self.db.get(headerKey) |
|
|
|
|
header = rlp.decode(blockHeaderData, sedes=BlockHeader) |
|
|
|
|
header_key = header_prefix + num + hash |
|
|
|
|
block_header_data = self.db.get(header_key) |
|
|
|
|
header = rlp.decode(block_header_data, sedes=BlockHeader) |
|
|
|
|
return header |
|
|
|
|
|
|
|
|
|
def _get_address_by_hash(self, hash): |
|
|
|
|
''' |
|
|
|
|
get mapped address by its hash |
|
|
|
|
''' |
|
|
|
|
addressKey = addressPrefix + hash |
|
|
|
|
return self.db.get(addressKey) |
|
|
|
|
address_key = address_prefix + hash |
|
|
|
|
return self.db.get(address_key) |
|
|
|
|
|
|
|
|
|
def _get_last_indexed_number(self): |
|
|
|
|
''' |
|
|
|
|
latest indexed block number |
|
|
|
|
''' |
|
|
|
|
return self.db.get(addressMappingHeadKey) |
|
|
|
|
return self.db.get(address_mapping_head_key) |
|
|
|
|
|
|
|
|
|
def _get_block_receipts(self, hash, num): |
|
|
|
|
''' |
|
|
|
|
get block transaction receipts by block header hash & number |
|
|
|
|
''' |
|
|
|
|
number = _formatBlockNumber(num) |
|
|
|
|
receiptsKey = blockReceiptsPrefix + number + hash |
|
|
|
|
receiptsData = self.db.get(receiptsKey) |
|
|
|
|
receipts = rlp.decode(receiptsData, sedes=CountableList(ReceiptForStorage)) |
|
|
|
|
number = _format_block_number(num) |
|
|
|
|
receipts_key = block_receipts_prefix + number + hash |
|
|
|
|
receipts_data = self.db.get(receipts_key) |
|
|
|
|
receipts = rlp.decode(receipts_data, sedes=CountableList(ReceiptForStorage)) |
|
|
|
|
return receipts |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -143,7 +143,7 @@ class LevelDBWriter(object): |
|
|
|
|
''' |
|
|
|
|
sets latest indexed block number |
|
|
|
|
''' |
|
|
|
|
return self.db.put(addressMappingHeadKey, _formatBlockNumber(number)) |
|
|
|
|
return self.db.put(address_mapping_head_key, _format_block_number(number)) |
|
|
|
|
|
|
|
|
|
def _start_writing(self): |
|
|
|
|
''' |
|
|
|
@ -161,8 +161,8 @@ class LevelDBWriter(object): |
|
|
|
|
''' |
|
|
|
|
get block transaction receipts by block header hash & number |
|
|
|
|
''' |
|
|
|
|
addressKey = addressPrefix + utils.sha3(address) |
|
|
|
|
self.wb.put(addressKey, address) |
|
|
|
|
address_key = address_prefix + utils.sha3(address) |
|
|
|
|
self.wb.put(address_key, address) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EthLevelDB(object): |
|
|
|
@ -211,8 +211,8 @@ class EthLevelDB(object): |
|
|
|
|
tries to find corresponding account address |
|
|
|
|
''' |
|
|
|
|
indexer = AccountIndexer(self) |
|
|
|
|
addressHash = binascii.a2b_hex(utils.remove_0x_head(hash)) |
|
|
|
|
address = indexer.get_contract_by_hash(addressHash) |
|
|
|
|
address_hash = binascii.a2b_hex(utils.remove_0x_head(hash)) |
|
|
|
|
address = indexer.get_contract_by_hash(address_hash) |
|
|
|
|
if address: |
|
|
|
|
return _encode_hex(address) |
|
|
|
|
else: |
|
|
|
@ -223,18 +223,18 @@ class EthLevelDB(object): |
|
|
|
|
gets block header by block number |
|
|
|
|
''' |
|
|
|
|
hash = self.reader._get_block_hash(number) |
|
|
|
|
blockNumber = _formatBlockNumber(number) |
|
|
|
|
return self.reader._get_block_header(hash, blockNumber) |
|
|
|
|
block_number = _format_block_number(number) |
|
|
|
|
return self.reader._get_block_header(hash, block_number) |
|
|
|
|
|
|
|
|
|
def eth_getBlockByNumber(self, number): |
|
|
|
|
''' |
|
|
|
|
gets block body by block number |
|
|
|
|
''' |
|
|
|
|
blockHash = self.reader._get_block_hash(number) |
|
|
|
|
blockNumber = _formatBlockNumber(number) |
|
|
|
|
bodyKey = bodyPrefix + blockNumber + blockHash |
|
|
|
|
blockData = self.db.get(bodyKey) |
|
|
|
|
body = rlp.decode(blockData, sedes=Block) |
|
|
|
|
block_hash = self.reader._get_block_hash(number) |
|
|
|
|
block_number = _format_block_number(number) |
|
|
|
|
body_key = body_prefix + block_number + block_hash |
|
|
|
|
block_data = self.db.get(body_key) |
|
|
|
|
body = rlp.decode(block_data, sedes=Block) |
|
|
|
|
return body |
|
|
|
|
|
|
|
|
|
def eth_getCode(self, address): |
|
|
|
|