def test_fee_utils_indirectly( w3, fee_history_rewards, expected_max_prio_calc ) -> None: fail_max_prio_middleware = construct_error_generator_middleware( {RPCEndpoint("eth_maxPriorityFeePerGas"): lambda *_: ''} ) fee_history_result_middleware = construct_result_generator_middleware( {RPCEndpoint('eth_feeHistory'): lambda *_: {'reward': fee_history_rewards}} ) w3.middleware_onion.add(fail_max_prio_middleware, 'fail_max_prio') w3.middleware_onion.inject(fee_history_result_middleware, 'fee_history_result', layer=0) with pytest.warns( UserWarning, match="There was an issue with the method eth_maxPriorityFeePerGas. Calculating using " "eth_feeHistory." ): max_priority_fee = w3.eth.max_priority_fee assert is_integer(max_priority_fee) assert max_priority_fee == expected_max_prio_calc # clean up w3.middleware_onion.remove('fail_max_prio') w3.middleware_onion.remove('fee_history_result')
class RPC: # core getContent = RPCEndpoint("alexandria_getContent") retrieveContent = RPCEndpoint("alexandria_retrieveContent") # pinned addContent = RPCEndpoint("alexandria_addContent") deleteContent = RPCEndpoint("alexandria_deleteContent")
class RPC: alexandria_nodeId = RPCEndpoint('alexandria_nodeId') alexandria_routingTableStats = RPCEndpoint('alexandria_routingTableStats') alexandria_routingTableBucketInfo = RPCEndpoint('alexandria_routingTableBucketInfo') # network methods alexandria_ping = RPCEndpoint('alexandria_ping') alexandria_findNodes = RPCEndpoint('alexandria_findNodes') alexandria_advertise = RPCEndpoint('alexandria_advertise') alexandria_locate = RPCEndpoint('alexandria_locate') alexandria_retrieve = RPCEndpoint('alexandria_retrieve') # content alexandria_contentStats = RPCEndpoint('alexandria_contentStats') alexandria_addContent = RPCEndpoint('alexandria_addContent')
def test_alchemy_request_with_retry(): retries = 4 test_responses = [ # alchemy-specific failures RPCResponse(error=RPCError( code=-32000, message= 'Your app has exceeded its compute units per second capacity. If you have ' 'retries enabled, you can safely ignore this message. If not, ' 'check out https://docs.alchemyapi.io/guides/rate-limits')), RPCResponse( error= 'Your app has exceeded its compute units per second capacity. If you have retries enabled, ' 'you can safely ignore this message. If not, ' 'check out https://docs.alchemyapi.io/guides/rate-limits') ] for test_response in test_responses: make_request = Mock() make_request.return_value = test_response retry_middleware = AlchemyRetryRequestMiddleware( make_request=make_request, w3=Mock(), retries=retries, exponential_backoff=False) response = retry_middleware(method=RPCEndpoint('eth_call'), params=None) assert response == test_response assert make_request.call_count == ( retries + 1) # initial call, and then the number of retries
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: namespace, _, endpoint = method.partition('_') from eth_tester.exceptions import TransactionFailed try: delegator = self.api_endpoints[namespace][endpoint] except KeyError: return RPCResponse({ "error": "Unknown RPC Endpoint: {0}".format(method), }) try: response = delegator(self.ethereum_tester, params) except NotImplementedError: return RPCResponse({ "error": "RPC Endpoint has not been implemented: {0}".format(method), }) except TransactionFailed as e: if type(e.args[0]) == str: reason = e.args[0] else: reason = decode_single('(string)', e.args[0].args[0][4:])[0] raise SolidityError(f'execution reverted: {reason}') else: return { 'result': response, }
def build_method_validators(w3: "Web3", method: RPCEndpoint) -> FormattersDict: request_formatters = {} if RPCEndpoint(method) in METHODS_TO_VALIDATE: w3_chain_id = w3.eth.chain_id for method in METHODS_TO_VALIDATE: request_formatters[method] = _chain_id_validator(w3_chain_id) return _build_formatters_dict(request_formatters)
def check_if_retry_on_failure(method: RPCEndpoint) -> bool: root = method.split('_')[0] if root in whitelist: return True elif method in whitelist: return True else: return False
async def async_build_method_validators(async_w3: "Web3", method: RPCEndpoint) -> FormattersDict: request_formatters: Formatters = {} if RPCEndpoint(method) in METHODS_TO_VALIDATE: w3_chain_id = await async_w3.eth.chain_id # type: ignore for method in METHODS_TO_VALIDATE: request_formatters[method] = _chain_id_validator(w3_chain_id) return _build_formatters_dict(request_formatters)
class RPC: eth_getBlockByNumber = RPCEndpoint("eth_getBlockByNumber") eth_getBlockByHash = RPCEndpoint("eth_getBlockByHash") eth_getBlockTransactionCountByNumber = RPCEndpoint( "eth_getBlockTransactionCountByNumber") eth_getBlockTransactionCountByHash = RPCEndpoint( "eth_getBlockTransactionCountByHash") eth_getUncleCountByBlockNumber = RPCEndpoint( "eth_getUncleCountByBlockNumber") eth_getUncleCountByBlockHash = RPCEndpoint("eth_getUncleCountByBlockHash") eth_getUncleByBlockNumberAndIndex = RPCEndpoint( "eth_getUncleByBlockNumberAndIndex") eth_getUncleByBlockHashAndIndex = RPCEndpoint( "eth_getUncleByBlockHashAndIndex") eth_getTransactionByBlockNumberAndIndex = RPCEndpoint( "eth_getTransactionByBlockNumberAndIndex") eth_getTransactionByBlockHashAndIndex = RPCEndpoint( "eth_getTransactionByBlockHashAndIndex")
def isConnected(self) -> bool: try: response = self.make_request(RPCEndpoint('web3_clientVersion'), []) except IOError: return False assert response['jsonrpc'] == '2.0' assert 'error' not in response return True
class FlashbotsRPC: eth_sendBundle = RPCEndpoint("eth_sendBundle") eth_callBundle = RPCEndpoint("eth_callBundle") eth_sendPrivateTransaction = RPCEndpoint("eth_sendPrivateTransaction") eth_cancelPrivateTransaction = RPCEndpoint("eth_cancelPrivateTransaction") flashbots_getBundleStats = RPCEndpoint("flashbots_getBundleStats") flashbots_getUserStats = RPCEndpoint("flashbots_getUserStats")
def test_request_with_non_retry_exception(retry_middleware_class): def forbidden_request(method: RPCEndpoint, params: Any): raise HTTPError(response=Mock(status_code=400)) make_request = Mock() make_request.side_effect = forbidden_request retry_middleware = retry_middleware_class(make_request=make_request, w3=Mock(), exponential_backoff=False) with pytest.raises(HTTPError): retry_middleware(method=RPCEndpoint('web3_clientVersion'), params=None) assert make_request.call_count == 1 # only initial call, exception gets raised
def test_request_success_with_no_retry(retry_middleware_class): # Success Case - retry not needed make_request = Mock() make_request.return_value = SUCCESSFUL_RESPONSE retry_middleware = retry_middleware_class(make_request=make_request, w3=Mock(), retries=10, exponential_backoff=False) retry_response = retry_middleware(method=RPCEndpoint('web3_clientVersion'), params=None) assert retry_response == SUCCESSFUL_RESPONSE assert make_request.call_count == 1 # first call was successful, no need for retries
class RPC: # core getContent = RPCEndpoint("alexandria_getContent") # commons getCommonsContent = RPCEndpoint("alexandria_getCommonsContent") addCommonsContent = RPCEndpoint("alexandria_addCommonsContent") deleteCommonsContent = RPCEndpoint("alexandria_deleteCommonsContent") # pinned getPinnedContent = RPCEndpoint("alexandria_getPinnedContent") addPinnedContent = RPCEndpoint("alexandria_addPinnedContent") deletePinnedContent = RPCEndpoint("alexandria_deletePinnedContent")
def test_request_with_retry(retry_middleware_class): retries = 4 make_request = Mock() retry_middleware = retry_middleware_class(make_request=make_request, w3=Mock(), retries=retries, exponential_backoff=False) # Retry Case - RPCResponse fails due to limits, and retry required make_request.return_value = TOO_MANY_REQUESTS retry_response = retry_middleware(method=RPCEndpoint('web3_clientVersion'), params=None) assert retry_response == TOO_MANY_REQUESTS assert make_request.call_count == ( retries + 1) # initial call, and then the number of retries
def middleware(method: RPCEndpoint, params: Any) -> RPCResponse: if method != "eth_sendTransaction": return make_request(method, params) else: transaction = format_and_fill_tx(params[0]) if 'from' not in transaction: return make_request(method, params) elif transaction.get('from') not in accounts: return make_request(method, params) account = accounts[transaction['from']] raw_tx = account.sign_transaction(transaction).rawTransaction return make_request(RPCEndpoint("eth_sendRawTransaction"), [raw_tx])
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: namespace, _, endpoint = method.partition('_') try: delegator = self.api_endpoints[namespace][endpoint] except KeyError: return { "error": "Unknown RPC Endpoint: {0}".format(method), } try: response = delegator(self.ethereum_tester, params) except NotImplementedError: return { "error": "RPC Endpoint has not been implemented: {0}".format(method), } else: return { 'result': response, }
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: namespace, _, endpoint = method.partition('_') from eth_tester.exceptions import TransactionFailed try: delegator = self.api_endpoints[namespace][endpoint] except KeyError: return RPCResponse({"error": f"Unknown RPC Endpoint: {method}"}) try: response = delegator(self.ethereum_tester, params) except NotImplementedError: return RPCResponse( {"error": f"RPC Endpoint has not been implemented: {method}"}) except TransactionFailed as e: try: reason = decode_single('(string)', e.args[0].args[0][4:])[0] except (InsufficientDataBytes, AttributeError): reason = e.args[0] raise TransactionFailed(f'execution reverted: {reason}') else: return { 'result': response, }
def test_request_with_retry_exponential_backoff(): retries = 1 make_request = Mock() # Retry Case - RPCResponse fails due to limits, and retry required make_request.return_value = TOO_MANY_REQUESTS retry_middleware = RetryRequestMiddleware(make_request=make_request, w3=Mock(), retries=1, exponential_backoff=True) start = maya.now() retry_response = retry_middleware(RPCEndpoint('web3_clientVersion'), None) end = maya.now() assert retry_response == TOO_MANY_REQUESTS assert make_request.call_count == ( retries + 1) # initial call, and then the number of retries # check exponential backoff delta = end - start assert delta.total_seconds() >= 2**retries
def test_infura_request_with_retry(): retries = 4 test_responses = [ # infura-specific failures { "jsonrpc": "2.0", "id": 1, "error": { "code": -32005, "message": "project ID request rate exceeded", "data": { "see": "https://infura.io/docs/ethereum/jsonrpc/ratelimits", "current_rps": 13.333, "allowed_rps": 10.0, "backoff_seconds": 30.0, } } }, ] for test_response in test_responses: make_request = Mock() make_request.return_value = test_response retry_middleware = InfuraRetryRequestMiddleware( make_request=make_request, w3=Mock(), retries=retries, exponential_backoff=False) response = retry_middleware(method=RPCEndpoint('eth_blockNumber'), params=None) assert response == test_response assert make_request.call_count == ( retries + 1) # initial call, and then the number of retries
'gas_used': 'gasUsed', 'base_fee_per_gas': 'baseFeePerGas', } block_result_remapper = apply_key_map(BLOCK_RESULT_KEY_MAPPING) RECEIPT_RESULT_FORMATTERS = { 'logs': apply_formatter_to_array(log_result_remapper), } receipt_result_formatter = apply_formatters_to_dict(RECEIPT_RESULT_FORMATTERS) ethereum_tester_middleware = construct_formatting_middleware( request_formatters={ # Eth RPCEndpoint('eth_getBlockByNumber'): apply_formatters_to_args( apply_formatter_if(is_not_named_block, to_integer_if_hex), ), RPCEndpoint('eth_getFilterChanges'): apply_formatters_to_args(hex_to_integer), RPCEndpoint('eth_getFilterLogs'): apply_formatters_to_args(hex_to_integer), RPCEndpoint('eth_getBlockTransactionCountByNumber'): apply_formatters_to_args( apply_formatter_if(is_not_named_block, to_integer_if_hex), ), RPCEndpoint('eth_getUncleCountByBlockNumber'): apply_formatters_to_args( apply_formatter_if(is_not_named_block, to_integer_if_hex), ), RPCEndpoint('eth_getTransactionByBlockHashAndIndex'): apply_formatters_to_args( identity, to_integer_if_hex, ), RPCEndpoint('eth_getTransactionByBlockNumberAndIndex'): apply_formatters_to_args(
def _query_and_track( self, from_block: BlockNumber, to_block: BlockNumber) -> Tuple[List[DecodedEvent], float]: """Query the blockchain up to `to_block` and create the filters for the smart contracts deployed during the current batch. Because of how polling is optimized, filters for smart contracts deployed in the current batch must be created, queried, and be merged into the same batch. This is necessary to avoid race conditions on restarts that could lead to loss of events. Example: last confirmed block | v v end of current batch / new confirmed block 4 9 Batch ####------ TNR ####--*--- TN --*- ^ ^ | new channel openned | new token network registered For this example, the current batch is fetching the range `[4, 9]`. In this range a new token is registered at block 6, at block 8 a new channel is openned in the new network. If the events of the new TN are *not* queried, block 9 will be confirmed after processing the batch which adds the TN, and iff the node crashes right after processing this batch, on the next restart *all* filters will start from 9, thus missing the event for the new channel on block 8. """ filters_to_query: Iterable[SmartContractEvents] request_duration: float = 0 result: List[DecodedEvent] = [] filters_to_query = self._address_to_filters.values() # While there are new smart contracts to follow, this will query them # and add to the existing filters. # # The batch itself may have an event for a newly deployed smart # contract, e.g. a new token network. The new smart contract needs a # filter, and then the filter has to be queried before for the same # batch before it is dispatched. This is necessary to guarantee safety # of restarts. while filters_to_query: filter_params = filters_to_rpc(filters_to_query, from_block, to_block) log.debug("StatelessFilter: querying new entries", filter_params=filter_params) try: start = time.monotonic() # Using web3 because: # - It sets an unique request identifier, not strictly necessary. # - To avoid another abstraction to query the Ethereum client. blockchain_events: List[ LogReceipt] = self.web3.manager.request_blocking( RPCEndpoint("eth_getLogs"), [filter_params]) request_duration = time.monotonic() - start except ReadTimeout as ex: # The request timed out while waiting for a response (as opposed to a # ConnectTimeout). # This will usually be caused by overloading of the target eth node but can also # happen due to network conditions. raise EthGetLogsTimeout() from ex log.debug( "StatelessFilter: fetched new entries", filter_params=filter_params, blockchain_events=blockchain_events, request_duration=request_duration, ) if blockchain_events: decoded_events = [ decode_raiden_event_to_internal(self.event_to_abi(event), self.chain_id, event) for event in blockchain_events ] result.extend(decoded_events) # Go throught he results and create the child filters, if # necessary. # # The generator result is converted to a list because we need # to iterate over it twice filters_to_query = list( new_filters_from_events(self.contract_manager, decoded_events)) # Register the new filters, so that they will be fetched on the next iteration self._address_to_filters.update( (new_filter.contract_address, new_filter) for new_filter in filters_to_query) else: filters_to_query = [] return result, request_duration
class FlashbotsRPC: eth_sendBundle = RPCEndpoint("eth_sendBundle") eth_callBundle = RPCEndpoint("eth_callBundle")
import functools from cachetools import LRUCache from web3.gas_strategies.time_based import construct_time_based_gas_price_strategy from web3.middleware.cache import construct_simple_cache_middleware from web3.types import RPCEndpoint BLOCK_HASH_CACHE_RPC_WHITELIST = {RPCEndpoint("eth_getBlockByHash")} block_hash_cache_middleware = construct_simple_cache_middleware( # default sample size of gas price strategies is 120 cache_class=functools.partial(LRUCache, 150), # type: ignore rpc_whitelist=BLOCK_HASH_CACHE_RPC_WHITELIST, ) faster_gas_price_strategy = construct_time_based_gas_price_strategy( max_wait_seconds=15, sample_size=120, probability=99 )
from eth_utils.curried import ( # type: ignore apply_formatters_to_dict, apply_key_map, ) from eth_utils.toolz import ( compose, ) from hexbytes import ( HexBytes, ) from web3.middleware.formatting import ( construct_formatting_middleware, ) from web3.types import ( RPCEndpoint, ) remap_geth_poa_fields = apply_key_map({ 'extraData': 'proofOfAuthorityData', }) pythonic_geth_poa = apply_formatters_to_dict({ 'proofOfAuthorityData': HexBytes, }) geth_poa_cleanup = compose(pythonic_geth_poa, remap_geth_poa_fields) geth_poa_middleware = construct_formatting_middleware(result_formatters={ RPCEndpoint("eth_getBlockByHash"): geth_poa_cleanup, RPCEndpoint("eth_getBlockByNumber"): geth_poa_cleanup, }, )
class RPC: # admin admin_addPeer = RPCEndpoint("admin_addPeer") admin_datadir = RPCEndpoint("admin_datadir") admin_nodeInfo = RPCEndpoint("admin_nodeInfo") admin_peers = RPCEndpoint("admin_peers") admin_startRPC = RPCEndpoint("admin_startRPC") admin_startWS = RPCEndpoint("admin_startWS") admin_stopRPC = RPCEndpoint("admin_stopRPC") admin_stopWS = RPCEndpoint("admin_stopWS") # eth eth_accounts = RPCEndpoint("eth_accounts") eth_blockNumber = RPCEndpoint("eth_blockNumber") eth_call = RPCEndpoint("eth_call") eth_chainId = RPCEndpoint("eth_chainId") eth_coinbase = RPCEndpoint("eth_coinbase") eth_estimateGas = RPCEndpoint("eth_estimateGas") eth_feeHistory = RPCEndpoint("eth_feeHistory") eth_maxPriorityFeePerGas = RPCEndpoint("eth_maxPriorityFeePerGas") eth_gasPrice = RPCEndpoint("eth_gasPrice") eth_getBalance = RPCEndpoint("eth_getBalance") eth_getBlockByHash = RPCEndpoint("eth_getBlockByHash") eth_getBlockByNumber = RPCEndpoint("eth_getBlockByNumber") eth_getBlockTransactionCountByHash = RPCEndpoint( "eth_getBlockTransactionCountByHash") eth_getBlockTransactionCountByNumber = RPCEndpoint( "eth_getBlockTransactionCountByNumber") eth_getCode = RPCEndpoint("eth_getCode") eth_getFilterChanges = RPCEndpoint("eth_getFilterChanges") eth_getFilterLogs = RPCEndpoint("eth_getFilterLogs") eth_getLogs = RPCEndpoint("eth_getLogs") eth_getProof = RPCEndpoint("eth_getProof") eth_getRawTransactionByHash = RPCEndpoint("eth_getRawTransactionByHash") eth_getStorageAt = RPCEndpoint("eth_getStorageAt") eth_getTransactionByBlockHashAndIndex = RPCEndpoint( "eth_getTransactionByBlockHashAndIndex") eth_getTransactionByBlockNumberAndIndex = RPCEndpoint( "eth_getTransactionByBlockNumberAndIndex") eth_getRawTransactionByBlockHashAndIndex = RPCEndpoint( "eth_getRawTransactionByBlockHashAndIndex") eth_getRawTransactionByBlockNumberAndIndex = RPCEndpoint( "eth_getRawTransactionByBlockNumberAndIndex") eth_getTransactionByHash = RPCEndpoint("eth_getTransactionByHash") eth_getTransactionCount = RPCEndpoint("eth_getTransactionCount") eth_getTransactionReceipt = RPCEndpoint("eth_getTransactionReceipt") eth_getUncleByBlockHashAndIndex = RPCEndpoint( "eth_getUncleByBlockHashAndIndex") eth_getUncleByBlockNumberAndIndex = RPCEndpoint( "eth_getUncleByBlockNumberAndIndex") eth_getUncleCountByBlockHash = RPCEndpoint("eth_getUncleCountByBlockHash") eth_getUncleCountByBlockNumber = RPCEndpoint( "eth_getUncleCountByBlockNumber") eth_getWork = RPCEndpoint("eth_getWork") eth_hashrate = RPCEndpoint("eth_hashrate") eth_mining = RPCEndpoint("eth_mining") eth_newBlockFilter = RPCEndpoint("eth_newBlockFilter") eth_newFilter = RPCEndpoint("eth_newFilter") eth_newPendingTransactionFilter = RPCEndpoint( "eth_newPendingTransactionFilter") eth_protocolVersion = RPCEndpoint("eth_protocolVersion") eth_sendRawTransaction = RPCEndpoint("eth_sendRawTransaction") eth_sendTransaction = RPCEndpoint("eth_sendTransaction") eth_sign = RPCEndpoint("eth_sign") eth_signTransaction = RPCEndpoint("eth_signTransaction") eth_signTypedData = RPCEndpoint("eth_signTypedData") eth_submitHashrate = RPCEndpoint("eth_submitHashrate") eth_submitWork = RPCEndpoint("eth_submitWork") eth_syncing = RPCEndpoint("eth_syncing") eth_uninstallFilter = RPCEndpoint("eth_uninstallFilter") # evm evm_mine = RPCEndpoint("evm_mine") evm_reset = RPCEndpoint("evm_reset") evm_revert = RPCEndpoint("evm_revert") evm_snapshot = RPCEndpoint("evm_snapshot") # miner miner_makeDag = RPCEndpoint("miner_makeDag") miner_setExtra = RPCEndpoint("miner_setExtra") miner_setEtherbase = RPCEndpoint("miner_setEtherbase") miner_setGasPrice = RPCEndpoint("miner_setGasPrice") miner_start = RPCEndpoint("miner_start") miner_stop = RPCEndpoint("miner_stop") miner_startAutoDag = RPCEndpoint("miner_startAutoDag") miner_stopAutoDag = RPCEndpoint("miner_stopAutoDag") # net net_listening = RPCEndpoint("net_listening") net_peerCount = RPCEndpoint("net_peerCount") net_version = RPCEndpoint("net_version") # parity parity_addReservedPeer = RPCEndpoint("parity_addReservedPeer") parity_enode = RPCEndpoint("parity_enode") parity_listStorageKeys = RPCEndpoint("parity_listStorageKeys") parity_netPeers = RPCEndpoint("parity_netPeers") parity_mode = RPCEndpoint("parity_mode") parity_setMode = RPCEndpoint("parity_setMode") # personal personal_ecRecover = RPCEndpoint("personal_ecRecover") personal_importRawKey = RPCEndpoint("personal_importRawKey") personal_listAccounts = RPCEndpoint("personal_listAccounts") personal_listWallets = RPCEndpoint("personal_listWallets") personal_lockAccount = RPCEndpoint("personal_lockAccount") personal_newAccount = RPCEndpoint("personal_newAccount") personal_sendTransaction = RPCEndpoint("personal_sendTransaction") personal_sign = RPCEndpoint("personal_sign") personal_signTypedData = RPCEndpoint("personal_signTypedData") personal_unlockAccount = RPCEndpoint("personal_unlockAccount") # testing testing_timeTravel = RPCEndpoint("testing_timeTravel") # trace trace_block = RPCEndpoint("trace_block") trace_call = RPCEndpoint("trace_call") trace_filter = RPCEndpoint("trace_filter") trace_rawTransaction = RPCEndpoint("trace_rawTransaction") trace_replayBlockTransactions = RPCEndpoint( "trace_replayBlockTransactions") trace_replayTransaction = RPCEndpoint("trace_replayTransaction") trace_transaction = RPCEndpoint("trace_transaction") # txpool txpool_content = RPCEndpoint("txpool_content") txpool_inspect = RPCEndpoint("txpool_inspect") txpool_status = RPCEndpoint("txpool_status") # web3 web3_clientVersion = RPCEndpoint("web3_clientVersion")
class RPC: # eth eth_accounts = RPCEndpoint("eth_accounts") eth_blockNumber = RPCEndpoint("eth_blockNumber") eth_call = RPCEndpoint("eth_call") eth_chainId = RPCEndpoint("eth_chainId") eth_coinbase = RPCEndpoint("eth_coinbase") eth_estimateGas = RPCEndpoint("eth_estimateGas") eth_gasPrice = RPCEndpoint("eth_gasPrice") eth_getBalance = RPCEndpoint("eth_getBalance") eth_getBlockByHash = RPCEndpoint("eth_getBlockByHash") eth_getBlockByNumber = RPCEndpoint("eth_getBlockByNumber") eth_getBlockTransactionCountByHash = RPCEndpoint( "eth_getBlockTransactionCountByHash") eth_getBlockTransactionCountByNumber = RPCEndpoint( "eth_getBlockTransactionCountByNumber") eth_getCode = RPCEndpoint("eth_getCode") eth_getFilterChanges = RPCEndpoint("eth_getFilterChanges") eth_getFilterLogs = RPCEndpoint("eth_getFilterLogs") eth_getLogs = RPCEndpoint("eth_getLogs") eth_getProof = RPCEndpoint("eth_getProof") eth_getStorageAt = RPCEndpoint("eth_getStorageAt") eth_getTransactionByBlockHashAndIndex = RPCEndpoint( "eth_getTransactionByBlockHashAndIndex") eth_getTransactionByBlockNumberAndIndex = RPCEndpoint( "eth_getTransactionByBlockNumberAndIndex") eth_getTransactionByHash = RPCEndpoint("eth_getTransactionByHash") eth_getTransactionCount = RPCEndpoint("eth_getTransactionCount") eth_getTransactionReceipt = RPCEndpoint("eth_getTransactionReceipt") eth_getUncleByBlockHashAndIndex = RPCEndpoint( "eth_getUncleByBlockHashAndIndex") eth_getUncleByBlockNumberAndIndex = RPCEndpoint( "eth_getUncleByBlockNumberAndIndex") eth_getUncleCountByBlockHash = RPCEndpoint("eth_getUncleCountByBlockHash") eth_getUncleCountByBlockNumber = RPCEndpoint( "eth_getUncleCountByBlockNumber") eth_getWork = RPCEndpoint("eth_getWork") eth_hashrate = RPCEndpoint("eth_hashrate") eth_mining = RPCEndpoint("eth_mining") eth_newBlockFilter = RPCEndpoint("eth_newBlockFilter") eth_newFilter = RPCEndpoint("eth_newFilter") eth_newPendingTransactionFilter = RPCEndpoint( "eth_newPendingTransactionFilter") eth_protocolVersion = RPCEndpoint("eth_protocolVersion") eth_sendRawTransaction = RPCEndpoint("eth_sendRawTransaction") eth_sendTransaction = RPCEndpoint("eth_sendTransaction") eth_sign = RPCEndpoint("eth_sign") eth_signTransaction = RPCEndpoint("eth_signTransaction") eth_signTypedData = RPCEndpoint("eth_signTypedData") eth_submitHashrate = RPCEndpoint("eth_submitHashrate") eth_submitWork = RPCEndpoint("eth_submitWork") eth_syncing = RPCEndpoint("eth_syncing") eth_uninstallFilter = RPCEndpoint("eth_uninstallFilter") # personal personal_ecRecover = RPCEndpoint("personal_ecRecover") personal_importRawKey = RPCEndpoint("personal_importRawKey") personal_listAccounts = RPCEndpoint("personal_listAccounts") personal_newAccount = RPCEndpoint("personal_newAccount") personal_sendTransaction = RPCEndpoint("personal_sendTransaction") personal_sign = RPCEndpoint("personal_sign") personal_signTypedData = RPCEndpoint("personal_signTypedData") # evm evm_mine = RPCEndpoint("evm_mine") evm_reset = RPCEndpoint("evm_reset") evm_revert = RPCEndpoint("evm_revert") evm_snapshot = RPCEndpoint("evm_snapshot") # net net_listening = RPCEndpoint("net_listening") net_peerCount = RPCEndpoint("net_peerCount") net_version = RPCEndpoint("net_version") # trace trace_block = RPCEndpoint("trace_block") trace_call = RPCEndpoint("trace_call") trace_filter = RPCEndpoint("trace_filter") trace_rawTransaction = RPCEndpoint("trace_rawTransaction") trace_replayBlockTransactions = RPCEndpoint( "trace_replayBlockTransactions") trace_replayTransaction = RPCEndpoint("trace_replayTransaction") trace_transaction = RPCEndpoint("trace_transaction") # testing testing_timeTravel = RPCEndpoint("testing_timeTravel") # shh shh_addPrivateKey = RPCEndpoint("shh_addPrivateKey") shh_addSymKey = RPCEndpoint("shh_addSymKey") shh_deleteKey = RPCEndpoint("shh_deleteKey") shh_deleteKeyPair = RPCEndpoint("shh_deleteKeyPair") shh_deleteMessageFilter = RPCEndpoint("shh_deleteMessageFilter") shh_deleteSymKey = RPCEndpoint("shh_deleteSymKey") shh_generateSymKeyFromPassword = RPCEndpoint( "shh_generateSymKeyFromPassword") shh_getFilterMessages = RPCEndpoint("shh_getFilterMessages") shh_getPrivateKey = RPCEndpoint("shh_getPrivateKey") shh_getPublicKey = RPCEndpoint("shh_getPublicKey") shh_getSymKey = RPCEndpoint("shh_getSymKey") shh_hasKeyPair = RPCEndpoint("shh_hasKeyPair") shh_hasSymKey = RPCEndpoint("shh_hasSymKey") shh_info = RPCEndpoint("shh_info") shh_markTrustedPeer = RPCEndpoint("shh_markTrustedPeer") shh_newKeyPair = RPCEndpoint("shh_newKeyPair") shh_newMessageFilter = RPCEndpoint("shh_newMessageFilter") shh_newSymKey = RPCEndpoint("shh_newSymKey") shh_post = RPCEndpoint("shh_post") shh_setMaxMessageSize = RPCEndpoint("shh_setMaxMessageSize") shh_setMinPoW = RPCEndpoint("shh_setMinPoW") shh_subscribe = RPCEndpoint("shh_subscribe") shh_unsubscribe = RPCEndpoint("shh_unsubscribe") shh_version = RPCEndpoint("shh_version") # admin admin_addPeer = RPCEndpoint("admin_addPeer") admin_datadir = RPCEndpoint("admin_datadir") admin_nodeInfo = RPCEndpoint("admin_nodeInfo") admin_peers = RPCEndpoint("admin_peers") admin_startRPC = RPCEndpoint("admin_startRPC") admin_startWS = RPCEndpoint("admin_startWS") admin_stopRPC = RPCEndpoint("admin_stopRPC") admin_stopWS = RPCEndpoint("admin_stopWS") # txpool txpool_content = RPCEndpoint("txpool_content") txpool_inspect = RPCEndpoint("txpool_inspect") txpool_status = RPCEndpoint("txpool_status") # web3 web3_clientVersion = RPCEndpoint("web3_clientVersion") # parity parity_addReservedPeer = RPCEndpoint("parity_addReservedPeer") parity_enode = RPCEndpoint("parity_enode") parity_listStorageKeys = RPCEndpoint("parity_listStorageKeys") parity_netPeers = RPCEndpoint("parity_netPeers") parity_mode = RPCEndpoint("parity_mode") parity_setMode = RPCEndpoint("parity_setMode")
transaction_formatter = apply_formatters_to_dict(TRANSACTION_FORMATTERS) RECEIPT_FORMATTERS = { 'logs': apply_formatter_to_array(log_key_remapper), } receipt_formatter = apply_formatters_to_dict(RECEIPT_FORMATTERS) transaction_params_transformer = compose(transaction_params_remapper, transaction_params_formatter) ethereum_tester_middleware = construct_formatting_middleware( request_formatters={ # Eth RPCEndpoint('eth_getBlockByNumber'): apply_formatters_to_args( apply_formatter_if(is_not_named_block, to_integer_if_hex), ), RPCEndpoint('eth_getFilterChanges'): apply_formatters_to_args(hex_to_integer), RPCEndpoint('eth_getFilterLogs'): apply_formatters_to_args(hex_to_integer), RPCEndpoint('eth_getBlockTransactionCountByNumber'): apply_formatters_to_args( apply_formatter_if(is_not_named_block, to_integer_if_hex), ), RPCEndpoint('eth_getUncleCountByBlockNumber'): apply_formatters_to_args( apply_formatter_if(is_not_named_block, to_integer_if_hex), ), RPCEndpoint('eth_getTransactionByBlockHashAndIndex'): apply_formatters_to_args( identity,
def _query_and_track( self, from_block: BlockNumber, to_block: BlockNumber ) -> Tuple[List[DecodedEvent], float]: """Query the blockchain up to `to_block` and create the filters for the smart contracts deployed during the current batch. Because of how polling is optimized, filters for smart contracts deployed in the current batch must be created, queried, and be merged into the same batch. This is necessary to avoid race conditions on restarts that could lead to loss of events. Example: last confirmed block | v v end of current batch / new confirmed block 4 9 Batch ####------ TNR ####--*--- TN --*- ^ ^ | new channel opened | new token network registered For this example, the current batch is fetching the range `[4, 9]`. In this range a new token is registered at block 6, at block 8 a new channel is opened in the new network. If the events of the new TN are *not* queried, block 9 will be confirmed after processing the batch which adds the TN, and iff the node crashes right after processing this batch, on the next restart *all* filters will start from 9, thus missing the event for the new channel on block 8. """ max_request_duration: float = 0 result: List[DecodedEvent] = [] event_filter: Optional[RaidenContractFilter] = self.event_filter # While there are new smart contracts to follow, this will query them # and add to the existing filters. # # The batch itself may have an event for a newly deployed smart # contract, e.g. a new token network. The new smart contract needs a # filter, and then the filter has to be queried before for the same # batch before it is dispatched. This is necessary to guarantee safety # of restarts. i = 0 while event_filter: i += 1 blockchain_events: List[LogReceipt] = [] for filter_params in event_filter.to_web3_filters( self.contract_manager, from_block, to_block, self.node_address ): log.debug( "Querying new blockchain events", from_block=from_block, to_block=to_block, event_filter=event_filter, filter_params=filter_params, i=i, node=to_checksum_address(self.node_address), ) filter_name = filter_params.pop("_name") # type: ignore try: start = time.monotonic() # Using web3 because: # - It sets an unique request identifier, not strictly necessary. # - To avoid another abstraction to query the Ethereum client. new_events: List[LogReceipt] = self.web3.manager.request_blocking( RPCEndpoint("eth_getLogs"), [filter_params] ) request_duration = time.monotonic() - start max_request_duration = max(max_request_duration, request_duration) except ReadTimeout as ex: # The request timed out while waiting for a response (as opposed to a # ConnectTimeout). # This will usually be caused by overloading of the target # eth node but can also happen due to network conditions. raise EthGetLogsTimeout() from ex log.debug( "Fetched new blockchain events", from_block=filter_params["fromBlock"], to_block=filter_params["toBlock"], addresses=filter_params["address"], filter_name=filter_name, new_events=new_events, request_duration=request_duration, i=i, node=to_checksum_address(self.node_address), ) blockchain_events.extend(new_events) if blockchain_events: # If this should ever decode events from non-controlled contracts, we need # to make sure no unrecoverable error is thrown. If this was an unrecoverable # it would open a surface for attacks. decoded_events = [ decode_raiden_event_to_internal( self._address_to_abi[to_canonical_address(event["address"])], self.chain_id, event, ) for event in blockchain_events ] sort_events(decoded_events) from dataclasses import asdict log.debug( "Decoded new blockchain events", decoded_events=[asdict(e) for e in decoded_events], node=to_checksum_address(self.node_address), ) result.extend(decoded_events) # Go through the results and create the child filters, if necessary. event_filter = new_filters_from_events(decoded_events) # Register the new filters, so that they will be fetched on the next iteration self.event_filter = self.event_filter.union(event_filter) self._address_to_abi.update( event_filter.abi_of_contract_address(self.contract_manager) ) else: event_filter = None return result, max_request_duration
class RPC: nodeInfo = RPCEndpoint("discv5_nodeInfo") routingTableInfo = RPCEndpoint("discv5_routingTableInfo") ping = RPCEndpoint("discv5_ping")