class RpcTest(TestCase): client = None def setUp(self): self.client = EthJsonRpc() def tearDown(self): self.client.close() def test_eth_coinbase(self): coinbase = self.client.eth_coinbase() self.assertTrue(coinbase.startswith("0x"), "coinbase should be a hex string") self.assertEqual(len(coinbase), 42, "coinbase is a string with length of 42") def test_eth_blockNumber(self): block_number = self.client.eth_blockNumber() self.assertGreater( block_number, 0, "we have made sure the blockNumber is > 0 for testing") def test_eth_getBalance(self): balance = self.client.eth_getBalance( address="0x0000000000000000000000000000000000000000") self.assertGreater(balance, 10000000, "specified address should have a lot of balance") def test_eth_getStorageAt(self): storage = self.client.eth_getStorageAt( address="0x0000000000000000000000000000000000000000") self.assertEqual( storage, '0x0000000000000000000000000000000000000000000000000000000000000000' ) def test_eth_getBlockByNumber(self): block = self.client.eth_getBlockByNumber(0) self.assertEqual( block["extraData"], "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", "the data of the first block should be right") def test_eth_getCode(self): # TODO: can't find a proper address for getting code code = self.client.eth_getCode( address="0x0000000000000000000000000000000000000001") self.assertEqual(code, "0x") def test_eth_getTransactionReceipt(self): transaction = self.client.eth_getTransactionReceipt( tx_hash= "0xe363505adc6b2996111f8bd774f8653a61d244cc6567b5372c2e781c6c63b737" ) self.assertEqual(transaction["from"], "0x22f2dcff5ad78c3eb6850b5cb951127b659522e6") self.assertEqual(transaction["to"], "0x0000000000000000000000000000000000000000")
def initialize(self, rpchost, rpcport, sync_all): eth = EthJsonRpc(rpchost, rpcport) if self.last_block: blockNum = self.last_block print("Resuming synchronization from block " + str(blockNum)) else: blockNum = eth.eth_blockNumber() print("Starting synchronization from latest block: " + str(blockNum)) while (blockNum > 0): if not blockNum % 1000: print("Processing block " + str(blockNum) + ", " + str(len(self.contracts.keys())) + " individual contracts in database") block = eth.eth_getBlockByNumber(blockNum) for tx in block['transactions']: if not tx['to']: receipt = eth.eth_getTransactionReceipt(tx['hash']) contract_address = receipt['contractAddress'] contract_code = eth.eth_getCode(contract_address) contract_balance = eth.eth_getBalance(contract_address) if not contract_balance or sync_all: # skip contracts with zero balance (disable with --sync-all) continue code = ETHContract(contract_code, tx['input']) m = hashlib.md5() m.update(contract_code.encode('UTF-8')) contract_hash = m.digest() try: self.contracts[contract_hash] except KeyError: self.contracts[contract_hash] = code m = InstanceList() self.instance_lists[contract_hash] = m self.instance_lists[contract_hash].add( contract_address, contract_balance) transaction.commit() self.last_block = blockNum blockNum -= 1
class LocalNotifier(Notifier): def __init__(self, rpc_address, rpc_port): """ Constructor for LocalNotifier class :param rpc_address: Address of ethereum rpc interface :param rpc_port: Port of ethereum rpc interface :param callback: Callback function to call when a contract is found """ logging.info("Initializing local notifier") super().__init__() self.rpc_client = EthJsonRpc(rpc_address, rpc_port, True) logging.info("Initialized rpc client") logging.info("Geth version: {}".format( self.rpc_client.web3_clientVersion())) self.current_block = self.rpc_client.eth_blockNumber() logging.info("The ethereum client is currently at block {}".format( self.current_block)) def scan(self): """ Scan for new blocks and examine them for new contracts """ new_block = self.rpc_client.eth_blockNumber() logging.info("Starting analysis of blocks {} to {}".format( self.current_block + 1, new_block)) for i in range(self.current_block + 1, new_block): self._examine_block(i) self.current_block = new_block - 1 def _new_blocks(self): """ :return: Amount of new blocks available """ return self.rpc_client.eth_blockNumber() - self.current_block def _examine_block(self, number): """ Examine all transactions in a block and report found contracts :param number: blocknumber of block to examine """ # Gets the block by number, true indicates that we want the entire transactions instead of only hashes block = self.rpc_client.eth_getBlockByNumber(number, True) logging.info("Examining block with number {}".format(number)) try: transactions = block['transactions'] except TypeError: logging.debug( "No transactions element found in block {}".format(number)) # Examine all transactions for transaction in transactions: self._examine_transaction(transaction) def _examine_transaction(self, transaction_object): """ Examine a transaction and report any found contracts :param transaction_object: object from ethjsonrpc describing the transaction """ if transaction_object['to'] is not None: logging.debug( "Transaction with hash {} is not a contract creating transaction" .format(transaction_object['hash'])) return logging.info("Found contract creating transaction with hash {}".format( transaction_object['hash'])) transaction_receipt = self.rpc_client.eth_getTransactionReceipt( transaction_object['hash']) try: contract_address = transaction_receipt['contractAddress'] except TypeError: logging.debug( f"Found transaction with no to value and the receipt contained no contract address. Transaction hash: {transaction_object['hash']}" ) return logging.info( "Found new contract with address {}".format(contract_address)) self.encounter(contract_address, "LocalNotifier")