STObject::applyTemplate() throws with description of error:

The `STObject` member function `setType()` has been renamed to
applyTemplate() and modified to throw if there is a template
mismatch.

The error description in the exception is, in certain cases,
used, to better indicate why a particular transaction was
considered ill formed.

Fixes #2585.
This commit is contained in:
Scott Schurr
2018-11-02 17:50:27 -07:00
committed by Nik Bougalis
parent c354809e1c
commit ad5c5f1969
12 changed files with 221 additions and 132 deletions

View File

@@ -98,10 +98,7 @@ STArray::STArray (SerialIter& sit, SField const& f, int depth)
v_.emplace_back(sit, fn, depth+1);
if (v_.back().setTypeFromSField (fn) == STObject::typeSetFail)
{
Throw<std::runtime_error> ("Malformed object in array");
}
v_.back().applyTemplateFromSField (fn); // May throw
}
}

View File

@@ -73,17 +73,7 @@ void STLedgerEntry::setSLEType ()
Throw<std::runtime_error> ("invalid ledger entry type");
type_ = format->getType ();
if (!setType (format->elements))
{
if (auto j = debugLog().error())
{
j << "Ledger entry not valid for type " << format->getName ();
j << "Object: " << getJson (0);
}
Throw<std::runtime_error> ("ledger entry not valid for type");
}
applyTemplate (format->elements); // May throw
}
std::string STLedgerEntry::getFullText () const

View File

@@ -58,15 +58,16 @@ STObject::STObject (SOTemplate const& type,
}
STObject::STObject (SOTemplate const& type,
SerialIter & sit, SField const& name)
SerialIter & sit, SField const& name) noexcept (false)
: STBase (name)
{
v_.reserve(type.size());
set (sit);
setType (type);
applyTemplate (type); // May throw
}
STObject::STObject (SerialIter& sit, SField const& name, int depth)
STObject::STObject (
SerialIter& sit, SField const& name, int depth) noexcept (false)
: STBase(name)
, mType(nullptr)
{
@@ -99,9 +100,17 @@ void STObject::set (const SOTemplate& type)
}
}
bool STObject::setType (const SOTemplate& type)
void STObject::applyTemplate (const SOTemplate& type) noexcept (false)
{
bool valid = true;
auto throwFieldErr = [] (std::string const& field, char const* description)
{
std::stringstream ss;
ss << "Field '" << field << "' " << description;
std::string text {ss.str()};
JLOG (debugLog().error()) << "STObject::applyTemplate failed: " << text;
Throw<FieldErr> (text);
};
mType = &type;
decltype(v_) v;
v.reserve(type.size());
@@ -114,10 +123,8 @@ bool STObject::setType (const SOTemplate& type)
{
if ((e->flags == SOE_DEFAULT) && iter->get().isDefault())
{
JLOG (debugLog().error())
<< "setType(" << getFName().getName()
<< "): explicit default " << e->e_field.fieldName;
valid = false;
throwFieldErr (e->e_field.fieldName,
"may not be explicitly set to default.");
}
v.emplace_back(std::move(*iter));
v_.erase(iter);
@@ -126,10 +133,8 @@ bool STObject::setType (const SOTemplate& type)
{
if (e->flags == SOE_REQUIRED)
{
JLOG (debugLog().error())
<< "setType(" << getFName().getName()
<< "): missing " << e->e_field.fieldName;
valid = false;
throwFieldErr (e->e_field.fieldName,
"is required but missing.");
}
v.emplace_back(detail::nonPresentObject, e->e_field);
}
@@ -139,34 +144,25 @@ bool STObject::setType (const SOTemplate& type)
// Anything left over in the object must be discardable
if (! e->getFName().isDiscardable())
{
JLOG (debugLog().error())
<< "setType(" << getFName().getName()
<< "): non-discardable leftover " << e->getFName().getName ();
valid = false;
throwFieldErr (e->getFName().getName(),
"found in disallowed location.");
}
}
// Swap the template matching data in for the old data,
// freeing any leftover junk
v_.swap(v);
return valid;
}
STObject::ResultOfSetTypeFromSField
STObject::setTypeFromSField (SField const& sField)
void STObject::applyTemplateFromSField (SField const& sField) noexcept (false)
{
ResultOfSetTypeFromSField ret = noTemplate;
SOTemplate const* elements =
InnerObjectFormats::getInstance ().findSOTemplateBySField (sField);
if (elements)
{
ret = setType (*elements) ? typeIsSet : typeSetFail;
}
return ret;
applyTemplate (*elements); // May throw
}
// return true = terminated with end-of-object
bool STObject::set (SerialIter& sit, int depth)
bool STObject::set (SerialIter& sit, int depth) noexcept (false)
{
bool reachedEndOfObject = false;
@@ -211,10 +207,8 @@ bool STObject::set (SerialIter& sit, int depth)
// If the object type has a known SOTemplate then set it.
STObject* const obj = dynamic_cast <STObject*> (&(v_.back().get()));
if (obj && (obj->setTypeFromSField (fn) == typeSetFail))
{
Throw<std::runtime_error> ("field deserialization error");
}
if (obj)
obj->applyTemplateFromSField (fn); // May throw
}
}
@@ -628,6 +622,11 @@ void STObject::setFieldAmount (SField const& field, STAmount const& v)
setFieldUsingAssignment (field, v);
}
void STObject::setFieldPathSet (SField const& field, STPathSet const& v)
{
setFieldUsingAssignment (field, v);
}
void STObject::setFieldArray (SField const& field, STArray const& v)
{
setFieldUsingAssignment (field, v);

View File

@@ -804,20 +804,19 @@ static boost::optional <STObject> parseObject (
}
// Some inner object types have templates. Attempt to apply that.
if (data.setTypeFromSField (inName) == STObject::typeSetFail)
{
error = template_mismatch (inName);
return boost::none;
}
data.applyTemplateFromSField (inName); // May throw
return std::move (data);
}
catch (STObject::FieldErr const&)
{
error = template_mismatch (inName);
}
catch (std::exception const&)
{
error = invalid_data (json_name);
return boost::none;
}
return boost::none;
}
static boost::optional <detail::STVar> parseArray (

View File

@@ -55,18 +55,15 @@ auto getTxFormat (TxType type)
return format;
}
STTx::STTx (STObject&& object)
STTx::STTx (STObject&& object) noexcept (false)
: STObject (std::move (object))
{
tx_type_ = static_cast <TxType> (getFieldU16 (sfTransactionType));
if (!setType (getTxFormat (tx_type_)->elements))
Throw<std::runtime_error> ("transaction not valid");
applyTemplate (getTxFormat (tx_type_)->elements); // may throw
tid_ = getHash(HashPrefix::transactionID);
}
STTx::STTx (SerialIter& sit)
STTx::STTx (SerialIter& sit) noexcept (false)
: STObject (sfTransaction)
{
int length = sit.getBytesLeft ();
@@ -77,9 +74,7 @@ STTx::STTx (SerialIter& sit)
set (sit);
tx_type_ = static_cast<TxType> (getFieldU16 (sfTransactionType));
if (!setType (getTxFormat (tx_type_)->elements))
Throw<std::runtime_error> ("transaction not valid");
applyTemplate (getTxFormat (tx_type_)->elements); // May throw
tid_ = getHash(HashPrefix::transactionID);
}