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