From ec8419fc7968002224036153c8bc36d8120a5bb5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 8 Apr 2012 01:40:11 -0700 Subject: [PATCH 01/14] Warn about throwing. --- src/ECIES.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ECIES.cpp b/src/ECIES.cpp index c3ba79481..94e477054 100644 --- a/src/ECIES.cpp +++ b/src/ECIES.cpp @@ -32,6 +32,9 @@ // 3) Encrypted: Original plaintext // 4) Encrypted: Rest of block/padding +// ECIES operations throw on any error such as a corrupt message or incorrect +// key. They *must* be called in try/catch blocks. + // Algorithmic choices: #define ECIES_KEY_HASH SHA512 // Hash used to expand shared secret #define ECIES_KEY_LENGTH (512/8) // Size of expanded shared secret From d7669944de1efe23f73635c853be11fe5cd9058e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 8 Apr 2012 16:33:28 -0700 Subject: [PATCH 02/14] Ability to compare serialized types. --- src/SerializedObject.cpp | 16 ++++++++++ src/SerializedObject.h | 1 + src/SerializedTransaction.cpp | 10 +++++++ src/SerializedTransaction.h | 1 + src/SerializedTypes.cpp | 56 +++++++++++++++++++++++++++++++++-- src/SerializedTypes.h | 16 ++++++++++ 6 files changed, 98 insertions(+), 2 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index e27ce55d2..c09e67904 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -167,6 +167,22 @@ std::string STObject::getText() const return ret; } +bool STObject::isEquivalent(const SerializedType& t) const +{ + const STObject* v=dynamic_cast(&t); + if(!v) return false; + boost::ptr_vector::const_iterator it1=mData.begin(), end1=mData.end(); + boost::ptr_vector::const_iterator it2=v->mData.begin(), end2=v->mData.end(); + while((it1!=end1) && (it2!=end2)) + { + if(it1->getType() != it2->getType()) return false; + if(!it1->isEquivalent(*it2)) return false; + ++it1; + ++it2; + } + return (it1==end1) && (it2==end2); +} + int STObject::getFieldIndex(SOE_Field field) const { int i=0; diff --git a/src/SerializedObject.h b/src/SerializedObject.h index f1e53ad14..16dc18285 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -58,6 +58,7 @@ public: int getLength() const; SerializedTypeID getType() const { return STI_OBJECT; } STObject* duplicate() const { return new STObject(*this); } + virtual bool isEquivalent(const SerializedType& t) const; void add(Serializer& s) const; std::string getFullText() const; diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 8192a8e71..88dd761c3 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -77,6 +77,16 @@ int SerializedTransaction::getTransaction(Serializer& s, bool include_length) co return l; } +bool SerializedTransaction::isEquivalent(const SerializedType& t) const +{ // Signatures are not compared + const SerializedTransaction* v=dynamic_cast(&t); + if(!v) return false; + if(type != v->type) return false; + if(mMiddleTxn != v->mMiddleTxn) return false; + if(mInnerTxn != v->mInnerTxn) return false; + return true; +} + uint256 SerializedTransaction::getSigningHash() const { Serializer s; diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 644634d8f..3f6458954 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -31,6 +31,7 @@ public: std::string getFullText() const; std::string getText() const; void add(Serializer& s) const { getTransaction(s, true); } + virtual bool isEquivalent(const SerializedType& t) const; // outer transaction functions / signature functions std::vector getSignature() const; diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 80d63de30..a7527b332 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -31,6 +31,12 @@ std::string STUInt8::getText() const return boost::lexical_cast(value); } +bool STUInt8::isEquivalent(const SerializedType& t) const +{ + const STUInt8* v=dynamic_cast(&t); + return v && (value==v->value); +} + STUInt16* STUInt16::construct(SerializerIterator& u, const char *name) { return new STUInt16(name, u.get16()); @@ -41,8 +47,14 @@ std::string STUInt16::getText() const return boost::lexical_cast(value); } -STUInt32* STUInt32::construct(SerializerIterator& u, const char *name) +bool STUInt16::isEquivalent(const SerializedType& t) const { + const STUInt16* v=dynamic_cast(&t); + return v && (value==v->value); +} + +STUInt32* STUInt32::construct(SerializerIterator& u, const char *name) + { return new STUInt32(name, u.get32()); } @@ -51,6 +63,12 @@ std::string STUInt32::getText() const return boost::lexical_cast(value); } +bool STUInt32::isEquivalent(const SerializedType& t) const +{ + const STUInt32* v=dynamic_cast(&t); + return v && (value==v->value); +} + STUInt64* STUInt64::construct(SerializerIterator& u, const char *name) { return new STUInt64(name, u.get64()); @@ -61,6 +79,12 @@ std::string STUInt64::getText() const return boost::lexical_cast(value); } +bool STUInt64::isEquivalent(const SerializedType& t) const +{ + const STUInt64* v=dynamic_cast(&t); + return v && (value==v->value); +} + STHash128* STHash128::construct(SerializerIterator& u, const char *name) { return new STHash128(name, u.get128()); @@ -71,6 +95,12 @@ std::string STHash128::getText() const return value.GetHex(); } +bool STHash128::isEquivalent(const SerializedType& t) const +{ + const STHash128* v=dynamic_cast(&t); + return v && (value==v->value); +} + STHash160* STHash160::construct(SerializerIterator& u, const char *name) { return new STHash160(name, u.get160()); @@ -81,6 +111,12 @@ std::string STHash160::getText() const return value.GetHex(); } +bool STHash160::isEquivalent(const SerializedType& t) const +{ + const STHash160* v=dynamic_cast(&t); + return v && (value==v->value); +} + STHash256* STHash256::construct(SerializerIterator& u, const char *name) { return new STHash256(name, u.get256()); @@ -91,6 +127,12 @@ std::string STHash256::getText() const return value.GetHex(); } +bool STHash256::isEquivalent(const SerializedType& t) const +{ + const STHash256* v=dynamic_cast(&t); + return v && (value==v->value); +} + static std::string hex(const std::vector& value) { int dlen=value.size(), i=0; @@ -115,6 +157,12 @@ int STVariableLength::getLength() const return Serializer::encodeLengthLength(value.size()) + value.size(); } +bool STVariableLength::isEquivalent(const SerializedType& t) const +{ + const STVariableLength* v=dynamic_cast(&t); + return v && (value==v->value); +} + std::string STAccount::getText() const { uint160 u; @@ -177,4 +225,8 @@ int STTaggedList::getLength() const return ret; } - +bool STTaggedList::isEquivalent(const SerializedType& t) const +{ + const STTaggedList* v=dynamic_cast(&t); + return v && (value==v->value); +} diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 53b1375c6..3c43e1aad 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -46,6 +46,13 @@ public: SerializedType* new_clone(const SerializedType& s) { return s.duplicate(); } void delete_clone(const SerializedType* s) { boost::checked_delete(s); } + + virtual bool isEquivalent(const SerializedType& t) const { return true; } + + bool operator==(const SerializedType& t) const + { return (getType()==t.getType()) && isEquivalent(t); } + bool operator!=(const SerializedType& t) const + { return (getType()!=t.getType()) || !isEquivalent(t); } }; class STUInt8 : public SerializedType @@ -70,6 +77,7 @@ public: operator unsigned char() const { return value; } STUInt8& operator=(unsigned char v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STUInt16 : public SerializedType @@ -94,6 +102,7 @@ public: operator uint16() const { return value; } STUInt16& operator=(uint16 v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STUInt32 : public SerializedType @@ -118,6 +127,7 @@ public: operator uint32() const { return value; } STUInt32& operator=(uint32 v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STUInt64 : public SerializedType @@ -142,6 +152,7 @@ public: operator uint64() const { return value; } STUInt64& operator=(uint64 v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STHash128 : public SerializedType @@ -167,6 +178,7 @@ public: operator uint128() const { return value; } STHash128& operator=(const uint128& v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STHash160 : public SerializedType @@ -192,6 +204,7 @@ public: operator uint160() const { return value; } STHash160& operator=(const uint160& v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STHash256 : public SerializedType @@ -217,6 +230,7 @@ public: operator uint256() const { return value; } STHash256& operator=(const uint256& v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STVariableLength : public SerializedType @@ -245,6 +259,7 @@ public: operator std::vector() const { return value; } STVariableLength& operator=(const std::vector& v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; class STAccount : public STVariableLength @@ -299,6 +314,7 @@ public: operator std::vector() const { return value; } STTaggedList& operator=(const std::vector& v) { value=v; return *this; } + virtual bool isEquivalent(const SerializedType& t) const; }; #endif From 21bb574e969f5f27285e326ea41a7117b11ec9e5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 8 Apr 2012 19:56:48 -0700 Subject: [PATCH 03/14] Having a function in a base class that's widely overloaded called 'getType' is a bad idea. Change it to 'getSType'. --- src/SerializedObject.cpp | 54 ++++++++++++++++++------------------- src/SerializedObject.h | 2 +- src/SerializedTransaction.h | 4 +-- src/SerializedTypes.cpp | 2 +- src/SerializedTypes.h | 26 +++++++++--------- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index c09e67904..07bf10772 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -175,7 +175,7 @@ bool STObject::isEquivalent(const SerializedType& t) const boost::ptr_vector::const_iterator it2=v->mData.begin(), end2=v->mData.end(); while((it1!=end1) && (it2!=end2)) { - if(it1->getType() != it2->getType()) return false; + if(it1->getSType() != it2->getSType()) return false; if(!it1->isEquivalent(*it2)) return false; ++it1; ++it2; @@ -223,7 +223,7 @@ bool STObject::isFieldPresent(SOE_Field field) const { int index=getFieldIndex(field); if(index==-1) return false; - return peekAtIndex(field).getType()==STI_OBJECT; + return peekAtIndex(field).getSType()==STI_OBJECT; } bool STObject::setFlag(int f) @@ -256,7 +256,7 @@ void STObject::makeFieldPresent(SOE_Field field) { int index=getFieldIndex(field); if(index==-1) throw std::runtime_error("Field not found"); - if(peekAtIndex(field).getType()!=STI_OBJECT) return; + if(peekAtIndex(field).getSType()!=STI_OBJECT) return; mData.replace(index, makeDefaultObject(mType[index]->e_id, mType[index]->e_name)); setFlag(mType[index]->e_flags); } @@ -265,7 +265,7 @@ void STObject::makeFieldAbsent(SOE_Field field) { int index=getFieldIndex(field); if(index==-1) throw std::runtime_error("Field not found"); - if(peekAtIndex(field).getType()==STI_OBJECT) return; + if(peekAtIndex(field).getSType()==STI_OBJECT) return; mData.replace(index, new STObject(mType[index]->e_name)); clearFlag(mType[index]->e_flags); } @@ -281,7 +281,7 @@ unsigned char STObject::getValueFieldU8(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return 0; // optional field not present const STUInt8 *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -292,7 +292,7 @@ uint16 STObject::getValueFieldU16(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return 0; // optional field not present const STUInt16 *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -303,7 +303,7 @@ uint32 STObject::getValueFieldU32(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return 0; // optional field not present const STUInt32 *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -314,7 +314,7 @@ uint64 STObject::getValueFieldU64(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return 0; // optional field not present const STUInt64 *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -325,7 +325,7 @@ uint160 STObject::getValueFieldH160(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return uint160(); // optional field not present const STHash160 *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -336,7 +336,7 @@ uint256 STObject::getValueFieldH256(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return uint256(); // optional field not present const STHash256 *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -347,7 +347,7 @@ std::vector STObject::getValueFieldVL(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return std::vector(); // optional field not present const STVariableLength *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -358,7 +358,7 @@ std::vector STObject::getValueFieldTL(SOE_Field field) const { const SerializedType* rf=peekAtPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) return std::vector(); // optional field not present const STTaggedList *cf=dynamic_cast(rf); if(!cf) throw std::runtime_error("Wrong field type"); @@ -369,12 +369,12 @@ void STObject::setValueFieldU8(SOE_Field field, unsigned char v) { SerializedType* rf=getPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) { makeFieldPresent(field); rf=getPField(field); - id=rf->getType(); + id=rf->getSType(); } STUInt8* cf=dynamic_cast(rf); if(!cf) throw(std::runtime_error("Wrong field type")); @@ -385,12 +385,12 @@ void STObject::setValueFieldU16(SOE_Field field, uint16 v) { SerializedType* rf=getPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) { makeFieldPresent(field); rf=getPField(field); - id=rf->getType(); + id=rf->getSType(); } STUInt16* cf=dynamic_cast(rf); if(!cf) throw(std::runtime_error("Wrong field type")); @@ -401,12 +401,12 @@ void STObject::setValueFieldU32(SOE_Field field, uint32 v) { SerializedType* rf=getPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) { makeFieldPresent(field); rf=getPField(field); - id=rf->getType(); + id=rf->getSType(); } STUInt32* cf=dynamic_cast(rf); if(!cf) throw(std::runtime_error("Wrong field type")); @@ -417,12 +417,12 @@ void STObject::setValueFieldU64(SOE_Field field, uint64 v) { SerializedType* rf=getPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) { makeFieldPresent(field); rf=getPField(field); - id=rf->getType(); + id=rf->getSType(); } STUInt64* cf=dynamic_cast(rf); if(!cf) throw(std::runtime_error("Wrong field type")); @@ -433,12 +433,12 @@ void STObject::setValueFieldH160(SOE_Field field, const uint160& v) { SerializedType* rf=getPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) { makeFieldPresent(field); rf=getPField(field); - id=rf->getType(); + id=rf->getSType(); } STHash160* cf=dynamic_cast(rf); if(!cf) throw(std::runtime_error("Wrong field type")); @@ -449,12 +449,12 @@ void STObject::setValueFieldVL(SOE_Field field, const std::vector { SerializedType* rf=getPField(field); if(!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id=rf->getType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) { makeFieldPresent(field); rf=getPField(field); - id=rf->getType(); + id=rf->getSType(); } STVariableLength* cf=dynamic_cast(rf); if(!cf) throw(std::runtime_error("Wrong field type")); @@ -465,12 +465,12 @@ void STObject::setValueFieldTL(SOE_Field field, const std::vectorgetType(); + SerializedTypeID id=rf->getSType(); if(id==STI_OBJECT) { makeFieldPresent(field); rf=getPField(field); - id=rf->getType(); + id=rf->getSType(); } STTaggedList* cf=dynamic_cast(rf); if(!cf) throw(std::runtime_error("Wrong field type")); @@ -483,7 +483,7 @@ Json::Value STObject::getJson(int options) const int index=1; for(boost::ptr_vector::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it, ++index) { - if(it->getType()!=STI_NOTPRESENT) + if(it->getSType()!=STI_NOTPRESENT) { if(it->getName()==NULL) ret[boost::lexical_cast(index)]=it->getText(); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 16dc18285..89273571f 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -56,7 +56,7 @@ public: virtual ~STObject() { ; } int getLength() const; - SerializedTypeID getType() const { return STI_OBJECT; } + SerializedTypeID getSType() const { return STI_OBJECT; } STObject* duplicate() const { return new STObject(*this); } virtual bool isEquivalent(const SerializedType& t) const; diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 3f6458954..5ec8ca700 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -26,7 +26,7 @@ public: // STObject functions int getLength() const; - SerializedTypeID getType() const { return STI_TRANSACTION; } + SerializedTypeID getSType() const { return STI_TRANSACTION; } SerializedTransaction* duplicate() const { return new SerializedTransaction(*this); } std::string getFullText() const; std::string getText() const; @@ -63,7 +63,7 @@ public: // inner transaction field functions int getITFieldIndex(SOE_Field field) const; int getITFieldCount() const; - const SerializedType& peekITField(SOE_Field field); + const SerializedType& peekITField(SOE_Field field) const; SerializedType& getITField(SOE_Field field); // inner transaction field value functions diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index a7527b332..4e3c1f233 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -9,7 +9,7 @@ std::string SerializedType::getFullText() const { std::string ret; - if(getType()!=STI_NOTPRESENT) + if(getSType()!=STI_NOTPRESENT) { if(name!=NULL) { diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 3c43e1aad..5e894e151 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -35,7 +35,7 @@ public: const char *getName() const { return name; } virtual int getLength() const { return 0; } - virtual SerializedTypeID getType() const { return STI_NOTPRESENT; } + virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; } virtual SerializedType* duplicate() const { return new SerializedType(name); } virtual std::string getFullText() const; @@ -50,9 +50,9 @@ public: virtual bool isEquivalent(const SerializedType& t) const { return true; } bool operator==(const SerializedType& t) const - { return (getType()==t.getType()) && isEquivalent(t); } + { return (getSType()==t.getSType()) && isEquivalent(t); } bool operator!=(const SerializedType& t) const - { return (getType()!=t.getType()) || !isEquivalent(t); } + { return (getSType()!=t.getSType()) || !isEquivalent(t); } }; class STUInt8 : public SerializedType @@ -67,7 +67,7 @@ public: static STUInt8* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 1; } - SerializedTypeID getType() const { return STI_UINT8; } + SerializedTypeID getSType() const { return STI_UINT8; } STUInt8* duplicate() const { return new STUInt8(name, value); } std::string getText() const; void add(Serializer& s) const { s.add8(value); } @@ -92,7 +92,7 @@ public: static STUInt16* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 2; } - SerializedTypeID getType() const { return STI_UINT16; } + SerializedTypeID getSType() const { return STI_UINT16; } STUInt16* duplicate() const { return new STUInt16(name, value); } std::string getText() const; void add(Serializer& s) const { s.add16(value); } @@ -117,7 +117,7 @@ public: static STUInt32* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 4; } - SerializedTypeID getType() const { return STI_UINT32; } + SerializedTypeID getSType() const { return STI_UINT32; } STUInt32* duplicate() const { return new STUInt32(name, value); } std::string getText() const; void add(Serializer& s) const { s.add32(value); } @@ -142,7 +142,7 @@ public: static STUInt64* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 8; } - SerializedTypeID getType() const { return STI_UINT64; } + SerializedTypeID getSType() const { return STI_UINT64; } STUInt64* duplicate() const { return new STUInt64(name, value); } std::string getText() const; void add(Serializer& s) const { s.add64(value); } @@ -168,7 +168,7 @@ public: static STHash128* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 20; } - SerializedTypeID getType() const { return STI_HASH128; } + SerializedTypeID getSType() const { return STI_HASH128; } STHash128* duplicate() const { return new STHash128(name, value); } virtual std::string getText() const; void add(Serializer& s) const { s.add128(value); } @@ -194,7 +194,7 @@ public: static STHash160* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 20; } - SerializedTypeID getType() const { return STI_HASH160; } + SerializedTypeID getSType() const { return STI_HASH160; } STHash160* duplicate() const { return new STHash160(name, value); } virtual std::string getText() const; void add(Serializer& s) const { s.add160(value); } @@ -220,7 +220,7 @@ public: static STHash256* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 32; } - SerializedTypeID getType() const { return STI_HASH256; } + SerializedTypeID getSType() const { return STI_HASH256; } STHash256* duplicate() const { return new STHash256(name, value); } std::string getText() const; void add(Serializer& s) const { s.add256(value); } @@ -247,7 +247,7 @@ public: static STVariableLength* construct(SerializerIterator&, const char *name=NULL); int getLength() const; - virtual SerializedTypeID getType() const { return STI_VL; } + virtual SerializedTypeID getSType() const { return STI_VL; } virtual STVariableLength* duplicate() const { return new STVariableLength(name, value); } virtual std::string getText() const; void add(Serializer& s) const { s.addVL(value); } @@ -272,7 +272,7 @@ public: STAccount() { ; } static STAccount* construct(SerializerIterator&, const char *name=NULL); - SerializedTypeID getType() const { return STI_ACCOUNT; } + SerializedTypeID getSType() const { return STI_ACCOUNT; } virtual STAccount* duplicate() const { return new STAccount(name, value); } std::string getText() const; @@ -295,7 +295,7 @@ public: static STTaggedList* construct(SerializerIterator&, const char *name=NULL); int getLength() const; - SerializedTypeID getType() const { return STI_TL; } + SerializedTypeID getSType() const { return STI_TL; } STTaggedList* duplicate() const { return new STTaggedList(name, value); } std::string getText() const; void add(Serializer& s) const { if(s.addTaggedList(value)<0) throw(0); } From 28d870e7f90ee20bc2ded997b1453e1b87bd63fd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 8 Apr 2012 19:57:22 -0700 Subject: [PATCH 04/14] Finish the serialized ledger classes. --- src/SerializedLedger.cpp | 49 +++++++++++++++++++++++++++++++++++++++ src/SerializedLedger.h | 50 +++++++++++++++++++++++++++++++++++----- 2 files changed, 93 insertions(+), 6 deletions(-) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 3ae422ec7..937673d2e 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -1,3 +1,52 @@ #include "SerializedLedger.h" +SerializedLedger::SerializedLedger(SerializerIterator& sit, const uint256& index) + : STObject("LedgerEntry"), mIndex(index) +{ + uint16 type=sit.get16(); + mFormat=getLgrFormat(static_cast(type)); + if(mFormat==NULL) throw std::runtime_error("invalid ledger entry type"); + mType=mFormat->t_type; + mVersion.setValue(type); + mObject=STObject(mFormat->elements, sit, "Entry"); +} + +SerializedLedger::SerializedLedger(LedgerEntryType type) : STObject("LedgerEntry"), mType(type) +{ + mFormat=getLgrFormat(type); + if(mFormat==NULL) throw std::runtime_error("invalid ledger entry type"); + mVersion.setValue(static_cast(mFormat->t_type)); + mObject=STObject(mFormat->elements, "Entry"); +} + +std::string SerializedLedger::getFullText() const +{ + std::string ret="\""; + ret+=mIndex.GetHex(); + ret+="\" = { "; + ret+=mFormat->t_name; + ret+=", "; + ret+=mObject.getFullText(); + ret+="}"; + return ret; +} + +std::string SerializedLedger::getText() const +{ + std::string ret="{"; + ret+=mIndex.GetHex(); + ret+=mVersion.getText(); + ret+=mObject.getText(); + ret+="}"; + return ret; +} + +bool SerializedLedger::isEquivalent(const SerializedType& t) const +{ // locators are not compared + const SerializedLedger* v=dynamic_cast(&t); + if(!v) return false; + if(mType != v->mType) return false; + if(mObject != v->mObject) return false; + return true; +} diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 4bdc7d8d4..3cca93bec 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -10,21 +10,59 @@ public: typedef boost::shared_ptr pointer; protected: + uint256 mIndex; LedgerEntryType mType; STUInt16 mVersion; STObject mObject; LedgerEntryFormat* mFormat; public: - SerializedLedger(SerializerIterator& sit); + SerializedLedger(SerializerIterator& sit, const uint256& index); SerializedLedger(LedgerEntryType type); int getLength() const { return mVersion.getLength() + mObject.getLength(); } - SerializedTypeID getType() const { return STI_LEDGERENTRY; } - SerializedLedger* duplicate() const { return new SerializedLedger(*this); } - std::string getFullText() const; - std::string getText() const; - void add(Serializer& s) const { mVersion.add(s); mObject.add(s); } + SerializedTypeID getSType() const { return STI_LEDGERENTRY; } + SerializedLedger* duplicate() const { return new SerializedLedger(*this); } + std::string getFullText() const; + std::string getText() const; + void add(Serializer& s) const { mVersion.add(s); mObject.add(s); } + virtual bool isEquivalent(const SerializedType& t) const; + + const uint256& getIndex() const { return mIndex; } + void setIndex(const uint256& i) { mIndex=i; } + + LedgerEntryType getType() const { return mType; } + uint16 getVersion() const { return mVersion.getValue(); } + LedgerEntryFormat* getFormat() { return mFormat; } + + int getIFieldIndex(SOE_Field field) const { return mObject.getFieldIndex(field); } + int getIFieldCount() const { return mObject.getCount(); } + const SerializedType& peekIField(SOE_Field field) const { return mObject.peekAtField(field); } + SerializedType& getIField(SOE_Field field) { return mObject.getField(field); } + + std::string getIFieldString(SOE_Field field) const { return mObject.getFieldString(field); } + unsigned char getIFieldU8(SOE_Field field) const { return mObject.getValueFieldU8(field); } + uint16 getIFieldU16(SOE_Field field) const { return mObject.getValueFieldU16(field); } + uint32 getIFieldU32(SOE_Field field) const { return mObject.getValueFieldU32(field); } + uint64 getIFieldU64(SOE_Field field) const { return mObject.getValueFieldU64(field); } + uint160 getIFieldH160(SOE_Field field) const { return mObject.getValueFieldH160(field); } + uint256 getIFieldH256(SOE_Field field) const { return mObject.getValueFieldH256(field); } + std::vector getIFieldVL(SOE_Field field) const { return mObject.getValueFieldVL(field); } + std::vector getIFieldTL(SOE_Field field) const { return mObject.getValueFieldTL(field); } + void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); } + void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); } + void setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); } + void setIFieldU64(SOE_Field field, uint32 v) { return mObject.setValueFieldU64(field, v); } + void setIFieldH160(SOE_Field field, const uint160& v) { return mObject.setValueFieldH160(field, v); } + void setIFieldH256(SOE_Field field, const uint256& v) { return mObject.setValueFieldH256(field, v); } + void setIFieldVL(SOE_Field field, const std::vector& v) + { return mObject.setValueFieldVL(field, v); } + void setIFieldTL(SOE_Field field, const std::vector& v) + { return mObject.setValueFieldTL(field, v); } + + bool getIFieldPresent(SOE_Field field) const { return mObject.isFieldPresent(field); } + void makeIFieldPresent(SOE_Field field) { return mObject.makeFieldPresent(field); } + void makeIFieldAbsent(SOE_Field field) { return mObject.makeFieldAbsent(field); } }; From b4f1aa0e473e3788de9bf7536557f2f806aeb25a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 8 Apr 2012 19:57:32 -0700 Subject: [PATCH 05/14] Missing 'const' --- src/SerializedTransaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 88dd761c3..ebcb290ca 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -216,7 +216,7 @@ bool SerializedTransaction::getITFieldPresent(SOE_Field field) const return mInnerTxn.isFieldPresent(field); } -const SerializedType& SerializedTransaction::peekITField(SOE_Field field) +const SerializedType& SerializedTransaction::peekITField(SOE_Field field) const { return mInnerTxn.peekAtField(field); } From f085cc4a659649d06dff835d058364959f2ba041 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Apr 2012 02:51:20 -0700 Subject: [PATCH 06/14] Base structures for currencies. --- src/Currency.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/Currency.h diff --git a/src/Currency.h b/src/Currency.h new file mode 100644 index 000000000..fd98d8521 --- /dev/null +++ b/src/Currency.h @@ -0,0 +1,70 @@ +#ifndef __CURRENCY__ +#define __CURRENCY__ + +#include + +#include "uint256.h" + +enum CurrencyType +{ + ctNATIVE, // Currency transaction fees are paid in + ctNATIONAL, // State-issued or ISO-recognized currencies + ctCUSTOM, // Custom currencies +}; + +class Currency +{ +protected: + uint160 mValue; + CurrencyType mType; + +public: + Currency() : mType(ctNATIVE) { ; } + Currency(const uint160& v); + Currency(const std::string& iso, uint16 version, unsigned char scale); + + bool isCommensurate(const Currency&) const; + bool isNational() const { return mType == ctNATIONAL; } + bool isNative() const { return mType == ctNATIVE; } + bool isCustom() const { return mType == ctCUSTOM; } + + const uint160& getCurrency() { return mValue; } + unsigned char getScale() const; + + // These are only valid for national currencies + std::string getISO() const; + uint16 getVersion() const; +}; + +class Amount +{ +protected: + Currency mCurrency; + uint64 mQuantity; + +public: + + Amount(const Currency& c, const uint64& q) : mCurrency(c), mQuantity(q) { ; } + + const Currency& getCurrency() const { return mCurrency; } + uint64 getQuantity() const { return mQuantity; } + double getDisplayQuantity() const; + + // These throw if the currencies are incommensurate + // They handle scaling and represent the result as accurately as possible + bool operator==(const Amount&) const; + bool operator!=(const Amount&) const; + bool operator>=(const Amount&) const; + bool operator<=(const Amount&) const; + bool operator>(const Amount&) const; + bool operator<(const Amount&) const; + Amount operator+(const Amount&) const; + Amount operator-(const Amount&) const; + Amount& operator+=(const Amount&); + Amount& operator-=(const Amount&); + + // This is used to score offers and works with incommensurate currencies + friend void divide(const Amount& offering, const Amount& taking, uint16& exponent, uint64& mantissa); +}; + +#endif From 1402d99a3dbfc69a080e9aa222594541e1195a39 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Apr 2012 03:59:23 -0700 Subject: [PATCH 07/14] Continue currency work. --- src/Currency.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Currency.h b/src/Currency.h index fd98d8521..2fca53bd3 100644 --- a/src/Currency.h +++ b/src/Currency.h @@ -18,6 +18,9 @@ protected: uint160 mValue; CurrencyType mType; + static uint160 sNatMask; // bits that indicate national currency ISO code and version + static uint160 sNatZero; // bits that must be zero on a national currency + public: Currency() : mType(ctNATIVE) { ; } Currency(const uint160& v); @@ -30,6 +33,7 @@ public: const uint160& getCurrency() { return mValue; } unsigned char getScale() const; + void setScale(unsigned char c); // These are only valid for national currencies std::string getISO() const; @@ -38,13 +42,19 @@ public: class Amount { + // CAUTION: Currency operations throw on overflows, underflos, or + // incommensurate currency opeations (like adding USD to Euros) protected: Currency mCurrency; uint64 mQuantity; + void canonicalize(); + + static uint64 sMaxCanon; // Max native currency value before shift + public: - Amount(const Currency& c, const uint64& q) : mCurrency(c), mQuantity(q) { ; } + Amount(const Currency& c, const uint64& q) : mCurrency(c), mQuantity(q) { canonicalize(); } const Currency& getCurrency() const { return mCurrency; } uint64 getQuantity() const { return mQuantity; } @@ -58,13 +68,13 @@ public: bool operator<=(const Amount&) const; bool operator>(const Amount&) const; bool operator<(const Amount&) const; - Amount operator+(const Amount&) const; - Amount operator-(const Amount&) const; - Amount& operator+=(const Amount&); - Amount& operator-=(const Amount&); + Amount& operator+=(const Amount& a) { return *this = *this + a; } + Amount& operator-=(const Amount& a) { return *this = *this - a; } // This is used to score offers and works with incommensurate currencies friend void divide(const Amount& offering, const Amount& taking, uint16& exponent, uint64& mantissa); + friend Amount& operator+(const Amount&, const Amount&); + friend Amount& operator-(const Amount&, const Amount&); }; #endif From 3e91ddc6d736e699fcbaeb219ddf1b58fc81ddeb Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Apr 2012 03:59:36 -0700 Subject: [PATCH 08/14] Currency work. --- src/Currency.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/Currency.cpp diff --git a/src/Currency.cpp b/src/Currency.cpp new file mode 100644 index 000000000..34a9d03fa --- /dev/null +++ b/src/Currency.cpp @@ -0,0 +1,56 @@ + +#include "Currency.h" + +#include +#include + +uint160 Currency::sNatMask("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000"); +uint160 Currency::sNatZero("FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000"); +uint64 Amount::sMaxCanon(1ull << 63); + +Currency::Currency(const uint160& v) : mValue(v) +{ + if (!v) mType = ctNATIVE; + if (!(v & sNatZero)) mType = ctNATIONAL; + mType = ctNATIONAL; +} + +bool Currency::isCommensurate(const Currency& c) const +{ + if (isNative()) + return c.isNative(); + if (isCustom()) + return mValue == c.mValue; + if (!c.isNational()) return false; + return (mValue & sNatMask) == (c.mValue & sNatMask); +} + +unsigned char Currency::getScale() const +{ + return *(mValue.begin()); +} + +void Currency::setScale(unsigned char s) +{ + *(mValue.begin()) = s; +} + +void Amount::canonicalize() +{ // clear high bit to avoid overflows + if(mQuantity > sMaxCanon) + { + if (!mCurrency.isNational()) throw std::runtime_error("Currency overflow"); + unsigned char s = mCurrency.getScale(); + if (s==255) throw std::runtime_error("Currency overflow"); + mCurrency.setScale(s + 1); + mQuantity /= 10.0; + } +} + +double Amount::getDisplayQuantity() const +{ + if(!mCurrency.isNational()) throw std::runtime_error("Can only scale national currencies"); + int scale=mCurrency.getScale(); + return static_cast(mQuantity) * pow(10, 128-scale); +} + From fcdf42e7993b316328b77ce2b7f502619ee8013e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Apr 2012 19:36:51 -0700 Subject: [PATCH 09/14] Promote 'amounts' to a new type. Codify storage format, both internal and serialized. Define operators. --- src/Amount.cpp | 71 ++++++++++++++++++++++++++++++++++++++ src/LedgerFormats.cpp | 8 ++--- src/SerializedObject.cpp | 6 ++++ src/SerializedTypes.h | 62 +++++++++++++++++++++++++++++++++ src/TransactionFormats.cpp | 8 ++--- 5 files changed, 147 insertions(+), 8 deletions(-) create mode 100644 src/Amount.cpp diff --git a/src/Amount.cpp b/src/Amount.cpp new file mode 100644 index 000000000..752a0f3bf --- /dev/null +++ b/src/Amount.cpp @@ -0,0 +1,71 @@ + +#include + +#include + +#include "SerializedTypes.h" + +void STAmount::canonicalize() +{ + if(value==0) + { + offset=0; + value=0; + } + while(valuecMaxValue) + { // 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(value>>(64-8)); + offset-=142; + value&=~(255ull<<(64-8)); + if(value==0) + { + if(offset!=0) + throw std::runtime_error("invalid currency value"); + } + else + { + if( (valuecMaxValue) || (offsetcMaxOffset) ) + throw std::runtime_error("invalid currency value"); + } + return new STAmount(name, value, offset); +} + +std::string STAmount::getText() const +{ + return boost::lexical_cast(static_cast(*this)); +} + +void STAmount::add(Serializer& s) const +{ + uint64 v=value; + v+=(static_cast(offset+142) << (64-8)); + s.add64(v); +} + +bool STAmount::isEquivalent(const SerializedType& t) const +{ + const STAmount* v=dynamic_cast(&t); + if(!v) return false; + return (value==v->value) && (offset==v->offset); +} + +STAmount::operator double() const +{ + if(!value) return 0.0; + return static_cast(value) * pow(10.0, offset); +} diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 89f6b34b0..1f76a9ffa 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -9,7 +9,7 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 }, { S_FIELD(Account), STI_ACCOUNT, 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(LastTxn), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 1 }, @@ -23,8 +23,8 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Borrower), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Lender), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Currency), STI_HASH160, SOE_IFFLAG, 1 }, - { S_FIELD(Limit), STI_UINT64, SOE_REQUIRED, 0 }, - { S_FIELD(Balance), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(Limit), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(CurrentRate), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(RateLock), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(NextRate), STI_UINT32, SOE_IFFLAG, 8 }, @@ -37,7 +37,7 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 }, { S_FIELD(Nickname), STI_HASH256, 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(Extensions), STI_TL, SOE_IFFLAG, 32768 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 07bf10772..576d90103 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -16,6 +16,9 @@ SerializedType* STObject::makeDefaultObject(SerializedTypeID id, const char *nam case STI_UINT64: return new STUInt64(name); + case STI_AMOUNT: + return new STAmount(name); + case STI_HASH160: return new STHash160(name); @@ -49,6 +52,9 @@ SerializedType* STObject::makeDeserializedObject(SerializedTypeID id, const char case STI_UINT64: return STUInt64::construct(sit, name); + case STI_AMOUNT: + return STAmount::construct(sit, name); + case STI_HASH160: return STHash160::construct(sit, name); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 5e894e151..b65265b9f 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -15,6 +15,7 @@ enum SerializedTypeID // standard types 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_AMOUNT=11, // high level types STI_ACCOUNT=100, STI_TRANSACTION=101, STI_LEDGERENTRY=102 @@ -155,6 +156,67 @@ public: 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 { protected: diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 528a86d3e..c59a78e63 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -8,7 +8,7 @@ TransactionFormat InnerTxnFormats[]= { "MakePayment", ttMAKE_PAYMENT, { { S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 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(SourceTag), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 4 }, @@ -19,7 +19,7 @@ TransactionFormat InnerTxnFormats[]= { "Invoice", ttINVOICE, { { S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 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(SourceTag), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 4 }, @@ -30,9 +30,9 @@ TransactionFormat InnerTxnFormats[]= }, { "Offer", ttEXCHANGE_OFFER, { { 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(AmountOut), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(AmountOut), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(CurrencyOut), STI_HASH160, SOE_IFFLAG, 4 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 8 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 16 }, From 0a1cd82ee018f05213bb48493dafbac733715a91 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 9 Apr 2012 20:43:12 -0700 Subject: [PATCH 10/14] Have git ignore bin/newcoind. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 12994b884..135e02d19 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ # Ignore object files. *.o obj/* +bin/newcoind newcoind From 79ccc827b32a4dac76807d1ae16213ea4d0463ec Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 9 Apr 2012 20:47:01 -0700 Subject: [PATCH 11/14] Initial check in of scripts for managing testing hosts. --- bin/network-build | 6 ++++++ bin/network-init | 10 ++++++++++ bin/network-restart | 5 +++++ bin/network-start | 6 ++++++ bin/network-stop | 6 ++++++ bin/network-update | 5 +++++ bin/nx | 7 +++++++ 7 files changed, 45 insertions(+) create mode 100755 bin/network-build create mode 100755 bin/network-init create mode 100755 bin/network-restart create mode 100755 bin/network-start create mode 100755 bin/network-stop create mode 100755 bin/network-update create mode 100755 bin/nx diff --git a/bin/network-build b/bin/network-build new file mode 100755 index 000000000..d40e3ee95 --- /dev/null +++ b/bin/network-build @@ -0,0 +1,6 @@ +#!/bin/sh -x + +cd ~/NewCoin +git pull +scons -j 2 +cp -p newcoind bin/ diff --git a/bin/network-init b/bin/network-init new file mode 100755 index 000000000..60c3c26a8 --- /dev/null +++ b/bin/network-init @@ -0,0 +1,10 @@ +#!/bin/sh + +# XXX Should not need to make db directory. newcoind should do this. +for SITE in $HOSTS +do + echo "Clearing db for:" $SITE + DB_DIR="/var/www/$SITE/db/" + mkdir -p "/var/www/$SITE/db/" + rm -rf "/var/www/$SITE/db/*" +done diff --git a/bin/network-restart b/bin/network-restart new file mode 100755 index 000000000..34dd6a394 --- /dev/null +++ b/bin/network-restart @@ -0,0 +1,5 @@ +#!/bin/sh -x + +network-stop +sleep 1 +network-start diff --git a/bin/network-start b/bin/network-start new file mode 100755 index 000000000..4d59c634b --- /dev/null +++ b/bin/network-start @@ -0,0 +1,6 @@ +#!/bin/sh + +for SITE in $HOSTS +do + (nx $SITE &) +done diff --git a/bin/network-stop b/bin/network-stop new file mode 100755 index 000000000..cee718e5c --- /dev/null +++ b/bin/network-stop @@ -0,0 +1,6 @@ +#!/bin/sh + +for SITE in $HOSTS +do + (nx $SITE stop &) +done diff --git a/bin/network-update b/bin/network-update new file mode 100755 index 000000000..03a14b6d6 --- /dev/null +++ b/bin/network-update @@ -0,0 +1,5 @@ +#!/bin/sh -x +echo "Building and restarting." + +network-build +network-restart diff --git a/bin/nx b/bin/nx new file mode 100755 index 000000000..e602581b5 --- /dev/null +++ b/bin/nx @@ -0,0 +1,7 @@ +#!/bin/sh + +SITE=$1 +shift +COMMAND=$@ +cd "/var/www/$SITE" +newcoind $COMMAND From 005ea61f9b95309b1fe29ce8c5dfda691fc6d3ee Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Apr 2012 21:00:27 -0700 Subject: [PATCH 12/14] All currency operations except the three weirdest ones for exchanges. --- src/Amount.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++ src/SerializedTypes.h | 18 +++++-- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 752a0f3bf..3cc30d7e0 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -14,11 +14,13 @@ void STAmount::canonicalize() } 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; } @@ -64,6 +66,110 @@ bool STAmount::isEquivalent(const SerializedType& t) const return (value==v->value) && (offset==v->offset); } +bool STAmount::operator==(const STAmount& a) const +{ + return (offset==a.offset) && (value==a.value); +} + +bool STAmount::operator!=(const STAmount& a) const +{ + 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; + return 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; + return value >= a.value; +} + +STAmount& STAmount::operator+=(const STAmount& a) +{ + *this = *this + a; + return *this; +} + +STAmount& STAmount::operator-=(const STAmount& a) +{ + *this = *this - a; + return *this; +} + +STAmount& STAmount::operator=(const STAmount& a) +{ + value=a.value; + offset=a.offset; + return *this; +} + +STAmount& STAmount::operator=(uint64 v) +{ + return *this=STAmount(v, 0); +} + +STAmount& STAmount::operator+=(uint64 v) +{ + return *this+=STAmount(v); +} + +STAmount& STAmount::operator-=(uint64 v) +{ + return *this-=STAmount(v); +} + +STAmount operator+(STAmount v1, STAmount v2) +{ // We can check for precision loss here (value%10)!=0 + while(v1.offset < v2.offset) + { + v1.value/=10; + v1.offset+=1; + } + while(v2.offset < v1.offset) + { + v2.value/=10; + v2.offset+=1; + } + // this addition cannot overflow + return STAmount(v1.name, v1.value + v2.value, v1.offset); +} + +STAmount operator-(STAmount v1, STAmount v2) +{ // We can check for precision loss here (value%10)!=0 + while(v1.offset < v2.offset) + { + v1.value/=10; + v1.offset+=1; + } + while(v2.offset < v1.offset) + { + v2.value/=10; + v2.offset+=1; + } + if(v1.value < v2.value) throw std::runtime_error("value overflow"); + return STAmount(v1.name, v1.value - v2.value, v1.offset); +} + STAmount::operator double() const { if(!value) return 0.0; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index b65265b9f..1a4958d41 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -30,6 +30,7 @@ public: SerializedType() : name(NULL) { ; } SerializedType(const char *n) : name(n) { ; } + SerializedType(const SerializedType& n) : name(n.name) { ; } virtual ~SerializedType() { ; } void setName(const char *n) { name=n; } @@ -170,7 +171,7 @@ class STAmount : public SerializedType // Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive protected: - int offset; // These variables *always* hold canonical values + int offset; // These variables *always* hold canonical values on entry/exit uint64 value; void canonicalize(); @@ -183,6 +184,7 @@ public: { 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(); } + STAmount(const STAmount& a) : SerializedType(a), offset(a.offset), value(a.value) { ; } static STAmount* construct(SerializerIterator&, const char *name=NULL); int getLength() const { return 8; } @@ -212,9 +214,17 @@ public: 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); + friend STAmount operator+(STAmount v1, STAmount v2); + friend STAmount operator-(STAmount v1, STAmount v2); + + // Someone is offering X for Y, what is the rate? + friend STAmount getRate(const STAmount& offerIn, const STAmount& offerOut); + + // Someone is offering X for Y, I pay Z, how much do I get? + friend STAmount getClaimed(const STAmount& offerIn, const STAmount& offerOut, const STAmount& paid); + + // Someone is offering X for Y, I need Z, how much fo I pay + friend STAmount getNeeded(const STAmount& offerIn, const STAmount& offerOut, const STAmount& needed); }; class STHash128 : public SerializedType From b2b30ef0e6bec8ede70981bddbf369aa50325386 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Apr 2012 21:14:47 -0700 Subject: [PATCH 13/14] Typo. --- src/SerializedTypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 1a4958d41..ceddccb17 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -223,7 +223,7 @@ public: // Someone is offering X for Y, I pay Z, how much do I get? friend STAmount getClaimed(const STAmount& offerIn, const STAmount& offerOut, const STAmount& paid); - // Someone is offering X for Y, I need Z, how much fo I pay + // Someone is offering X for Y, I need Z, how much do I pay friend STAmount getNeeded(const STAmount& offerIn, const STAmount& offerOut, const STAmount& needed); }; From 3cac1416ae2d55c21901f77e482e7a96ce787faf Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 9 Apr 2012 21:50:43 -0700 Subject: [PATCH 14/14] Ignore editor backups. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 135e02d19..2530f7eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ # Ignore python compiled files. *.pyc +# Ignore backup/temps +*~ + # Ignore object files. *.o obj/*