Remove runtime inference of unrecognized SFields

This commit is contained in:
Scott Schurr
2019-02-13 14:08:55 -08:00
committed by Nik Bougalis
parent 9279a3fee7
commit 57fe197d3e
6 changed files with 241 additions and 169 deletions

View File

@@ -24,8 +24,6 @@
#include <ripple/json/json_value.h>
#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <utility>
namespace ripple {
@@ -104,17 +102,8 @@ field_code(int id, int index)
/** Identifies fields.
Fields are necessary to tag data in signed transactions so that
the binary format of the transaction can be canonicalized.
There are two categories of these fields:
1. Those that are created at compile time.
2. Those that are created at run time.
Both are always const. Category 1 can only be created in FieldNames.cpp.
This is enforced at compile time. Category 2 can only be created by
calling getField with an as yet unused fieldType and fieldValue (or the
equivalent fieldCode).
the binary format of the transaction can be canonicalized. All
SFields are created at compile time.
Each SField, once constructed, lives until program termination, and there
is only one instance per fieldType/fieldValue pair which serves the entire
@@ -156,21 +145,14 @@ public:
SField& operator=(SField&&) = delete;
public:
struct private_access_tag_t; // public, but still an implementation detail
struct private_access_tag_t; // public, but still an implementation detail
// These constructors can only be called from SField.cpp
SField (private_access_tag_t, SerializedTypeID tid, int fv,
const char* fn, int meta = sMD_Default,
IsSigning signing = IsSigning::yes);
explicit SField (private_access_tag_t, int fc);
SField (private_access_tag_t, SerializedTypeID tid, int fv);
protected:
// These constructors can only be called from SField.cpp
explicit SField (SerializedTypeID tid, int fv);
public:
// getField will dynamically construct a new SField if necessary
static const SField& getField (int fieldCode);
static const SField& getField (std::string const& fieldName);
static const SField& getField (int type, int value)
@@ -270,10 +252,7 @@ public:
private:
static int num;
static std::mutex SField_mutex;
static std::map<int, SField const*> knownCodeToField;
static std::map<int, std::unique_ptr<SField const>> unknownCodeToField;
};
/** A field with a type known at compile time. */

View File

@@ -20,6 +20,7 @@
#ifndef RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED
#define RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED
#include <ripple/basics/contract.h>
#include <ripple/protocol/SField.h>
#include <boost/range.hpp>
#include <memory>
@@ -49,6 +50,8 @@ public:
: e_field (fieldName)
, flags (flags)
{
if (! e_field.isUseful())
Throw<std::runtime_error> ("SField in SOElement must be useful.");
}
};

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include <ripple/basics/safe_cast.h>
#include <ripple/protocol/SField.h>
#include <cassert>
#include <string>
@@ -28,11 +27,7 @@ namespace ripple {
// Storage for static const members.
SField::IsSigning const SField::notSigning;
int SField::num = 0;
std::mutex SField::SField_mutex;
std::map<int, SField const*> SField::knownCodeToField;
std::map<int, std::unique_ptr<SField const>> SField::unknownCodeToField;
using StaticScopedLockType = std::lock_guard <std::mutex>;
// Give only this translation unit permission to construct SFields
struct SField::private_access_tag_t
@@ -40,7 +35,7 @@ struct SField::private_access_tag_t
explicit private_access_tag_t() = default;
};
SField::private_access_tag_t access;
static SField::private_access_tag_t access;
// Construct all compile-time SFields, and register them in the knownCodeToField
// database:
@@ -270,29 +265,6 @@ SField::SField(private_access_tag_t, int fc)
knownCodeToField[fieldCode] = this;
}
// call with the map mutex to protect num.
// This is naturally done with no extra expense
// from getField(int code).
SField::SField(SerializedTypeID tid, int fv)
: fieldCode (field_code (tid, fv))
, fieldType (tid)
, fieldValue (fv)
, fieldName (std::to_string (tid) + '/' + std::to_string (fv))
, fieldMeta (sMD_Default)
, fieldNum (++num)
, signingField (IsSigning::yes)
, jsonName (fieldName.c_str())
{
assert ((fv != 1) || ((tid != STI_ARRAY) && (tid != STI_OBJECT)));
}
SField::SField(private_access_tag_t,
SerializedTypeID tid, int fv)
: SField(tid, fv)
{
knownCodeToField[fieldCode] = this;
}
SField const&
SField::getField (int code)
{
@@ -300,54 +272,9 @@ SField::getField (int code)
if (it != knownCodeToField.end ())
{
// 99+% of the time, it will be a valid, known field
return * (it->second);
}
int type = code >> 16;
int field = code & 0xffff;
// Don't dynamically extend types that have no binary encoding.
if ((field > 255) || (code < 0))
return sfInvalid;
switch (type)
{
// Types we are willing to dynamically extend
// types (common)
case STI_UINT16:
case STI_UINT32:
case STI_UINT64:
case STI_HASH128:
case STI_HASH256:
case STI_AMOUNT:
case STI_VL:
case STI_ACCOUNT:
case STI_OBJECT:
case STI_ARRAY:
// types (uncommon)
case STI_UINT8:
case STI_HASH160:
case STI_PATHSET:
case STI_VECTOR256:
break;
default:
return sfInvalid;
}
{
// Lookup in the run-time data base, and create if it does not
// yet exist.
StaticScopedLockType sl (SField_mutex);
auto it = unknownCodeToField.find (code);
if (it != unknownCodeToField.end ())
return * (it->second);
return *(unknownCodeToField[code] = std::unique_ptr<SField const>(
new SField(safe_cast<SerializedTypeID>(type), field)));
}
return sfInvalid;
}
int SField::compare (SField const& f1, SField const& f2)
@@ -373,15 +300,6 @@ SField::getField (std::string const& fieldName)
if (fieldPair.second->fieldName == fieldName)
return * (fieldPair.second);
}
{
StaticScopedLockType sl (SField_mutex);
for (auto const & fieldPair : unknownCodeToField)
{
if (fieldPair.second->fieldName == fieldName)
return * (fieldPair.second);
}
}
return sfInvalid;
}

View File

@@ -28,18 +28,20 @@ void SOTemplate::push_back (SOElement const& r)
//
if (mIndex.empty ())
{
// Unmapped indices will be set to -1
// Unmapped indices are initialized to -1
//
mIndex.resize (SField::getNumFields () + 1, -1);
}
// Make sure the field's index is in range
//
assert (r.e_field.getNum () < mIndex.size ());
if (r.e_field.getNum() <= 0 || r.e_field.getNum() >= mIndex.size())
Throw<std::runtime_error> ("Invalid field index for SOTemplate.");
// Make sure that this field hasn't already been assigned
//
assert (getIndex (r.e_field) == -1);
if (getIndex (r.e_field) != -1)
Throw<std::runtime_error> ("Duplicate field index for SOTemplate.");
// Add the field to the index mapping table
//