Author

Topic: [python] Bitcoin-friendly JSON-RPC library (Read 4654 times)

legendary
Activity: 1232
Merit: 1076
April 02, 2011, 11:26:22 AM
#6
Yep, I meant along the lines of: increment class counter, store it as private ID.
legendary
Activity: 1596
Merit: 1100
Using the ID count is clever. Would it maybe be a good idea to either make that a class variable? For when people instantiate multiple Proxies across threads or something.

ID is unique per connection, and multiple threads / instances should use their own id counter.  It is used to match query and response.

legendary
Activity: 1596
Merit: 1100
The class on the wiki already supports automatic introspection and uses python's Decimal class:
[...]
How does this improve on that? I saw that you're using httplib instead of urllib. Any reasons for that?

There is a list in the source code and top post that answers these questions...

legendary
Activity: 1232
Merit: 1076
The class on the wiki already supports automatic introspection and uses python's Decimal class:
https://en.bitcoin.it/wiki/API_reference_%28JSON-RPC%29#Python

Code:
import urllib
import decimal
import json
 
class JSONRPCException(Exception):
    def __init__(self, rpcError):
        Exception.__init__(self)
        self.error = rpcError
 
class ServiceProxy(object):
    def __init__(self, serviceURL, serviceName=None):
        self.__serviceURL = serviceURL
        self.__serviceName = serviceName
 
    def __getattr__(self, name):
        if self.__serviceName != None:
            name = "%s.%s" % (self.__serviceName, name)
        return ServiceProxy(self.__serviceURL, name)
 
    def __call__(self, *args):
         postdata = json.dumps({"method": self.__serviceName, 'params': args, 'id':'jsonrpc'})
         respdata = urllib.urlopen(self.__serviceURL, postdata).read()
         resp = json.loads(respdata, parse_float=decimal.Decimal)
         if resp['error'] != None:
             raise JSONRPCException(resp['error'])
         else:
             return resp['result']

How does this improve on that? I saw that you're using httplib instead of urllib. Any reasons for that?

Also you may wish to read,
http://www.python.org/dev/peps/pep-0008/

Python libraries generally follow that style as to provide a consistent API. It doesn't always happen but everybody tries to use that same standard Smiley

Using the ID count is clever. Would it maybe be a good idea to either make that a class variable? For when people instantiate multiple Proxies across threads or something.
legendary
Activity: 2576
Merit: 1186
The HTTP/1.1 improvements aside... the use of Decimal is in fact a regression. Here's why:

It will encourage people to treat bitcoin values as BTC internally, rather than atomic units. Besides being simply wrong, this also creates a problem because according to the current JSON-RPC rules, one end is allowed to send the value "0.999999999" and the other end should process it as 100000000 units (eg, 1 BTC).

Whether the library returns float or Decimal, the application still needs to process all amounts with round(1e8 * amount). Float is more efficient, and clearly discourages bad behaviour, so is a better fit in this particular case.
legendary
Activity: 1596
Merit: 1100
When hacking JSON-RPC calls together for bitcoin, in python, a common solution appears to be using python-jsonrpc.  This choice is less than optimal, for [at least] two reasons:  (1) no way to use Decimal with JSON values, as is required in monetary software, and (2) does not support HTTP/1.1 persistent connections.

So, I have created the python AuthServiceProxy class specifically for bitcoin users, based on the usage model of python-jsonrpc:

     http://yyz.us/bitcoin/authproxy.py

This creates a python object whose methods are the JSON-RPC method calls.  Example:

Code:
import authproxy
import pprint

BITCOINRPC = 'http://myusername:[email protected]:8332/'
pp = pprint.PrettyPrinter(indent=4)

bitcoin = authproxy.AuthServiceProxy(BITCOINRPC)
data = bitcoin.getwork()     # call bitcoin 'getwork' RPC
pp.pprint(data)

data = bitcoin.getinfo()        # call bitcoin 'getinfo' RPC
pp.pprint(data)

This should be all that is needed for python programmers to use bitcoin's unique flavor of JSON-RPC over http or https.

In the latter 'getinfo' case, you can see that Decimal values are properly returned, rather than floats, as recently discussed in this thread:

Code:
{   'balance': Decimal('1.10000000'),
    'blocks': 116260,
    'connections': 48,
    'difficulty': Decimal('68978.89245792'),
    'errors': '',
    'generate': False,
    'genproclimit': 1,
    'hashespersec': 0,
    'keypoololdest': 1296778330,
    'paytxfee': Decimal('0.01000000'),
    'proxy': '',
    'testnet': False,
    'version': 32100}
Jump to: