Improvements to protocol serialization:

A few serialization changes coming from m-of-n development:

 o Improve readability of SField.cpp.
 o Better initialization of STObject.
 o Trimming of STObject public methods.
 o Add STObject::getFieldObject and STObject::setFieldObject.
 o Make STObject::isEquivalent more robust.
 o Improvements to whitespace, overrides, and virtuals.
This commit is contained in:
Scott Schurr
2015-02-03 18:17:11 -08:00
committed by Vinnie Falco
parent 2f3834359e
commit 92799187ed
18 changed files with 436 additions and 324 deletions

View File

@@ -88,7 +88,7 @@ LedgerFormats::LedgerFormats ()
;
add ("EnabledAmendments", ltAMENDMENTS)
<< SOElement (sfAmendments, SOE_REQUIRED)
<< SOElement (sfAmendments, SOE_REQUIRED)
;
add ("FeeSettings", ltFEE_SETTINGS)

View File

@@ -34,6 +34,9 @@ static std::mutex SField_mutex;
static std::map<int, SField const*> knownCodeToField;
static std::map<int, std::unique_ptr<SField const>> unknownCodeToField;
// Storage for static const member.
SField::IsSigning const SField::notSigning;
int SField::num = 0;
typedef std::lock_guard <std::mutex> StaticScopedLockType;
@@ -173,9 +176,9 @@ SField const sfDeliveredAmount = make::one(&sfDeliveredAmount, STI_AMOUNT, 18, "
// variable length
TypedField<STBlob> const sfPublicKey = make::one<STBlob>(&sfPublicKey, STI_VL, 1, "PublicKey");
TypedField<STBlob> const sfSigningPubKey = make::one<STBlob>(&sfSigningPubKey, STI_VL, 3, "SigningPubKey");
TypedField<STBlob> const sfSignature = make::one<STBlob>(&sfSignature, STI_VL, 6, "Signature", SField::sMD_Default, false);
TypedField<STBlob> const sfSignature = make::one<STBlob>(&sfSignature, STI_VL, 6, "Signature", SField::sMD_Default, SField::notSigning);
SField const sfMessageKey = make::one(&sfMessageKey, STI_VL, 2, "MessageKey");
SField const sfTxnSignature = make::one(&sfTxnSignature, STI_VL, 4, "TxnSignature", SField::sMD_Default, false);
SField const sfTxnSignature = make::one(&sfTxnSignature, STI_VL, 4, "TxnSignature", SField::sMD_Default, SField::notSigning);
SField const sfDomain = make::one(&sfDomain, STI_VL, 7, "Domain");
SField const sfFundCode = make::one(&sfFundCode, STI_VL, 8, "FundCode");
SField const sfRemoveCode = make::one(&sfRemoveCode, STI_VL, 9, "RemoveCode");
@@ -216,7 +219,7 @@ SField const sfMemo = make::one(&sfMemo, STI_OBJEC
// array of objects
// ARRAY/1 is reserved for end of array
SField const sfSigningAccounts = make::one(&sfSigningAccounts, STI_ARRAY, 2, "SigningAccounts");
SField const sfTxnSignatures = make::one(&sfTxnSignatures, STI_ARRAY, 3, "TxnSignatures", SField::sMD_Default, false);
SField const sfTxnSignatures = make::one(&sfTxnSignatures, STI_ARRAY, 3, "TxnSignatures", SField::sMD_Default, SField::notSigning);
SField const sfSignatures = make::one(&sfSignatures, STI_ARRAY, 4, "Signatures");
SField const sfTemplate = make::one(&sfTemplate, STI_ARRAY, 5, "Template");
SField const sfNecessary = make::one(&sfNecessary, STI_ARRAY, 6, "Necessary");
@@ -225,7 +228,7 @@ SField const sfAffectedNodes = make::one(&sfAffectedNodes, STI_ARRAY, 8, "Af
SField const sfMemos = make::one(&sfMemos, STI_ARRAY, 9, "Memos");
SField::SField (SerializedTypeID tid, int fv, const char* fn,
int meta, bool signing)
int meta, IsSigning signing)
: fieldCode (field_code (tid, fv))
, fieldType (tid)
, fieldValue (fv)
@@ -244,7 +247,7 @@ SField::SField (int fc)
, fieldValue (0)
, fieldMeta (sMD_Never)
, fieldNum (++num)
, signingField (true)
, signingField (IsSigning::yes)
, rawJsonName (getName ())
, jsonName (rawJsonName.c_str ())
{
@@ -257,7 +260,7 @@ SField::SField (SerializedTypeID tid, int fv)
: fieldCode (field_code (tid, fv)), fieldType (tid), fieldValue (fv),
fieldMeta (sMD_Default),
fieldNum (++num),
signingField (true),
signingField (IsSigning::yes),
jsonName (nullptr)
{
fieldName = std::to_string (tid) + '/' + std::to_string (fv);

View File

@@ -264,39 +264,6 @@ std::string STObject::getFullText () const
return ret;
}
void STObject::add (Serializer& s, bool withSigningFields) const
{
std::map<int, STBase const*> fields;
for (auto const& e : v_)
{
// pick out the fields and sort them
if ((e->getSType() != STI_NOTPRESENT) &&
e->getFName().shouldInclude (withSigningFields))
{
fields.insert (std::make_pair (
e->getFName().fieldCode, &e.get()));
}
}
// insert sorted
for (auto const& e : fields)
{
auto const field = e.second;
// When we serialize an object inside another object,
// the type associated by rule with this field name
// must be OBJECT, or the object cannot be deserialized
assert ((field->getSType() != STI_OBJECT) ||
(field->getFName().fieldType == STI_OBJECT));
field->addFieldID (s);
field->add (s);
if (dynamic_cast<const STArray*> (field) != nullptr)
s.addFieldID (STI_ARRAY, 1);
else if (dynamic_cast<const STObject*> (field) != nullptr)
s.addFieldID (STI_OBJECT, 1);
}
}
std::string STObject::getText () const
{
std::string ret = "{";
@@ -326,32 +293,10 @@ bool STObject::isEquivalent (const STBase& t) const
return false;
}
auto it1 = v_.begin (), end1 = v_.end ();
auto it2 = v->v_.begin (), end2 = v->v_.end ();
if (mType != nullptr && (v->mType == mType))
return equivalentSTObjectSameTemplate (*this, *v);
while ((it1 != end1) && (it2 != end2))
{
if ((it1->get().getSType () != it2->get().getSType ()) ||
!it1->get().isEquivalent (it2->get()))
{
if (it1->get().getSType () != it2->get().getSType ())
{
WriteLog (lsDEBUG, STObject) << "notEquiv type " <<
it1->get().getFullText() << " != " << it2->get().getFullText();
}
else
{
WriteLog (lsDEBUG, STObject) << "notEquiv " <<
it1->get().getFullText() << " != " << it2->get().getFullText();
}
return false;
}
++it1;
++it2;
}
return (it1 == end1) && (it2 == end2);
return equivalentSTObject (*this, *v);
}
uint256 STObject::getHash (std::uint32_t prefix) const
@@ -448,20 +393,12 @@ bool STObject::isFieldPresent (SField const& field) const
STObject& STObject::peekFieldObject (SField const& field)
{
STBase* rf = getPField (field, true);
return peekField<STObject> (field);
}
if (!rf)
throw std::runtime_error ("Field not found");
if (rf->getSType () == STI_NOTPRESENT)
rf = makeFieldPresent (field);
STObject* cf = dynamic_cast<STObject*> (rf);
if (!cf)
throw std::runtime_error ("Wrong field type");
return *cf;
STArray& STObject::peekFieldArray (SField const& field)
{
return peekField<STArray> (field);
}
bool STObject::setFlag (std::uint32_t f)
@@ -650,12 +587,6 @@ STAmount const& STObject::getFieldAmount (SField const& field) const
return getFieldByConstRef <STAmount> (field, empty);
}
const STArray& STObject::getFieldArray (SField const& field) const
{
static STArray const empty{};
return getFieldByConstRef <STArray> (field, empty);
}
STPathSet const& STObject::getFieldPathSet (SField const& field) const
{
static STPathSet const empty{};
@@ -668,6 +599,18 @@ const STVector256& STObject::getFieldV256 (SField const& field) const
return getFieldByConstRef <STVector256> (field, empty);
}
const STArray& STObject::getFieldArray (SField const& field) const
{
static STArray const empty{};
return getFieldByConstRef <STArray> (field, empty);
}
const STObject& STObject::getFieldObject (SField const& field) const
{
static STObject const empty{sfInvalid};
return getFieldByConstRef <STObject> (field, empty);
}
void
STObject::set (std::unique_ptr<STBase> v)
{
@@ -760,6 +703,11 @@ void STObject::setFieldArray (SField const& field, STArray const& v)
setFieldUsingAssignment (field, v);
}
void STObject::setFieldObject (SField const& field, STObject const& v)
{
setFieldUsingAssignment (field, v);
}
Json::Value STObject::getJson (int options) const
{
Json::Value ret (Json::objectValue);
@@ -830,4 +778,96 @@ bool STObject::operator== (const STObject& obj) const
return true;
}
void STObject::add (Serializer& s, bool withSigningFields) const
{
std::map<int, STBase const*> fields;
for (auto const& e : v_)
{
// pick out the fields and sort them
if ((e->getSType() != STI_NOTPRESENT) &&
e->getFName().shouldInclude (withSigningFields))
{
fields.insert (std::make_pair (
e->getFName().fieldCode, &e.get()));
}
}
// insert sorted
for (auto const& e : fields)
{
auto const field = e.second;
// When we serialize an object inside another object,
// the type associated by rule with this field name
// must be OBJECT, or the object cannot be deserialized
assert ((field->getSType() != STI_OBJECT) ||
(field->getFName().fieldType == STI_OBJECT));
field->addFieldID (s);
field->add (s);
if (dynamic_cast<const STArray*> (field) != nullptr)
s.addFieldID (STI_ARRAY, 1);
else if (dynamic_cast<const STObject*> (field) != nullptr)
s.addFieldID (STI_OBJECT, 1);
}
}
std::vector<STBase const*>
STObject::getSortedFields (STObject const& objToSort)
{
std::vector<STBase const*> sf;
sf.reserve (objToSort.getCount ());
// Choose the fields that we need to sort.
for (detail::STVar const& elem : objToSort.v_)
{
// Pick out the fields and sort them.
STBase const& base = elem.get();
if ((base.getSType () != STI_NOTPRESENT) &&
base.getFName ().shouldInclude (true))
{
sf.push_back (&base);
}
}
// Sort the fields by fieldCode.
std::sort (sf.begin (), sf.end (),
[] (STBase const* a, STBase const* b) -> bool
{
return a->getFName ().fieldCode < b->getFName ().fieldCode;
});
// There should never be duplicate fields in an STObject. Verify that
// in debug mode.
assert (std::adjacent_find (sf.cbegin (), sf.cend ()) == sf.cend ());
return sf;
}
bool STObject::equivalentSTObjectSameTemplate (
STObject const& obj1, STObject const& obj2)
{
assert (obj1.mType != nullptr);
assert (obj1.mType == obj2.mType);
return std::equal (obj1.begin (), obj1.end (), obj2.begin (), obj2.end (),
[] (STBase const& st1, STBase const& st2)
{
return (st1.getSType() == st2.getSType()) &&
st1.isEquivalent (st2);
});
}
bool STObject::equivalentSTObject (STObject const& obj1, STObject const& obj2)
{
auto sf1 = getSortedFields (obj1);
auto sf2 = getSortedFields (obj2);
return std::equal (sf1.begin (), sf1.end (), sf2.begin (), sf2.end (),
[] (STBase const* st1, STBase const* st2)
{
return (st1->getSType() == st2->getSType()) &&
st1->isEquivalent (*st2);
});
}
} // ripple

View File

@@ -155,7 +155,7 @@ static Blob getSigningData (STTx const& that)
{
Serializer s;
s.add32 (HashPrefix::txSign);
that.add (s, false);
that.addWithoutSigningFields (s);
return s.getData();
}

View File

@@ -27,7 +27,7 @@ sign (STObject& st, HashPrefix const& prefix,
{
Serializer ss;
ss.add32(prefix);
st.add(ss, false);
st.addWithoutSigningFields(ss);
set(st, sfSignature,
sk.sign(ss.data(), ss.size()));
}
@@ -42,7 +42,7 @@ verify (STObject const& st,
return false;
Serializer ss;
ss.add32(prefix);
st.add(ss, false);
st.addWithoutSigningFields(ss);
return pk.verify(
ss.data(), ss.size(),
sig->data(), sig->size());