Bitcoin Forum
December 10, 2016, 06:55:51 PM *
News: Latest stable version of Bitcoin Core: 0.13.1  [Torrent].
 
   Home   Help Search Donate Login Register  
Pages: [1]
  Print  
Author Topic: [python] Bitcoin-friendly JSON-RPC library  (Read 4093 times)
jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
April 02, 2011, 06:23:26 AM
 #1

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:

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}

Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
1481396151
Hero Member
*
Offline Offline

Posts: 1481396151

View Profile Personal Message (Offline)

Ignore
1481396151
Reply with quote  #2

1481396151
Report to moderator
1481396151
Hero Member
*
Offline Offline

Posts: 1481396151

View Profile Personal Message (Offline)

Ignore
1481396151
Reply with quote  #2

1481396151
Report to moderator
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1481396151
Hero Member
*
Offline Offline

Posts: 1481396151

View Profile Personal Message (Offline)

Ignore
1481396151
Reply with quote  #2

1481396151
Report to moderator
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2100



View Profile
April 02, 2011, 02:35:03 PM
 #2

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.

genjix
Legendary
*
expert
Offline Offline

Activity: 1232


View Profile
April 02, 2011, 02:52:37 PM
 #3

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.
jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
April 02, 2011, 04:00:49 PM
 #4

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...


Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
April 02, 2011, 04:22:59 PM
 #5

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.


Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
genjix
Legendary
*
expert
Offline Offline

Activity: 1232


View Profile
April 02, 2011, 04:26:22 PM
 #6

Yep, I meant along the lines of: increment class counter, store it as private ID.
Pages: [1]
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!