Browse Source

Merge pull request #6239

7d8ffac Changes necessary now that zero values accepted in AmountFromValue (Wladimir J. van der Laan)
a04bdef Get rid of fPlus argument to FormatMoney (Wladimir J. van der Laan)
4b4b9a8 Don't go through double in AmountFromValue and ValueFromAmount (Wladimir J. van der Laan)
0.13
Wladimir J. van der Laan 10 years ago
parent
commit
643114f539
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 21
      src/rpcserver.cpp
  2. 3
      src/test/rpc_tests.cpp
  3. 44
      src/test/util_tests.cpp
  4. 4
      src/utilmoneystr.cpp
  5. 2
      src/utilmoneystr.h
  6. 12
      src/wallet/rpcwallet.cpp

21
src/rpcserver.cpp

@ -11,6 +11,7 @@
#include "sync.h" #include "sync.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "util.h" #include "util.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
#include "wallet/wallet.h" #include "wallet/wallet.h"
@ -118,25 +119,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) CAmount AmountFromValue(const UniValue& value)
{ {
double dAmount = value.get_real(); if (!value.isReal() && !value.isNum())
if (dAmount <= 0.0 || dAmount > 21000000.0) throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); CAmount amount;
CAmount nAmount = roundint64(dAmount * COIN); if (!ParseMoney(value.getValStr(), amount))
if (!MoneyRange(nAmount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); 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) UniValue ValueFromAmount(const CAmount& amount)
{ {
return (double)amount / (double)COIN; return UniValue(UniValue::VREAL, FormatMoney(amount));
} }
uint256 ParseHashV(const UniValue& v, string strName) uint256 ParseHashV(const UniValue& v, string strName)

3
src/test/rpc_tests.cpp

@ -131,6 +131,9 @@ static UniValue ValueFromString(const std::string &str)
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{ {
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL); BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);

44
src/test/util_tests.cpp

@ -146,29 +146,27 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_AUTO_TEST_CASE(util_FormatMoney) BOOST_AUTO_TEST_CASE(util_FormatMoney)
{ {
BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00"); BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789"); BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), "12345.6789");
BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00"); BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), "100000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), "10000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), "1000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), "100000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), "10000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), "1000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN*100), "100.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN*10), "10.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN/10), "0.10");
BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00"); BOOST_CHECK_EQUAL(FormatMoney(COIN/100), "0.01");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10"); BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), "0.001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01"); BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), "0.0001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001"); BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), "0.00001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001"); BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), "0.000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001"); BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), "0.0000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001"); BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), "0.00000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
} }
BOOST_AUTO_TEST_CASE(util_ParseMoney) BOOST_AUTO_TEST_CASE(util_ParseMoney)

4
src/utilmoneystr.cpp

@ -11,7 +11,7 @@
using namespace std; using namespace std;
string FormatMoney(const CAmount& n, bool fPlus) std::string FormatMoney(const CAmount& n)
{ {
// Note: not using straight sprintf here because we do NOT want // Note: not using straight sprintf here because we do NOT want
// localized number formatting. // localized number formatting.
@ -29,8 +29,6 @@ string FormatMoney(const CAmount& n, bool fPlus)
if (n < 0) if (n < 0)
str.insert((unsigned int)0, 1, '-'); str.insert((unsigned int)0, 1, '-');
else if (fPlus && n > 0)
str.insert((unsigned int)0, 1, '+');
return str; return str;
} }

2
src/utilmoneystr.h

@ -14,7 +14,7 @@
#include "amount.h" #include "amount.h"
std::string FormatMoney(const CAmount& n, bool fPlus=false); std::string FormatMoney(const CAmount& n);
bool ParseMoney(const std::string& str, CAmount& nRet); bool ParseMoney(const std::string& str, CAmount& nRet);
bool ParseMoney(const char* pszIn, CAmount& nRet); bool ParseMoney(const char* pszIn, CAmount& nRet);

12
src/wallet/rpcwallet.cpp

@ -414,6 +414,8 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
// Amount // Amount
CAmount nAmount = AmountFromValue(params[1]); CAmount nAmount = AmountFromValue(params[1]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments // Wallet comments
CWalletTx wtx; CWalletTx wtx;
@ -809,6 +811,8 @@ UniValue movecmd(const UniValue& params, bool fHelp)
string strFrom = AccountFromValue(params[0]); string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]); string strTo = AccountFromValue(params[1]);
CAmount nAmount = AmountFromValue(params[2]); CAmount nAmount = AmountFromValue(params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
if (params.size() > 3) if (params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though // unused parameter, used to be nMinDepth, keep type-checking it though
(void)params[3].get_int(); (void)params[3].get_int();
@ -888,6 +892,8 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CAmount nAmount = AmountFromValue(params[2]); CAmount nAmount = AmountFromValue(params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1; int nMinDepth = 1;
if (params.size() > 3) if (params.size() > 3)
nMinDepth = params[3].get_int(); nMinDepth = params[3].get_int();
@ -987,6 +993,8 @@ UniValue sendmany(const UniValue& params, bool fHelp)
CScript scriptPubKey = GetScriptForDestination(address.Get()); CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(sendTo[name_]); CAmount nAmount = AmountFromValue(sendTo[name_]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
totalAmount += nAmount; totalAmount += nAmount;
bool fSubtractFeeFromAmount = false; bool fSubtractFeeFromAmount = false;
@ -2168,9 +2176,7 @@ UniValue settxfee(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
// Amount // Amount
CAmount nAmount = 0; CAmount nAmount = AmountFromValue(params[0]);
if (params[0].get_real() != 0.0)
nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
payTxFee = CFeeRate(nAmount, 1000); payTxFee = CFeeRate(nAmount, 1000);
return true; return true;

Loading…
Cancel
Save