Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: jgarzik on April 02, 2011, 06:23:26 AM



Title: [python] Bitcoin-friendly JSON-RPC library
Post by: jgarzik on April 02, 2011, 06:23:26 AM
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:sekritpass@127.0.0.1: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 (http://bitcointalk.org/index.php?topic=4086.0):

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}


Title: Re: [python] Bitcoin-friendly JSON-RPC library
Post by: Luke-Jr on April 02, 2011, 02:35:03 PM
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.


Title: Re: [python] Bitcoin-friendly JSON-RPC library
Post by: genjix on April 02, 2011, 02:52:37 PM
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 :)

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.


Title: Re: [python] Bitcoin-friendly JSON-RPC library
Post by: jgarzik on April 02, 2011, 04:00:49 PM
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...



Title: Re: [python] Bitcoin-friendly JSON-RPC library
Post by: jgarzik on April 02, 2011, 04:22:59 PM
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.



Title: Re: [python] Bitcoin-friendly JSON-RPC library
Post by: genjix on April 02, 2011, 04:26:22 PM
Yep, I meant along the lines of: increment class counter, store it as private ID.