From d3627d81fd135a1fc7334403e20b141fb4bcd663 Mon Sep 17 00:00:00 2001 From: nolash Date: Thu, 6 Aug 2020 09:41:42 +0200 Subject: [PATCH] Add middleware example in scripts --- scripts/server.py | 30 +++++++++++--- scripts/web3_middleware.py | 81 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 scripts/web3_middleware.py diff --git a/scripts/server.py b/scripts/server.py index 57df180..0584294 100644 --- a/scripts/server.py +++ b/scripts/server.py @@ -53,9 +53,10 @@ methods = { } -def jsonrpc_error(id, err): +def jsonrpc_error(rpc_id, err): return { 'json-rpc': '2.0', + 'id': rpc_id, 'error': { 'code': err.CODE, 'message': err.MESSAGE, @@ -71,6 +72,12 @@ def jsonrpc_ok(rpc_id, response): } +def is_valid_json(j): + if j.get('id') == 'None': + raise ValueError('id missing') + return True + + def process_input(j): rpc_id = j['id'] @@ -81,20 +88,33 @@ def process_input(j): def start_server(): - os.unlink('/tmp/foo.ipc') + try: + os.unlink('/tmp/foo.ipc') + except FileNotFoundError: + pass s = socket.socket(family = socket.AF_UNIX, type = socket.SOCK_STREAM) s.bind('/tmp/foo.ipc') s.listen(10) while True: (csock, caddr) = s.accept() d = csock.recv(4096) + j = None try: - j = json.loads(b) - process_input(j) + j = json.loads(d) + is_valid_json(j) logg.debug('{}'.format(d.decode('utf-8'))) - csock.send(json.dumps(jsonrpc_ok(0, [])).encode('utf-8')) except: csock.send(json.dumps(jsonrpc_error(None, JSONRPCParseError)).encode('utf-8')) + csock.close() + continue + + try: + (rpc_id, r) = process_input(j) + csock.send(json.dumps(jsonrpc_ok(rpc_id, r)).encode('utf-8')) + except: + # TODO: handle cases to give better error context to caller + csock.send(json.dumps(jsonrpc_error(j['id'], JSONRPCServerError)).encode('utf-8')) + csock.close() s.close() diff --git a/scripts/web3_middleware.py b/scripts/web3_middleware.py new file mode 100644 index 0000000..821ee9f --- /dev/null +++ b/scripts/web3_middleware.py @@ -0,0 +1,81 @@ +import logging +import re +import socket +import uuid +import json + +from web3 import Web3, WebsocketProvider, IPCProvider + + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger('foo') + + +def jsonrpc_request(method, params): + uu = uuid.uuid4() + return { + "jsonrpc": "2.0", + "id": str(uu), + "method": method, + "params": params, + } + +class PlatformMiddleware: + + # id for the request is not available, meaning we cannot easily short-circuit + # hack workaround + id_seq = -1 + re_personal = re.compile('^personal_.*') + ipcaddr = '/tmp/foo.ipc' + + + def __init__(self, make_request, w3): + self.w3 = w3 + self.make_request = make_request + + + # single entry input gives a tuple on params, wtf... + @staticmethod + def _translate_params(params): + if params.__class__.__name__ == 'tuple': + r = [] + for p in params: + r.append(p) + return r + + + def __call__(self, method, suspect_params): + self.id_seq += 1 + params = PlatformMiddleware._translate_params(suspect_params) + + logg.debug('method {} params {} original paramsĀ {}'.format(method, params, suspect_params)) + if self.re_personal.match(method) != None: + # multiple providers is broken in web3.py 5.12.0 + # https://github.com/ethereum/web3.py/issues/1701 + # hack workaround + s = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM, proto=0) + ipc_provider_workaround = s.connect(self.ipcaddr) + + logg.debug('redirecting method {}'.format(method)) + o = jsonrpc_request(method, params) + j = json.dumps(o) + logg.debug('send {}'.format(j)) + s.send(j.encode('utf-8')) + r = s.recv(4096) + s.close() + logg.debug('got recv {}'.format(str(r))) + jr = json.loads(r) + jr['id'] = self.id_seq + #return str(json.dumps(jr)) + return jr + + r = self.make_request(method, params) + logg.debug('retular response {}'.format(r)) + return r + + +w3 = Web3(WebsocketProvider('ws://127.0.0.1:8546')) +w3.eth.personal = w3.geth.personal +w3.middleware_onion.add(PlatformMiddleware) +print(w3.eth.personal.newAccount('foo')) +#print(w3.eth.blockNumber)