mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 13:35:54 +00:00
Support for compiling on 32-bit platforms. The main issue was BN_ULONG size and not using 'long' where
'long long' or 'uint64' should be used.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <limits.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
@@ -15,8 +16,16 @@
|
||||
SETUP_LOG();
|
||||
|
||||
uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1));
|
||||
static const uint64_t tenTo14 = 100000000000000ul;
|
||||
static const uint64_t tenTo17 = 100000000000000000ul;
|
||||
static const uint64 tenTo14 = 100000000000000ull;
|
||||
static const uint64 tenTo17 = tenTo14 * 1000;
|
||||
|
||||
#if (ULONG_MAX > UINT_MAX)
|
||||
#define BN_add_word64(bn, word) BN_add_word(bn, word)
|
||||
#define BN_mul_word64(bn, word) BN_mul_word(bn, word)
|
||||
#define BN_div_word64(bn, word) BN_div_word(bn, word)
|
||||
#else
|
||||
#include "BigNum64.h"
|
||||
#endif
|
||||
|
||||
bool STAmount::issuerFromString(uint160& uDstIssuer, const std::string& sIssuer)
|
||||
{
|
||||
@@ -901,9 +910,9 @@ STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint16
|
||||
|
||||
// Compute (numerator * 10^17) / denominator
|
||||
CBigNum v;
|
||||
if ((BN_add_word(&v, numVal) != 1) ||
|
||||
(BN_mul_word(&v, tenTo17) != 1) ||
|
||||
(BN_div_word(&v, denVal) == ((BN_ULONG) -1)))
|
||||
if ((BN_add_word64(&v, numVal) != 1) ||
|
||||
(BN_mul_word64(&v, tenTo17) != 1) ||
|
||||
(BN_div_word64(&v, denVal) == ((uint64) -1)))
|
||||
{
|
||||
throw std::runtime_error("internal bn error");
|
||||
}
|
||||
@@ -911,7 +920,7 @@ STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint16
|
||||
// 10^16 <= quotient <= 10^18
|
||||
assert(BN_num_bytes(&v) <= 64);
|
||||
|
||||
return STAmount(uCurrencyID, uIssuerID, v.getulong() + 5,
|
||||
return STAmount(uCurrencyID, uIssuerID, v.getuint64() + 5,
|
||||
numOffset - denOffset - 17, num.mIsNegative != den.mIsNegative);
|
||||
}
|
||||
|
||||
@@ -924,9 +933,9 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16
|
||||
{
|
||||
uint64 minV = (v1.getSNValue() < v2.getSNValue()) ? v1.getSNValue() : v2.getSNValue();
|
||||
uint64 maxV = (v1.getSNValue() < v2.getSNValue()) ? v2.getSNValue() : v1.getSNValue();
|
||||
if (minV > 3000000000) // sqrt(cMaxNative)
|
||||
if (minV > 3000000000ull) // sqrt(cMaxNative)
|
||||
throw std::runtime_error("Native value overflow");
|
||||
if (((maxV >> 32) * minV) > 2095475792) // cMaxNative / 2^32
|
||||
if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
|
||||
throw std::runtime_error("Native value overflow");
|
||||
return STAmount(v1.getFName(), minV * maxV);
|
||||
}
|
||||
@@ -955,9 +964,9 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16
|
||||
// Compute (numerator * denominator) / 10^14 with rounding
|
||||
// 10^16 <= result <= 10^18
|
||||
CBigNum v;
|
||||
if ((BN_add_word(&v, value1) != 1) ||
|
||||
(BN_mul_word(&v, value2) != 1) ||
|
||||
(BN_div_word(&v, tenTo14) == ((BN_ULONG) -1)))
|
||||
if ((BN_add_word64(&v, value1) != 1) ||
|
||||
(BN_mul_word64(&v, value2) != 1) ||
|
||||
(BN_div_word64(&v, tenTo14) == ((uint64) -1)))
|
||||
{
|
||||
throw std::runtime_error("internal bn error");
|
||||
}
|
||||
@@ -965,7 +974,7 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16
|
||||
// 10^16 <= product <= 10^18
|
||||
assert(BN_num_bytes(&v) <= 64);
|
||||
|
||||
return STAmount(uCurrencyID, uIssuerID, v.getulong() + 7, offset1 + offset2 + 14,
|
||||
return STAmount(uCurrencyID, uIssuerID, v.getuint64() + 7, offset1 + offset2 + 14,
|
||||
v1.mIsNegative != v2.mIsNegative);
|
||||
}
|
||||
|
||||
@@ -1119,13 +1128,13 @@ uint64 STAmount::muldiv(uint64 a, uint64 b, uint64 c)
|
||||
if ((a == 0) || (b == 0)) return 0;
|
||||
|
||||
CBigNum v;
|
||||
if ((BN_add_word(&v, a * 10 + 5) != 1) ||
|
||||
(BN_mul_word(&v, b * 10 + 5) != 1) ||
|
||||
(BN_div_word(&v, c) == ((BN_ULONG) -1)) ||
|
||||
(BN_div_word(&v, 100) == ((BN_ULONG) -1)))
|
||||
if ((BN_add_word64(&v, a * 10 + 5) != 1) ||
|
||||
(BN_mul_word64(&v, b * 10 + 5) != 1) ||
|
||||
(BN_div_word64(&v, c) == ((uint64) -1)) ||
|
||||
(BN_div_word64(&v, 100) == ((uint64) -1)))
|
||||
throw std::runtime_error("muldiv error");
|
||||
|
||||
return v.getulong();
|
||||
return v.getuint64();
|
||||
}
|
||||
|
||||
uint64 STAmount::convertToDisplayAmount(const STAmount& internalAmount, uint64 totalNow, uint64 totalInit)
|
||||
@@ -1239,7 +1248,6 @@ BOOST_AUTO_TEST_CASE( NativeCurrency_test )
|
||||
{
|
||||
STAmount zero, one(1), hundred(100);
|
||||
|
||||
if (sizeof(BN_ULONG) < (64 / 8)) BOOST_FAIL("BN too small");
|
||||
if (serdes(zero) != zero) BOOST_FAIL("STAmount fail");
|
||||
if (serdes(one) != one) BOOST_FAIL("STAmount fail");
|
||||
if (serdes(hundred) != hundred) BOOST_FAIL("STAmount fail");
|
||||
@@ -1385,13 +1393,13 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test )
|
||||
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail");
|
||||
|
||||
if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
|
||||
BOOST_FAIL("STAmount multiply fail");
|
||||
BOOST_FAIL("STAmount multiply fail 1");
|
||||
if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XRP).getText() != "60")
|
||||
BOOST_FAIL("STAmount multiply fail");
|
||||
BOOST_FAIL("STAmount multiply fail 2");
|
||||
if (STAmount::multiply(STAmount(20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
|
||||
BOOST_FAIL("STAmount multiply fail");
|
||||
BOOST_FAIL("STAmount multiply fail 3");
|
||||
if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XRP).getText() != "60")
|
||||
BOOST_FAIL("STAmount multiply fail");
|
||||
BOOST_FAIL("STAmount multiply fail 4");
|
||||
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
|
||||
{
|
||||
cLog(lsFATAL) << "60/3 = " <<
|
||||
@@ -1466,25 +1474,39 @@ static void mulTest(int a, int b)
|
||||
|
||||
BOOST_AUTO_TEST_CASE( CurrencyMulDivTests )
|
||||
{
|
||||
CBigNum b;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
uint64 r = rand();
|
||||
r <<= 32;
|
||||
r |= rand();
|
||||
b.setuint64(r);
|
||||
if (b.getuint64() != r)
|
||||
{
|
||||
cLog(lsFATAL) << r << " != " << b.getuint64() << " " << b.ToString(16);
|
||||
BOOST_FAIL("setull64/getull64 failure");
|
||||
}
|
||||
}
|
||||
|
||||
// Test currency multiplication and division operations such as
|
||||
// convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded
|
||||
|
||||
if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
|
||||
BOOST_FAIL("STAmount getRate fail");
|
||||
if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ull-14)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 1");
|
||||
if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ull-16)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 2");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ull-14)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 3");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ull-16)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 4");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(10)) != (((100ull-14)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 5");
|
||||
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(1)) != (((100ull-16)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 6");
|
||||
if (STAmount::getRate(STAmount(1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ull-14)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 7");
|
||||
if (STAmount::getRate(STAmount(10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ull-16)<<(64-8))|1000000000000000ull))
|
||||
BOOST_FAIL("STAmount getRate fail 8");
|
||||
|
||||
roundTest(1, 3, 3); roundTest(2, 3, 9); roundTest(1, 7, 21); roundTest(1, 2, 4);
|
||||
roundTest(3, 9, 18); roundTest(7, 11, 44);
|
||||
|
||||
22
src/cpp/ripple/BigNum64.h
Normal file
22
src/cpp/ripple/BigNum64.h
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
// Support 64-bit word operations on 32-bit platforms
|
||||
|
||||
static int BN_add_word64(BIGNUM *a, uint64 w)
|
||||
{
|
||||
CBigNum bn(w);
|
||||
return BN_add(a, &bn, a);
|
||||
}
|
||||
|
||||
static int BN_mul_word64(BIGNUM *a, uint64 w)
|
||||
{
|
||||
CBigNum bn(w);
|
||||
CAutoBN_CTX ctx;
|
||||
return BN_mul(a, &bn, a, ctx);
|
||||
}
|
||||
|
||||
static uint64 BN_div_word64(BIGNUM *a, uint64 w)
|
||||
{
|
||||
CBigNum bn(w);
|
||||
CAutoBN_CTX ctx;
|
||||
return (BN_div(a, NULL, a, &bn, ctx) == 1) ? 0 : ((uint64)-1);
|
||||
}
|
||||
@@ -1039,7 +1039,7 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
|
||||
if (value.isString())
|
||||
data.push_back(new STUInt32(field, lexical_cast_st<uint32>(value.asString())));
|
||||
else if (value.isInt())
|
||||
data.push_back(new STUInt32(field, range_check_cast<uint32>(value.asInt(), 0, 4294967295)));
|
||||
data.push_back(new STUInt32(field, range_check_cast<uint32>(value.asInt(), 0, 4294967295u)));
|
||||
else if (value.isUInt())
|
||||
data.push_back(new STUInt32(field, static_cast<uint32>(value.asUInt())));
|
||||
else
|
||||
|
||||
@@ -51,7 +51,7 @@ inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char
|
||||
if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
|
||||
throw bignum_error("EncodeBase58 : BN_div failed");
|
||||
bn = dv;
|
||||
unsigned int c = rem.getulong();
|
||||
unsigned int c = rem.getuint();
|
||||
str += ALPHABET[c];
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
bnChar.setulong(p1 - ALPHABET);
|
||||
bnChar.setuint(p1 - ALPHABET);
|
||||
if (!BN_mul(&bn, &bn, &bn58, pctx))
|
||||
throw bignum_error("DecodeBase58 : BN_mul failed");
|
||||
bn += bnChar;
|
||||
|
||||
@@ -89,7 +89,6 @@ public:
|
||||
CBigNum(unsigned char n) { BN_init(this); setulong(n); }
|
||||
CBigNum(unsigned short n) { BN_init(this); setulong(n); }
|
||||
CBigNum(unsigned int n) { BN_init(this); setulong(n); }
|
||||
CBigNum(unsigned long n) { BN_init(this); setulong(n); }
|
||||
CBigNum(uint64 n) { BN_init(this); setuint64(n); }
|
||||
explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); }
|
||||
|
||||
@@ -99,15 +98,9 @@ public:
|
||||
setvch(vch);
|
||||
}
|
||||
|
||||
void setulong(unsigned long n)
|
||||
void setuint(unsigned int n)
|
||||
{
|
||||
if (!BN_set_word(this, n))
|
||||
throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
|
||||
}
|
||||
|
||||
unsigned long getulong() const
|
||||
{
|
||||
return BN_get_word(this);
|
||||
setulong(static_cast<unsigned long>(n));
|
||||
}
|
||||
|
||||
unsigned int getuint() const
|
||||
@@ -159,31 +152,46 @@ public:
|
||||
BN_mpi2bn(pch, p - pch, this);
|
||||
}
|
||||
|
||||
uint64 getuint64() const
|
||||
{
|
||||
#if (ULONG_MAX > UINT_MAX)
|
||||
return static_cast<uint64>(getulong());
|
||||
#else
|
||||
int len = BN_num_bytes(this);
|
||||
if (len > 9)
|
||||
throw std::runtime_error("BN getuint64 overflow");
|
||||
|
||||
unsigned char buf[9];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
BN_bn2bin(this, buf + 9 - len);
|
||||
if (buf[0] != 0)
|
||||
throw std::runtime_error("BN getuint64 overflow");
|
||||
|
||||
return
|
||||
static_cast<uint64>(buf[1]) << 56 | static_cast<uint64>(buf[2]) << 48 |
|
||||
static_cast<uint64>(buf[3]) << 40 | static_cast<uint64>(buf[4]) << 32 |
|
||||
static_cast<uint64>(buf[5]) << 24 | static_cast<uint64>(buf[6]) << 16 |
|
||||
static_cast<uint64>(buf[7]) << 8 | static_cast<uint64>(buf[8]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setuint64(uint64 n)
|
||||
{
|
||||
unsigned char pch[sizeof(n) + 6];
|
||||
unsigned char* p = pch + 4;
|
||||
bool fLeadingZeroes = true;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
unsigned char c = (n >> 56) & 0xff;
|
||||
n <<= 8;
|
||||
if (fLeadingZeroes)
|
||||
{
|
||||
if (c == 0)
|
||||
continue;
|
||||
if (c & 0x80)
|
||||
*p++ = 0;
|
||||
fLeadingZeroes = false;
|
||||
}
|
||||
*p++ = c;
|
||||
}
|
||||
unsigned int nSize = p - (pch + 4);
|
||||
pch[0] = (nSize >> 24) & 0xff;
|
||||
pch[1] = (nSize >> 16) & 0xff;
|
||||
pch[2] = (nSize >> 8) & 0xff;
|
||||
pch[3] = (nSize) & 0xff;
|
||||
BN_mpi2bn(pch, p - pch, this);
|
||||
#if (ULONG_MAX > UINT_MAX)
|
||||
setulong(static_cast<unsigned long>(n));
|
||||
#else
|
||||
unsigned char buf[9];
|
||||
buf[0] = 0;
|
||||
buf[1] = static_cast<unsigned char>((n >> 56) & 0xff);
|
||||
buf[2] = static_cast<unsigned char>((n >> 48) & 0xff);
|
||||
buf[3] = static_cast<unsigned char>((n >> 40) & 0xff);
|
||||
buf[4] = static_cast<unsigned char>((n >> 32) & 0xff);
|
||||
buf[5] = static_cast<unsigned char>((n >> 24) & 0xff);
|
||||
buf[6] = static_cast<unsigned char>((n >> 16) & 0xff);
|
||||
buf[7] = static_cast<unsigned char>((n >> 8) & 0xff);
|
||||
buf[8] = static_cast<unsigned char>((n) & 0xff);
|
||||
BN_bin2bn(buf, 9, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setuint256(const uint256& n)
|
||||
@@ -300,7 +308,7 @@ public:
|
||||
if (!BN_div(&dv, &rem, &bn, &bnBase, pctx))
|
||||
throw bignum_error("CBigNum::ToString() : BN_div failed");
|
||||
bn = dv;
|
||||
unsigned int c = rem.getulong();
|
||||
unsigned int c = rem.getuint();
|
||||
str += "0123456789abcdef"[c];
|
||||
}
|
||||
if (BN_is_negative(this))
|
||||
@@ -435,6 +443,22 @@ public:
|
||||
friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b);
|
||||
|
||||
private:
|
||||
|
||||
// private because the size of an unsigned long varies by platform
|
||||
|
||||
void setulong(unsigned long n)
|
||||
{
|
||||
if (!BN_set_word(this, n))
|
||||
throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
|
||||
}
|
||||
|
||||
unsigned long getulong() const
|
||||
{
|
||||
return BN_get_word(this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user