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