diff --git a/src/Amount.cpp b/src/Amount.cpp index f51dbd5204..b53aaaa2a2 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -164,6 +164,7 @@ void STAmount::canonicalize() if (mValue == 0) { mOffset = 0; + mIsNegative = false; return; } @@ -187,6 +188,7 @@ void STAmount::canonicalize() if (mValue == 0) { mOffset = -100; + mIsNegative = false; return; } @@ -217,13 +219,16 @@ void STAmount::add(Serializer& s) const if (mIsNative) { assert(mOffset == 0); - s.add64(mValue); + if (!mIsNegative) s.add64(mValue | cPosNative); + else s.add64(mValue); return; } if (isZero()) s.add64(cNotNative); - else // Adding 396 centers the offset and sets the "not native" flag - s.add64(mValue + (static_cast(mOffset + 396) << (64 - 9))); + else if (mIsNegative) // 512 = not native + s.add64(mValue | (static_cast(mOffset + 512 + 97) << (64 - 10))); + else // 256 = positive + s.add64(mValue | (static_cast(mOffset + 512 + 256 + 97) << (64 - 10))); s.add160(mCurrency); } @@ -232,34 +237,45 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) uint64 value = sit.get64(); if ((value & cNotNative) == 0) - return new STAmount(name, value); + { // native + if ((value & cPosNative) != 0) + return new STAmount(name, value & ~cPosNative, false); // positive + return new STAmount(name, value, true); // negative + } uint160 currency = sit.get160(); if (!currency) throw std::runtime_error("invalid native currency"); - int offset = static_cast(value >> (64-9)); // 9 bits for the offset and "not native" flag - value &= ~(1023ull << (64-9)); + int offset = static_cast(value >> (64 - 10)); // 10 bits for the offset, sign and "not native" flag + value &= ~(1023ull << (64-10)); if (value == 0) { - if (offset != 256) + if (offset != 512) throw std::runtime_error("invalid currency value"); + return new STAmount(name, currency); } - else - { - offset -= 396; // center the range and remove the "not native" bit - if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset)) - throw std::runtime_error("invalid currency value"); - } - return new STAmount(name, currency, value, offset); + + bool isNegative = (offset & 256) == 0; + offset = (offset & 255) - 97; // center the range + if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset)) + throw std::runtime_error("invalid currency value"); + return new STAmount(name, currency, value, offset, isNegative); } std::string STAmount::getRaw() const { // show raw internal form if (mValue == 0) return "0"; - if (mIsNative) return boost::lexical_cast(mValue); - return mCurrency.GetHex() + ": " + + if (mIsNative) + { + if (mIsNegative) return std::string("-") + boost::lexical_cast(mValue); + else return boost::lexical_cast(mValue); + } + if (mIsNegative) + return mCurrency.GetHex() + ": -" + + boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + else return mCurrency.GetHex() + ": " + boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); } @@ -267,9 +283,19 @@ std::string STAmount::getText() const { // keep full internal accuracy, but make more human friendly if posible if (isZero()) return "0"; if (mIsNative) - return boost::lexical_cast(mValue); + { + if (mIsNegative) + return std::string("-") + boost::lexical_cast(mValue); + else return boost::lexical_cast(mValue); + } if ((mOffset < -25) || (mOffset > -5)) - return boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + { + if (mIsNegative) + return std::string("-") + boost::lexical_cast(mValue) + + "e" + boost::lexical_cast(mOffset); + else + return boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + } std::string val = "000000000000000000000000000"; val += boost::lexical_cast(mValue); @@ -285,6 +311,9 @@ std::string STAmount::getText() const pre = pre.substr(s_pre); size_t s_post = post.find_last_not_of('0'); + + if (mIsNegative) pre = std::string("-") + pre; + if (s_post == std::string::npos) return pre; else @@ -365,6 +394,12 @@ STAmount& STAmount::operator-=(const STAmount& a) return *this; } +STAmount STAmount::operator-(void) const +{ + if (mValue == 0) return STAmount(NULL, mValue, mOffset, mIsNative, !mIsNegative); + return *this; +} + STAmount& STAmount::operator=(const STAmount& a) { mValue = a.mValue; @@ -779,6 +814,8 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) uint160 currency(1); STAmount zero(currency), one(currency, 1), hundred(currency, 100); + serdes(one).getRaw(); + if (serdes(zero) != zero) BOOST_FAIL("STAmount fail"); if (serdes(one) != one) BOOST_FAIL("STAmount fail"); if (serdes(hundred) != hundred) BOOST_FAIL("STAmount fail"); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 957e868ab2..40f969cf77 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -208,49 +208,68 @@ protected: uint160 mCurrency; uint64 mValue; int mOffset; - bool mIsNative; + bool mIsNative, mIsNegative; void canonicalize(); - STAmount* duplicate() const { return new STAmount(name, mCurrency, mValue, mOffset); } + STAmount* duplicate() const { return new STAmount(*this); } static STAmount* construct(SerializerIterator&, const char* name = NULL); - STAmount(bool, uint64 value) : mValue(value), mOffset(0), mIsNative(true) { ; } static const int cMinOffset = -96, cMaxOffset = 80; static const uint64 cMinValue = 1000000000000000ull, cMaxValue = 9999999999999999ull; static const uint64 cMaxNative = 9000000000000000000ull; static const uint64 cNotNative = 0x8000000000000000ull; + static const uint64 cPosNative = 0x4000000000000000ull; + + STAmount(bool, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(false) { ; } + + STAmount(const char *name, uint64 value, bool isNegative) + : SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) + { ; } + + STAmount(const char *nm, const uint160& cur, uint64 v, int off, bool isNegative) + : SerializedType(nm), mCurrency(cur), mValue(v), mOffset(off), mIsNative(false), mIsNegative(isNegative) + { ; } public: - STAmount(uint64 v = 0) : mValue(v), mOffset(0), mIsNative(true) + STAmount(uint64 v = 0) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } - STAmount(const char* n, uint64 v = 0) : SerializedType(n), mValue(v), mOffset(0), mIsNative(true) + STAmount(const char* n, uint64 v = 0) + : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } - STAmount(const uint160& currency, uint64 v = 0, int off = 0) : mCurrency(currency), mValue(v), mOffset(off) + STAmount(const uint160& currency, uint64 v = 0, int off = 0) + : mCurrency(currency), mValue(v), mOffset(off), mIsNegative(false) { canonicalize(); } STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0) : SerializedType(n), - mCurrency(currency), mValue(v), mOffset(off) + mCurrency(currency), mValue(v), mOffset(off), mIsNegative(false) { canonicalize(); } static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return mIsNative ? 8 : 28; } - SerializedTypeID getSType() const { return STI_AMOUNT; } + int getLength() const { return mIsNative ? 8 : 28; } + SerializedTypeID getSType() const { return STI_AMOUNT; } std::string getText() const; std::string getRaw() const; void add(Serializer& s) const; - int getOffset() const { return mOffset; } - uint64 getValue() const { return mValue; } - void setValue(const STAmount& v) { mValue=v; } + int getOffset() const { return mOffset; } + uint64 getValue() const { return mValue; } + void setValue(const STAmount& v) { mValue=v; } std::string getCurrencyHuman(); - bool isNative() const { return mIsNative; } + + bool isNative() const { return mIsNative; } + bool isZero() const { return mValue == 0; } + bool isNegative() const { return mIsNegative && !isZero(); } + bool isPositive() const { return !mIsNegative && !isZero(); } + bool isGEZero() const { return !mIsNegative; } + + void changeSign() { if (!isZero()) mIsNegative = !mIsNegative; } + void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; mIsNegative = false; } + const uint160& getCurrency() const { return mCurrency; } - void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; } - bool isZero() const { return mValue == 0; } bool setValue(const std::string& sAmount, const std::string& sCurrency); virtual bool isEquivalent(const SerializedType& t) const; @@ -271,6 +290,7 @@ public: bool operator>=(uint64) const; STAmount operator+(uint64) const; STAmount operator-(uint64) const; + STAmount operator-(void) const; STAmount& operator+=(const STAmount&); STAmount& operator-=(const STAmount&);