mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
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:
committed by
Vinnie Falco
parent
2f3834359e
commit
92799187ed
@@ -88,7 +88,7 @@ LedgerFormats::LedgerFormats ()
|
||||
;
|
||||
|
||||
add ("EnabledAmendments", ltAMENDMENTS)
|
||||
<< SOElement (sfAmendments, SOE_REQUIRED)
|
||||
<< SOElement (sfAmendments, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("FeeSettings", ltFEE_SETTINGS)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user