import requests import json from web3 import Web3, HTTPProvider from eth_utils import is_dict from web3.utils.datastructures import AttributeDict from web3.utils.toolz import assoc from .output import Output, OutputException from hexbytes import HexBytes console = Output() class TxBatch(object): """An extremely simple JSON-RPC batch request for web3.eth.getTransaction, to use until web3 adds batch.""" req = None web3 = None def __init__(self, web3_provider=None): """Initialise a TxBatch.""" if web3_provider is None: self.web3 = egs.settings.get_web3_provider() else: self.web3 = web3_provider self._setRequestFromProvider(self.web3) def batchRequest(self, method, hex_list): """submit and process batchRequest.""" if len(hex_list) == 0: # there's no reason to go make a request for an # empty batch. return {} req_list = [] idx = 0 for tx_hash in hex_list: req = { 'jsonrpc': '2.0', 'method': method, 'params': [ tx_hash ], 'id': idx } req_list.append(req) idx += 1 results = self._postBatch(req_list) if results is False: console.warn("Transaction batch request failed") return {} req_results = {} for result in results: key = hex_list[int(result['id'])] value = self._castAttributeDict( self._formatTransactionResult( result['result'])) req_results[key] = value return req_results def nonceBatch(self, method, hex_list, block): if len(hex_list) == 0: # there's no reason to go make a request for an # empty batch. return {} req_list = [] idx = 0 block = hex(block) for from_add in hex_list: req = { 'jsonrpc':'2.0', 'method':method, 'params':[from_add, block], 'id':idx } req_list.append(req) idx += 1 results = self._postBatch(req_list) if results is False: console.warn("Transaction batch request failed") return {} req_results = {} for result in results: key = hex_list[int(result['id'])] value = int(result['result'], 16) req_results[key] = value return req_results def _postBatch(self, post_data_object): """Make a batch JSON-RPC request to the geth endpoint.""" try: res = requests.post(self.endpoint_uri, json=post_data_object, timeout=self.timeout) if res.status_code == 200: return res.json() else: return False except Exception as e: console.warn (e) console.warn ("post_batch failure") return False def _setRequestFromProvider(self, web3_provider): """Get the RPC HTTP endpoint URI from an instantiated Web3 provider.""" for provider in web3_provider.providers: if isinstance(provider, HTTPProvider): self.endpoint_uri = provider.endpoint_uri self.timeout = provider.egs_timeout def _castAttributeDict(self, maybe_dict): """Return an AttributeDict as is provided by web3 middleware.""" if is_dict(maybe_dict) and not isinstance(maybe_dict, AttributeDict): return AttributeDict.recursive(maybe_dict) else: return maybe_dict def _formatTransactionResult(self, result): """Get proper types from returned hex.""" if isinstance(result, dict): for key, value in result.items(): if key == 'blockHash': pass elif key == 'hash': pass elif key == 'to': pass elif key == 'from': pass else: if isinstance(value, str): strlen = len(value) if strlen >= 3 and value[0:2] == '0x': result[key] = int(value, 16) return result class TxBatchError(Exception): pass