diff --git a/.gitignore b/.gitignore index c7a5cec4b..69bb5bff7 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,7 @@ tmp # Ignore database directory. db/*.db -db/*.db-journal +db/*.db-* # Ignore obj files Debug/*.* diff --git a/src/cpp/ripple/Amount.cpp b/src/cpp/ripple/Amount.cpp index 8a3038fc2..862613719 100644 --- a/src/cpp/ripple/Amount.cpp +++ b/src/cpp/ripple/Amount.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -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); diff --git a/src/cpp/ripple/BigNum64.h b/src/cpp/ripple/BigNum64.h new file mode 100644 index 000000000..9150a25ca --- /dev/null +++ b/src/cpp/ripple/BigNum64.h @@ -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); +} diff --git a/src/cpp/ripple/CallRPC.cpp b/src/cpp/ripple/CallRPC.cpp index ae963cd7d..27b173a2c 100644 --- a/src/cpp/ripple/CallRPC.cpp +++ b/src/cpp/ripple/CallRPC.cpp @@ -539,7 +539,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams) if (i < 0) { - return rpcError(rpcBAD_SYNTAX); + return rpcError(rpcUNKNOWN_COMMAND); } else if ((commandsA[i].iMinParams >= 0 && jvParams.size() < commandsA[i].iMinParams) || (commandsA[i].iMaxParams >= 0 && jvParams.size() > commandsA[i].iMaxParams)) diff --git a/src/cpp/ripple/RPCErr.cpp b/src/cpp/ripple/RPCErr.cpp index 5d7e3e163..d09283fbd 100644 --- a/src/cpp/ripple/RPCErr.cpp +++ b/src/cpp/ripple/RPCErr.cpp @@ -64,7 +64,7 @@ Json::Value rpcError(int iError, Json::Value jvResult) { rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." }, { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, - { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown command." }, + { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method." }, { rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." }, }; diff --git a/src/cpp/ripple/RegularKeySetTransactor.cpp b/src/cpp/ripple/RegularKeySetTransactor.cpp index 0b88bc478..226ee7082 100644 --- a/src/cpp/ripple/RegularKeySetTransactor.cpp +++ b/src/cpp/ripple/RegularKeySetTransactor.cpp @@ -3,7 +3,7 @@ SETUP_LOG(); -uint64_t RegularKeySetTransactor::calculateBaseFee() +uint64 RegularKeySetTransactor::calculateBaseFee() { if ( !(mTxnAccount->getFlags() & lsfPasswordSpent) && (mSigningPubKey.getAccountID() == mTxnAccountID)) diff --git a/src/cpp/ripple/RegularKeySetTransactor.h b/src/cpp/ripple/RegularKeySetTransactor.h index 705a7dbfe..7d2fc53fe 100644 --- a/src/cpp/ripple/RegularKeySetTransactor.h +++ b/src/cpp/ripple/RegularKeySetTransactor.h @@ -2,7 +2,7 @@ class RegularKeySetTransactor : public Transactor { - uint64_t calculateBaseFee(); + uint64 calculateBaseFee(); public: RegularKeySetTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {} TER checkFee(); diff --git a/src/cpp/ripple/SerializedObject.cpp b/src/cpp/ripple/SerializedObject.cpp index bc20aaf1a..fc5e710c2 100644 --- a/src/cpp/ripple/SerializedObject.cpp +++ b/src/cpp/ripple/SerializedObject.cpp @@ -1039,7 +1039,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r if (value.isString()) data.push_back(new STUInt32(field, lexical_cast_st(value.asString()))); else if (value.isInt()) - data.push_back(new STUInt32(field, range_check_cast(value.asInt(), 0, 4294967295))); + data.push_back(new STUInt32(field, range_check_cast(value.asInt(), 0, 4294967295u))); else if (value.isUInt()) data.push_back(new STUInt32(field, static_cast(value.asUInt()))); else diff --git a/src/cpp/ripple/Transactor.cpp b/src/cpp/ripple/Transactor.cpp index a85d63f59..b9ace30fd 100644 --- a/src/cpp/ripple/Transactor.cpp +++ b/src/cpp/ripple/Transactor.cpp @@ -45,7 +45,7 @@ void Transactor::calculateFee() mFeeDue = STAmount(mEngine->getLedger()->scaleFeeLoad(calculateBaseFee())); } -uint64_t Transactor::calculateBaseFee() +uint64 Transactor::calculateBaseFee() { return theConfig.FEE_DEFAULT; } diff --git a/src/cpp/ripple/Transactor.h b/src/cpp/ripple/Transactor.h index c61878634..bce4c4e36 100644 --- a/src/cpp/ripple/Transactor.h +++ b/src/cpp/ripple/Transactor.h @@ -27,7 +27,7 @@ protected: void calculateFee(); // Returns the fee, not scaled for load (Should be in fee units. FIXME) - virtual uint64_t calculateBaseFee(); + virtual uint64 calculateBaseFee(); virtual TER checkSig(); virtual TER doApply()=0; diff --git a/src/cpp/ripple/base58.h b/src/cpp/ripple/base58.h index 733216faa..e2fa1c367 100644 --- a/src/cpp/ripple/base58.h +++ b/src/cpp/ripple/base58.h @@ -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& 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; diff --git a/src/cpp/ripple/bignum.h b/src/cpp/ripple/bignum.h index a9a08eda2..d2e4e5549 100644 --- a/src/cpp/ripple/bignum.h +++ b/src/cpp/ripple/bignum.h @@ -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(n)); } unsigned int getuint() const @@ -159,31 +152,42 @@ public: BN_mpi2bn(pch, p - pch, this); } + uint64 getuint64() const + { +#if (ULONG_MAX > UINT_MAX) + return static_cast(getulong()); +#else + int len = BN_num_bytes(this); + if (len > 8) + throw std::runtime_error("BN getuint64 overflow"); + + unsigned char buf[8]; + memset(buf, 0, sizeof(buf)); + BN_bn2bin(this, buf + 8 - len); + return + static_cast(buf[0]) << 56 | static_cast(buf[1]) << 48 | + static_cast(buf[2]) << 40 | static_cast(buf[3]) << 32 | + static_cast(buf[4]) << 24 | static_cast(buf[5]) << 16 | + static_cast(buf[6]) << 8 | static_cast(buf[7]); +#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(n)); +#else + unsigned char buf[8]; + buf[0] = static_cast((n >> 56) & 0xff); + buf[1] = static_cast((n >> 48) & 0xff); + buf[2] = static_cast((n >> 40) & 0xff); + buf[3] = static_cast((n >> 32) & 0xff); + buf[4] = static_cast((n >> 24) & 0xff); + buf[5] = static_cast((n >> 16) & 0xff); + buf[6] = static_cast((n >> 8) & 0xff); + buf[7] = static_cast((n) & 0xff); + BN_bin2bn(buf, 8, this); +#endif } void setuint256(const uint256& n) @@ -300,7 +304,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 +439,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); + } + }; diff --git a/src/cpp/ripple/uint256.h b/src/cpp/ripple/uint256.h index eb74f0f5e..88048bb69 100644 --- a/src/cpp/ripple/uint256.h +++ b/src/cpp/ripple/uint256.h @@ -73,7 +73,7 @@ public: zero(); // Put in least significant bits. - ((uint64_t *) end())[-1] = htobe64(uHost); + ((uint64*) end())[-1] = htobe64(uHost); return *this; } @@ -438,7 +438,7 @@ public: zero(); // Put in least significant bits. - ((uint64_t *) end())[-1] = htobe64(uHost); + ((uint64*) end())[-1] = htobe64(uHost); return *this; } @@ -656,7 +656,7 @@ public: zero(); // Put in least significant bits. - ((uint64_t *) end())[-1] = htobe64(uHost); + ((uint64*) end())[-1] = htobe64(uHost); return *this; } diff --git a/src/js/amount.js b/src/js/amount.js index 0191ee6b1..0cef359a5 100644 --- a/src/js/amount.js +++ b/src/js/amount.js @@ -778,6 +778,7 @@ Amount.prototype.ratio_human = function (denominator) { if (denominator._is_native) { numerator = numerator.clone(); numerator._value = numerator._value.multiply(consts.bi_xns_unit); + numerator.canonicalize(); } return numerator.divide(denominator); @@ -812,6 +813,7 @@ Amount.prototype.product_human = function (factor) { // See also Amount#ratio_human. if (factor._is_native) { product._value = product._value.divide(consts.bi_xns_unit); + product.canonicalize(); } return product;