mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
[WIP] Turns out that adding a new serialized type is harder than it looks
This commit is contained in:
@@ -49,6 +49,8 @@ template <int>
|
||||
class STBitString;
|
||||
template <class>
|
||||
class STInteger;
|
||||
template <class>
|
||||
class STTypedInteger;
|
||||
class STNumber;
|
||||
class STXChainBridge;
|
||||
class STVector256;
|
||||
@@ -89,6 +91,8 @@ class STCurrency;
|
||||
STYPE(STI_ISSUE, 24) \
|
||||
STYPE(STI_XCHAIN_BRIDGE, 25) \
|
||||
STYPE(STI_CURRENCY, 26) \
|
||||
STYPE(STI_TENTHBIPS16, 27) \
|
||||
STYPE(STI_TENTHBIPS32, 28) \
|
||||
\
|
||||
/* high-level types */ \
|
||||
/* cannot be serialized inside other types */ \
|
||||
@@ -358,15 +362,12 @@ using SF_UINT256 = TypedField<STBitString<256>>;
|
||||
using SF_UINT384 = TypedField<STBitString<384>>;
|
||||
using SF_UINT512 = TypedField<STBitString<512>>;
|
||||
|
||||
// These BIPS and TENTHBIPS values are serialized as the underlying type.
|
||||
// These TENTHBIPS values are serialized as the underlying type.
|
||||
// The tag is only applied when deserialized.
|
||||
//
|
||||
// Basis points (bips) values:
|
||||
using SF_BIPS16 = TypedField<STInteger<Bips16>>;
|
||||
using SF_BIPS32 = TypedField<STInteger<Bips32>>;
|
||||
// Tenth of a basis point values:
|
||||
using SF_TENTHBIPS16 = TypedField<STInteger<TenthBips16>>;
|
||||
using SF_TENTHBIPS32 = TypedField<STInteger<TenthBips32>>;
|
||||
using SF_TENTHBIPS16 = TypedField<STTypedInteger<TenthBips16>>;
|
||||
using SF_TENTHBIPS32 = TypedField<STTypedInteger<TenthBips32>>;
|
||||
|
||||
using SF_ACCOUNT = TypedField<STAccount>;
|
||||
using SF_AMOUNT = TypedField<STAmount>;
|
||||
@@ -384,23 +385,17 @@ using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
|
||||
#undef UNTYPED_SFIELD
|
||||
#pragma push_macro("TYPED_SFIELD")
|
||||
#undef TYPED_SFIELD
|
||||
#pragma push_macro("INTERPRETED_SFIELD")
|
||||
#undef INTERPRETED_SFIELD
|
||||
|
||||
#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \
|
||||
extern SField const sfName;
|
||||
#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \
|
||||
extern SF_##stiSuffix const sfName;
|
||||
#define INTERPRETED_SFIELD(sfName, stiSuffix, fieldValue, stiInterpreted, ...) \
|
||||
extern SF_##stiInterpreted const sfName;
|
||||
|
||||
extern SField const sfInvalid;
|
||||
extern SField const sfGeneric;
|
||||
|
||||
#include <xrpl/protocol/detail/sfields.macro>
|
||||
|
||||
#undef INTERPRETED_SFIELD
|
||||
#pragma pop_macro("INTERPRETED_SFIELD")
|
||||
#undef TYPED_SFIELD
|
||||
#pragma pop_macro("TYPED_SFIELD")
|
||||
#undef UNTYPED_SFIELD
|
||||
|
||||
@@ -61,6 +61,26 @@ struct STExchange<STInteger<U>, T>
|
||||
}
|
||||
};
|
||||
|
||||
template <class U, class T>
|
||||
struct STExchange<STTypedInteger<U>, T>
|
||||
{
|
||||
explicit STExchange() = default;
|
||||
|
||||
using value_type = U;
|
||||
|
||||
static void
|
||||
get(std::optional<T>& t, STTypedInteger<U> const& u)
|
||||
{
|
||||
t = u.value();
|
||||
}
|
||||
|
||||
static std::unique_ptr<STInteger<U>>
|
||||
set(SField const& f, T const& t)
|
||||
{
|
||||
return std::make_unique<STTypedInteger<U>>(f, t);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct STExchange<STBlob, Slice>
|
||||
{
|
||||
|
||||
@@ -82,12 +82,42 @@ using STUInt16 = STInteger<std::uint16_t>;
|
||||
using STUInt32 = STInteger<std::uint32_t>;
|
||||
using STUInt64 = STInteger<std::uint64_t>;
|
||||
|
||||
// Basis points (bips) values:
|
||||
using SFBips16 = STInteger<Bips16>;
|
||||
using SFBips32 = STInteger<Bips32>;
|
||||
template <class TypedInteger>
|
||||
class STTypedInteger : public STInteger<typename TypedInteger::value_type>,
|
||||
public CountedObject<STTypedInteger<TypedInteger>>
|
||||
{
|
||||
public:
|
||||
using value_type = TypedInteger;
|
||||
using base_value_type = TypedInteger::value_type;
|
||||
using base = STInteger<base_value_type>;
|
||||
|
||||
public:
|
||||
using base::add;
|
||||
using base::getJson;
|
||||
using base::getSType;
|
||||
using base::getText;
|
||||
using base::isDefault;
|
||||
using base::isEquivalent;
|
||||
using base::STInteger;
|
||||
|
||||
SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
STTypedInteger&
|
||||
operator=(value_type const& v);
|
||||
|
||||
value_type
|
||||
value() const noexcept;
|
||||
|
||||
void
|
||||
setValue(TypedInteger v);
|
||||
|
||||
operator TypedInteger() const;
|
||||
};
|
||||
|
||||
// Tenth of a basis point values:
|
||||
using SFTenthBips16 = STInteger<TenthBips16>;
|
||||
using SFTenthBips32 = STInteger<TenthBips32>;
|
||||
using STTenthBips16 = STTypedInteger<TenthBips16>;
|
||||
using STTenthBips32 = STTypedInteger<TenthBips32>;
|
||||
|
||||
template <typename Integer>
|
||||
inline STInteger<Integer>::STInteger(Integer v) : value_(v)
|
||||
@@ -169,6 +199,34 @@ inline STInteger<Integer>::operator Integer() const
|
||||
return value_;
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline STTypedInteger<TypedInteger>&
|
||||
STTypedInteger<TypedInteger>::operator=(value_type const& v)
|
||||
{
|
||||
base::setValue(v.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline typename STTypedInteger<TypedInteger>::value_type
|
||||
STTypedInteger<TypedInteger>::value() const noexcept
|
||||
{
|
||||
return value_type(base::value());
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline void
|
||||
STTypedInteger<TypedInteger>::setValue(TypedInteger v)
|
||||
{
|
||||
base::setValue(v.value());
|
||||
}
|
||||
|
||||
template <typename TypedInteger>
|
||||
inline STTypedInteger<TypedInteger>::operator TypedInteger() const
|
||||
{
|
||||
return TypedInteger(base::value());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -301,6 +301,7 @@ public:
|
||||
}
|
||||
|
||||
/** Returns the number of drops */
|
||||
// TODO: Move this to a new class, maybe with the old "TaggedFee" name
|
||||
constexpr value_type
|
||||
fee() const
|
||||
{
|
||||
|
||||
@@ -61,7 +61,9 @@ TYPED_SFIELD(sfHookEmitCount, UINT16, 18)
|
||||
TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19)
|
||||
TYPED_SFIELD(sfHookApiVersion, UINT16, 20)
|
||||
TYPED_SFIELD(sfLedgerFixType, UINT16, 21)
|
||||
INTERPRETED_SFIELD(sfManagementFeeRate, UINT16, 22, TENTHBIPS16)
|
||||
|
||||
// 16-bit integers represented as 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfManagementFeeRate, TENTHBIPS16, 1)
|
||||
|
||||
// 32-bit integers (common)
|
||||
TYPED_SFIELD(sfNetworkID, UINT32, 1)
|
||||
@@ -123,12 +125,15 @@ TYPED_SFIELD(sfPreviousPaymentDate, UINT32, 55)
|
||||
TYPED_SFIELD(sfNextPaymentDueDate, UINT32, 56)
|
||||
TYPED_SFIELD(sfPaymentRemaining, UINT32, 57)
|
||||
TYPED_SFIELD(sfPaymentTotal, UINT32, 58)
|
||||
INTERPRETED_SFIELD(sfCoverRateMinimum, UINT32, 59, TENTHBIPS32)
|
||||
INTERPRETED_SFIELD(sfCoverRateLiquidation, UINT32, 60, TENTHBIPS32)
|
||||
INTERPRETED_SFIELD(sfInterestRate, UINT32, 61, TENTHBIPS32)
|
||||
INTERPRETED_SFIELD(sfLateInterestRate, UINT32, 62, TENTHBIPS32)
|
||||
INTERPRETED_SFIELD(sfCloseInterestRate, UINT32, 63, TENTHBIPS32)
|
||||
INTERPRETED_SFIELD(sfOverpaymentInterestRate, UINT32, 64, TENTHBIPS32)
|
||||
|
||||
|
||||
// 32-bit integers represented as 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfCoverRateMinimum, TENTHBIPS32, 1)
|
||||
TYPED_SFIELD(sfCoverRateLiquidation, TENTHBIPS32, 2)
|
||||
TYPED_SFIELD(sfInterestRate, TENTHBIPS32, 3)
|
||||
TYPED_SFIELD(sfLateInterestRate, TENTHBIPS32, 4)
|
||||
TYPED_SFIELD(sfCloseInterestRate, TENTHBIPS32, 5)
|
||||
TYPED_SFIELD(sfOverpaymentInterestRate, TENTHBIPS32, 6)
|
||||
|
||||
// 64-bit integers (common)
|
||||
TYPED_SFIELD(sfIndexNext, UINT64, 1)
|
||||
|
||||
@@ -54,8 +54,6 @@ TypedField<T>::TypedField(private_access_tag_t pat, Args&&... args)
|
||||
#undef UNTYPED_SFIELD
|
||||
#pragma push_macro("TYPED_SFIELD")
|
||||
#undef TYPED_SFIELD
|
||||
#pragma push_macro("INTERPRETED_SFIELD")
|
||||
#undef INTERPRETED_SFIELD
|
||||
|
||||
#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \
|
||||
SField const sfName( \
|
||||
@@ -71,13 +69,6 @@ TypedField<T>::TypedField(private_access_tag_t pat, Args&&... args)
|
||||
fieldValue, \
|
||||
std::string_view(#sfName).substr(2).data(), \
|
||||
##__VA_ARGS__);
|
||||
#define INTERPRETED_SFIELD(sfName, stiSuffix, fieldValue, stiInterpreted, ...) \
|
||||
SF_##stiInterpreted const sfName( \
|
||||
access, \
|
||||
STI_##stiSuffix, \
|
||||
fieldValue, \
|
||||
std::string_view(#sfName).substr(2).data(), \
|
||||
##__VA_ARGS__);
|
||||
|
||||
// SFields which, for historical reasons, do not follow naming conventions.
|
||||
SField const sfInvalid(access, -1);
|
||||
@@ -89,8 +80,6 @@ SField const sfIndex(access, STI_UINT256, 258, "index");
|
||||
|
||||
#include <xrpl/protocol/detail/sfields.macro>
|
||||
|
||||
#undef INTERPRETED_SFIELD
|
||||
#pragma pop_macro("INTERPRETED_SFIELD")
|
||||
#undef TYPED_SFIELD
|
||||
#pragma pop_macro("TYPED_SFIELD")
|
||||
#undef UNTYPED_SFIELD
|
||||
|
||||
@@ -229,4 +229,18 @@ STUInt64::getJson(JsonOptions) const
|
||||
return convertToString(value_, 16); // Convert to base 16
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STTenthBips16::getSType() const override
|
||||
{
|
||||
return STI_TENTHBIPS16;
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STTenthBips32::getSType() const override
|
||||
{
|
||||
return STI_TENTHBIPS32;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -190,6 +190,12 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args)
|
||||
case STI_UINT64:
|
||||
construct<STUInt64>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_TENTHBIPS16:
|
||||
construct<STTenthBips16>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_TENTHBIPS32:
|
||||
construct<STTenthBips32>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_AMOUNT:
|
||||
construct<STAmount>(std::forward<Args>(args)...);
|
||||
return;
|
||||
|
||||
@@ -174,20 +174,15 @@ struct valueUnitField
|
||||
using OV = ValueType;
|
||||
using base = JTxField<SF, SV, OV>;
|
||||
|
||||
static_assert(std::is_same_v<SV, typename SField::type::value_type>);
|
||||
static_assert(
|
||||
std::is_same_v<SV, typename SField::type::value_type::value_type>);
|
||||
static_assert(std::is_same_v<
|
||||
OV,
|
||||
typename SField::type::value_type::value_type::value_type>);
|
||||
std::is_same_v<OV, typename SField::type::value_type::value_type>);
|
||||
|
||||
protected:
|
||||
using base::value_;
|
||||
|
||||
public:
|
||||
explicit valueUnitField(SF const& sfield, SV const& value)
|
||||
: JTxField(sfield, value)
|
||||
{
|
||||
}
|
||||
using base::JTxField;
|
||||
|
||||
OV
|
||||
value() const override
|
||||
@@ -675,7 +670,7 @@ auto const coverRateMinimum =
|
||||
valueUnitWrapper<SF_TENTHBIPS32>(sfCoverRateMinimum);
|
||||
|
||||
auto const coverRateLiquidation =
|
||||
simpleField<SF_TENTHBIPS32>(sfCoverRateLiquidation);
|
||||
valueUnitWrapper<SF_TENTHBIPS32>(sfCoverRateLiquidation);
|
||||
|
||||
} // namespace loanBroker
|
||||
|
||||
|
||||
@@ -193,8 +193,8 @@ LoanBrokerSet::doApply()
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
*/
|
||||
|
||||
auto maybePseudo = createPseudoAccount(
|
||||
view, broker->key(), PseudoAccountOwnerType::LoanBroker);
|
||||
auto maybePseudo =
|
||||
createPseudoAccount(view, broker->key(), sfLoanBrokerID);
|
||||
if (!maybePseudo)
|
||||
return maybePseudo.error();
|
||||
auto& pseudo = *maybePseudo;
|
||||
|
||||
Reference in New Issue
Block a user