-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Add option -rpcamount for monetary amounts as strings/satoshis in RPC
#3759
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
BTW this same design can be trivially used to send monetary values via RPC in any desired way. For example, a mode that returns and takes satoshis as integer is just a matter of adding the necessary option parsing and updating Something like |
|
@laanwj I was thinking the same thing, RE outputting satoshis rather than strings or decimal numbers. |
|
JSON has no native integer type. Outputting satoshi counts is no better than outputting Bitcoin amounts (they'll be interpreted as floating point in both case). |
|
@sipa The former is true -- no integer type -- but the latter is not. Outputting satoshi amounts does not automatically imply interpretation as floating point. Most libs, including our own, provide integer or Decimal interpretations without an intermediate floating point conversion step. The options should be more bitcoin-specific, though, and are really a matrix of four possibilities:
|
|
Well I like strings (with the |
|
-rpcamounttype=[number | string] --- JSON string or number |
|
Hmm... can we still combine it into one option somehow? I don't like two separate options affecting the monetary format, one in one place is confusing enough :-) |
|
-rpcamount=[number-decimal, number-satoshis, string-decimal, string-satoshis] meh. Open to suggestions... it is a quad-state. |
|
That looks good to me. |
|
s/decimal/btc/ (in case someone wants to do mbtc or ubtc in the future)? |
|
@luke-jr Hmm... It was never my intention to add different units to the RPC. It's waay too easy to introduce thousandfold errors this way by having the client and server use a different setting. Integer (in lowest possible denomination) and decimal (BTC proper) is enough IMO. Confusion can be avoided with these four options by enforcing a Edit: not that I'm against using btc instead of decimal here, it may be more consistent nevertheless. |
|
OK implemented all four modes + added tests for them
|
|
If we're seriously thinking about making such pervasive changes to the RPC interface, I'd like to go all the way, and overhaul some other things:
|
|
@sipa Those all sound like good ideas to me. |
|
I would also like to see a full blown overhaul with proper REST versioning and grouped and prefixed method names along the same lines as what sipa suggests. I'm particularly keen on the idea of using named arguments. Positional arguments are not conducive to optional arguments at all. Having spent quite a bit of time on the RPC interface, I concur that the current positional design with optional parameters is already less than ideal. Also, I would suggest that all numeric values in regards to BTC are in satoshi. First, this would make the API more consistent since you would know any time you're dealing with a bitcoin amount, it is satoshi and not some other variant like full BTC, mBTC, uBTC, etc. Second, it would eliminate the need for using a value with a decimal in it altogether. The client would then be responsible for converting to and from satoshi depending on its particular set of needs or user preferences. |
|
+1
|
Currently the FormatMoney function always trims trailing zeros apart from two if possible. Add an option to avoid this trimming and always return a string with 8 decimals.
Converting monetary amounts is part of the RPC protocol, both the client and server need to share the same implementation.
No longer use doubles. This allows supporting alternative RPC representations of monetary values.
Support this option at both the client side and server side. Both sides need to be using the same value of this option, otherwise parse errors will ensue. Four modes are available: - number-btc: Format as number in decimal BTC (default) - number-satoshis: Format as number in satoshis - string-btc: Format as string in decimal BTC - string-satoshis: Format as string in satoshis Also add tests for AmountFromValue / ValueFromAmount for all four modes.
|
Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/f3f8460fe51be719231612a921dd37af638df46a for binaries and test log. |
|
No longer going to maintain this, at some point I suppose we'll want to do a RPC overhaul and the money amounts should just be integers in satoshis. |
@sipa luckily there are other implementations of JSON readers e.g. the world is not really always using JavaScript to parse JSON data. See also http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf (page 4):
This is a closed/pretty old issue now, I don't want to do much necromancy but maybe the improvements proposed by @sipa can get their own separate PR and this one be kept about the single incremental improvement proposed in OP? |
My prime gripe with JSON spirit was that monetary values still had to be converted from and to floating point which can cause deviations (see bitcoin#3759 and https://bitcoin.stackexchange.com/questions/22716/bitcoind-sendfrom-round-amount-error). As UniValue stores internal values as strings, this is no longer necessary. This avoids risky double-to-integer and integer-to-double conversions completely, and results in more elegant code to boot.
My prime gripe with JSON spirit was that monetary values still had to be converted from and to floating point which can cause deviations (see bitcoin#3759 and https://bitcoin.stackexchange.com/questions/22716/bitcoind-sendfrom-round-amount-error). As UniValue stores internal values as strings, this is no longer necessary. This avoids risky double-to-integer and integer-to-double conversions completely, and results in more elegant code to boot.
…4298) * Fixes issue bitcoin#3759 Add virtual destructors for CBLSWrapper and CBLSLazyWrapper * Fix linter errors Co-authored-by: UdjinM6 <[email protected]> Co-authored-by: PastaPastaPasta <[email protected]> Co-authored-by: UdjinM6 <[email protected]>
See this report: https://bitcoin.stackexchange.com/questions/22716/bitcoind-sendfrom-round-amount-error
I've been unable to reproduce it in either master or 0.8.6. However, in theory this could happen on architectures that have imprecise floating point types. Even though bitcoind itself doesn't rely on floating point types anywhere, Spirit JSON does use doubles internally for parsing values like 123.456 (and so do we in ValueFromAmount / AmountFromValue).
My first attempt was to try to fix this and make the parser use a fixed-point or string representation for JSON numbers (ie https://github.com/bitcoin/bitcoin/blob/master/src/json/json_spirit_reader_template.h#L499 ), but turned out to be a deep rabbit hole and doesn't solve the issue at the client side.
So this is my solution: add an option
-rpcstringamountsto represent monetary amounts as strings in RPC. With this option any monetary amount will be emitted as a string with fixed 8 decimals, very easy to parse. Also this changes the parsing to accept the same format (by using the existing ParseMoney function).Example getinfo:
Commits should be self-documenting.