1#include <xrpl/protocol/Feature.h>
3#include <xrpl/basics/Slice.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/protocol/digest.h>
9#include <boost/container_hash/hash.hpp>
10#include <boost/multi_index/hashed_index.hpp>
11#include <boost/multi_index/indexed_by.hpp>
12#include <boost/multi_index/member.hpp>
13#include <boost/multi_index/random_access_index.hpp>
14#include <boost/multi_index/tag.hpp>
15#include <boost/multi_index_container.hpp>
30 using namespace boost;
31 for (
auto const& n : feature)
32 hash_combine(seed, n);
67class FeatureCollections
75 explicit Feature(std::string name,
uint256 const& feature)
76 : name(std::
move(name)), feature(feature)
95 template <
class Tag,
typename Type, Type Feature::* PtrToMember>
96 using feature_hashed_unique = boost::multi_index::hashed_unique<
97 boost::multi_index::tag<Tag>,
98 boost::multi_index::member<Feature, Type, PtrToMember>>;
101 using feature_indexing = boost::multi_index::indexed_by<
102 boost::multi_index::random_access<boost::multi_index::tag<Feature::ByIndex>>,
103 feature_hashed_unique<Feature::ByFeature, uint256, &Feature::feature>,
104 feature_hashed_unique<Feature::ByName, std::string, &Feature::name>>;
108 boost::multi_index::multi_index_container<Feature, feature_indexing> features_;
109 std::map<std::string, AmendmentSupport> all_;
110 std::map<std::string, VoteBehavior> supported_;
111 std::size_t upVotes_ = 0;
112 std::size_t downVotes_ = 0;
113 mutable std::atomic<bool> readOnly_ =
false;
119 getByIndex(
size_t i)
const
121 if (i >= features_.size())
123 auto const& sequence = features_.get<Feature::ByIndex>();
127 getIndex(Feature
const& feature)
const
129 auto const& sequence = features_.get<Feature::ByIndex>();
130 auto const itTo = sequence.iterator_to(feature);
131 return itTo - sequence.begin();
134 getByFeature(
uint256 const& feature)
const
136 auto const& featureIndex = features_.get<Feature::ByFeature>();
137 auto const featureIt = featureIndex.find(feature);
138 return featureIt == featureIndex.end() ? nullptr : &*featureIt;
141 getByName(std::string
const& name)
const
143 auto const& nameIndex = features_.get<Feature::ByName>();
144 auto const nameIt = nameIndex.find(name);
145 return nameIt == nameIndex.end() ? nullptr : &*nameIt;
149 FeatureCollections();
151 std::optional<uint256>
171 std::map<std::string, AmendmentSupport>
const&
180 std::map<std::string, VoteBehavior>
const&
203FeatureCollections::FeatureCollections()
208std::optional<uint256>
209FeatureCollections::getRegisteredFeature(std::string
const& name)
const
212 readOnly_.
load(),
"xrpl::FeatureCollections::getRegisteredFeature : startup completed");
213 Feature
const* feature = getByName(name);
214 if (feature !=
nullptr)
215 return feature->feature;
220check(
bool condition,
char const* logicErrorMessage)
227FeatureCollections::registerFeature(std::string
const& name, Supported support,
VoteBehavior vote)
229 check(!readOnly_,
"Attempting to register a feature after startup.");
231 support == Supported::Yes || vote == VoteBehavior::DefaultNo,
232 "Invalid feature parameters. Must be supported to be up-voted.");
233 Feature
const* i = getByName(name);
236 check(features_.size() < detail::kNumFeatures,
"More features defined than allocated.");
240 features_.emplace_back(name, f);
242 auto const getAmendmentSupport = [=]() {
243 if (vote == VoteBehavior::Obsolete)
244 return AmendmentSupport::Retired;
245 return support == Supported::Yes ? AmendmentSupport::Supported
246 : AmendmentSupport::Unsupported;
248 all_.
emplace(name, getAmendmentSupport());
250 if (support == Supported::Yes)
252 supported_.
emplace(name, vote);
254 if (vote == VoteBehavior::DefaultYes)
263 check(upVotes_ + downVotes_ == supported_.
size(),
"Feature counting logic broke");
265 supported_.
size() <= features_.size(),
"More supported features than defined features");
266 check(features_.size() == all_.
size(),
"The 'all' features list is populated incorrectly");
276FeatureCollections::registrationIsDone()
283FeatureCollections::featureToBitsetIndex(
uint256 const& f)
const
286 readOnly_.
load(),
"xrpl::FeatureCollections::featureToBitsetIndex : startup completed");
288 Feature
const* feature = getByFeature(f);
289 if (feature ==
nullptr)
292 return getIndex(*feature);
296FeatureCollections::bitsetIndexToFeature(
size_t i)
const
299 readOnly_.
load(),
"xrpl::FeatureCollections::bitsetIndexToFeature : startup completed");
300 Feature
const& feature = getByIndex(i);
301 return feature.feature;
305FeatureCollections::featureToName(
uint256 const& f)
const
307 XRPL_ASSERT(readOnly_.
load(),
"xrpl::FeatureCollections::featureToName : startup completed");
308 Feature
const* feature = getByFeature(f);
309 return (feature !=
nullptr) ? feature->name :
to_string(f);
312FeatureCollections gFeatureCollections;
317std::map<std::string, AmendmentSupport>
const&
320 return gFeatureCollections.allAmendments();
329 return gFeatureCollections.supportedAmendments();
336 return gFeatureCollections.numDownVotedAmendments();
343 return gFeatureCollections.numUpVotedAmendments();
351 return gFeatureCollections.getRegisteredFeature(name);
357 return gFeatureCollections.registerFeature(name, support, vote);
372 return gFeatureCollections.registrationIsDone();
378 return gFeatureCollections.featureToBitsetIndex(f);
384 return gFeatureCollections.bitsetIndexToFeature(i);
390 return gFeatureCollections.featureToName(f);
396#pragma push_macro("XRPL_FEATURE")
398#pragma push_macro("XRPL_FIX")
400#pragma push_macro("XRPL_RETIRE_FEATURE")
401#undef XRPL_RETIRE_FEATURE
402#pragma push_macro("XRPL_RETIRE_FIX")
403#undef XRPL_RETIRE_FIX
413#define XRPL_FEATURE(name, supported, vote) \
414 uint256 const feature##name = \
415 registerFeature(enforceValidFeatureName([] { return #name; }), supported, vote);
416#define XRPL_FIX(name, supported, vote) \
417 uint256 const fix##name = \
418 registerFeature(enforceValidFeatureName([] { return "fix" #name; }), supported, vote);
421#define XRPL_RETIRE_FEATURE(name) \
422 [[deprecated("The referenced feature amendment has been retired")]] \
424 uint256 const retiredFeature##name = retireFeature(#name);
426#define XRPL_RETIRE_FIX(name) \
427 [[deprecated("The referenced fix amendment has been retired")]] \
429 uint256 const retiredFix##name = retireFeature("fix" #name);
432#include <xrpl/protocol/detail/features.macro>
436#undef XRPL_RETIRE_FEATURE
437#pragma pop_macro("XRPL_RETIRE_FEATURE")
438#undef XRPL_RETIRE_FIX
439#pragma pop_macro("XRPL_RETIRE_FIX")
441#pragma pop_macro("XRPL_FIX")
443#pragma pop_macro("XRPL_FEATURE")
449[[maybe_unused]]
static bool const kReadOnlySet = gFeatureCollections.registrationIsDone();
void check(bool condition, std::string const &message)
std::size_t numDownVotedAmendments()
Amendments that this server won't vote for by default.
std::map< std::string, VoteBehavior > const & supportedAmendments()
Amendments that this server supports and the default voting behavior.
static constexpr std::size_t kNumFeatures
std::size_t numUpVotedAmendments()
Amendments that this server will vote for by default.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
uint256 registerFeature(std::string const &name, Supported support, VoteBehavior vote)
consteval auto validFeatureNameSize(auto fn) -> bool
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
uint256 retireFeature(std::string const &name)
static bool const kReadOnlySet
size_t featureToBitsetIndex(uint256 const &f)
bool registrationIsDone()
Tell FeatureCollections when registration is complete.
void logicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
consteval auto enforceValidFeatureName(auto fn) -> char const *
std::map< std::string, AmendmentSupport > const & allAmendments()
All amendments libxrpl knows about.
std::string featureToName(uint256 const &f)
uint256 bitsetIndexToFeature(size_t i)
consteval auto validFeatureName(auto fn) -> bool
std::optional< uint256 > getRegisteredFeature(std::string const &name)
std::size_t hash_value(xrpl::uint256 const &feature)