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