diff --git a/src/Amount.cpp b/src/Amount.cpp index 13169332d..a034c35b0 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -6,12 +6,18 @@ #include "SerializedTypes.h" +// amount = value * [10 ^ offset] +// representation range is 10^80 - 10^(-80) +// on the wire, high 8 bits are (offset+142), low 56 bits are value +// value is zero if amount is zero, otherwise value is 10^15 - (10^16 - 1) inclusive + void STAmount::canonicalize() { if(value==0) { offset=0; value=0; + return; } while(valuecMaxValue) - { // Here we can make it throw on precision loss if we wish: ((value%10)!=0) + { if(offset>=cMaxOffset) throw std::runtime_error("value underflow"); value/=10; offset+=1; @@ -32,8 +38,10 @@ void STAmount::canonicalize() STAmount* STAmount::construct(SerializerIterator& sit, const char *name) { uint64 value = sit.get64(); - int offset = static_cast(value>>(64-8)); - value&=~(255ull<<(64-8)); + + int offset = static_cast(value >> (64-8)); + value &= ~(255ull << (64-8)); + if(value==0) { if(offset!=0) @@ -41,7 +49,7 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) } else { - offset-=142; + offset -= 142; // center the range if( (valuecMaxValue) || (offsetcMaxOffset) ) throw std::runtime_error("invalid currency value"); } @@ -49,7 +57,7 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) } std::string STAmount::getText() const -{ +{ // This should be re-implemented to put a '.' in the string form of the integer value std::ostringstream str; str << std::setprecision(16) << static_cast(*this); return str.str(); @@ -57,44 +65,48 @@ std::string STAmount::getText() const void STAmount::add(Serializer& s) const { - uint64 v=value; - if(v!=0) v+=(static_cast(offset+142) << (64-8)); - s.add64(v); + if (value==0) + s.add64(0); + else + s.add64(value + (static_cast(offset+142) << (64-8)))); } bool STAmount::isEquivalent(const SerializedType& t) const { - const STAmount* v=dynamic_cast(&t); + const STAmount* v = dynamic_cast(&t); if(!v) return false; - return (value==v->value) && (offset==v->offset); + return (value == v->value) && (offset == v->offset); } bool STAmount::operator==(const STAmount& a) const { - return (offset==a.offset) && (value==a.value); + return (offset == a.offset) && (value == a.value); } bool STAmount::operator!=(const STAmount& a) const { - return (offset!=a.offset) || (value!=a.value); + return (offset != a.offset) || (value != a.value); } bool STAmount::operator<(const STAmount& a) const { - if(offset(const STAmount& a) const { - if(offset>a.offset) return true; - if(a.offset>offset) return false; + if(value == 0) return a.value != 0; + if(offset > a.offset) return true; + if(a.offset > offset) return false; return value > a.value; } bool STAmount::operator<=(const STAmount& a) const { + if(value == 0) return a.value== 0; if(offset=(const STAmount& a) const { + if(value == 0) return true; if(offset>a.offset) return true; if(a.offset>offset) return false; return value >= a.value; @@ -175,7 +188,7 @@ STAmount operator-(STAmount v1, STAmount v2) v2.value/=10; v2.offset+=1; } - if(v1.value < v2.value) throw std::runtime_error("value overflow"); + if(v1.value < v2.value) throw std::runtime_error("value underflow"); return STAmount(v1.name, v1.value - v2.value, v1.offset); } @@ -183,22 +196,21 @@ STAmount getRate(const STAmount& offerIn, const STAmount& offerOut) { CBigNum numerator, denominator, quotient; - if(offerOut.value==0) throw std::runtime_error("illegal offer"); - if(offerIn.value==0) return STAmount(); + if(offerOut.value == 0) throw std::runtime_error("illegal offer"); + if(offerIn.value == 0) return STAmount(); - if( (BN_zero(&numerator)!=1) || (BN_zero(&denominator)!=1) || - (BN_add_word(&numerator, offerIn.value)!=1) || - (BN_add_word(&denominator, offerOut.value)!=1) || - (BN_mul_word(&numerator, 1000000000000000ull)!=1) || - (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX())!=1) ) - throw std::runtime_error("internal bn error"); - - int offset=offerIn.offset - offerOut.offset - 15; - - while(BN_num_bits("ient)>60) + // Compute (numerator * 10^16) / denominator + if( (BN_zero(&numerator) != 1) || (BN_zero(&denominator) != 1) || + (BN_add_word(&numerator, offerIn.value) != 1) || + (BN_add_word(&denominator, offerOut.value) != 1) || + (BN_mul_word(&numerator, 10000000000000000ull) != 1) || + (BN_div("ient, NULL, &numerator, &denominator, CAutoBN_CTX()) != 1) ) { - offset+=3; - BN_div_word("ient, 1000); + throw std::runtime_error("internal bn error"); } - return STAmount(quotient.getulong(), offset); + + // 10^15 <= quotient <= 10^17 + assert(BN_num_bytes("ient)<=60); + + return STAmount(quotient.getulong(), offerIn.offset - offerOut.offset - 16); }