mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Promote 'amounts' to a new type. Codify storage format, both internal
and serialized. Define operators.
This commit is contained in:
71
src/Amount.cpp
Normal file
71
src/Amount.cpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
#include "SerializedTypes.h"
|
||||||
|
|
||||||
|
void STAmount::canonicalize()
|
||||||
|
{
|
||||||
|
if(value==0)
|
||||||
|
{
|
||||||
|
offset=0;
|
||||||
|
value=0;
|
||||||
|
}
|
||||||
|
while(value<cMinValue)
|
||||||
|
{
|
||||||
|
value*=10;
|
||||||
|
offset-=1;
|
||||||
|
}
|
||||||
|
while(value>cMaxValue)
|
||||||
|
{ // Here we can make it throw on precision loss if we wish: ((value%10)!=0)
|
||||||
|
value/=10;
|
||||||
|
offset+=1;
|
||||||
|
}
|
||||||
|
assert( (value==0) || ( (value>=cMinValue) && (value<=cMaxValue) ) );
|
||||||
|
assert( (offset>=cMinOffset) && (offset<=cMaxOffset) );
|
||||||
|
}
|
||||||
|
|
||||||
|
STAmount* STAmount::construct(SerializerIterator& sit, const char *name)
|
||||||
|
{
|
||||||
|
uint64 value = sit.get64();
|
||||||
|
int offset = static_cast<int>(value>>(64-8));
|
||||||
|
offset-=142;
|
||||||
|
value&=~(255ull<<(64-8));
|
||||||
|
if(value==0)
|
||||||
|
{
|
||||||
|
if(offset!=0)
|
||||||
|
throw std::runtime_error("invalid currency value");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( (value<cMinValue) || (value>cMaxValue) || (offset<cMinOffset) || (offset>cMaxOffset) )
|
||||||
|
throw std::runtime_error("invalid currency value");
|
||||||
|
}
|
||||||
|
return new STAmount(name, value, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string STAmount::getText() const
|
||||||
|
{
|
||||||
|
return boost::lexical_cast<std::string>(static_cast<double>(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void STAmount::add(Serializer& s) const
|
||||||
|
{
|
||||||
|
uint64 v=value;
|
||||||
|
v+=(static_cast<uint64>(offset+142) << (64-8));
|
||||||
|
s.add64(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool STAmount::isEquivalent(const SerializedType& t) const
|
||||||
|
{
|
||||||
|
const STAmount* v=dynamic_cast<const STAmount*>(&t);
|
||||||
|
if(!v) return false;
|
||||||
|
return (value==v->value) && (offset==v->offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
STAmount::operator double() const
|
||||||
|
{
|
||||||
|
if(!value) return 0.0;
|
||||||
|
return static_cast<double>(value) * pow(10.0, offset);
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ LedgerEntryFormat LedgerFormats[]=
|
|||||||
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
||||||
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 },
|
{ S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Balance), STI_UINT64, SOE_REQUIRED, 0 },
|
{ S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 },
|
{ S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(LastTxn), STI_UINT32, SOE_REQUIRED, 0 },
|
{ S_FIELD(LastTxn), STI_UINT32, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 1 },
|
{ S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 1 },
|
||||||
@@ -23,8 +23,8 @@ LedgerEntryFormat LedgerFormats[]=
|
|||||||
{ S_FIELD(Borrower), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(Borrower), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Lender), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(Lender), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
|
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
|
||||||
{ S_FIELD(Limit), STI_UINT64, SOE_REQUIRED, 0 },
|
{ S_FIELD(Limit), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Balance), STI_UINT64, SOE_REQUIRED, 0 },
|
{ S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(CurrentRate), STI_UINT32, SOE_IFFLAG, 2 },
|
{ S_FIELD(CurrentRate), STI_UINT32, SOE_IFFLAG, 2 },
|
||||||
{ S_FIELD(RateLock), STI_UINT32, SOE_IFFLAG, 4 },
|
{ S_FIELD(RateLock), STI_UINT32, SOE_IFFLAG, 4 },
|
||||||
{ S_FIELD(NextRate), STI_UINT32, SOE_IFFLAG, 8 },
|
{ S_FIELD(NextRate), STI_UINT32, SOE_IFFLAG, 8 },
|
||||||
@@ -37,7 +37,7 @@ LedgerEntryFormat LedgerFormats[]=
|
|||||||
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
||||||
{ S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 },
|
{ S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(MinimumOffer), STI_UINT64, SOE_IFFLAG, 1 },
|
{ S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 },
|
||||||
{ S_FIELD(OfferCurrency),STI_HASH160, SOE_IFFLAG, 2 },
|
{ S_FIELD(OfferCurrency),STI_HASH160, SOE_IFFLAG, 2 },
|
||||||
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 },
|
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 },
|
||||||
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
|
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ SerializedType* STObject::makeDefaultObject(SerializedTypeID id, const char *nam
|
|||||||
case STI_UINT64:
|
case STI_UINT64:
|
||||||
return new STUInt64(name);
|
return new STUInt64(name);
|
||||||
|
|
||||||
|
case STI_AMOUNT:
|
||||||
|
return new STAmount(name);
|
||||||
|
|
||||||
case STI_HASH160:
|
case STI_HASH160:
|
||||||
return new STHash160(name);
|
return new STHash160(name);
|
||||||
|
|
||||||
@@ -49,6 +52,9 @@ SerializedType* STObject::makeDeserializedObject(SerializedTypeID id, const char
|
|||||||
case STI_UINT64:
|
case STI_UINT64:
|
||||||
return STUInt64::construct(sit, name);
|
return STUInt64::construct(sit, name);
|
||||||
|
|
||||||
|
case STI_AMOUNT:
|
||||||
|
return STAmount::construct(sit, name);
|
||||||
|
|
||||||
case STI_HASH160:
|
case STI_HASH160:
|
||||||
return STHash160::construct(sit, name);
|
return STHash160::construct(sit, name);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ enum SerializedTypeID
|
|||||||
// standard types
|
// standard types
|
||||||
STI_OBJECT=1, STI_UINT8=2, STI_UINT16=3, STI_UINT32=4, STI_UINT64=5,
|
STI_OBJECT=1, STI_UINT8=2, STI_UINT16=3, STI_UINT32=4, STI_UINT64=5,
|
||||||
STI_HASH128=6, STI_HASH160=7, STI_HASH256=8, STI_VL=9, STI_TL=10,
|
STI_HASH128=6, STI_HASH160=7, STI_HASH256=8, STI_VL=9, STI_TL=10,
|
||||||
|
STI_AMOUNT=11,
|
||||||
|
|
||||||
// high level types
|
// high level types
|
||||||
STI_ACCOUNT=100, STI_TRANSACTION=101, STI_LEDGERENTRY=102
|
STI_ACCOUNT=100, STI_TRANSACTION=101, STI_LEDGERENTRY=102
|
||||||
@@ -155,6 +156,67 @@ public:
|
|||||||
virtual bool isEquivalent(const SerializedType& t) const;
|
virtual bool isEquivalent(const SerializedType& t) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class STAmount : public SerializedType
|
||||||
|
{
|
||||||
|
// Internal form:
|
||||||
|
// 1: If amount is zero, then offset and value are both zero.
|
||||||
|
// 2: Otherwise:
|
||||||
|
// legal offset range is -96 to +80 inclusive
|
||||||
|
// value range is 10^15 to (10^16 - 1) inclusive
|
||||||
|
// amount = value * [10 ^ offset]
|
||||||
|
|
||||||
|
// Wire form:
|
||||||
|
// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive
|
||||||
|
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int offset; // These variables *always* hold canonical values
|
||||||
|
uint64 value;
|
||||||
|
|
||||||
|
void canonicalize();
|
||||||
|
|
||||||
|
static const int cMinOffset=-96, cMaxOffset=80;
|
||||||
|
static const uint64 cMinValue=1000000000000000ull, cMaxValue=9999999999999999ull;
|
||||||
|
|
||||||
|
public:
|
||||||
|
STAmount(uint64 v=0, int off=0) : offset(off), value(v)
|
||||||
|
{ canonicalize(); } // (1,0)=$1 (1,-2)=$.01 (100,0)=(10000,-2)=$.01
|
||||||
|
STAmount(const char *n, uint64 v=0, int off=1) : SerializedType(n), offset(off), value(v)
|
||||||
|
{ canonicalize(); }
|
||||||
|
static STAmount* construct(SerializerIterator&, const char *name=NULL);
|
||||||
|
|
||||||
|
int getLength() const { return 8; }
|
||||||
|
SerializedTypeID getSType() const { return STI_AMOUNT; }
|
||||||
|
STAmount* duplicate() const { return new STAmount(name, offset, value); }
|
||||||
|
std::string getText() const;
|
||||||
|
void add(Serializer& s) const;
|
||||||
|
|
||||||
|
int getOffset() const { return offset; }
|
||||||
|
uint64 getValue() const { return value; }
|
||||||
|
|
||||||
|
virtual bool isEquivalent(const SerializedType& t) const;
|
||||||
|
|
||||||
|
bool operator==(const STAmount&) const;
|
||||||
|
bool operator!=(const STAmount&) const;
|
||||||
|
bool operator<(const STAmount&) const;
|
||||||
|
bool operator>(const STAmount&) const;
|
||||||
|
bool operator<=(const STAmount&) const;
|
||||||
|
bool operator>=(const STAmount&) const;
|
||||||
|
|
||||||
|
STAmount& operator+=(const STAmount&);
|
||||||
|
STAmount& operator-=(const STAmount&);
|
||||||
|
STAmount& operator=(const STAmount&);
|
||||||
|
STAmount& operator+=(uint64);
|
||||||
|
STAmount& operator-=(uint64);
|
||||||
|
STAmount& operator=(uint64);
|
||||||
|
|
||||||
|
operator double() const;
|
||||||
|
|
||||||
|
friend STAmount operator+(const STAmount& v1, const STAmount& v2);
|
||||||
|
friend STAmount operator-(const STAmount& v1, const STAmount& v2);
|
||||||
|
friend STAmount operator/(const STAmount& v1, const STAmount& v2);
|
||||||
|
};
|
||||||
|
|
||||||
class STHash128 : public SerializedType
|
class STHash128 : public SerializedType
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ TransactionFormat InnerTxnFormats[]=
|
|||||||
{ "MakePayment", ttMAKE_PAYMENT, {
|
{ "MakePayment", ttMAKE_PAYMENT, {
|
||||||
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
||||||
{ S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Amount), STI_UINT64, SOE_REQUIRED, 0 },
|
{ S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
|
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
|
||||||
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
|
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
|
||||||
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 4 },
|
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 4 },
|
||||||
@@ -19,7 +19,7 @@ TransactionFormat InnerTxnFormats[]=
|
|||||||
{ "Invoice", ttINVOICE, {
|
{ "Invoice", ttINVOICE, {
|
||||||
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
||||||
{ S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Amount), STI_UINT64, SOE_REQUIRED, 0 },
|
{ S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
|
{ S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 },
|
||||||
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
|
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
|
||||||
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 4 },
|
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 4 },
|
||||||
@@ -30,9 +30,9 @@ TransactionFormat InnerTxnFormats[]=
|
|||||||
},
|
},
|
||||||
{ "Offer", ttEXCHANGE_OFFER, {
|
{ "Offer", ttEXCHANGE_OFFER, {
|
||||||
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
{ S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 },
|
||||||
{ S_FIELD(AmountIn), STI_UINT64, SOE_REQUIRED, 0 },
|
{ S_FIELD(AmountIn), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(CurrencyIn), STI_HASH160, SOE_IFFLAG, 2 },
|
{ S_FIELD(CurrencyIn), STI_HASH160, SOE_IFFLAG, 2 },
|
||||||
{ S_FIELD(AmountOut), STI_UINT64, SOE_REQUIRED, 0 },
|
{ S_FIELD(AmountOut), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(CurrencyOut), STI_HASH160, SOE_IFFLAG, 4 },
|
{ S_FIELD(CurrencyOut), STI_HASH160, SOE_IFFLAG, 4 },
|
||||||
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 8 },
|
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 8 },
|
||||||
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 16 },
|
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 16 },
|
||||||
|
|||||||
Reference in New Issue
Block a user