diff --git a/src/ripple/app/tx/impl/DID.cpp b/src/ripple/app/tx/impl/DID.cpp index c92162c83..1cad8992a 100644 --- a/src/ripple/app/tx/impl/DID.cpp +++ b/src/ripple/app/tx/impl/DID.cpp @@ -161,6 +161,13 @@ DIDSet::doApply() set(sfURI); set(sfDIDDocument); set(sfData); + if (ctx_.view().rules().enabled(fixEmptyDID) && + !sleDID->isFieldPresent(sfURI) && + !sleDID->isFieldPresent(sfDIDDocument) && + !sleDID->isFieldPresent(sfData)) + { + return tecEMPTY_DID; + } return addSLE(ctx_, sleDID, account_); } diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index fb30f23cb..3fbc88e65 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 = 102; +static constexpr std::size_t numFeatures = 103; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -390,6 +390,7 @@ extern uint256 const fixNFTokenReserve; extern uint256 const fixInnerObjTemplate; extern uint256 const fixAMMOverflowOffer; extern uint256 const featurePriceOracle; +extern uint256 const fixEmptyDID; } // namespace ripple diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 2c8b0fcfc..283a622fe 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -491,11 +491,12 @@ REGISTER_FEATURE(AMM, Supported::yes, VoteBehavior::De REGISTER_FEATURE(XChainBridge, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixDisallowIncomingV1, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FEATURE(DID, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX(fixFillOrKill, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FIX (fixFillOrKill, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixNFTokenReserve, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixInnerObjTemplate, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixAMMOverflowOffer, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FEATURE(PriceOracle, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FIX (fixEmptyDID, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/test/app/DID_test.cpp b/src/test/app/DID_test.cpp index ea79d90b6..43435b6ff 100644 --- a/src/test/app/DID_test.cpp +++ b/src/test/app/DID_test.cpp @@ -122,7 +122,7 @@ struct DID_test : public beast::unit_test::suite using namespace jtx; using namespace std::chrono; - Env env(*this); + Env env{*this, features}; Account const alice{"alice"}; env.fund(XRP(5000), alice); env.close(); @@ -169,6 +169,16 @@ struct DID_test : public beast::unit_test::suite env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); + // some empty fields, some optional fields + // pre-fix amendment + auto const fixEnabled = env.current()->rules().enabled(fixEmptyDID); + env(did::set(alice), + did::uri(""), + fixEnabled ? ter(tecEMPTY_DID) : ter(tesSUCCESS)); + env.close(); + auto const expectedOwnerReserve = fixEnabled ? 0 : 1; + BEAST_EXPECT(ownerCount(env, alice) == expectedOwnerReserve); + // Modifying a DID to become empty is checked in testSetModify } @@ -180,7 +190,7 @@ struct DID_test : public beast::unit_test::suite using namespace jtx; using namespace std::chrono; - Env env(*this); + Env env{*this, features}; Account const alice{"alice"}; env.fund(XRP(5000), alice); env.close(); @@ -211,7 +221,7 @@ struct DID_test : public beast::unit_test::suite using namespace jtx; using namespace std::chrono; - Env env(*this); + Env env{*this, features}; Account const alice{"alice"}; Account const bob{"bob"}; Account const charlie{"charlie"}; @@ -265,7 +275,7 @@ struct DID_test : public beast::unit_test::suite using namespace jtx; using namespace std::chrono; - Env env(*this); + Env env{*this, features}; Account const alice{"alice"}; env.fund(XRP(5000), alice); env.close(); @@ -382,13 +392,19 @@ struct DID_test : public beast::unit_test::suite run() override { using namespace test::jtx; - FeatureBitset const all{ - supported_amendments() | FeatureBitset{featureDID}}; + FeatureBitset const all{supported_amendments()}; + FeatureBitset const emptyDID{fixEmptyDID}; testEnabled(all); testAccountReserve(all); testSetInvalid(all); testDeleteInvalid(all); testSetModify(all); + + testEnabled(all - emptyDID); + testAccountReserve(all - emptyDID); + testSetInvalid(all - emptyDID); + testDeleteInvalid(all - emptyDID); + testSetModify(all - emptyDID); } };