Skip to content

Commit 4b4b9a8

Browse files
committed
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.
1 parent 12cdbab commit 4b4b9a8

File tree

1 file changed

+9
-12
lines changed

1 file changed

+9
-12
lines changed

src/rpcserver.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "sync.h"
1212
#include "ui_interface.h"
1313
#include "util.h"
14+
#include "utilmoneystr.h"
1415
#include "utilstrencodings.h"
1516
#ifdef ENABLE_WALLET
1617
#include "wallet/wallet.h"
@@ -118,25 +119,21 @@ void RPCTypeCheckObj(const UniValue& o,
118119
}
119120
}
120121

121-
static inline int64_t roundint64(double d)
122-
{
123-
return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
124-
}
125-
126122
CAmount AmountFromValue(const UniValue& value)
127123
{
128-
double dAmount = value.get_real();
129-
if (dAmount <= 0.0 || dAmount > 21000000.0)
130-
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
131-
CAmount nAmount = roundint64(dAmount * COIN);
132-
if (!MoneyRange(nAmount))
124+
if (!value.isReal() && !value.isNum())
125+
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
126+
CAmount amount;
127+
if (!ParseMoney(value.getValStr(), amount))
133128
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
134-
return nAmount;
129+
if (!MoneyRange(amount))
130+
throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
131+
return amount;
135132
}
136133

137134
UniValue ValueFromAmount(const CAmount& amount)
138135
{
139-
return (double)amount / (double)COIN;
136+
return UniValue(UniValue::VREAL, FormatMoney(amount, false));
140137
}
141138

142139
uint256 ParseHashV(const UniValue& v, string strName)

0 commit comments

Comments
 (0)