From 38cecf2d8f942d48777ba7ac44312e9be230ed4d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 25 Mar 2012 00:04:59 -0700 Subject: [PATCH] Code improvements: A way to avoid duplicate field indexes that Arthur came up with. Abstract out code to create individual fields. Field index operations. Flag operations. Optional field operations. --- src/SerializedObject.cpp | 241 ++++++++++++++++++++++++---------- src/SerializedObject.h | 59 +++++++-- src/SerializedTransaction.cpp | 44 ++++++- src/SerializedTransaction.h | 13 +- src/TransactionFormats.cpp | 72 +++++----- 5 files changed, 306 insertions(+), 123 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index e6f88cffc..fafbabdea 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -1,53 +1,100 @@ #include "SerializedObject.h" -STObject::STObject(SOElement* elem, const char *name) : SerializedType(name) +SerializedType* STObject::makeDefaultObject(SerializedTypeID id, const char *name) +{ + switch(id) + { + case STI_UINT16: + return new STUInt16(name); + + case STI_UINT32: + return new STUInt32(name); + + case STI_UINT64: + return new STUInt64(name); + + case STI_HASH160: + return new STHash160(name); + + case STI_HASH256: + return new STHash256(name); + + case STI_VL: + return new STVariableLength(name); + + case STI_TL: + return new STTaggedList(name); + + #if 0 + case STI_ACCOUNT: // CHECKME: Should an account be variable length? + return new STVariableLength(name); + #endif + + default: + return NULL; + } +} + +SerializedType* STObject::makeDeserializedObject(SerializedTypeID id, const char *name, SerializerIterator& sit) +{ + switch(id) + { + case STI_UINT16: + return STUInt16::construct(sit, name); + + case STI_UINT32: + return STUInt32::construct(sit, name); + + case STI_UINT64: + return STUInt64::construct(sit, name); + + case STI_HASH160: + return STHash160::construct(sit, name); + + case STI_HASH256: + return STHash256::construct(sit, name); + + case STI_VL: + return STVariableLength::construct(sit, name); + + case STI_TL: + return STTaggedList::construct(sit, name); + +#if 0 + case STI_ACCOUNT: // CHECKME: Should an account be variable length? + return STVariableLength::construct(sit, name); + +#endif + default: + return NULL; + } +} + +STObject::STObject(SOElement* elem, const char *name) : SerializedType(name), mFlagIdx(-1) { while(elem->e_id!=STI_DONE) { - type.push_back(elem); + if(elem->e_type==SOE_FLAGS) mFlagIdx=mType.size(); + mType.push_back(elem); if( (elem->e_type==SOE_IFFLAG) || (elem->e_type==SOE_IFNFLAG) ) giveObject(new STObject(elem->e_name)); - else switch(elem->e_id) + else { - case STI_UINT16: - giveObject(new STUInt16(elem->e_name)); - break; - case STI_UINT32: - giveObject(new STUInt32(elem->e_name)); - break; - case STI_UINT64: - giveObject(new STUInt64(elem->e_name)); - break; - case STI_HASH160: - giveObject(new STHash160(elem->e_name)); - break; - case STI_HASH256: - giveObject(new STHash256(elem->e_name)); - break; - case STI_VL: - giveObject(new STVariableLength(elem->e_name)); - break; - case STI_TL: - giveObject(new STTaggedList(elem->e_name)); - break; -#if 0 - case STI_ACCOUNT: // CHECKME: Should an account be variable length? - giveObject(new STVariableLength(elem->e_name)); - break; -#endif - default: throw(std::runtime_error("invalid transaction element")); + SerializedType* t=makeDefaultObject(elem->e_id, elem->e_name); + if(!t) throw(std::runtime_error("invalid transaction element")); + giveObject(t); } elem++; } } -STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) : SerializedType(name) +STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) : SerializedType(name), mFlagIdx(-1) { int flags=-1; while(elem->e_id!=STI_DONE) { - type.push_back(elem); + mType.push_back(elem); bool done=false; if(elem->e_type==SOE_IFFLAG) { @@ -63,41 +110,14 @@ STObject::STObject(SOElement* elem, SerializerIterator& sit, const char *name) : { assert(elem->e_id==STI_UINT16); flags=sit.get16(); - giveObject(new STUInt16(elem->e_name, flags)); + mFlagIdx=giveObject(new STUInt16(elem->e_name, flags)); done=true; } if(!done) { - switch(elem->e_id) - { - case STI_UINT16: - giveObject(STUInt16::construct(sit, elem->e_name)); - break; - case STI_UINT32: - giveObject(STUInt32::construct(sit, elem->e_name)); - break; - case STI_UINT64: - giveObject(STUInt64::construct(sit, elem->e_name)); - break; - case STI_HASH160: - giveObject(STHash160::construct(sit, elem->e_name)); - break; - case STI_HASH256: - giveObject(STHash256::construct(sit, elem->e_name)); - break; - case STI_VL: - giveObject(STVariableLength::construct(sit, elem->e_name)); - break; - case STI_TL: - giveObject(STTaggedList::construct(sit, elem->e_name)); - break; - #if 0 - case STI_ACCOUNT: // CHECKME: Should an account be variable length? - giveObject(STVariableLength::construct(sit, elem->e_name)); - break; - #endif - default: throw(std::runtime_error("invalid transaction element")); - } + SerializedType* t=makeDeserializedObject(elem->e_id, elem->e_name, sit); + if(!t) throw(std::runtime_error("invalid transaction element")); + giveObject(t); } elem++; } @@ -112,7 +132,7 @@ std::string STObject::getFullText() const ret+=" = {"; } else ret="{"; - for(boost::ptr_vector::const_iterator it=data.begin(), end=data.end(); it!=end; ++it) + for(boost::ptr_vector::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it) ret+=it->getFullText(); ret+="}"; return ret; @@ -121,14 +141,14 @@ std::string STObject::getFullText() const int STObject::getLength() const { int ret=0; - for(boost::ptr_vector::const_iterator it=data.begin(), end=data.end(); it!=end; ++it) + for(boost::ptr_vector::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it) ret+=it->getLength(); return ret; } void STObject::add(Serializer& s) const { - for(boost::ptr_vector::const_iterator it=data.begin(), end=data.end(); it!=end; ++it) + for(boost::ptr_vector::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it) it->add(s); } @@ -136,7 +156,7 @@ std::string STObject::getText() const { std::string ret="{"; bool first=false; - for(boost::ptr_vector::const_iterator it=data.begin(), end=data.end(); it!=end; ++it) + for(boost::ptr_vector::const_iterator it=mData.begin(), end=mData.end(); it!=end; ++it) { if(!first) { @@ -148,3 +168,90 @@ std::string STObject::getText() const ret+="}"; return ret; } + +int STObject::getFieldIndex(SOE_Field field) const +{ + int i=0; + for(std::vector::const_iterator it=mType.begin(), end=mType.end(); it!=end; ++it, ++i) + if((*it)->e_field==field) return i; + return -1; +} + +const SerializedType& STObject::peekAtField(SOE_Field field) const +{ + int index=getFieldIndex(field); + if(index==-1) throw std::runtime_error("Field not found"); + return peekAtIndex(index); +} + +SerializedType& STObject::getField(SOE_Field field) +{ + int index=getFieldIndex(field); + if(index==-1) throw std::runtime_error("Field not found"); + return getIndex(index); +} + +const SerializedType* STObject::peekAtPField(SOE_Field field) +{ + int index=getFieldIndex(field); + if(index==-1) return NULL; + return peekAtPIndex(index); +} + +SerializedType* STObject::getPField(SOE_Field field) +{ + int index=getFieldIndex(field); + if(index==-1) return NULL; + return getPIndex(index); +} + +bool STObject::isFieldPresent(SOE_Field field) const +{ + int index=getFieldIndex(field); + if(index==-1) return false; + return peekAtIndex(field).getType()==STI_OBJECT; +} + +bool STObject::setFlag(int f) +{ + if(mFlagIdx<0) return false; + STUInt16* t=dynamic_cast(getPIndex(mFlagIdx)); + assert(t); + t->setValue(t->getValue() | f); + return true; +} + +bool STObject::clearFlag(int f) +{ + if(mFlagIdx<0) return false; + STUInt16* t=dynamic_cast(getPIndex(mFlagIdx)); + assert(t); + t->setValue(t->getValue() & ~f); + return true; +} + +int STObject::getFlag(void) const +{ + if(mFlagIdx<0) return 0; + const STUInt16* t=dynamic_cast(peekAtPIndex(mFlagIdx)); + assert(t); + return t->getValue(); +} + +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; + mData.replace(index, makeDefaultObject(mType[index]->e_id, mType[index]->e_name)); + setFlag(mType[index]->e_flags); +} + +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; + mData.replace(index, new STObject(mType[index]->e_name)); + clearFlag(mType[index]->e_flags); +} diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 8480fe775..d7e81b6f3 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -12,8 +12,22 @@ enum SOE_Type SOE_NEVER=-1, SOE_REQUIRED=0, SOE_FLAGS, SOE_IFFLAG=1, SOE_IFNFLAG=2 }; +enum SOE_Field +{ + sfInvalid=-1, + sfGeneric=0, + + // common fields + sfFlags, sfSequence, sfExtensions, sfTargetLedger, sfSourceTag, sfIdentifier, + sfDestination, sfTarget, sfAmount, sfCurrency, + sfAmountIn, sfAmountOut, sfCurrencyIn, sfCurrencyOut, + sfInvoiceID, + sfExpireLedger +}; + struct SOElement { // An element in the description of a serialized object + SOE_Field e_field; const char *e_name; SerializedTypeID e_id; SOE_Type e_type; @@ -23,11 +37,15 @@ struct SOElement class STObject : public SerializedType { protected: - boost::ptr_vector data; - std::vector type; + int mFlagIdx; // the offset to the flags object, -1 if none + boost::ptr_vector mData; + std::vector mType; + + static SerializedType* makeDefaultObject(SerializedTypeID id, const char *name); + static SerializedType* makeDeserializedObject(SerializedTypeID id, const char *name, SerializerIterator&); public: - STObject(const char *n=NULL) : SerializedType(n) { ; } + STObject(const char *n=NULL) : SerializedType(n), mFlagIdx(-1) { ; } STObject(SOElement *t, const char *n=NULL); STObject(SOElement *t, SerializerIterator& u, const char *n=NULL); virtual ~STObject() { ; } @@ -40,16 +58,33 @@ public: std::string getFullText() const; std::string getText() const; - void addObject(const SerializedType& t) { data.push_back(t.duplicate()); } - void giveObject(SerializedType* t) { data.push_back(t); } - const boost::ptr_vector& peekData() const { return data; } - boost::ptr_vector& peekData() { return data; } + int addObject(const SerializedType& t) { mData.push_back(t.duplicate()); return mData.size()-1; } + int giveObject(SerializedType* t) { mData.push_back(t); return mData.size()-1; } + const boost::ptr_vector& peekData() const { return mData; } + boost::ptr_vector& peekData() { return mData; } - int getCount() const { return data.size(); } - const SerializedType& peekAt(int offset) const { return data[offset]; } - SerializedType& getAt(int offset) { return data[offset]; } - const SerializedType* peekAtP(int offset) const { return &(data[offset]); } - SerializedType* getAtP(int offset) { return &(data[offset]); } + int getCount() const { return mData.size(); } + + bool setFlag(int); + bool clearFlag(int); + int getFlag() const; + + const SerializedType& peekAtIndex(int offset) const { return mData[offset]; } + SerializedType& getIndex(int offset) { return mData[offset]; } + const SerializedType* peekAtPIndex(int offset) const { return &(mData[offset]); } + SerializedType* getPIndex(int offset) { return &(mData[offset]); } + + int getFieldIndex(SOE_Field field) const; + + const SerializedType& peekAtField(SOE_Field field) const; + SerializedType& getField(SOE_Field field); + const SerializedType* peekAtPField(SOE_Field field); + SerializedType* getPField(SOE_Field field); + const SOElement* getFieldType(SOE_Field field) const; + + bool isFieldPresent(SOE_Field field) const; + void makeFieldPresent(SOE_Field field); + void makeFieldAbsent(SOE_Field field); }; diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 45a06fde9..24117a455 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -103,28 +103,64 @@ void SerializedTransaction::setSignature(const std::vector& sig) uint32 SerializedTransaction::getVersion() const { - const STUInt32* v=dynamic_cast(mMiddleTxn.peekAtP(0)); + const STUInt32* v=dynamic_cast(mMiddleTxn.peekAtPIndex(0)); if(!v) throw(std::runtime_error("corrupt transaction")); return v->getValue(); } void SerializedTransaction::setVersion(uint32 ver) { - STUInt32* v=dynamic_cast(mMiddleTxn.getAtP(0)); + STUInt32* v=dynamic_cast(mMiddleTxn.getPIndex(0)); if(!v) throw(std::runtime_error("corrupt transaction")); v->setValue(ver); } uint64 SerializedTransaction::getTransactionFee() const { - const STUInt64* v=dynamic_cast(mMiddleTxn.peekAtP(3)); + const STUInt64* v=dynamic_cast(mMiddleTxn.peekAtPIndex(3)); if(!v) throw(std::runtime_error("corrupt transaction")); return v->getValue(); } void SerializedTransaction::setTransactionFee(uint64 fee) { - STUInt64* v=dynamic_cast(mMiddleTxn.getAtP(3)); + STUInt64* v=dynamic_cast(mMiddleTxn.getPIndex(3)); if(!v) throw(std::runtime_error("corrupt transaction")); v->setValue(fee); } + +int SerializedTransaction::getITFieldIndex(SOE_Field field) const +{ + return mInnerTxn.getFieldIndex(field); +} + +int SerializedTransaction::getITFieldCount() const +{ + return mInnerTxn.getCount(); +} + +bool SerializedTransaction::getITFieldPresent(SOE_Field field) const +{ + return mInnerTxn.isFieldPresent(field); +} + +const SerializedType& SerializedTransaction::peekITField(SOE_Field field) +{ + return mInnerTxn.peekAtField(field); +} + +SerializedType& SerializedTransaction::getITField(SOE_Field field) +{ + return mInnerTxn.getField(field); +} + +void SerializedTransaction::makeITFieldPresent(SOE_Field field) +{ + return mInnerTxn.makeFieldPresent(field); +} + +void SerializedTransaction::makeITFieldAbsent(SOE_Field field) +{ + return mInnerTxn.makeFieldAbsent(field); +} + \ No newline at end of file diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 2422b839f..40aec0137 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -49,12 +49,15 @@ public: void setSequence(uint32); // inner transaction field functions - int getITFieldIndex(const char *) const; + int getITFieldIndex(SOE_Field field) const; int getITFieldCount() const; - bool getITFieldPresent(int index) const; - const SerializedType& peekITField(int index); - SerializedType& getITField(int index); - void makeITFieldPresent(int index); + const SerializedType& peekITField(SOE_Field field); + SerializedType& getITField(SOE_Field field); + + // optional field functions + bool getITFieldPresent(SOE_Field field) const; + void makeITFieldPresent(SOE_Field field); + void makeITFieldAbsent(SOE_Field field); // whole transaction functions int getTransaction(Serializer& s, bool include_length) const; diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index ce11a294d..272636b34 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -1,49 +1,51 @@ #include "TransactionFormats.h" +#define S_FIELD(x) sf##x, #x + TransactionFormat InnerTxnFormats[]= { { "MakePayment", ttMAKE_PAYMENT, { - { "Flags", STI_UINT16, SOE_FLAGS, 0 }, - { "Sequence", STI_UINT32, SOE_REQUIRED, 0 }, - { "Destination", STI_ACCOUNT, SOE_REQUIRED, 0 }, - { "Amount", STI_UINT64, SOE_REQUIRED, 0 }, - { "Currency", STI_HASH160, SOE_IFFLAG, 1 }, - { "SourceTag", STI_UINT32, SOE_IFFLAG, 2 }, - { "TargetLedger", STI_UINT32, SOE_IFFLAG, 4 }, - { "InvoiceID", STI_HASH256, SOE_IFFLAG, 8 }, - { "Extensions", STI_TL, SOE_IFFLAG, 32768 }, - { NULL, STI_DONE, SOE_NEVER, -1 } } + { S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 }, + { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Amount), STI_UINT64, 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 }, + { S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Invoice", ttINVOICE, { - { "Flags", STI_UINT16, SOE_FLAGS, 0 }, - { "Sequence", STI_UINT32, SOE_REQUIRED, 0 }, - { "Target", STI_ACCOUNT, SOE_REQUIRED, 0 }, - { "Amount", STI_UINT64, SOE_REQUIRED, 0 }, - { "Currency", STI_HASH160, SOE_IFFLAG, 1 }, - { "SourceTag", STI_UINT32, SOE_IFFLAG, 2 }, - { "Destination", STI_ACCOUNT, SOE_IFFLAG, 4 }, - { "TargetLedger", STI_UINT32, SOE_IFFLAG, 8 }, - { "Identifier", STI_VL, SOE_IFFLAG, 16 }, - { "Extensions", STI_TL, SOE_IFFLAG, 32768 }, - { NULL, STI_DONE, SOE_NEVER, -1 } } + { S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 }, + { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Amount), STI_UINT64, 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 }, + { S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 8 }, + { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 16 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Offer", ttEXCHANGE_OFFER, { - { "Flags", STI_UINT16, SOE_FLAGS, 0 }, - { "Sequence", STI_UINT32, SOE_REQUIRED, 0 }, - { "AmountIn", STI_UINT64, SOE_REQUIRED, 0 }, - { "CurrencyIn", STI_HASH160, SOE_IFFLAG, 2 }, - { "AmountOut", STI_UINT64, SOE_REQUIRED, 0 }, - { "CurrencyOut", STI_HASH160, SOE_IFFLAG, 4 }, - { "SourceTag", STI_UINT32, SOE_IFFLAG, 8 }, - { "Destination", STI_ACCOUNT, SOE_IFFLAG, 16 }, - { "TargetLedger", STI_UINT32, SOE_IFFLAG, 32 }, - { "ExpireLedger", STI_UINT32, SOE_IFFLAG, 64 }, - { "Identifier", STI_VL, SOE_IFFLAG, 128 }, - { "Extensions", STI_TL, SOE_IFFLAG, 32768 }, - { NULL, STI_DONE, SOE_NEVER, -1 } } + { S_FIELD(Flags), STI_UINT16, SOE_FLAGS, 0 }, + { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(AmountIn), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(CurrencyIn), STI_HASH160, SOE_IFFLAG, 2 }, + { S_FIELD(AmountOut), STI_UINT64, 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 }, + { S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 32 }, + { S_FIELD(ExpireLedger), STI_UINT32, SOE_IFFLAG, 64 }, + { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 128 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 32768 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, - { NULL, ttINVALID } + { NULL, ttINVALID } }; TransactionFormat* getFormat(TransactionType t)