From c66dff3dc70862dd4bac78ca2bcf8f3ff004bb8a Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 4 Jun 2015 14:22:26 +0200 Subject: [PATCH] Don't go through double in AmountFromValue and ValueFromAmount 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 #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. --- src/rpcserver.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 89250b54a..c31d86096 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -11,6 +11,7 @@ #include "sync.h" #include "ui_interface.h" #include "util.h" +#include "utilmoneystr.h" #include "utilstrencodings.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" @@ -121,25 +122,21 @@ void RPCTypeCheckObj(const UniValue& o, } } -static inline int64_t roundint64(double d) -{ - return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); -} - CAmount AmountFromValue(const UniValue& value) { - double dAmount = value.get_real(); - if (dAmount <= 0.0 || dAmount > 21000000.0) + if (!value.isReal() && !value.isNum()) + throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number"); + CAmount amount; + if (!ParseMoney(value.getValStr(), amount)) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); - CAmount nAmount = roundint64(dAmount * COIN); - if (!MoneyRange(nAmount)) - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); - return nAmount; + if (!MoneyRange(amount)) + throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range"); + return amount; } UniValue ValueFromAmount(const CAmount& amount) { - return (double)amount / (double)COIN; + return UniValue(UniValue::VREAL, FormatMoney(amount, false)); } uint256 ParseHashV(const UniValue& v, string strName)