#include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { namespace { // Use a static inside a function to help prevent order-of-initialization issues LocalValue>& getCurrentTransactionRulesRef() { static LocalValue> kR; return kR; } } // namespace std::optional const& getCurrentTransactionRules() { return *getCurrentTransactionRulesRef(); } void setCurrentTransactionRules(std::optional r) { // Make global changes associated with the rules before the value is moved. // Push the appropriate setting, instead of having the class pull every time // the value is needed. That could get expensive fast. // The improved accuracy that will come from enabling large // mantissas is a goal separate from SAV and LP. It was originally // only tied to those two amendments to avoid needing a new // amendment of it's own, and because they require that behavior. // Because fixCleanup3_2_0 fixes a separate bug related to the large // mantissas, that can take precedence and activate the large // mantissas even in the absence of the other two amendments. bool const enableCuspRoundingFix = !r || r->enabled(fixCleanup3_2_0); bool const enableVaultNumbers = enableCuspRoundingFix || (r->enabled(featureSingleAssetVault) || r->enabled(featureLendingProtocol)); Number::setMantissaScale( enableCuspRoundingFix ? MantissaRange::MantissaScale::Large : enableVaultNumbers ? MantissaRange::MantissaScale::LargeLegacy : MantissaRange::MantissaScale::Small); *getCurrentTransactionRulesRef() = std::move(r); } class Rules::Impl { private: std::unordered_set> set_; std::optional digest_; std::unordered_set> const& presets_; public: explicit Impl(std::unordered_set> const& presets) : presets_(presets) { } Impl( std::unordered_set> const& presets, std::optional const& digest, STVector256 const& amendments) : digest_(digest), presets_(presets) { set_.reserve(amendments.size()); set_.insert(amendments.begin(), amendments.end()); } [[nodiscard]] std::unordered_set> const& presets() const { return presets_; } [[nodiscard]] bool enabled(uint256 const& feature) const { if (presets_.contains(feature)) return true; return set_.contains(feature); } bool operator==(Impl const& other) const { if (!digest_ && !other.digest_) return true; if (!digest_ || !other.digest_) return false; XRPL_ASSERT( presets_ == other.presets_, "xrpl::Rules::Impl::operator==(Impl) const : input presets do " "match"); return *digest_ == *other.digest_; } }; Rules::Rules(std::unordered_set> const& presets) : impl_(std::make_shared(presets)) { } Rules::Rules( std::unordered_set> const& presets, std::optional const& digest, STVector256 const& amendments) : impl_(std::make_shared(presets, digest, amendments)) { } std::unordered_set> const& Rules::presets() const { return impl_->presets(); } bool Rules::enabled(uint256 const& feature) const { XRPL_ASSERT(impl_, "xrpl::Rules::enabled : initialized"); return impl_->enabled(feature); } bool Rules::operator==(Rules const& other) const { XRPL_ASSERT(impl_ && other.impl_, "xrpl::Rules::operator==(Rules) const : both initialized"); if (impl_.get() == other.impl_.get()) return true; return *impl_ == *other.impl_; } bool Rules::operator!=(Rules const& other) const { return !(*this == other); } bool isFeatureEnabled(uint256 const& feature, bool resultIfNoRules) { auto const& rules = getCurrentTransactionRules(); if (!rules) return resultIfNoRules; return rules->enabled(feature); } bool isFeatureEnabled(uint256 const& feature) { return isFeatureEnabled(feature, false); } } // namespace xrpl