Bitcoin Forum
April 26, 2024, 01:45:42 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: [python] Bitcoin-friendly JSON-RPC library  (Read 4617 times)
jgarzik (OP)
Legendary
*
qt
Offline Offline

Activity: 1596
Merit: 1091


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, Bloq CEO, former bitcoin core dev team; opinions are my own.
Visit bloq.com / metronome.io
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
1714139142
Hero Member
*
Offline Offline

Posts: 1714139142

View Profile Personal Message (Offline)

Ignore
1714139142
Reply with quote  #2

1714139142
Report to moderator
Each block is stacked on top of the previous one. Adding another block to the top makes all lower blocks more difficult to remove: there is more "weight" above each block. A transaction in a block 6 blocks deep (6 confirmations) will be very difficult to remove.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2576
Merit: 1186



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
Merit: 1072


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 (OP)
Legendary
*
qt
Offline Offline

Activity: 1596
Merit: 1091


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, Bloq CEO, former bitcoin core dev team; opinions are my own.
Visit bloq.com / metronome.io
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
jgarzik (OP)
Legendary
*
qt
Offline Offline

Activity: 1596
Merit: 1091


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, Bloq CEO, former bitcoin core dev team; opinions are my own.
Visit bloq.com / metronome.io
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
genjix
Legendary
*
expert
Offline Offline

Activity: 1232
Merit: 1072


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:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!