From ed68fe40c1f7ed62552044c196b24443563a1fd0 Mon Sep 17 00:00:00 2001 From: Forrest Voight Date: Tue, 14 Aug 2012 01:35:15 -0400 Subject: [PATCH] dynamically create subclasses of jsonrpc.Error for individual error codes so they can be caught more flexibly --- p2pool/bitcoin/height_tracker.py | 7 ++++--- p2pool/main.py | 8 +++----- p2pool/util/jsonrpc.py | 24 +++++++++++++++++------- p2pool/work.py | 6 +++--- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/p2pool/bitcoin/height_tracker.py b/p2pool/bitcoin/height_tracker.py index 201aed5..b54b8e6 100644 --- a/p2pool/bitcoin/height_tracker.py +++ b/p2pool/bitcoin/height_tracker.py @@ -96,10 +96,11 @@ def get_height_rel_highest_func(bitcoind, factory, best_block_func, net): def height_cacher(block_hash): try: x = yield bitcoind.rpc_getblock('%x' % (block_hash,)) - except jsonrpc.Error, e: - if e.code == -5 and not p2pool.DEBUG: + except jsonrpc.Error_for_code(-5): # Block not found + if not p2pool.DEBUG: raise deferral.RetrySilentlyException() - raise + else: + raise defer.returnValue(x['blockcount'] if 'blockcount' in x else x['height']) best_height_cached = variable.Variable((yield deferral.retry()(height_cacher)(best_block_func()))) def get_height_rel_highest(block_hash): diff --git a/p2pool/main.py b/p2pool/main.py index c3cede8..d3425b6 100644 --- a/p2pool/main.py +++ b/p2pool/main.py @@ -31,11 +31,9 @@ import p2pool, p2pool.data as p2pool_data def getwork(bitcoind): try: work = yield bitcoind.rpc_getmemorypool() - except jsonrpc.Error, e: - if e.code == -32601: # Method not found - print >>sys.stderr, 'Error: Bitcoin version too old! Upgrade to v0.5 or newer!' - raise deferral.RetrySilentlyException() - raise + except jsonrpc.Error_for_code(-32601): # Method not found + print >>sys.stderr, 'Error: Bitcoin version too old! Upgrade to v0.5 or newer!' + raise deferral.RetrySilentlyException() packed_transactions = [x.decode('hex') for x in work['transactions']] if 'height' not in work: work['height'] = (yield bitcoind.rpc_getblock(work['previousblockhash']))['height'] + 1 diff --git a/p2pool/util/jsonrpc.py b/p2pool/util/jsonrpc.py index adf3c21..aa334a6 100644 --- a/p2pool/util/jsonrpc.py +++ b/p2pool/util/jsonrpc.py @@ -1,15 +1,18 @@ from __future__ import division import json +import weakref from twisted.internet import defer from twisted.python import log from twisted.web import client, error -import deferred_resource +from p2pool.util import deferred_resource, memoize class Error(Exception): def __init__(self, code, message, data=None): + if type(self) is Error: + raise TypeError("can't directly instantiate Error class; use Error_for_code") if not isinstance(code, int): raise TypeError('code must be an int') #if not isinstance(message, unicode): @@ -24,6 +27,13 @@ class Error(Exception): 'data': self.data, } +@memoize.memoize_with_backing(weakref.WeakValueDictionary()) +def Error_for_code(code): + class NarrowError(Error): + def __init__(self, *args, **kwargs): + Error.__init__(self, code, *args, **kwargs) + return NarrowError + class Proxy(object): def __init__(self, url, headers={}, timeout=5): self._url = url @@ -58,7 +68,7 @@ class Proxy(object): if resp['id'] != id_: raise ValueError('invalid id') if 'error' in resp and resp['error'] is not None: - raise Error(**resp['error']) + raise Error_for_code(resp['error']['code'])(resp['error']['message'], resp['error'].get('data', None)) defer.returnValue(resp['result']) def __getattr__(self, attr): @@ -82,19 +92,19 @@ class Server(deferred_resource.DeferredResource): try: req = json.loads(data) except Exception: - raise Error(-32700, u'Parse error') + raise Error_for_code(-32700)(u'Parse error') id_ = req.get('id', None) method = req.get('method', None) if not isinstance(method, basestring): - raise Error(-32600, u'Invalid Request') + raise Error_for_code(-32600)(u'Invalid Request') params = req.get('params', []) if not isinstance(params, list): - raise Error(-32600, u'Invalid Request') + raise Error_for_code(-32600)(u'Invalid Request') method_meth = getattr(self._provider, 'rpc_' + method, None) if method_meth is None: - raise Error(-32601, u'Method not found') + raise Error_for_code(-32601)(u'Method not found') result = yield method_meth(request, *params) error = None @@ -102,7 +112,7 @@ class Server(deferred_resource.DeferredResource): raise except Exception: log.err(None, 'Squelched JSON error:') - raise Error(-32099, u'Unknown error') + raise Error_for_code(-32099)(u'Unknown error') except Error, e: result = None error = e._to_obj() diff --git a/p2pool/work.py b/p2pool/work.py index b430d8b..e98831c 100644 --- a/p2pool/work.py +++ b/p2pool/work.py @@ -162,11 +162,11 @@ class WorkerBridge(worker_interface.WorkerBridge): def get_work(self, pubkey_hash, desired_share_target, desired_pseudoshare_target): if len(self.p2p_node.peers) == 0 and self.net.PERSIST: - raise jsonrpc.Error(-12345, u'p2pool is not connected to any peers') + raise jsonrpc.Error_for_code(-12345)(u'p2pool is not connected to any peers') if self.best_share_var.value is None and self.net.PERSIST: - raise jsonrpc.Error(-12345, u'p2pool is downloading shares') + raise jsonrpc.Error_for_code(-12345)(u'p2pool is downloading shares') if time.time() > self.current_work.value['last_update'] + 60: - raise jsonrpc.Error(-12345, u'lost contact with bitcoind') + raise jsonrpc.Error_for_code(-12345)(u'lost contact with bitcoind') if self.merged_work.value: tree, size = bitcoin_data.make_auxpow_tree(self.merged_work.value) -- 1.7.1