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>
175 std::map<std::string, AmendmentSupport>
const&
186 std::map<std::string, VoteBehavior>
const&
213FeatureCollections::FeatureCollections()
218std::optional<uint256>
219FeatureCollections::getRegisteredFeature(std::string
const& name)
const
222 readOnly_.
load(),
"xrpl::FeatureCollections::getRegisteredFeature : startup completed");
223 Feature
const* feature = getByName(name);
224 if (feature !=
nullptr)
225 return feature->feature;
230check(
bool condition,
char const* logicErrorMessage)
237FeatureCollections::registerFeature(std::string
const& name, Supported support,
VoteBehavior vote)
239 check(!readOnly_,
"Attempting to register a feature after startup.");
241 support == Supported::Yes || vote == VoteBehavior::DefaultNo,
242 "Invalid feature parameters. Must be supported to be up-voted.");
243 Feature
const* i = getByName(name);
246 check(features_.size() < detail::kNumFeatures,
"More features defined than allocated.");
250 features_.emplace_back(name, f);
252 auto const getAmendmentSupport = [=]() {
253 if (vote == VoteBehavior::Obsolete)
254 return AmendmentSupport::Retired;
255 return support == Supported::Yes ? AmendmentSupport::Supported
256 : AmendmentSupport::Unsupported;
258 all_.
emplace(name, getAmendmentSupport());
260 if (support == Supported::Yes)
262 supported_.
emplace(name, vote);
264 if (vote == VoteBehavior::DefaultYes)
273 check(upVotes_ + downVotes_ == supported_.
size(),
"Feature counting logic broke");
275 supported_.
size() <= features_.size(),
"More supported features than defined features");
276 check(features_.size() == all_.
size(),
"The 'all' features list is populated incorrectly");
288FeatureCollections::registrationIsDone()
295FeatureCollections::featureToBitsetIndex(
uint256 const& f)
const
298 readOnly_.
load(),
"xrpl::FeatureCollections::featureToBitsetIndex : startup completed");
300 Feature
const* feature = getByFeature(f);
301 if (feature ==
nullptr)
304 return getIndex(*feature);
308FeatureCollections::bitsetIndexToFeature(
size_t i)
const
311 readOnly_.
load(),
"xrpl::FeatureCollections::bitsetIndexToFeature : startup completed");
312 Feature
const& feature = getByIndex(i);
313 return feature.feature;
317FeatureCollections::featureToName(
uint256 const& f)
const
319 XRPL_ASSERT(readOnly_.
load(),
"xrpl::FeatureCollections::featureToName : startup completed");
320 Feature
const* feature = getByFeature(f);
321 return (feature !=
nullptr) ? feature->name :
to_string(f);
324FeatureCollections gFeatureCollections;
331std::map<std::string, AmendmentSupport>
const&
334 return gFeatureCollections.allAmendments();
345 return gFeatureCollections.supportedAmendments();
354 return gFeatureCollections.numDownVotedAmendments();
363 return gFeatureCollections.numUpVotedAmendments();
371 return gFeatureCollections.getRegisteredFeature(name);
377 return gFeatureCollections.registerFeature(name, support, vote);
394 return gFeatureCollections.registrationIsDone();
400 return gFeatureCollections.featureToBitsetIndex(f);
406 return gFeatureCollections.bitsetIndexToFeature(i);
412 return gFeatureCollections.featureToName(f);
418#pragma push_macro("XRPL_FEATURE")
420#pragma push_macro("XRPL_FIX")
422#pragma push_macro("XRPL_RETIRE_FEATURE")
423#undef XRPL_RETIRE_FEATURE
424#pragma push_macro("XRPL_RETIRE_FIX")
425#undef XRPL_RETIRE_FIX
435#define XRPL_FEATURE(name, supported, vote) \
436 uint256 const feature##name = \
437 registerFeature(enforceValidFeatureName([] { return #name; }), supported, vote);
438#define XRPL_FIX(name, supported, vote) \
439 uint256 const fix##name = \
440 registerFeature(enforceValidFeatureName([] { return "fix" #name; }), supported, vote);
443#define XRPL_RETIRE_FEATURE(name) \
444 [[deprecated("The referenced feature amendment has been retired")]] \
446 uint256 const retiredFeature##name = retireFeature(#name);
448#define XRPL_RETIRE_FIX(name) \
449 [[deprecated("The referenced fix amendment has been retired")]] \
451 uint256 const retiredFix##name = retireFeature("fix" #name);
454#include <xrpl/protocol/detail/features.macro>
458#undef XRPL_RETIRE_FEATURE
459#pragma pop_macro("XRPL_RETIRE_FEATURE")
460#undef XRPL_RETIRE_FIX
461#pragma pop_macro("XRPL_RETIRE_FIX")
463#pragma pop_macro("XRPL_FIX")
465#pragma pop_macro("XRPL_FEATURE")
471[[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.
@ Yes
We have consensus along with the network.
@ No
We do not have consensus.
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)