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 xrpl {
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(env.balance(alice) == acctReserve + incReserve + drops(baseFee - 1));
64 env.close();
65
66 // alice still does not have enough XRP for the reserve of a DID.
68 env.close();
69 BEAST_EXPECT(ownerCount(env, alice) == 0);
70
71 // Pay alice enough to make the reserve for a DID.
72 env(pay(env.master, alice, drops(baseFee + 1)));
73 env.close();
74
75 // Now alice can create a DID.
76 env(did::setValid(alice));
77 env.close();
78 BEAST_EXPECT(ownerCount(env, alice) == 1);
79
80 // alice deletes her DID.
81 env(did::del(alice));
82 BEAST_EXPECT(ownerCount(env, alice) == 0);
83 env.close();
84 }
85
86 void
88 {
89 testcase("Invalid DIDSet");
90
91 using namespace jtx;
92 using namespace std::chrono;
93
94 Env env{*this, features};
95 Account const alice{"alice"};
96 env.fund(XRP(5000), alice);
97 env.close();
98
99 //----------------------------------------------------------------------
100 // preflight
101
102 // invalid flags
103 BEAST_EXPECT(ownerCount(env, alice) == 0);
104 env(did::setValid(alice), txflags(0x00010000), ter(temINVALID_FLAG));
105 env.close();
106 BEAST_EXPECT(ownerCount(env, alice) == 0);
107
108 // no fields
109 env(did::set(alice), ter(temEMPTY_DID));
110 env.close();
111 BEAST_EXPECT(ownerCount(env, alice) == 0);
112
113 // all empty fields
114 env(did::set(alice), did::uri(""), did::document(""), did::data(""), ter(temEMPTY_DID));
115 env.close();
116 BEAST_EXPECT(ownerCount(env, alice) == 0);
117
118 // uri is too long
119 std::string const longString(257, 'a');
120 env(did::set(alice), did::uri(longString), ter(temMALFORMED));
121 env.close();
122 BEAST_EXPECT(ownerCount(env, alice) == 0);
123
124 // document is too long
125 env(did::set(alice), did::document(longString), ter(temMALFORMED));
126 env.close();
127 BEAST_EXPECT(ownerCount(env, alice) == 0);
128
129 // attestation is too long
130 env(did::set(alice), did::document("data"), did::data(longString), ter(temMALFORMED));
131 env.close();
132 BEAST_EXPECT(ownerCount(env, alice) == 0);
133
134 // some empty fields, some optional fields
135 // pre-fix amendment
136 auto const fixEnabled = env.current()->rules().enabled(fixEmptyDID);
137 env(did::set(alice), did::uri(""), fixEnabled ? ter(tecEMPTY_DID) : ter(tesSUCCESS));
138 env.close();
139 auto const expectedOwnerReserve = fixEnabled ? 0 : 1;
140 BEAST_EXPECT(ownerCount(env, alice) == expectedOwnerReserve);
141
142 // Modifying a DID to become empty is checked in testSetModify
143 }
144
145 void
147 {
148 testcase("Invalid DIDDelete");
149
150 using namespace jtx;
151 using namespace std::chrono;
152
153 Env env{*this, features};
154 Account const alice{"alice"};
155 env.fund(XRP(5000), alice);
156 env.close();
157
158 //----------------------------------------------------------------------
159 // preflight
160
161 // invalid flags
162 BEAST_EXPECT(ownerCount(env, alice) == 0);
163 env(did::del(alice), txflags(0x00010000), ter(temINVALID_FLAG));
164 env.close();
165 BEAST_EXPECT(ownerCount(env, alice) == 0);
166
167 //----------------------------------------------------------------------
168 // doApply
169
170 // DID doesn't exist
171 env(did::del(alice), ter(tecNO_ENTRY));
172 env.close();
173 BEAST_EXPECT(ownerCount(env, alice) == 0);
174 }
175
176 void
178 {
179 testcase("Valid Initial DIDSet");
180
181 using namespace jtx;
182 using namespace std::chrono;
183
184 Env env{*this, features};
185 Account const alice{"alice"};
186 Account const bob{"bob"};
187 Account const charlie{"charlie"};
188 Account const dave{"dave"};
189 Account const edna{"edna"};
190 Account const francis{"francis"};
191 Account const george{"george"};
192 env.fund(XRP(5000), alice, bob, charlie, dave, edna, francis);
193 env.close();
194 BEAST_EXPECT(ownerCount(env, alice) == 0);
195 BEAST_EXPECT(ownerCount(env, bob) == 0);
196 BEAST_EXPECT(ownerCount(env, charlie) == 0);
197
198 // only URI
199 env(did::set(alice), did::uri("uri"));
200 BEAST_EXPECT(ownerCount(env, alice) == 1);
201
202 // only DIDDocument
203 env(did::set(bob), did::document("data"));
204 BEAST_EXPECT(ownerCount(env, bob) == 1);
205
206 // only Data
207 env(did::set(charlie), did::data("data"));
208 BEAST_EXPECT(ownerCount(env, charlie) == 1);
209
210 // URI + Data
211 env(did::set(dave), did::uri("uri"), did::data("attest"));
212 BEAST_EXPECT(ownerCount(env, dave) == 1);
213
214 // URI + DIDDocument
215 env(did::set(edna), did::uri("uri"), did::document("data"));
216 BEAST_EXPECT(ownerCount(env, edna) == 1);
217
218 // DIDDocument + Data
219 env(did::set(francis), did::document("data"), did::data("attest"));
220 BEAST_EXPECT(ownerCount(env, francis) == 1);
221
222 // URI + DIDDocument + Data
223 env(did::set(george), did::uri("uri"), did::document("data"), did::data("attest"));
224 BEAST_EXPECT(ownerCount(env, george) == 1);
225 }
226
227 void
229 {
230 testcase("Modify DID with DIDSet");
231
232 using namespace jtx;
233 using namespace std::chrono;
234
235 Env env{*this, features};
236 Account const alice{"alice"};
237 env.fund(XRP(5000), alice);
238 env.close();
239 BEAST_EXPECT(ownerCount(env, alice) == 0);
240 auto const ar = env.le(alice);
241
242 // Create DID
243 std::string const initialURI = "uri";
244 {
245 env(did::set(alice), did::uri(initialURI));
246 BEAST_EXPECT(ownerCount(env, alice) == 1);
247 auto const sleDID = env.le(keylet::did(alice.id()));
248 BEAST_EXPECT(sleDID);
249 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
250 BEAST_EXPECT(!sleDID->isFieldPresent(sfDIDDocument));
251 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
252 }
253
254 // Try to delete URI, fails because no elements are set
255 {
256 env(did::set(alice), did::uri(""), ter(tecEMPTY_DID));
257 BEAST_EXPECT(ownerCount(env, alice) == 1);
258 auto const sleDID = env.le(keylet::did(alice.id()));
259 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
260 BEAST_EXPECT(!sleDID->isFieldPresent(sfDIDDocument));
261 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
262 }
263
264 // Set DIDDocument
265 std::string const initialDocument = "data";
266 {
267 env(did::set(alice), did::document(initialDocument));
268 BEAST_EXPECT(ownerCount(env, alice) == 1);
269 auto const sleDID = env.le(keylet::did(alice.id()));
270 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
271 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
272 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
273 }
274
275 // Set Data
276 std::string const initialData = "attest";
277 {
278 env(did::set(alice), did::data(initialData));
279 BEAST_EXPECT(ownerCount(env, alice) == 1);
280 auto const sleDID = env.le(keylet::did(alice.id()));
281 BEAST_EXPECT(checkVL((*sleDID)[sfURI], initialURI));
282 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
283 BEAST_EXPECT(checkVL((*sleDID)[sfData], initialData));
284 }
285
286 // Remove URI
287 {
288 env(did::set(alice), did::uri(""));
289 BEAST_EXPECT(ownerCount(env, alice) == 1);
290 auto const sleDID = env.le(keylet::did(alice.id()));
291 BEAST_EXPECT(!sleDID->isFieldPresent(sfURI));
292 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
293 BEAST_EXPECT(checkVL((*sleDID)[sfData], initialData));
294 }
295
296 // Remove Data
297 {
298 env(did::set(alice), did::data(""));
299 BEAST_EXPECT(ownerCount(env, alice) == 1);
300 auto const sleDID = env.le(keylet::did(alice.id()));
301 BEAST_EXPECT(!sleDID->isFieldPresent(sfURI));
302 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], initialDocument));
303 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
304 }
305
306 // Remove Data + set URI
307 std::string const secondURI = "uri2";
308 {
309 env(did::set(alice), did::uri(secondURI), did::document(""));
310 BEAST_EXPECT(ownerCount(env, alice) == 1);
311 auto const sleDID = env.le(keylet::did(alice.id()));
312 BEAST_EXPECT(checkVL((*sleDID)[sfURI], secondURI));
313 BEAST_EXPECT(!sleDID->isFieldPresent(sfDIDDocument));
314 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
315 }
316
317 // Remove URI + set DIDDocument
318 std::string const secondDocument = "data2";
319 {
320 env(did::set(alice), did::uri(""), did::document(secondDocument));
321 BEAST_EXPECT(ownerCount(env, alice) == 1);
322 auto const sleDID = env.le(keylet::did(alice.id()));
323 BEAST_EXPECT(!sleDID->isFieldPresent(sfURI));
324 BEAST_EXPECT(checkVL((*sleDID)[sfDIDDocument], secondDocument));
325 BEAST_EXPECT(!sleDID->isFieldPresent(sfData));
326 }
327
328 // Remove DIDDocument + set Data
329 std::string const secondData = "randomData";
330 {
331 env(did::set(alice), did::document(""), did::data(secondData));
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(!sleDID->isFieldPresent(sfDIDDocument));
336 BEAST_EXPECT(checkVL((*sleDID)[sfData], secondData));
337 }
338
339 // Delete DID
340 {
341 env(did::del(alice));
342 BEAST_EXPECT(ownerCount(env, alice) == 0);
343 auto const sleDID = env.le(keylet::did(alice.id()));
344 BEAST_EXPECT(!sleDID);
345 }
346 }
347
348 void
349 run() override
350 {
351 using namespace test::jtx;
353 FeatureBitset const emptyDID{fixEmptyDID};
359
360 testEnabled(all - emptyDID);
361 testAccountReserve(all - emptyDID);
362 testSetInvalid(all - emptyDID);
363 testDeleteInvalid(all - emptyDID);
364 testSetModify(all - emptyDID);
365 }
366};
367
368BEAST_DEFINE_TESTSUITE(DID, app, xrpl);
369
370} // namespace test
371} // namespace xrpl
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:148
Immutable cryptographic account descriptor.
Definition Account.h:20
A transaction testing environment.
Definition Env.h:98
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:450
Json::Value del(jtx::Account const &account)
Definition dids.cpp:33
Json::Value setValid(jtx::Account const &account)
Definition dids.cpp:23
Json::Value set(jtx::Account const &account)
Definition dids.cpp:14
std::uint32_t ownerCount(Env const &env, Account const &account)
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:90
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
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
bool checkVL(Slice const &result, std::string const &expected)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
@ temINVALID_FLAG
Definition TER.h:92
@ temEMPTY_DID
Definition TER.h:119
@ temMALFORMED
Definition TER.h:68
@ temDISABLED
Definition TER.h:95
@ tecNO_ENTRY
Definition TER.h:288
@ tecEMPTY_DID
Definition TER.h:335
@ tecINSUFFICIENT_RESERVE
Definition TER.h:289
@ tesSUCCESS
Definition TER.h:226
void testSetValidInitial(FeatureBitset features)
Definition DID_test.cpp:177
void testDeleteInvalid(FeatureBitset features)
Definition DID_test.cpp:146
void testEnabled(FeatureBitset features)
Definition DID_test.cpp:14
void testAccountReserve(FeatureBitset features)
Definition DID_test.cpp:36
void run() override
Runs the suite.
Definition DID_test.cpp:349
void testSetModify(FeatureBitset features)
Definition DID_test.cpp:228
void testSetInvalid(FeatureBitset features)
Definition DID_test.cpp:87