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