diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 7164cd46e4e..f0d0c8efbb5 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -74,7 +74,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 49; +static constexpr std::size_t numFeatures = 50; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -337,6 +337,7 @@ extern uint256 const featureNonFungibleTokensV1; extern uint256 const featureExpandedSignerList; extern uint256 const fixNFTokenDirV1; extern uint256 const fixNFTokenNegOffer; +extern uint256 const featureNonFungibleTokensV1_1; } // namespace ripple diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 1fcca56e884..4060067e30a 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -441,6 +441,7 @@ REGISTER_FEATURE(NonFungibleTokensV1, Supported::yes, DefaultVote::no) REGISTER_FEATURE(ExpandedSignerList, Supported::yes, DefaultVote::no); REGISTER_FIX (fixNFTokenDirV1, Supported::yes, DefaultVote::no); REGISTER_FIX (fixNFTokenNegOffer, Supported::yes, DefaultVote::no); +REGISTER_FEATURE(NonFungibleTokensV1_1, Supported::yes, DefaultVote::no); // The following amendments have been active for at least two years. Their // pre-amendment code has been removed and the identifiers are deprecated. diff --git a/src/ripple/protocol/impl/Rules.cpp b/src/ripple/protocol/impl/Rules.cpp index 3736764fcf9..baea81d6c99 100644 --- a/src/ripple/protocol/impl/Rules.cpp +++ b/src/ripple/protocol/impl/Rules.cpp @@ -17,10 +17,9 @@ */ //============================================================================== +#include #include -#include - namespace ripple { class Rules::Impl @@ -40,9 +39,8 @@ class Rules::Impl std::unordered_set> const& presets, std::optional const& digest, STVector256 const& amendments) - : presets_(presets) + : presets_(presets), digest_(digest) { - digest_ = digest; set_.reserve(amendments.size()); set_.insert(amendments.begin(), amendments.end()); } @@ -83,6 +81,18 @@ bool Rules::enabled(uint256 const& feature) const { assert(impl_); + + // The functionality of the "NonFungibleTokensV1_1" amendment is + // precisely the functionality of the following three amendments + // so if their status is ever queried individually, we inject an + // extra check here to simplify the checking elsewhere. + if (feature == featureNonFungibleTokensV1 || + feature == fixNFTokenNegOffer || feature == fixNFTokenDirV1) + { + if (impl_->enabled(featureNonFungibleTokensV1_1)) + return true; + } + return impl_->enabled(feature); } diff --git a/src/test/app/NFTokenDir_test.cpp b/src/test/app/NFTokenDir_test.cpp index 8f8d0f581f0..d50bd1584d6 100644 --- a/src/test/app/NFTokenDir_test.cpp +++ b/src/test/app/NFTokenDir_test.cpp @@ -1075,7 +1075,8 @@ class NFTokenDir_test : public beast::unit_test::suite { using namespace test::jtx; FeatureBitset const all{supported_amendments()}; - FeatureBitset const fixNFTDir{fixNFTokenDirV1}; + FeatureBitset const fixNFTDir{ + fixNFTokenDirV1, featureNonFungibleTokensV1_1}; testWithFeats(all - fixNFTDir); testWithFeats(all); diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 5a25b3670b8..2db31afe0db 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -96,7 +96,10 @@ class NFToken_test : public beast::unit_test::suite { // If the NFT amendment is not enabled, you should not be able // to create or burn NFTs. - Env env{*this, features - featureNonFungibleTokensV1}; + Env env{ + *this, + features - featureNonFungibleTokensV1 - + featureNonFungibleTokensV1_1}; Account const& master = env.master; BEAST_EXPECT(ownerCount(env, master) == 0); @@ -4650,7 +4653,8 @@ class NFToken_test : public beast::unit_test::suite // Test both with and without fixNFTokenNegOffer for (auto const& tweakedFeatures : - {features - fixNFTokenNegOffer, features | fixNFTokenNegOffer}) + {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1, + features | fixNFTokenNegOffer}) { // There was a bug in the initial NFT implementation that // allowed offers to be placed with negative amounts. Verify @@ -4759,7 +4763,9 @@ class NFToken_test : public beast::unit_test::suite // Test what happens if NFTokenOffers are created with negative amounts // and then fixNFTokenNegOffer goes live. What does an acceptOffer do? { - Env env{*this, features - fixNFTokenNegOffer}; + Env env{ + *this, + features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1}; env.fund(XRP(1000000), issuer, buyer, gw); env.close(); @@ -4844,7 +4850,8 @@ class NFToken_test : public beast::unit_test::suite // Test buy offers with a destination with and without // fixNFTokenNegOffer. for (auto const& tweakedFeatures : - {features - fixNFTokenNegOffer, features | fixNFTokenNegOffer}) + {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1, + features | fixNFTokenNegOffer}) { Env env{*this, tweakedFeatures};