xrpld
Loading...
Searching...
No Matches
DID_test.cpp
1
2#include <test/jtx/Account.h>
3#include <test/jtx/Env.h>
4#include <test/jtx/TestHelpers.h>
5#include <test/jtx/amount.h>
6#include <test/jtx/balance.h> // IWYU pragma: keep
7#include <test/jtx/did.h>
8#include <test/jtx/pay.h>
9#include <test/jtx/ter.h>
10#include <test/jtx/txflags.h>
11
12#include <xrpl/beast/unit_test/suite.h>
13#include <xrpl/protocol/Feature.h>
14#include <xrpl/protocol/Indexes.h>
15#include <xrpl/protocol/SField.h>
16#include <xrpl/protocol/TER.h>
17
18namespace xrpl::test {
19
21{
22 void
24 {
25 testcase("featureDID Enabled");
26
27 using namespace jtx;
28 // If the DID amendment is not enabled, you should not be able
29 // to set or delete DIDs.
30 Env env{*this, features - featureDID};
31 Account const alice{"alice"};
32 env.fund(XRP(5000), alice);
33 env.close();
34
35 BEAST_EXPECT(ownerCount(env, alice) == 0);
36 env(did::setValid(alice), Ter(temDISABLED));
37 env.close();
38
39 BEAST_EXPECT(ownerCount(env, alice) == 0);
40 env(did::del(alice), Ter(temDISABLED));
41 env.close();
42 }
43
44 void
46 {
47 // Verify that the reserve behaves as expected for minting.
48 testcase("DID Account Reserve");
49
50 using namespace test::jtx;
51
52 Env env{*this, features};
53 Account const alice{"alice"};
54
55 // Fund alice enough to exist, but not enough to meet
56 // the reserve for creating a DID.
57 auto const acctReserve = env.current()->fees().reserve;
58 auto const incReserve = env.current()->fees().increment;
59 auto const baseFee = env.current()->fees().base;
60 env.fund(acctReserve, alice);
61 env.close();
62 BEAST_EXPECT(env.balance(alice) == acctReserve);
63 BEAST_EXPECT(ownerCount(env, alice) == 0);
64
65 // alice does not have enough XRP to cover the reserve for a DID
67 env.close();
68 BEAST_EXPECT(ownerCount(env, alice) == 0);
69
70 // Pay alice almost enough to make the reserve for a DID.
71 env(pay(env.master, alice, drops(incReserve + 2 * baseFee - 1)));
72 BEAST_EXPECT(env.balance(alice) == acctReserve + incReserve + drops(baseFee - 1));
73 env.close();
74
75 // alice still does not have enough XRP for the reserve of a DID.
77 env.close();
78 BEAST_EXPECT(ownerCount(env, alice) == 0);
79
80 // Pay alice enough to make the reserve for a DID.
81 env(pay(env.master, alice, drops(baseFee + 1)));
82 env.close();
83
84 // Now alice can create a DID.
85 env(did::setValid(alice));
86 env.close();
87 BEAST_EXPECT(ownerCount(env, alice) == 1);
88
89 // alice deletes her DID.
90 env(did::del(alice));
91 BEAST_EXPECT(ownerCount(env, alice) == 0);
92 env.close();
93 }
94
95 void
97 {
98 testcase("Invalid DIDSet");
99
100 using namespace jtx;
101 using namespace std::chrono;
102
103 Env env{*this, features};
104 Account const alice{"alice"};
105 env.fund(XRP(5000), alice);
106 env.close();
107
108 //----------------------------------------------------------------------
109 // preflight
110
111 // invalid flags
112 BEAST_EXPECT(ownerCount(env, alice) == 0);
113 env(did::setValid(alice), Txflags(0x00010000), Ter(temINVALID_FLAG));
114 env.close();
115 BEAST_EXPECT(ownerCount(env, alice) == 0);
116
117 // no fields
118 env(did::set(alice), Ter(temEMPTY_DID));
119 env.close();
120 BEAST_EXPECT(ownerCount(env, alice) == 0);
121
122 // all empty fields
123 env(did::set(alice), did::Uri(""), did::Document(""), did::Data(""), Ter(temEMPTY_DID));
124 env.close();
125 BEAST_EXPECT(ownerCount(env, alice) == 0);
126
127 // uri is too long
128 std::string const longString(257, 'a');
129 env(did::set(alice), did::Uri(longString), Ter(temMALFORMED));
130 env.close();
131 BEAST_EXPECT(ownerCount(env, alice) == 0);
132
133 // document is too long
134 env(did::set(alice), did::Document(longString), Ter(temMALFORMED));
135 env.close();
136 BEAST_EXPECT(ownerCount(env, alice) == 0);
137
138 // attestation is too long
139 env(did::set(alice), did::Document("data"), did::Data(longString), Ter(temMALFORMED));
140 env.close();
141 BEAST_EXPECT(ownerCount(env, alice) == 0);
142
143 // some empty fields, some optional fields
144 // pre-fix amendment
145 auto const fixEnabled = env.current()->rules().enabled(fixEmptyDID);
146 env(did::set(alice), did::Uri(""), fixEnabled ? Ter(tecEMPTY_DID) : Ter(tesSUCCESS));
147 env.close();
148 auto const expectedOwnerReserve = fixEnabled ? 0 : 1;
149 BEAST_EXPECT(ownerCount(env, alice) == expectedOwnerReserve);
150
151 // Modifying a DID to become empty is checked in testSetModify
152 }
153
154 void
156 {
157 testcase("Invalid DIDDelete");
158
159 using namespace jtx;
160 using namespace std::chrono;
161
162 Env env{*this, features};
163 Account const alice{"alice"};
164 env.fund(XRP(5000), alice);
165 env.close();
166
167 //----------------------------------------------------------------------
168 // preflight
169
170 // invalid flags
171 BEAST_EXPECT(ownerCount(env, alice) == 0);
172 env(did::del(alice), Txflags(0x00010000), Ter(temINVALID_FLAG));
173 env.close();
174 BEAST_EXPECT(ownerCount(env, alice) == 0);
175
176 //----------------------------------------------------------------------
177 // doApply
178
179 // DID doesn't exist
180 env(did::del(alice), Ter(tecNO_ENTRY));
181 env.close();
182 BEAST_EXPECT(ownerCount(env, alice) == 0);
183 }
184
185 void
187 {
188 testcase("Valid Initial DIDSet");
189
190 using namespace jtx;
191 using namespace std::chrono;
192
193 Env env{*this, features};
194 Account const alice{"alice"};
195 Account const bob{"bob"};
196 Account const charlie{"charlie"};
197 Account const dave{"dave"};
198 Account const edna{"edna"};
199 Account const francis{"francis"};
200 Account const george{"george"};
201 env.fund(XRP(5000), alice, bob, charlie, dave, edna, francis, george);
202 env.close();
203 BEAST_EXPECT(ownerCount(env, alice) == 0);
204 BEAST_EXPECT(ownerCount(env, bob) == 0);
205 BEAST_EXPECT(ownerCount(env, charlie) == 0);
206
207 // only URI
208 env(did::set(alice), did::Uri("uri"));
209 BEAST_EXPECT(ownerCount(env, alice) == 1);
210
211 // only DIDDocument
212 env(did::set(bob), did::Document("data"));
213 BEAST_EXPECT(ownerCount(env, bob) == 1);
214
215 // only Data
216 env(did::set(charlie), did::Data("data"));
217 BEAST_EXPECT(ownerCount(env, charlie) == 1);
218
219 // URI + Data
220 env(did::set(dave), did::Uri("uri"), did::Data("attest"));
221 BEAST_EXPECT(ownerCount(env, dave) == 1);
222
223 // URI + DIDDocument
224 env(did::set(edna), did::Uri("uri"), did::Document("data"));
225 BEAST_EXPECT(ownerCount(env, edna) == 1);
226
227 // DIDDocument + Data
228 env(did::set(francis), did::Document("data"), did::Data("attest"));
229 BEAST_EXPECT(ownerCount(env, francis) == 1);
230
231 // URI + DIDDocument + Data
232 env(did::set(george), did::Uri("uri"), did::Document("data"), did::Data("attest"));
233 BEAST_EXPECT(ownerCount(env, george) == 1);
234 }
235
236 void
238 {
239 testcase("Modify DID with DIDSet");
240
241 using namespace jtx;
242 using namespace std::chrono;
243
244 Env env{*this, features};
245 Account const alice{"alice"};
246 env.fund(XRP(5000), alice);
247 env.close();
248 BEAST_EXPECT(ownerCount(env, alice) == 0);
249 auto const ar = env.le(alice);
250
251 // Create DID
252 std::string const initialURI = "uri";
253 {
254 env(did::set(alice), did::Uri(initialURI));
255 BEAST_EXPECT(ownerCount(env, alice) == 1);
256 auto const sleDID = env.le(keylet::did(alice.id()));
257 BEAST_EXPECT(sleDID);
258 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
259 BEAST_EXPECT(!sleDID->isFieldPresent(sfDIDDocument));
260 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
261 }
262
263 // Try to delete URI, fails because no elements are set
264 {
265 env(did::set(alice), did::Uri(""), Ter(tecEMPTY_DID));
266 BEAST_EXPECT(ownerCount(env, alice) == 1);
267 auto const sleDID = env.le(keylet::did(alice.id()));
268 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
269 BEAST_EXPECT(!sleDID->isFieldPresent(sfDIDDocument));
270 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
271 }
272
273 // Set DIDDocument
274 std::string const initialDocument = "data";
275 {
276 env(did::set(alice), did::Document(initialDocument));
277 BEAST_EXPECT(ownerCount(env, alice) == 1);
278 auto const sleDID = env.le(keylet::did(alice.id()));
279 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
280 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
281 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
282 }
283
284 // Set Data
285 std::string const initialData = "attest";
286 {
287 env(did::set(alice), did::Data(initialData));
288 BEAST_EXPECT(ownerCount(env, alice) == 1);
289 auto const sleDID = env.le(keylet::did(alice.id()));
290 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
291 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
292 BEAST_EXPECT(checkVL((*sleDID)[sfData], initialData));
293 }
294
295 // Remove URI
296 {
297 env(did::set(alice), did::Uri(""));
298 BEAST_EXPECT(ownerCount(env, alice) == 1);
299 auto const sleDID = env.le(keylet::did(alice.id()));
300 BEAST_EXPECT(!sleDID->isFieldPresent(sfURI));
301 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
302 BEAST_EXPECT(checkVL((*sleDID)[sfData], initialData));
303 }
304
305 // Remove Data
306 {
307 env(did::set(alice), did::Data(""));
308 BEAST_EXPECT(ownerCount(env, alice) == 1);
309 auto const sleDID = env.le(keylet::did(alice.id()));
310 BEAST_EXPECT(!sleDID->isFieldPresent(sfURI));
311 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
312 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
313 }
314
315 // Remove Data + set URI
316 std::string const secondURI = "uri2";
317 {
318 env(did::set(alice), did::Uri(secondURI), did::Document(""));
319 BEAST_EXPECT(ownerCount(env, alice) == 1);
320 auto const sleDID = env.le(keylet::did(alice.id()));
321 BEAST_EXPECT(checkVL((*sleDID)[sfURI], secondURI));
322 BEAST_EXPECT(!sleDID->isFieldPresent(sfDIDDocument));
323 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
324 }
325
326 // Remove URI + set DIDDocument
327 std::string const secondDocument = "data2";
328 {
329 env(did::set(alice), did::Uri(""), did::Document(secondDocument));
330 BEAST_EXPECT(ownerCount(env, alice) == 1);
331 auto const sleDID = env.le(keylet::did(alice.id()));
332 BEAST_EXPECT(!sleDID->isFieldPresent(sfURI));
333 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], secondDocument));
334 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
335 }
336
337 // Remove DIDDocument + set Data
338 std::string const secondData = "randomData";
339 {
340 env(did::set(alice), did::Document(""), did::Data(secondData));
341 BEAST_EXPECT(ownerCount(env, alice) == 1);
342 auto const sleDID = env.le(keylet::did(alice.id()));
343 BEAST_EXPECT(!sleDID->isFieldPresent(sfURI));
344 BEAST_EXPECT(!sleDID->isFieldPresent(sfDIDDocument));
345 BEAST_EXPECT(checkVL((*sleDID)[sfData], secondData));
346 }
347
348 // Delete DID
349 {
350 env(did::del(alice));
351 BEAST_EXPECT(ownerCount(env, alice) == 0);
352 auto const sleDID = env.le(keylet::did(alice.id()));
353 BEAST_EXPECT(!sleDID);
354 }
355 }
356
357 void
358 run() override
359 {
360 using namespace test::jtx;
362 FeatureBitset const emptyDID{fixEmptyDID};
363 testEnabled(all);
365 testSetInvalid(all);
368 testSetModify(all);
369
370 testEnabled(all - emptyDID);
371 testAccountReserve(all - emptyDID);
372 testSetInvalid(all - emptyDID);
373 testDeleteInvalid(all - emptyDID);
374 testSetValidInitial(all - emptyDID);
375 testSetModify(all - emptyDID);
376 }
377};
378
380
381} // namespace xrpl::test
A testsuite class.
Definition suite.h:50
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Immutable cryptographic account descriptor.
Definition jtx/Account.h:17
AccountID id() const
Returns the Account ID.
Definition jtx/Account.h:85
A transaction testing environment.
Definition Env.h:143
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:133
SLE::const_pointer le(Account const &account) const
Return an account root.
Definition Env.cpp:284
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:296
Account const & master
Definition Env.h:147
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition Env.cpp:201
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:353
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:13
Set the flags on a JTx.
Definition txflags.h:9
Sets the optional Data on a DIDSet.
Definition did.h:54
Sets the optional DIDDocument on a DIDSet.
Definition did.h:18
Sets the optional URI on a DIDSet.
Definition did.h:36
Keylet did(AccountID const &account) noexcept
Definition Indexes.cpp:509
json::Value setValid(jtx::Account const &account)
Definition dids.cpp:23
json::Value set(jtx::Account const &account)
Definition dids.cpp:14
json::Value del(jtx::Account const &account)
Definition dids.cpp:33
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:14
XrpT const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
std::uint32_t ownerCount(Env const &env, Account const &account)
FeatureBitset testableAmendments()
Definition Env.h:76
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
bool checkVL(Slice const &result, std::string const &expected)
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ temINVALID_FLAG
Definition TER.h:97
@ temEMPTY_DID
Definition TER.h:124
@ temMALFORMED
Definition TER.h:73
@ temDISABLED
Definition TER.h:100
@ tecNO_ENTRY
Definition TER.h:304
@ tecEMPTY_DID
Definition TER.h:351
@ tecINSUFFICIENT_RESERVE
Definition TER.h:305
@ tesSUCCESS
Definition TER.h:240
void testSetValidInitial(FeatureBitset features)
Definition DID_test.cpp:186
void testDeleteInvalid(FeatureBitset features)
Definition DID_test.cpp:155
void testEnabled(FeatureBitset features)
Definition DID_test.cpp:23
void testAccountReserve(FeatureBitset features)
Definition DID_test.cpp:45
void run() override
Runs the suite.
Definition DID_test.cpp:358
void testSetModify(FeatureBitset features)
Definition DID_test.cpp:237
void testSetInvalid(FeatureBitset features)
Definition DID_test.cpp:96