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