Difference between revisions of "Proper Money Handling (JSON-RPC)"

From Bitcoin Wiki
Jump to: navigation, search
(BASH)
(Python: python-jsonrpc should be avoided)
Line 43: Line 43:
  
 
== Python ==
 
== Python ==
If you are using [http://json-rpc.org/wiki/python-json-rpc python-json-rpc], you should convert its floating point values to and from the python long type. For example:
+
For python, python-jsonrpc should be avoided, due to poor HTTP/1.1 support and lack of support for converting JSON numbers to Decimal().
   from jsonrpc import ServiceProxy
+
 
 +
The recommended [http://yyz.us/bitcoin/authproxy.py AuthServiceProxy] properly converts all JSON monetary numbers to Decimal().
 +
 
 +
   from authproxy import AuthServiceProxy
 
   
 
   
   access = ServiceProxy("http://user:password@127.0.0.1:8332")
+
   access = AuthServiceProxy("http://user:password@127.0.0.1:8332")
 
   info = access.getinfo()
 
   info = access.getinfo()
   balance = long(round(info['balance'] * 1e8))
+
   balance = info['balance']
 
   amount_to_send = balance / 2
 
   amount_to_send = balance / 2
   access.sendtoaddress('...bitcoin address...', float(amount_to_send / 1e8))
+
   access.sendtoaddress('...bitcoin address...', amount_to_send)
  
 
[[Category:Technical]]
 
[[Category:Technical]]
 
[[Category:Developer]]
 
[[Category:Developer]]

Revision as of 18:17, 2 April 2011

Overview

The original bitcoin client stores all bitcoin values as 64-bit integers, with 1 BTC stored as 100,000,000 (one-hundred-million of the smallest possible bitcoin unit). Values are expressed as double-precision Numbers in the JSON API, with 1 BTC expressed as 1.00000000

If you are writing software that uses the JSON-RPC interface you need to be aware of possible floating-point conversion issues. You, or the JSON library you are using, should convert amounts to either a fixed-point Decimal representation (with 8 digits after the decimal point) or a 64-bit integer representation.

Improper value handling can lead to embarrassing errors; for example, if you truncate instead of doing proper rounding and your software will display the value "0.1 BTC" as "0.09999999 BTC" (or, worse, "0.09 BTC").

The original bitcoin client does proper, full-precision rounding for all values passed to it via the RPC interface. So, for example, if the value 0.1 is converted to the value "0.099999999999" by your JSON-RPC library, that value will be rounded to the nearest 0.00000001 bitcoin and will be treated as exactly 0.1 bitcoins.

The rest of this page gives sample code for various JSON libraries and programming languages.

BASH

 function JSONtoAmount() {
     printf '%.8f' "$1" | tr -d '.'
 }

C/C++

C/C++ JSON libraries return the JavaScript Number type as type 'double'. To convert, without loss of precision, from a double to a 64-bit integer multiply by 100,000,000 and round to the nearest integer:

int64_t JSONtoAmount(double value) {
    return (int64_t)(value * 1e8 + (value < 0.0 ? -.5 : .5));
}

To convert to a JSON value divide by 100,000,000.0, and make sure your JSON implementation outputs doubles with 8 or more digits after the decimal point:

 double forJSON = (double)amount / 1e8;

ECMAScript

function JSONtoAmount(value) {
    return amount = Math.round(1e8 * value);
}

Perl

sub JSONtoAmount {
    return sprintf '%.0f', 1e8 * shift;
}

PHP

function JSONtoAmount($value) {
    return round(value * 1e8);
}

Python

For python, python-jsonrpc should be avoided, due to poor HTTP/1.1 support and lack of support for converting JSON numbers to Decimal().

The recommended AuthServiceProxy properly converts all JSON monetary numbers to Decimal().

 from authproxy import AuthServiceProxy

 access = AuthServiceProxy("http://user:password@127.0.0.1:8332")
 info = access.getinfo()
 balance = info['balance']
 amount_to_send = balance / 2
 access.sendtoaddress('...bitcoin address...', amount_to_send)