dynamically create subclasses of jsonrpc.Error for individual error codes so they...
authorForrest Voight <forrest.voight@gmail.com>
Tue, 14 Aug 2012 05:35:15 +0000 (01:35 -0400)
committerForrest Voight <forrest.voight@gmail.com>
Tue, 14 Aug 2012 18:55:45 +0000 (14:55 -0400)
p2pool/bitcoin/height_tracker.py
p2pool/main.py
p2pool/util/jsonrpc.py
p2pool/work.py

index 201aed5..b54b8e6 100644 (file)
@@ -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):
index c3cede8..d3425b6 100644 (file)
@@ -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
index adf3c21..aa334a6 100644 (file)
@@ -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()
index b430d8b..e98831c 100644 (file)
@@ -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)