diff --git a/src/amount.h b/src/amount.h index 8a046e299..492bec515 100644 --- a/src/amount.h +++ b/src/amount.h @@ -1,221 +1,225 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_AMOUNT_H #define BITCOIN_AMOUNT_H #include "serialize.h" #include #include #include #include struct Amount { private: int64_t amount; public: constexpr Amount() : amount(0) {} template explicit constexpr Amount(T _camount) : amount(_camount) { static_assert(std::is_integral(), "Only integer types can be used as amounts"); } constexpr Amount(const Amount &_camount) : amount(_camount.amount) {} // Allow access to underlying value for non-monetary operations int64_t GetSatoshis() const { return *this / Amount(1); } /** * Implement standard operators */ Amount &operator+=(const Amount a) { amount += a.amount; return *this; } Amount &operator-=(const Amount a) { amount -= a.amount; return *this; } /** * Equality */ friend constexpr bool operator==(const Amount a, const Amount b) { return a.amount == b.amount; } friend constexpr bool operator!=(const Amount a, const Amount b) { return !(a == b); } /** * Comparison */ friend constexpr bool operator<(const Amount a, const Amount b) { return a.amount < b.amount; } friend constexpr bool operator>(const Amount a, const Amount b) { return b < a; } friend constexpr bool operator<=(const Amount a, const Amount b) { return !(a > b); } friend constexpr bool operator>=(const Amount a, const Amount b) { return !(a < b); } /** * Unary minus */ constexpr Amount operator-() const { return Amount(-amount); } /** * Addition and subtraction. */ friend constexpr Amount operator+(const Amount a, const Amount b) { return Amount(a.amount + b.amount); } friend constexpr Amount operator-(const Amount a, const Amount b) { return a + -b; } /** * Multiplication */ friend constexpr Amount operator*(const int64_t a, const Amount b) { return Amount(a * b.amount); } friend constexpr Amount operator*(const int a, const Amount b) { return Amount(a * b.amount); } /** * Division */ constexpr int64_t operator/(const Amount b) const { return amount / b.amount; } constexpr Amount operator/(const int64_t b) const { return Amount(amount / b); } constexpr Amount operator/(const int b) const { return Amount(amount / b); } + Amount &operator/=(const int64_t n) { + amount /= n; + return *this; + } /** * Modulus */ constexpr int64_t operator%(const Amount b) const { return Amount(amount % b.amount) / Amount(1); } constexpr Amount operator%(const int64_t b) const { return Amount(amount % b); } constexpr Amount operator%(const int b) const { return Amount(amount % b); } /** * Do not implement double ops to get an error with double and ensure * casting to integer is explicit. */ friend constexpr Amount operator*(const double a, const Amount b) = delete; constexpr Amount operator/(const double b) const = delete; constexpr Amount operator%(const double b) const = delete; // ostream support friend std::ostream &operator<<(std::ostream &stream, const Amount &ca) { return stream << ca.amount; } std::string ToString() const; // serialization support ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(amount); } }; static const Amount SATOSHI(1); static const Amount CASH = 100 * SATOSHI; static const Amount COIN = 100000000 * SATOSHI; static const Amount CENT = COIN / 100; extern const std::string CURRENCY_UNIT; /** * No amount larger than this (in satoshi) is valid. * * Note that this constant is *not* the total money supply, which in Bitcoin * currently happens to be less than 21,000,000 BCH for various reasons, but * rather a sanity check. As this sanity check is used by consensus-critical * validation code, the exact value of the MAX_MONEY constant is consensus * critical; in unusual circumstances like a(nother) overflow bug that allowed * for the creation of coins out of thin air modification could lead to a fork. */ static const Amount MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(const Amount nValue) { return (nValue >= Amount(0) && nValue <= MAX_MONEY); } /** * Fee rate in satoshis per kilobyte: Amount / kB */ class CFeeRate { private: // unit is satoshis-per-1,000-bytes Amount nSatoshisPerK; public: /** Fee rate of 0 satoshis per kB */ CFeeRate() : nSatoshisPerK(0) {} explicit CFeeRate(const Amount _nSatoshisPerK) : nSatoshisPerK(_nSatoshisPerK) {} /** * Constructor for a fee rate in satoshis per kB. The size in bytes must not * exceed (2^63 - 1) */ CFeeRate(const Amount nFeePaid, size_t nBytes); CFeeRate(const CFeeRate &other) { nSatoshisPerK = other.nSatoshisPerK; } /** * Return the fee in satoshis for the given size in bytes. */ Amount GetFee(size_t nBytes) const; /** * Return the fee in satoshis for a size of 1000 bytes */ Amount GetFeePerK() const { return GetFee(1000); } friend bool operator<(const CFeeRate &a, const CFeeRate &b) { return a.nSatoshisPerK < b.nSatoshisPerK; } friend bool operator>(const CFeeRate &a, const CFeeRate &b) { return a.nSatoshisPerK > b.nSatoshisPerK; } friend bool operator==(const CFeeRate &a, const CFeeRate &b) { return a.nSatoshisPerK == b.nSatoshisPerK; } friend bool operator<=(const CFeeRate &a, const CFeeRate &b) { return a.nSatoshisPerK <= b.nSatoshisPerK; } friend bool operator>=(const CFeeRate &a, const CFeeRate &b) { return a.nSatoshisPerK >= b.nSatoshisPerK; } CFeeRate &operator+=(const CFeeRate &a) { nSatoshisPerK += a.nSatoshisPerK; return *this; } std::string ToString() const; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(nSatoshisPerK); } }; #endif // BITCOIN_AMOUNT_H diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index 90272b99a..80655fed6 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -1,82 +1,79 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utilmoneystr.h" #include "primitives/transaction.h" #include "tinyformat.h" #include "utilstrencodings.h" std::string FormatMoney(const Amount amt) { // Note: not using straight sprintf here because we do NOT want localized // number formatting. - int64_t n = amt.GetSatoshis(); - int64_t n_abs = (n > 0 ? n : -n); - int64_t quotient = n_abs / COIN.GetSatoshis(); - int64_t remainder = n_abs % COIN.GetSatoshis(); - std::string str = strprintf("%d.%08d", quotient, remainder); + Amount amt_abs = amt > Amount(0) ? amt : -amt; + std::string str = strprintf("%d.%08d", amt_abs / COIN, amt_abs % COIN); // Right-trim excess zeros before the decimal point: int nTrim = 0; for (int i = str.size() - 1; (str[i] == '0' && isdigit(str[i - 2])); --i) { ++nTrim; } if (nTrim) { str.erase(str.size() - nTrim, nTrim); } - if (n < 0) { + if (amt < Amount(0)) { str.insert((unsigned int)0, 1, '-'); } return str; } bool ParseMoney(const std::string &str, Amount &nRet) { return ParseMoney(str.c_str(), nRet); } bool ParseMoney(const char *pszIn, Amount &nRet) { std::string strWhole; - int64_t nUnits = 0; + Amount nUnits(0); const char *p = pszIn; while (isspace(*p)) { p++; } for (; *p; p++) { if (*p == '.') { p++; - int64_t nMult = 10 * CENT.GetSatoshis(); - while (isdigit(*p) && (nMult > 0)) { - nUnits += nMult * (*p++ - '0'); + Amount nMult = 10 * CENT; + while (isdigit(*p) && (nMult > Amount(0))) { + nUnits += (*p++ - '0') * nMult; nMult /= 10; } break; } if (isspace(*p)) { break; } if (!isdigit(*p)) { return false; } strWhole.insert(strWhole.end(), *p); } for (; *p; p++) { if (!isspace(*p)) { return false; } } // guard against 63 bit overflow if (strWhole.size() > 10) { return false; } - if (nUnits < 0 || nUnits > COIN.GetSatoshis()) { + if (nUnits < Amount(0) || nUnits > COIN) { return false; } - int64_t nWhole = atoi64(strWhole); - Amount nValue = nWhole * COIN + Amount(nUnits); - nRet = nValue; + Amount nWhole = atoi64(strWhole) * COIN; + + nRet = nWhole + Amount(nUnits); return true; }