Python and JSON-RPC
Sunday, December 1, 2013In playing with Bitcoin, in this case specifically with the bitcoin-qt client, I found myself wanting to more granularly control which of my coins I spent. This probably isn't something most people care about, or maybe even solve by using multiple wallets, but I thought that it would be nice to choose which addresses were used for transactions. I found that I was not alone in that desire. But sadly, the patch has yet to be merged despite going through a number of iterations.
Enter contrib/spendfrom/spendfrom.py. This Python script purported to solve
the problem to some extent. But it wasn't quite as easy as I had hoped to get
working. There is a
README.md
that highlights a dependency on "jsonrpc." That seemed easy enough, since I run
Windows on this particular machine, I tried using
C:\Python27\Scripts\easy_install.exe jsonrpc which indeed installed
jsonrpc just not the one linked in
the documentation, which I
overlooked.
Once I got the right jsonrpc checked out from Bazaar, and copied to my
site-packages directory, I thought I was good to go. However, I ran into a
problem that spendfrom.py tests for:
def check_json_precision():
"""Make sure json library being used does not lose precision converting BTC values"""
n = Decimal("20000000.00000003")
satoshis = int(json.loads(json.dumps(float(n)))*1.0e8)
if satoshis != 2000000000000003:
raise RuntimeError("JSON encode/decode loses precision")
So I started digging, and found that the json object that jsonrpc comes
with did some serialization by using
unicode()
that showed a loss of precision with the given value. This was pretty easy to
verify, and I pushed a
change
to a github hosted version of the json-rpc.org bzr repository, thanks to
git-remote-bzr. The change inserts a call to
repr()
before passing that string to unicode().
Finally, to get everything to work, I replaced all of the uses of Decimal()
in the spendfrom.py script to just use float() and have not seen any
issues. Granted I have not done a huge number of transactions, nor have I done
any that were more than four decimal places. Hopefully I didn't introduce some
insidious bug.