mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 04:52:59 +01:00
Merge pull request #6456
ec249d4
util: use locale-independent parsing in ParseDouble (Wladimir J. van der Laan)7650449
univalue: Avoid unnecessary roundtrip through double for numbers (Wladimir J. van der Laan)e061e27
rpc: Make ValueFromAmount always return 8 decimals (Wladimir J. van der Laan)
This commit is contained in:
commit
bfd807ff32
@ -14,6 +14,7 @@ from struct import *
|
|||||||
import binascii
|
import binascii
|
||||||
import json
|
import json
|
||||||
import StringIO
|
import StringIO
|
||||||
|
import decimal
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import http.client as httplib
|
import http.client as httplib
|
||||||
@ -243,7 +244,7 @@ class RESTTest (BitcoinTestFramework):
|
|||||||
response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"json", "", True)
|
response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"json", "", True)
|
||||||
assert_equal(response_header_json.status, 200)
|
assert_equal(response_header_json.status, 200)
|
||||||
response_header_json_str = response_header_json.read()
|
response_header_json_str = response_header_json.read()
|
||||||
json_obj = json.loads(response_header_json_str)
|
json_obj = json.loads(response_header_json_str, parse_float=decimal.Decimal)
|
||||||
assert_equal(len(json_obj), 1) #ensure that there is one header in the json response
|
assert_equal(len(json_obj), 1) #ensure that there is one header in the json response
|
||||||
assert_equal(json_obj[0]['hash'], bb_hash) #request/response hash should be the same
|
assert_equal(json_obj[0]['hash'], bb_hash) #request/response hash should be the same
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#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"
|
||||||
@ -121,7 +120,7 @@ void RPCTypeCheckObj(const UniValue& o,
|
|||||||
|
|
||||||
CAmount AmountFromValue(const UniValue& value)
|
CAmount AmountFromValue(const UniValue& value)
|
||||||
{
|
{
|
||||||
if (!value.isReal() && !value.isNum())
|
if (!value.isNum())
|
||||||
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
|
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
|
||||||
CAmount amount;
|
CAmount amount;
|
||||||
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
|
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
|
||||||
@ -133,7 +132,12 @@ CAmount AmountFromValue(const UniValue& value)
|
|||||||
|
|
||||||
UniValue ValueFromAmount(const CAmount& amount)
|
UniValue ValueFromAmount(const CAmount& amount)
|
||||||
{
|
{
|
||||||
return UniValue(UniValue::VREAL, FormatMoney(amount));
|
bool sign = amount < 0;
|
||||||
|
int64_t n_abs = (sign ? -amount : amount);
|
||||||
|
int64_t quotient = n_abs / COIN;
|
||||||
|
int64_t remainder = n_abs % COIN;
|
||||||
|
return UniValue(UniValue::VNUM,
|
||||||
|
strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 ParseHashV(const UniValue& v, string strName)
|
uint256 ParseHashV(const UniValue& v, string strName)
|
||||||
|
@ -120,6 +120,29 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
|
|||||||
BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
|
BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
|
||||||
BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
|
BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
|
||||||
BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
|
BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010");
|
||||||
|
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001");
|
||||||
}
|
}
|
||||||
|
|
||||||
static UniValue ValueFromString(const std::string &str)
|
static UniValue ValueFromString(const std::string &str)
|
||||||
|
@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
|
|||||||
|
|
||||||
double vd = -7.21;
|
double vd = -7.21;
|
||||||
UniValue v7(vd);
|
UniValue v7(vd);
|
||||||
BOOST_CHECK(v7.isReal());
|
BOOST_CHECK(v7.isNum());
|
||||||
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
|
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
|
||||||
|
|
||||||
string vs("yawn");
|
string vs("yawn");
|
||||||
@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(univalue_set)
|
|||||||
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
|
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
|
||||||
|
|
||||||
BOOST_CHECK(v.setFloat(-1.01));
|
BOOST_CHECK(v.setFloat(-1.01));
|
||||||
BOOST_CHECK(v.isReal());
|
BOOST_CHECK(v.isNum());
|
||||||
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
|
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
|
||||||
|
|
||||||
BOOST_CHECK(v.setInt((int)1023));
|
BOOST_CHECK(v.setInt((int)1023));
|
||||||
@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
|
|||||||
objTypes["distance"] = UniValue::VNUM;
|
objTypes["distance"] = UniValue::VNUM;
|
||||||
objTypes["time"] = UniValue::VNUM;
|
objTypes["time"] = UniValue::VNUM;
|
||||||
objTypes["calories"] = UniValue::VNUM;
|
objTypes["calories"] = UniValue::VNUM;
|
||||||
objTypes["temperature"] = UniValue::VREAL;
|
objTypes["temperature"] = UniValue::VNUM;
|
||||||
objTypes["cat1"] = UniValue::VNUM;
|
objTypes["cat1"] = UniValue::VNUM;
|
||||||
objTypes["cat2"] = UniValue::VNUM;
|
objTypes["cat2"] = UniValue::VNUM;
|
||||||
BOOST_CHECK(obj.checkObject(objTypes));
|
BOOST_CHECK(obj.checkObject(objTypes));
|
||||||
|
@ -86,7 +86,7 @@ bool UniValue::setFloat(double val)
|
|||||||
oss << std::setprecision(16) << val;
|
oss << std::setprecision(16) << val;
|
||||||
|
|
||||||
bool ret = setNumStr(oss.str());
|
bool ret = setNumStr(oss.str());
|
||||||
typ = VREAL;
|
typ = VNUM;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +210,6 @@ const char *uvTypeName(UniValue::VType t)
|
|||||||
case UniValue::VARR: return "array";
|
case UniValue::VARR: return "array";
|
||||||
case UniValue::VSTR: return "string";
|
case UniValue::VSTR: return "string";
|
||||||
case UniValue::VNUM: return "number";
|
case UniValue::VNUM: return "number";
|
||||||
case UniValue::VREAL: return "number";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// not reached
|
// not reached
|
||||||
@ -280,7 +279,7 @@ int64_t UniValue::get_int64() const
|
|||||||
|
|
||||||
double UniValue::get_real() const
|
double UniValue::get_real() const
|
||||||
{
|
{
|
||||||
if (typ != VREAL && typ != VNUM)
|
if (typ != VNUM)
|
||||||
throw std::runtime_error("JSON value is not a number as expected");
|
throw std::runtime_error("JSON value is not a number as expected");
|
||||||
double retval;
|
double retval;
|
||||||
if (!ParseDouble(getValStr(), &retval))
|
if (!ParseDouble(getValStr(), &retval))
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
class UniValue {
|
class UniValue {
|
||||||
public:
|
public:
|
||||||
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VREAL, VBOOL, };
|
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
|
||||||
|
|
||||||
UniValue() { typ = VNULL; }
|
UniValue() { typ = VNULL; }
|
||||||
UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
|
UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
|
||||||
@ -78,7 +78,6 @@ public:
|
|||||||
bool isBool() const { return (typ == VBOOL); }
|
bool isBool() const { return (typ == VBOOL); }
|
||||||
bool isStr() const { return (typ == VSTR); }
|
bool isStr() const { return (typ == VSTR); }
|
||||||
bool isNum() const { return (typ == VNUM); }
|
bool isNum() const { return (typ == VNUM); }
|
||||||
bool isReal() const { return (typ == VREAL); }
|
|
||||||
bool isArray() const { return (typ == VARR); }
|
bool isArray() const { return (typ == VARR); }
|
||||||
bool isObject() const { return (typ == VOBJ); }
|
bool isObject() const { return (typ == VOBJ); }
|
||||||
|
|
||||||
|
@ -61,13 +61,6 @@ string UniValue::write(unsigned int prettyIndent,
|
|||||||
case VSTR:
|
case VSTR:
|
||||||
s += "\"" + json_escape(val) + "\"";
|
s += "\"" + json_escape(val) + "\"";
|
||||||
break;
|
break;
|
||||||
case VREAL:
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << std::showpoint << std::fixed << std::setprecision(8) << get_real();
|
|
||||||
s += ss.str();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VNUM:
|
case VNUM:
|
||||||
s += val;
|
s += val;
|
||||||
break;
|
break;
|
||||||
|
@ -464,11 +464,12 @@ bool ParseDouble(const std::string& str, double *out)
|
|||||||
return false;
|
return false;
|
||||||
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
|
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
|
||||||
return false;
|
return false;
|
||||||
char *endp = NULL;
|
std::istringstream text(str);
|
||||||
errno = 0; // strtod will not set errno if valid
|
text.imbue(std::locale::classic());
|
||||||
double n = strtod(str.c_str(), &endp);
|
double result;
|
||||||
if(out) *out = n;
|
text >> result;
|
||||||
return endp && *endp == 0 && !errno;
|
if(out) *out = result;
|
||||||
|
return text.eof() && !text.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
|
std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
|
||||||
|
Loading…
Reference in New Issue
Block a user