rippled
AccountSet_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2016 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 <ripple/basics/StringUtilities.h>
21 #include <ripple/protocol/AmountConversions.h>
22 #include <ripple/protocol/Feature.h>
23 #include <ripple/protocol/jss.h>
24 #include <ripple/protocol/Quality.h>
25 #include <ripple/protocol/Rate.h>
26 #include <test/jtx.h>
27 
28 namespace ripple {
29 
30 class AccountSet_test : public beast::unit_test::suite
31 {
32 public:
33 
35  {
36  testcase ("No AccountSet");
37 
38  using namespace test::jtx;
39  Env env(*this);
40  Account const alice ("alice");
41  env.fund(XRP(10000), noripple(alice));
42  //ask for the ledger entry - account root, to check its flags
43  auto const jrr = env.le(alice);
44  BEAST_EXPECT((*env.le(alice))[ sfFlags ] == 0u);
45  }
46 
48  {
49  testcase ("Most Flags");
50 
51  using namespace test::jtx;
52  Account const alice ("alice");
53 
54  // Test without DepositAuth enabled initially.
55  Env env(*this, supported_amendments() - featureDepositAuth);
56  env.fund(XRP(10000), noripple(alice));
57 
58  // Give alice a regular key so she can legally set and clear
59  // her asfDisableMaster flag.
60  Account const alie {"alie", KeyType::secp256k1};
61  env(regkey (alice, alie));
62  env.close();
63 
64  auto testFlags = [this, &alice, &alie, &env]
66  {
67  std::uint32_t const orig_flags = (*env.le(alice))[ sfFlags ];
68  for (std::uint32_t flag {1u};
69  flag < std::numeric_limits<std::uint32_t>::digits; ++flag)
70  {
71  if (flag == asfNoFreeze)
72  {
73  // The asfNoFreeze flag can't be cleared. It is tested
74  // elsewhere.
75  continue;
76  }
77  else if (std::find (goodFlags.begin(), goodFlags.end(), flag) !=
78  goodFlags.end())
79  {
80  // Good flag
81  env.require(nflags(alice, flag));
82  env(fset(alice, flag), sig(alice));
83  env.close();
84  env.require(flags(alice, flag));
85  env(fclear(alice, flag), sig(alie));
86  env.close();
87  env.require(nflags(alice, flag));
88  std::uint32_t const now_flags = (*env.le(alice))[ sfFlags ];
89  BEAST_EXPECT(now_flags == orig_flags);
90  }
91  else
92  {
93  // Bad flag
94  BEAST_EXPECT((*env.le(alice))[ sfFlags ] == orig_flags);
95  env(fset(alice, flag), sig(alice));
96  env.close();
97  BEAST_EXPECT((*env.le(alice))[ sfFlags ] == orig_flags);
98  env(fclear(alice, flag), sig(alie));
99  env.close();
100  BEAST_EXPECT((*env.le(alice))[ sfFlags ] == orig_flags);
101  }
102  }
103  };
104 
105  // Test with featureDepositAuth disabled.
108 
109  // Enable featureDepositAuth and retest.
110  env.enableFeature (featureDepositAuth);
111  env.close();
114  asfDepositAuth});
115  }
116 
118  {
119  testcase ("Set and reset AccountTxnID");
120 
121  using namespace test::jtx;
122  Env env(*this);
123  Account const alice ("alice");
124  env.fund(XRP(10000), noripple(alice));
125 
126  std::uint32_t const orig_flags = (*env.le(alice))[ sfFlags ];
127 
128  // asfAccountTxnID is special and not actually set as a flag,
129  // so we check the field presence instead
130  BEAST_EXPECT(! env.le(alice)->isFieldPresent(sfAccountTxnID));
131  env(fset(alice, asfAccountTxnID), sig(alice));
132  BEAST_EXPECT(env.le(alice)->isFieldPresent(sfAccountTxnID));
133  env(fclear(alice, asfAccountTxnID));
134  BEAST_EXPECT(! env.le(alice)->isFieldPresent(sfAccountTxnID));
135  std::uint32_t const now_flags = (*env.le(alice))[ sfFlags ];
136  BEAST_EXPECT(now_flags == orig_flags);
137  }
138 
140  {
141  testcase ("Set NoFreeze");
142 
143  using namespace test::jtx;
144  Env env(*this);
145  Account const alice ("alice");
146  env.fund(XRP(10000), noripple(alice));
147  env.memoize("eric");
148  env(regkey(alice, "eric"));
149 
150  env.require(nflags(alice, asfNoFreeze));
151  env(fset(alice, asfNoFreeze), sig("eric"), ter(tecNEED_MASTER_KEY));
152  env(fset(alice, asfNoFreeze), sig(alice));
153  env.require(flags(alice, asfNoFreeze));
154  env(fclear(alice, asfNoFreeze), sig(alice));
155  // verify flag is still set (clear does not clear in this case)
156  env.require(flags(alice, asfNoFreeze));
157  }
158 
159  void testDomain()
160  {
161  testcase ("Domain");
162 
163  using namespace test::jtx;
164  Env env(*this);
165  Account const alice ("alice");
166  env.fund(XRP(10000), alice);
167  auto jt = noop(alice);
168  // The Domain field is represented as the hex string of the lowercase
169  // ASCII of the domain. For example, the domain example.com would be
170  // represented as "6578616d706c652e636f6d".
171  //
172  // To remove the Domain field from an account, send an AccountSet with
173  // the Domain set to an empty string.
174  std::string const domain = "example.com";
175  jt[sfDomain.fieldName] = strHex(domain);
176  env(jt);
177  BEAST_EXPECT((*env.le(alice))[ sfDomain ] == makeSlice(domain));
178 
179  jt[sfDomain.fieldName] = "";
180  env(jt);
181  BEAST_EXPECT(! env.le(alice)->isFieldPresent(sfDomain));
182 
183  // The upper limit on the length is 256 bytes
184  // (defined as DOMAIN_BYTES_MAX in SetAccount)
185  // test the edge cases: 255, 256, 257.
186  std::size_t const maxLength = 256;
187  for (std::size_t len = maxLength - 1; len <= maxLength + 1; ++len)
188  {
189  std::string domain2 =
190  std::string(len - domain.length() - 1, 'a') + "." + domain;
191 
192  BEAST_EXPECT (domain2.length() == len);
193 
194  jt[sfDomain.fieldName] = strHex(domain2);
195 
196  if (len <= maxLength)
197  {
198  env(jt);
199  BEAST_EXPECT((*env.le(alice))[ sfDomain ] == makeSlice(domain2));
200  }
201  else
202  {
203  env(jt, ter(telBAD_DOMAIN));
204  }
205  }
206  }
207 
209  {
210  testcase ("MessageKey");
211 
212  using namespace test::jtx;
213  Env env(*this);
214  Account const alice ("alice");
215  env.fund(XRP(10000), alice);
216  auto jt = noop(alice);
217 
218  auto const rkp = randomKeyPair(KeyType::ed25519);
219  jt[sfMessageKey.fieldName] = strHex(rkp.first.slice());
220  env(jt);
221  BEAST_EXPECT(strHex((*env.le(alice))[ sfMessageKey ]) == strHex(rkp.first.slice()));
222 
223  jt[sfMessageKey.fieldName] = "";
224  env(jt);
225  BEAST_EXPECT(! env.le(alice)->isFieldPresent(sfMessageKey));
226 
227  using namespace std::string_literals;
228  jt[sfMessageKey.fieldName] = strHex("NOT_REALLY_A_PUBKEY"s);
229  env(jt, ter(telBAD_PUBLIC_KEY));
230  }
231 
233  {
234  testcase ("WalletID");
235 
236  using namespace test::jtx;
237  Env env(*this);
238  Account const alice ("alice");
239  env.fund(XRP(10000), alice);
240  auto jt = noop(alice);
241 
242  uint256 somehash = from_hex_text<uint256>("9633ec8af54f16b5286db1d7b519ef49eefc050c0c8ac4384f1d88acd1bfdf05");
243  jt[sfWalletLocator.fieldName] = to_string(somehash);
244  env(jt);
245  BEAST_EXPECT((*env.le(alice))[ sfWalletLocator ] == somehash);
246 
247  jt[sfWalletLocator.fieldName] = "";
248  env(jt);
249  BEAST_EXPECT(! env.le(alice)->isFieldPresent(sfWalletLocator));
250  }
251 
253  {
254  testcase ("EmailHash");
255 
256  using namespace test::jtx;
257  Env env(*this);
258  Account const alice ("alice");
259  env.fund(XRP(10000), alice);
260  auto jt = noop(alice);
261 
262  uint128 somehash = from_hex_text<uint128>("fff680681c2f5e6095324e2e08838f221a72ab4f");
263  jt[sfEmailHash.fieldName] = to_string(somehash);
264  env(jt);
265  BEAST_EXPECT((*env.le(alice))[ sfEmailHash ] == somehash);
266 
267  jt[sfEmailHash.fieldName] = "";
268  env(jt);
269  BEAST_EXPECT(! env.le(alice)->isFieldPresent(sfEmailHash));
270  }
271 
273  {
274  struct test_results
275  {
276  double set;
277  TER code;
278  double get;
279  };
280 
281  testcase ("TransferRate");
282 
283  using namespace test::jtx;
284  auto doTests = [this] (FeatureBitset const& features,
286  {
287  Env env (*this, features);
288 
289  Account const alice ("alice");
290  env.fund(XRP(10000), alice);
291 
292  for (auto const& r : testData)
293  {
294  env(rate(alice, r.set), ter(r.code));
295  env.close();
296 
297  // If the field is not present expect the default value
298  if (!(*env.le(alice))[~sfTransferRate])
299  BEAST_EXPECT(r.get == 1.0);
300  else
301  BEAST_EXPECT(*(*env.le(alice))[~sfTransferRate] ==
302  r.get * QUALITY_ONE);
303  }
304  };
305 
306  doTests (supported_amendments(),
307  {
308  { 1.0, tesSUCCESS, 1.0 },
309  { 1.1, tesSUCCESS, 1.1 },
310  { 2.0, tesSUCCESS, 2.0 },
311  { 2.1, temBAD_TRANSFER_RATE, 2.0 },
312  { 0.0, tesSUCCESS, 1.0 },
313  { 2.0, tesSUCCESS, 2.0 },
314  { 0.9, temBAD_TRANSFER_RATE, 2.0 }
315  });
316  }
317 
318  void testGateway()
319  {
320  testcase ("Gateway");
321 
322  using namespace test::jtx;
323 
324  Account const alice ("alice");
325  Account const bob ("bob");
326  Account const gw ("gateway");
327  auto const USD = gw["USD"];
328 
329  // Test gateway with a variety of allowed transfer rates
330  for (double transferRate = 1.0;
331  transferRate <= 2.0; transferRate += 0.03125)
332  {
333  Env env (*this);
334  env.fund(XRP(10000), gw, alice, bob);
335  env.close();
336  env.trust(USD(10), alice, bob);
337  env.close();
338  env(rate(gw, transferRate));
339  env.close();
340 
341  auto const amount = USD(1);
342  Rate const rate (transferRate * QUALITY_ONE);
343  auto const amountWithRate =
344  toAmount<STAmount> (multiply(amount.value(), rate));
345 
346  env(pay(gw, alice, USD(10)));
347  env.close();
348  env(pay(alice, bob, USD(1)), sendmax(USD(10)));
349  env.close();
350 
351  env.require(balance(alice, USD(10) - amountWithRate));
352  env.require(balance(bob, USD(1)));
353  }
354 
355  // Since fix1201 was enabled on Nov 14 2017 a rate in excess of
356  // 2.0 has been blocked by the transactor. But there are a few
357  // accounts on the MainNet that have larger-than-currently-allowed
358  // TransferRates. We'll bypass the transactor so we can check
359  // operation of these legacy TransferRates.
360  //
361  // Two out-of-bound values are currently in the ledger (March 2020)
362  // They are 4.0 and 4.294967295. So those are the values we test.
363  for (double transferRate : {4.0, 4.294967295})
364  {
365  Env env (*this);
366  env.fund(XRP(10000), gw, alice, bob);
367  env.close();
368  env.trust(USD(10), alice, bob);
369  env.close();
370 
371  // We'd like to use transferRate here, but the transactor
372  // blocks transfer rates that large. So we use an acceptable
373  // transfer rate here and later hack the ledger to replace
374  // the acceptable value with an out-of-bounds value.
375  env(rate(gw, 2.0));
376  env.close();
377 
378  // Note that we're bypassing almost all of the ledger's safety
379  // checks with this modify() call. If you call close() between
380  // here and the end of the test all the effort will be lost.
381  env.app().openLedger().modify(
382  [&gw, transferRate] (OpenView& view, beast::Journal j)
383  {
384  // Get the account root we want to hijack.
385  auto const sle = view.read (keylet::account(gw.id()));
386  if (! sle)
387  return false; // This would be really surprising!
388 
389  // We'll insert a replacement for the account root
390  // with the higher (currently invalid) transfer rate.
391  auto replacement =
392  std::make_shared<SLE>(*sle, sle->key());
393  (*replacement)[sfTransferRate] =
394  static_cast<std::uint32_t>(transferRate * QUALITY_ONE);
395  view.rawReplace (replacement);
396  return true;
397  });
398 
399  auto const amount = USD(1);
400  auto const amountWithRate =
402  multiply(amount.value(),
403  Rate (transferRate * QUALITY_ONE)));
404 
405  env(pay(gw, alice, USD(10)));
406  env(pay(alice, bob, amount), sendmax(USD(10)));
407 
408  env.require(balance(alice, USD(10) - amountWithRate));
409  env.require(balance(bob, amount));
410  }
411  }
412 
414  {
415  testcase ("Bad inputs");
416 
417  using namespace test::jtx;
418  Env env (*this);
419  Account const alice ("alice");
420  env.fund(XRP(10000), alice);
421 
422  auto jt = fset(alice, asfDisallowXRP);
423  jt[jss::ClearFlag] = asfDisallowXRP;
424  env(jt, ter(temINVALID_FLAG));
425 
426  jt = fset(alice, asfRequireAuth);
427  jt[jss::ClearFlag] = asfRequireAuth;
428  env(jt, ter(temINVALID_FLAG));
429 
430  jt = fset(alice, asfRequireDest);
431  jt[jss::ClearFlag] = asfRequireDest;
432  env(jt, ter(temINVALID_FLAG));
433 
434  jt = fset(alice, asfDisallowXRP);
436  env(jt, ter(temINVALID_FLAG));
437 
438  jt = fset(alice, asfRequireAuth);
440  env(jt, ter(temINVALID_FLAG));
441 
442  jt = fset(alice, asfRequireDest);
444  env(jt, ter(temINVALID_FLAG));
445 
446  jt = fset(alice, asfRequireDest);
448  env(jt, ter(temINVALID_FLAG));
449 
450  env(fset (alice, asfDisableMaster),
451  sig(alice),
452  ter(tecNO_ALTERNATIVE_KEY));
453  }
454 
456  {
457  testcase ("Require auth");
458 
459  using namespace test::jtx;
460  Env env(*this);
461  Account const alice ("alice");
462  Account const bob ("bob");
463 
464  env.fund(XRP(10000), alice);
465  env.close();
466 
467  // alice should have an empty directory.
468  BEAST_EXPECT(dirIsEmpty (*env.closed(), keylet::ownerDir(alice)));
469 
470  // Give alice a signer list, then there will be stuff in the directory.
471  env(signers(alice, 1, { { bob, 1} }));
472  env.close();
473  BEAST_EXPECT(! dirIsEmpty (*env.closed(), keylet::ownerDir(alice)));
474 
475  env(fset (alice, asfRequireAuth), ter(tecOWNERS));
476  }
477 
478  void run() override
479  {
481  testMostFlags();
483  testSetNoFreeze();
484  testDomain();
485  testGateway();
486  testMessageKey();
487  testWalletID();
488  testEmailHash();
489  testBadInputs();
492  }
493 };
494 
495 BEAST_DEFINE_TESTSUITE(AccountSet,app,ripple);
496 
497 }
498 
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:338
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:199
std::string
STL class.
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::Rate
Represents a transfer rate.
Definition: Rate.h:37
ripple::tecOWNERS
@ tecOWNERS
Definition: TER.h:263
ripple::AccountSet_test::testNullAccountSet
void testNullAccountSet()
Definition: AccountSet_test.cpp:34
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:52
ripple::asfGlobalFreeze
const std::uint32_t asfGlobalFreeze
Definition: TxFlags.h:71
std::find
T find(T... args)
std::string::length
T length(T... args)
ripple::sfMessageKey
const SF_Blob sfMessageKey(access, STI_VL, 2, "MessageKey")
Definition: SField.h:441
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:136
ripple::telBAD_DOMAIN
@ telBAD_DOMAIN
Definition: TER.h:54
ripple::asfDefaultRipple
const std::uint32_t asfDefaultRipple
Definition: TxFlags.h:72
ripple::sfFlags
const SF_U32 sfFlags(access, STI_UINT32, 2, "Flags")
Definition: SField.h:338
ripple::featureDepositAuth
const uint256 featureDepositAuth
Definition: Feature.cpp:164
ripple::sfWalletLocator
const SF_U256 sfWalletLocator(access, STI_HASH256, 7, "WalletLocator")
Definition: SField.h:407
ripple::asfDepositAuth
const std::uint32_t asfDepositAuth
Definition: TxFlags.h:73
ripple::asfDisallowXRP
const std::uint32_t asfDisallowXRP
Definition: TxFlags.h:67
ripple::tfOptionalDestTag
const std::uint32_t tfOptionalDestTag
Definition: TxFlags.h:55
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::temBAD_TRANSFER_RATE
@ temBAD_TRANSFER_RATE
Definition: TER.h:105
ripple::AccountSet_test::testGateway
void testGateway()
Definition: AccountSet_test.cpp:318
ripple::asfAccountTxnID
const std::uint32_t asfAccountTxnID
Definition: TxFlags.h:69
ripple::sfAccountTxnID
const SF_U256 sfAccountTxnID(access, STI_HASH256, 9, "AccountTxnID")
Definition: SField.h:409
ripple::KeyType::ed25519
@ ed25519
ripple::base_uint< 256 >
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:109
ripple::tfAllowXRP
const std::uint32_t tfAllowXRP
Definition: TxFlags.h:59
ripple::AccountSet_test::testRequireAuthWithDir
void testRequireAuthWithDir()
Definition: AccountSet_test.cpp:455
ripple::tecNO_ALTERNATIVE_KEY
@ tecNO_ALTERNATIVE_KEY
Definition: TER.h:261
ripple::AccountSet_test::testEmailHash
void testEmailHash()
Definition: AccountSet_test.cpp:252
ripple::asfRequireAuth
const std::uint32_t asfRequireAuth
Definition: TxFlags.h:66
ripple::AccountSet_test::run
void run() override
Definition: AccountSet_test.cpp:478
ripple::keylet::account
static const account_t account
Definition: Indexes.h:116
ripple::OpenView::rawReplace
void rawReplace(std::shared_ptr< SLE > const &sle) override
Unconditionally replace a state item.
Definition: OpenView.cpp:249
ripple::TERSubset< CanCvtToTER >
ripple::AccountSet_test::testTransferRate
void testTransferRate()
Definition: AccountSet_test.cpp:272
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id)
The root page of an account's directory.
Definition: Indexes.cpp:318
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:271
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::uint32_t
ripple::AccountSet_test::testDomain
void testDomain()
Definition: AccountSet_test.cpp:159
ripple::tecNEED_MASTER_KEY
@ tecNEED_MASTER_KEY
Definition: TER.h:273
ripple::asfRequireDest
const std::uint32_t asfRequireDest
Definition: TxFlags.h:65
ripple::AccountSet_test::testMostFlags
void testMostFlags()
Definition: AccountSet_test.cpp:47
ripple::KeyType::secp256k1
@ secp256k1
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:37
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:286
ripple::asfDisableMaster
const std::uint32_t asfDisableMaster
Definition: TxFlags.h:68
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:443
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::asfNoFreeze
const std::uint32_t asfNoFreeze
Definition: TxFlags.h:70
ripple::AccountSet_test::testBadInputs
void testBadInputs()
Definition: AccountSet_test.cpp:413
ripple::tfOptionalAuth
const std::uint32_t tfOptionalAuth
Definition: TxFlags.h:57
ripple::AccountSet_test::testSetNoFreeze
void testSetNoFreeze()
Definition: AccountSet_test.cpp:139
ripple::FeatureBitset
Definition: Feature.h:153
ripple::tfAccountSetMask
const std::uint32_t tfAccountSetMask
Definition: TxFlags.h:60
ripple::telBAD_PUBLIC_KEY
@ telBAD_PUBLIC_KEY
Definition: TER.h:56
ripple::OpenView::read
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
Definition: OpenView.cpp:164
std::size_t
ripple::sfTransferRate
const SF_U32 sfTransferRate(access, STI_UINT32, 11, "TransferRate")
Definition: SField.h:347
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:70
ripple::AccountSet_test::testMessageKey
void testMessageKey()
Definition: AccountSet_test.cpp:208
ripple::AccountSet_test::testSetAndResetAccountTxnID
void testSetAndResetAccountTxnID()
Definition: AccountSet_test.cpp:117
ripple::AccountSet_test::testWalletID
void testWalletID()
Definition: AccountSet_test.cpp:232
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:219
ripple::sfEmailHash
const SF_U128 sfEmailHash(access, STI_HASH128, 1, "EmailHash")
Definition: SField.h:392
ripple::toAmount< STAmount >
STAmount toAmount< STAmount >(STAmount const &amt)
Definition: AmountConversions.h:74
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:124
ripple::AccountSet_test
Definition: AccountSet_test.cpp:30
std::initializer_list
ripple::sfDomain
const SF_Blob sfDomain(access, STI_VL, 7, "Domain")
Definition: SField.h:445