rippled
MultiSign_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  Permission to use, copy, modify, and/or distribute this software for any
6  purpose with or without fee is hereby granted, provided that the above
7  copyright notice and this permission notice appear in all copies.
8  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 //==============================================================================
17 
18 #include <ripple/core/ConfigSections.h>
19 #include <ripple/protocol/Feature.h>
20 #include <ripple/protocol/jss.h>
21 #include <test/jtx.h>
22 
23 namespace ripple {
24 namespace test {
25 
26 class MultiSign_test : public beast::unit_test::suite
27 {
28  // Unfunded accounts to use for phantom signing.
61 
62 public:
63  void
65  {
66  testcase("No Reserve");
67 
68  using namespace jtx;
69  Env env{*this, features};
70  Account const alice{"alice", KeyType::secp256k1};
71 
72  // The reserve required for a signer list changes with the passage
73  // of featureMultiSignReserve. Make the required adjustments.
74  bool const reserve1{features[featureMultiSignReserve]};
75 
76  // Pay alice enough to meet the initial reserve, but not enough to
77  // meet the reserve for a SignerListSet.
78  auto const fee = env.current()->fees().base;
79  auto const smallSignersReserve = reserve1 ? XRP(250) : XRP(350);
80  env.fund(smallSignersReserve - drops(1), alice);
81  env.close();
82  env.require(owners(alice, 0));
83 
84  {
85  // Attach a signer list to alice. Should fail.
86  Json::Value smallSigners = signers(alice, 1, {{bogie, 1}});
87  env(smallSigners, ter(tecINSUFFICIENT_RESERVE));
88  env.close();
89  env.require(owners(alice, 0));
90 
91  // Fund alice enough to set the signer list, then attach signers.
92  env(pay(env.master, alice, fee + drops(1)));
93  env.close();
94  env(smallSigners);
95  env.close();
96  env.require(owners(alice, reserve1 ? 1 : 3));
97  }
98  {
99  // Pay alice enough to almost make the reserve for the biggest
100  // possible list.
101  auto const addReserveBigSigners = reserve1 ? XRP(0) : XRP(350);
102  env(pay(env.master, alice, addReserveBigSigners + fee - drops(1)));
103 
104  // Replace with the biggest possible signer list. Should fail.
105  Json::Value bigSigners = signers(
106  alice,
107  1,
108  {{bogie, 1},
109  {demon, 1},
110  {ghost, 1},
111  {haunt, 1},
112  {jinni, 1},
113  {phase, 1},
114  {shade, 1},
115  {spook, 1}});
116  env(bigSigners, ter(tecINSUFFICIENT_RESERVE));
117  env.close();
118  env.require(owners(alice, reserve1 ? 1 : 3));
119 
120  // Fund alice one more drop (plus the fee) and succeed.
121  env(pay(env.master, alice, fee + drops(1)));
122  env.close();
123  env(bigSigners);
124  env.close();
125  env.require(owners(alice, reserve1 ? 1 : 10));
126  }
127  // Remove alice's signer list and get the owner count back.
128  env(signers(alice, jtx::none));
129  env.close();
130  env.require(owners(alice, 0));
131  }
132 
133  void
135  {
136  testcase("SignerListSet");
137 
138  using namespace jtx;
139  Env env{*this, features};
140  Account const alice{"alice", KeyType::ed25519};
141  env.fund(XRP(1000), alice);
142 
143  // Add alice as a multisigner for herself. Should fail.
144  env(signers(alice, 1, {{alice, 1}}), ter(temBAD_SIGNER));
145 
146  // Add a signer with a weight of zero. Should fail.
147  env(signers(alice, 1, {{bogie, 0}}), ter(temBAD_WEIGHT));
148 
149  // Add a signer where the weight is too big. Should fail since
150  // the weight field is only 16 bits. The jtx framework can't do
151  // this kind of test, so it's commented out.
152  // env(signers(alice, 1, { { bogie, 0x10000} }), ter
153  // (temBAD_WEIGHT));
154 
155  // Add the same signer twice. Should fail.
156  env(signers(
157  alice,
158  1,
159  {{bogie, 1},
160  {demon, 1},
161  {ghost, 1},
162  {haunt, 1},
163  {jinni, 1},
164  {phase, 1},
165  {demon, 1},
166  {spook, 1}}),
167  ter(temBAD_SIGNER));
168 
169  // Set a quorum of zero. Should fail.
170  env(signers(alice, 0, {{bogie, 1}}), ter(temMALFORMED));
171 
172  // Make a signer list where the quorum can't be met. Should fail.
173  env(signers(
174  alice,
175  9,
176  {{bogie, 1},
177  {demon, 1},
178  {ghost, 1},
179  {haunt, 1},
180  {jinni, 1},
181  {phase, 1},
182  {shade, 1},
183  {spook, 1}}),
184  ter(temBAD_QUORUM));
185 
186  // clang-format off
187  // Make a signer list that's too big. Should fail. (Even with
188  // ExpandedSignerList)
189  Account const spare("spare", KeyType::secp256k1);
190  env(signers(
191  alice,
192  1,
193  features[featureExpandedSignerList]
194  ? std::vector<signer>{{bogie, 1}, {demon, 1}, {ghost, 1},
195  {haunt, 1}, {jinni, 1}, {phase, 1},
196  {shade, 1}, {spook, 1}, {spare, 1},
197  {acc10, 1}, {acc11, 1}, {acc12, 1},
198  {acc13, 1}, {acc14, 1}, {acc15, 1},
199  {acc16, 1}, {acc17, 1}, {acc18, 1},
200  {acc19, 1}, {acc20, 1}, {acc21, 1},
201  {acc22, 1}, {acc23, 1}, {acc24, 1},
202  {acc25, 1}, {acc26, 1}, {acc27, 1},
203  {acc28, 1}, {acc29, 1}, {acc30, 1},
204  {acc31, 1}, {acc32, 1}, {acc33, 1}}
205  : std::vector<signer>{{bogie, 1}, {demon, 1}, {ghost, 1},
206  {haunt, 1}, {jinni, 1}, {phase, 1},
207  {shade, 1}, {spook, 1}, {spare, 1}}),
208  ter(temMALFORMED));
209  // clang-format on
210  env.close();
211  env.require(owners(alice, 0));
212  }
213 
214  void
216  {
217  testcase("Phantom Signers");
218 
219  using namespace jtx;
220  Env env{*this, features};
221  Account const alice{"alice", KeyType::ed25519};
222  env.fund(XRP(1000), alice);
223  env.close();
224 
225  // Attach phantom signers to alice and use them for a transaction.
226  env(signers(alice, 1, {{bogie, 1}, {demon, 1}}));
227  env.close();
228  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4));
229 
230  // This should work.
231  auto const baseFee = env.current()->fees().base;
232  std::uint32_t aliceSeq = env.seq(alice);
233  env(noop(alice), msig(bogie, demon), fee(3 * baseFee));
234  env.close();
235  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
236 
237  // Either signer alone should work.
238  aliceSeq = env.seq(alice);
239  env(noop(alice), msig(bogie), fee(2 * baseFee));
240  env.close();
241  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
242 
243  aliceSeq = env.seq(alice);
244  env(noop(alice), msig(demon), fee(2 * baseFee));
245  env.close();
246  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
247 
248  // Duplicate signers should fail.
249  aliceSeq = env.seq(alice);
250  env(noop(alice), msig(demon, demon), fee(3 * baseFee), ter(temINVALID));
251  env.close();
252  BEAST_EXPECT(env.seq(alice) == aliceSeq);
253 
254  // A non-signer should fail.
255  aliceSeq = env.seq(alice);
256  env(noop(alice),
257  msig(bogie, spook),
258  fee(3 * baseFee),
260  env.close();
261  BEAST_EXPECT(env.seq(alice) == aliceSeq);
262 
263  // Don't meet the quorum. Should fail.
264  env(signers(alice, 2, {{bogie, 1}, {demon, 1}}));
265  aliceSeq = env.seq(alice);
266  env(noop(alice), msig(bogie), fee(2 * baseFee), ter(tefBAD_QUORUM));
267  env.close();
268  BEAST_EXPECT(env.seq(alice) == aliceSeq);
269 
270  // Meet the quorum. Should succeed.
271  aliceSeq = env.seq(alice);
272  env(noop(alice), msig(bogie, demon), fee(3 * baseFee));
273  env.close();
274  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
275  }
276 
277  void
279  {
280  testcase("Fee");
281 
282  using namespace jtx;
283  Env env{*this, features};
284  Account const alice{"alice", KeyType::ed25519};
285  env.fund(XRP(1000), alice);
286  env.close();
287 
288  // Attach maximum possible number of signers to alice.
289  env(signers(
290  alice,
291  1,
292  {{bogie, 1},
293  {demon, 1},
294  {ghost, 1},
295  {haunt, 1},
296  {jinni, 1},
297  {phase, 1},
298  {shade, 1},
299  {spook, 1}}));
300  env.close();
301  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 10));
302 
303  // This should work.
304  auto const baseFee = env.current()->fees().base;
305  std::uint32_t aliceSeq = env.seq(alice);
306  env(noop(alice), msig(bogie), fee(2 * baseFee));
307  env.close();
308 
309  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
310 
311  // This should fail because the fee is too small.
312  aliceSeq = env.seq(alice);
313  env(noop(alice),
314  msig(bogie),
315  fee((2 * baseFee) - 1),
317  env.close();
318 
319  BEAST_EXPECT(env.seq(alice) == aliceSeq);
320 
321  // This should work.
322  aliceSeq = env.seq(alice);
323  env(noop(alice),
325  fee(9 * baseFee));
326  env.close();
327 
328  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
329 
330  // This should fail because the fee is too small.
331  aliceSeq = env.seq(alice);
332  env(noop(alice),
334  fee((9 * baseFee) - 1),
336  env.close();
337 
338  BEAST_EXPECT(env.seq(alice) == aliceSeq);
339  }
340 
341  void
343  {
344  testcase("Misordered Signers");
345 
346  using namespace jtx;
347  Env env{*this, features};
348  Account const alice{"alice", KeyType::ed25519};
349  env.fund(XRP(1000), alice);
350  env.close();
351 
352  // The signatures in a transaction must be submitted in sorted order.
353  // Make sure the transaction fails if they are not.
354  env(signers(alice, 1, {{bogie, 1}, {demon, 1}}));
355  env.close();
356  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4));
357 
358  msig phantoms{bogie, demon};
359  std::reverse(phantoms.signers.begin(), phantoms.signers.end());
360  std::uint32_t const aliceSeq = env.seq(alice);
361  env(noop(alice), phantoms, ter(temINVALID));
362  env.close();
363  BEAST_EXPECT(env.seq(alice) == aliceSeq);
364  }
365 
366  void
368  {
369  testcase("Master Signers");
370 
371  using namespace jtx;
372  Env env{*this, features};
373  Account const alice{"alice", KeyType::ed25519};
374  Account const becky{"becky", KeyType::secp256k1};
375  Account const cheri{"cheri", KeyType::ed25519};
376  env.fund(XRP(1000), alice, becky, cheri);
377  env.close();
378 
379  // For a different situation, give alice a regular key but don't use it.
380  Account const alie{"alie", KeyType::secp256k1};
381  env(regkey(alice, alie));
382  env.close();
383  std::uint32_t aliceSeq = env.seq(alice);
384  env(noop(alice), sig(alice));
385  env(noop(alice), sig(alie));
386  env.close();
387  BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
388 
389  // Attach signers to alice
390  env(signers(alice, 4, {{becky, 3}, {cheri, 4}}), sig(alice));
391  env.close();
392  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4));
393 
394  // Attempt a multisigned transaction that meets the quorum.
395  auto const baseFee = env.current()->fees().base;
396  aliceSeq = env.seq(alice);
397  env(noop(alice), msig(cheri), fee(2 * baseFee));
398  env.close();
399  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
400 
401  // If we don't meet the quorum the transaction should fail.
402  aliceSeq = env.seq(alice);
403  env(noop(alice), msig(becky), fee(2 * baseFee), ter(tefBAD_QUORUM));
404  env.close();
405  BEAST_EXPECT(env.seq(alice) == aliceSeq);
406 
407  // Give becky and cheri regular keys.
408  Account const beck{"beck", KeyType::ed25519};
409  env(regkey(becky, beck));
410  Account const cher{"cher", KeyType::ed25519};
411  env(regkey(cheri, cher));
412  env.close();
413 
414  // becky's and cheri's master keys should still work.
415  aliceSeq = env.seq(alice);
416  env(noop(alice), msig(becky, cheri), fee(3 * baseFee));
417  env.close();
418  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
419  }
420 
421  void
423  {
424  testcase("Regular Signers");
425 
426  using namespace jtx;
427  Env env{*this, features};
428  Account const alice{"alice", KeyType::secp256k1};
429  Account const becky{"becky", KeyType::ed25519};
430  Account const cheri{"cheri", KeyType::secp256k1};
431  env.fund(XRP(1000), alice, becky, cheri);
432  env.close();
433 
434  // Attach signers to alice.
435  env(signers(alice, 1, {{becky, 1}, {cheri, 1}}), sig(alice));
436 
437  // Give everyone regular keys.
438  Account const alie{"alie", KeyType::ed25519};
439  env(regkey(alice, alie));
440  Account const beck{"beck", KeyType::secp256k1};
441  env(regkey(becky, beck));
442  Account const cher{"cher", KeyType::ed25519};
443  env(regkey(cheri, cher));
444  env.close();
445 
446  // Disable cheri's master key to mix things up.
447  env(fset(cheri, asfDisableMaster), sig(cheri));
448  env.close();
449 
450  // Attempt a multisigned transaction that meets the quorum.
451  auto const baseFee = env.current()->fees().base;
452  std::uint32_t aliceSeq = env.seq(alice);
453  env(noop(alice), msig(msig::Reg{cheri, cher}), fee(2 * baseFee));
454  env.close();
455  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
456 
457  // cheri should not be able to multisign using her master key.
458  aliceSeq = env.seq(alice);
459  env(noop(alice),
460  msig(cheri),
461  fee(2 * baseFee),
463  env.close();
464  BEAST_EXPECT(env.seq(alice) == aliceSeq);
465 
466  // becky should be able to multisign using either of her keys.
467  aliceSeq = env.seq(alice);
468  env(noop(alice), msig(becky), fee(2 * baseFee));
469  env.close();
470  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
471 
472  aliceSeq = env.seq(alice);
473  env(noop(alice), msig(msig::Reg{becky, beck}), fee(2 * baseFee));
474  env.close();
475  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
476 
477  // Both becky and cheri should be able to sign using regular keys.
478  aliceSeq = env.seq(alice);
479  env(noop(alice),
480  fee(3 * baseFee),
481  msig(msig::Reg{becky, beck}, msig::Reg{cheri, cher}));
482  env.close();
483  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
484  }
485 
486  void
488  {
489  testcase("Regular Signers Using submit_multisigned");
490 
491  using namespace jtx;
492  Env env(
493  *this,
495  cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
496  return cfg;
497  }),
498  features);
499  Account const alice{"alice", KeyType::secp256k1};
500  Account const becky{"becky", KeyType::ed25519};
501  Account const cheri{"cheri", KeyType::secp256k1};
502  env.fund(XRP(1000), alice, becky, cheri);
503  env.close();
504 
505  // Attach signers to alice.
506  env(signers(alice, 2, {{becky, 1}, {cheri, 1}}), sig(alice));
507 
508  // Give everyone regular keys.
509  Account const beck{"beck", KeyType::secp256k1};
510  env(regkey(becky, beck));
511  Account const cher{"cher", KeyType::ed25519};
512  env(regkey(cheri, cher));
513  env.close();
514 
515  // Disable cheri's master key to mix things up.
516  env(fset(cheri, asfDisableMaster), sig(cheri));
517  env.close();
518 
519  auto const baseFee = env.current()->fees().base;
520  std::uint32_t aliceSeq;
521 
522  // these represent oft-repeated setup for input json below
523  auto setup_tx = [&]() -> Json::Value {
524  Json::Value jv;
525  jv[jss::tx_json][jss::Account] = alice.human();
526  jv[jss::tx_json][jss::TransactionType] = jss::AccountSet;
527  jv[jss::tx_json][jss::Fee] = (8 * baseFee).jsonClipped();
528  jv[jss::tx_json][jss::Sequence] = env.seq(alice);
529  jv[jss::tx_json][jss::SigningPubKey] = "";
530  return jv;
531  };
532  auto cheri_sign = [&](Json::Value& jv) {
533  jv[jss::account] = cheri.human();
534  jv[jss::key_type] = "ed25519";
535  jv[jss::passphrase] = cher.name();
536  };
537  auto becky_sign = [&](Json::Value& jv) {
538  jv[jss::account] = becky.human();
539  jv[jss::secret] = beck.name();
540  };
541 
542  {
543  // Attempt a multisigned transaction that meets the quorum.
544  // using sign_for and submit_multisigned
545  aliceSeq = env.seq(alice);
546  Json::Value jv_one = setup_tx();
547  cheri_sign(jv_one);
548  auto jrr =
549  env.rpc("json", "sign_for", to_string(jv_one))[jss::result];
550  BEAST_EXPECT(jrr[jss::status] == "success");
551 
552  // for the second sign_for, use the returned tx_json with
553  // first signer info
554  Json::Value jv_two;
555  jv_two[jss::tx_json] = jrr[jss::tx_json];
556  becky_sign(jv_two);
557  jrr = env.rpc("json", "sign_for", to_string(jv_two))[jss::result];
558  BEAST_EXPECT(jrr[jss::status] == "success");
559 
560  Json::Value jv_submit;
561  jv_submit[jss::tx_json] = jrr[jss::tx_json];
562  jrr = env.rpc(
563  "json",
564  "submit_multisigned",
565  to_string(jv_submit))[jss::result];
566  BEAST_EXPECT(jrr[jss::status] == "success");
567  env.close();
568  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
569  }
570 
571  {
572  // failure case -- SigningPubKey not empty
573  aliceSeq = env.seq(alice);
574  Json::Value jv_one = setup_tx();
575  jv_one[jss::tx_json][jss::SigningPubKey] =
576  strHex(alice.pk().slice());
577  cheri_sign(jv_one);
578  auto jrr =
579  env.rpc("json", "sign_for", to_string(jv_one))[jss::result];
580  BEAST_EXPECT(jrr[jss::status] == "error");
581  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
582  BEAST_EXPECT(
583  jrr[jss::error_message] ==
584  "When multi-signing 'tx_json.SigningPubKey' must be empty.");
585  }
586 
587  {
588  // failure case - bad fee
589  aliceSeq = env.seq(alice);
590  Json::Value jv_one = setup_tx();
591  jv_one[jss::tx_json][jss::Fee] = -1;
592  cheri_sign(jv_one);
593  auto jrr =
594  env.rpc("json", "sign_for", to_string(jv_one))[jss::result];
595  BEAST_EXPECT(jrr[jss::status] == "success");
596 
597  // for the second sign_for, use the returned tx_json with
598  // first signer info
599  Json::Value jv_two;
600  jv_two[jss::tx_json] = jrr[jss::tx_json];
601  becky_sign(jv_two);
602  jrr = env.rpc("json", "sign_for", to_string(jv_two))[jss::result];
603  BEAST_EXPECT(jrr[jss::status] == "success");
604 
605  Json::Value jv_submit;
606  jv_submit[jss::tx_json] = jrr[jss::tx_json];
607  jrr = env.rpc(
608  "json",
609  "submit_multisigned",
610  to_string(jv_submit))[jss::result];
611  BEAST_EXPECT(jrr[jss::status] == "error");
612  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
613  BEAST_EXPECT(
614  jrr[jss::error_message] ==
615  "Invalid Fee field. Fees must be greater than zero.");
616  }
617 
618  {
619  // failure case - bad fee v2
620  aliceSeq = env.seq(alice);
621  Json::Value jv_one = setup_tx();
622  jv_one[jss::tx_json][jss::Fee] =
623  alice["USD"](10).value().getFullText();
624  cheri_sign(jv_one);
625  auto jrr =
626  env.rpc("json", "sign_for", to_string(jv_one))[jss::result];
627  BEAST_EXPECT(jrr[jss::status] == "success");
628 
629  // for the second sign_for, use the returned tx_json with
630  // first signer info
631  Json::Value jv_two;
632  jv_two[jss::tx_json] = jrr[jss::tx_json];
633  becky_sign(jv_two);
634  jrr = env.rpc("json", "sign_for", to_string(jv_two))[jss::result];
635  BEAST_EXPECT(jrr[jss::status] == "success");
636 
637  Json::Value jv_submit;
638  jv_submit[jss::tx_json] = jrr[jss::tx_json];
639  jrr = env.rpc(
640  "json",
641  "submit_multisigned",
642  to_string(jv_submit))[jss::result];
643  BEAST_EXPECT(jrr[jss::status] == "error");
644  BEAST_EXPECT(jrr[jss::error] == "internal");
645  BEAST_EXPECT(jrr[jss::error_message] == "Internal error.");
646  }
647 
648  {
649  // cheri should not be able to multisign using her master key.
650  aliceSeq = env.seq(alice);
651  Json::Value jv = setup_tx();
652  jv[jss::account] = cheri.human();
653  jv[jss::secret] = cheri.name();
654  auto jrr = env.rpc("json", "sign_for", to_string(jv))[jss::result];
655  BEAST_EXPECT(jrr[jss::status] == "error");
656  BEAST_EXPECT(jrr[jss::error] == "masterDisabled");
657  env.close();
658  BEAST_EXPECT(env.seq(alice) == aliceSeq);
659  }
660 
661  {
662  // Unlike cheri, becky should also be able to sign using her master
663  // key
664  aliceSeq = env.seq(alice);
665  Json::Value jv_one = setup_tx();
666  cheri_sign(jv_one);
667  auto jrr =
668  env.rpc("json", "sign_for", to_string(jv_one))[jss::result];
669  BEAST_EXPECT(jrr[jss::status] == "success");
670 
671  // for the second sign_for, use the returned tx_json with
672  // first signer info
673  Json::Value jv_two;
674  jv_two[jss::tx_json] = jrr[jss::tx_json];
675  jv_two[jss::account] = becky.human();
676  jv_two[jss::key_type] = "ed25519";
677  jv_two[jss::passphrase] = becky.name();
678  jrr = env.rpc("json", "sign_for", to_string(jv_two))[jss::result];
679  BEAST_EXPECT(jrr[jss::status] == "success");
680 
681  Json::Value jv_submit;
682  jv_submit[jss::tx_json] = jrr[jss::tx_json];
683  jrr = env.rpc(
684  "json",
685  "submit_multisigned",
686  to_string(jv_submit))[jss::result];
687  BEAST_EXPECT(jrr[jss::status] == "success");
688  env.close();
689  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
690  }
691 
692  {
693  // check for bad or bogus accounts in the tx
694  Json::Value jv = setup_tx();
695  jv[jss::tx_json][jss::Account] = "DEADBEEF";
696  cheri_sign(jv);
697  auto jrr = env.rpc("json", "sign_for", to_string(jv))[jss::result];
698  BEAST_EXPECT(jrr[jss::status] == "error");
699  BEAST_EXPECT(jrr[jss::error] == "srcActMalformed");
700 
701  Account const jimmy{"jimmy"};
702  jv[jss::tx_json][jss::Account] = jimmy.human();
703  jrr = env.rpc("json", "sign_for", to_string(jv))[jss::result];
704  BEAST_EXPECT(jrr[jss::status] == "error");
705  BEAST_EXPECT(jrr[jss::error] == "srcActNotFound");
706  }
707 
708  {
709  aliceSeq = env.seq(alice);
710  Json::Value jv = setup_tx();
711  jv[jss::tx_json][sfSigners.fieldName] =
713  becky_sign(jv);
714  auto jrr = env.rpc(
715  "json", "submit_multisigned", to_string(jv))[jss::result];
716  BEAST_EXPECT(jrr[jss::status] == "error");
717  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
718  BEAST_EXPECT(
719  jrr[jss::error_message] ==
720  "tx_json.Signers array may not be empty.");
721  env.close();
722  BEAST_EXPECT(env.seq(alice) == aliceSeq);
723  }
724  }
725 
726  void
728  {
729  testcase("Heterogenious Signers");
730 
731  using namespace jtx;
732  Env env{*this, features};
733  Account const alice{"alice", KeyType::secp256k1};
734  Account const becky{"becky", KeyType::ed25519};
735  Account const cheri{"cheri", KeyType::secp256k1};
736  Account const daria{"daria", KeyType::ed25519};
737  env.fund(XRP(1000), alice, becky, cheri, daria);
738  env.close();
739 
740  // alice uses a regular key with the master disabled.
741  Account const alie{"alie", KeyType::secp256k1};
742  env(regkey(alice, alie));
743  env(fset(alice, asfDisableMaster), sig(alice));
744 
745  // becky is master only without a regular key.
746 
747  // cheri has a regular key, but leaves the master key enabled.
748  Account const cher{"cher", KeyType::secp256k1};
749  env(regkey(cheri, cher));
750 
751  // daria has a regular key and disables her master key.
752  Account const dari{"dari", KeyType::ed25519};
753  env(regkey(daria, dari));
754  env(fset(daria, asfDisableMaster), sig(daria));
755  env.close();
756 
757  // Attach signers to alice.
758  env(signers(alice, 1, {{becky, 1}, {cheri, 1}, {daria, 1}, {jinni, 1}}),
759  sig(alie));
760  env.close();
761  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 6));
762 
763  // Each type of signer should succeed individually.
764  auto const baseFee = env.current()->fees().base;
765  std::uint32_t aliceSeq = env.seq(alice);
766  env(noop(alice), msig(becky), fee(2 * baseFee));
767  env.close();
768  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
769 
770  aliceSeq = env.seq(alice);
771  env(noop(alice), msig(cheri), fee(2 * baseFee));
772  env.close();
773  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
774 
775  aliceSeq = env.seq(alice);
776  env(noop(alice), msig(msig::Reg{cheri, cher}), fee(2 * baseFee));
777  env.close();
778  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
779 
780  aliceSeq = env.seq(alice);
781  env(noop(alice), msig(msig::Reg{daria, dari}), fee(2 * baseFee));
782  env.close();
783  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
784 
785  aliceSeq = env.seq(alice);
786  env(noop(alice), msig(jinni), fee(2 * baseFee));
787  env.close();
788  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
789 
790  // Should also work if all signers sign.
791  aliceSeq = env.seq(alice);
792  env(noop(alice),
793  fee(5 * baseFee),
794  msig(becky, msig::Reg{cheri, cher}, msig::Reg{daria, dari}, jinni));
795  env.close();
796  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
797 
798  // Require all signers to sign.
799  env(signers(
800  alice,
801  0x3FFFC,
802  {{becky, 0xFFFF},
803  {cheri, 0xFFFF},
804  {daria, 0xFFFF},
805  {jinni, 0xFFFF}}),
806  sig(alie));
807  env.close();
808  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 6));
809 
810  aliceSeq = env.seq(alice);
811  env(noop(alice),
812  fee(9 * baseFee),
813  msig(becky, msig::Reg{cheri, cher}, msig::Reg{daria, dari}, jinni));
814  env.close();
815  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
816 
817  // Try cheri with both key types.
818  aliceSeq = env.seq(alice);
819  env(noop(alice),
820  fee(5 * baseFee),
821  msig(becky, cheri, msig::Reg{daria, dari}, jinni));
822  env.close();
823  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
824 
825  // Makes sure the maximum allowed number of signers works.
826  env(signers(
827  alice,
828  0x7FFF8,
829  {{becky, 0xFFFF},
830  {cheri, 0xFFFF},
831  {daria, 0xFFFF},
832  {haunt, 0xFFFF},
833  {jinni, 0xFFFF},
834  {phase, 0xFFFF},
835  {shade, 0xFFFF},
836  {spook, 0xFFFF}}),
837  sig(alie));
838  env.close();
839  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 10));
840 
841  aliceSeq = env.seq(alice);
842  env(noop(alice),
843  fee(9 * baseFee),
844  msig(
845  becky,
846  msig::Reg{cheri, cher},
847  msig::Reg{daria, dari},
848  haunt,
849  jinni,
850  phase,
851  shade,
852  spook));
853  env.close();
854  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
855 
856  // One signer short should fail.
857  aliceSeq = env.seq(alice);
858  env(noop(alice),
859  msig(becky, cheri, haunt, jinni, phase, shade, spook),
860  fee(8 * baseFee),
861  ter(tefBAD_QUORUM));
862  env.close();
863  BEAST_EXPECT(env.seq(alice) == aliceSeq);
864 
865  // Remove alice's signer list and get the owner count back.
866  env(signers(alice, jtx::none), sig(alie));
867  env.close();
868  env.require(owners(alice, 0));
869  }
870 
871  // We want to always leave an account signable. Make sure the that we
872  // disallow removing the last way a transaction may be signed.
873  void
875  {
876  testcase("Key Disable");
877 
878  using namespace jtx;
879  Env env{*this, features};
880  Account const alice{"alice", KeyType::ed25519};
881  env.fund(XRP(1000), alice);
882 
883  // There are three negative tests we need to make:
884  // M0. A lone master key cannot be disabled.
885  // R0. A lone regular key cannot be removed.
886  // L0. A lone signer list cannot be removed.
887  //
888  // Additionally, there are 6 positive tests we need to make:
889  // M1. The master key can be disabled if there's a regular key.
890  // M2. The master key can be disabled if there's a signer list.
891  //
892  // R1. The regular key can be removed if there's a signer list.
893  // R2. The regular key can be removed if the master key is enabled.
894  //
895  // L1. The signer list can be removed if the master key is enabled.
896  // L2. The signer list can be removed if there's a regular key.
897 
898  // Master key tests.
899  // M0: A lone master key cannot be disabled.
900  env(fset(alice, asfDisableMaster),
901  sig(alice),
903 
904  // Add a regular key.
905  Account const alie{"alie", KeyType::ed25519};
906  env(regkey(alice, alie));
907 
908  // M1: The master key can be disabled if there's a regular key.
909  env(fset(alice, asfDisableMaster), sig(alice));
910 
911  // R0: A lone regular key cannot be removed.
912  env(regkey(alice, disabled), sig(alie), ter(tecNO_ALTERNATIVE_KEY));
913 
914  // Add a signer list.
915  env(signers(alice, 1, {{bogie, 1}}), sig(alie));
916 
917  // R1: The regular key can be removed if there's a signer list.
918  env(regkey(alice, disabled), sig(alie));
919 
920  // L0: A lone signer list cannot be removed.
921  auto const baseFee = env.current()->fees().base;
922  env(signers(alice, jtx::none),
923  msig(bogie),
924  fee(2 * baseFee),
926 
927  // Enable the master key.
928  env(fclear(alice, asfDisableMaster), msig(bogie), fee(2 * baseFee));
929 
930  // L1: The signer list can be removed if the master key is enabled.
931  env(signers(alice, jtx::none), msig(bogie), fee(2 * baseFee));
932 
933  // Add a signer list.
934  env(signers(alice, 1, {{bogie, 1}}), sig(alice));
935 
936  // M2: The master key can be disabled if there's a signer list.
937  env(fset(alice, asfDisableMaster), sig(alice));
938 
939  // Add a regular key.
940  env(regkey(alice, alie), msig(bogie), fee(2 * baseFee));
941 
942  // L2: The signer list can be removed if there's a regular key.
943  env(signers(alice, jtx::none), sig(alie));
944 
945  // Enable the master key.
946  env(fclear(alice, asfDisableMaster), sig(alie));
947 
948  // R2: The regular key can be removed if the master key is enabled.
949  env(regkey(alice, disabled), sig(alie));
950  }
951 
952  // Verify that the first regular key can be made for free using the
953  // master key, but not when multisigning.
954  void
956  {
957  testcase("Regular Key");
958 
959  using namespace jtx;
960  Env env{*this, features};
961  Account const alice{"alice", KeyType::secp256k1};
962  env.fund(XRP(1000), alice);
963 
964  // Give alice a regular key with a zero fee. Should succeed. Once.
965  Account const alie{"alie", KeyType::ed25519};
966  env(regkey(alice, alie), sig(alice), fee(0));
967 
968  // Try it again and creating the regular key for free should fail.
969  Account const liss{"liss", KeyType::secp256k1};
970  env(regkey(alice, liss), sig(alice), fee(0), ter(telINSUF_FEE_P));
971 
972  // But paying to create a regular key should succeed.
973  env(regkey(alice, liss), sig(alice));
974 
975  // In contrast, trying to multisign for a regular key with a zero
976  // fee should always fail. Even the first time.
977  Account const becky{"becky", KeyType::ed25519};
978  env.fund(XRP(1000), becky);
979 
980  env(signers(becky, 1, {{alice, 1}}), sig(becky));
981  env(regkey(becky, alie), msig(alice), fee(0), ter(telINSUF_FEE_P));
982 
983  // Using the master key to sign for a regular key for free should
984  // still work.
985  env(regkey(becky, alie), sig(becky), fee(0));
986  }
987 
988  // See if every kind of transaction can be successfully multi-signed.
989  void
991  {
992  testcase("Transaction Types");
993 
994  using namespace jtx;
995  Env env{*this, features};
996  Account const alice{"alice", KeyType::secp256k1};
997  Account const becky{"becky", KeyType::ed25519};
998  Account const zelda{"zelda", KeyType::secp256k1};
999  Account const gw{"gw"};
1000  auto const USD = gw["USD"];
1001  env.fund(XRP(1000), alice, becky, zelda, gw);
1002  env.close();
1003 
1004  // alice uses a regular key with the master disabled.
1005  Account const alie{"alie", KeyType::secp256k1};
1006  env(regkey(alice, alie));
1007  env(fset(alice, asfDisableMaster), sig(alice));
1008 
1009  // Attach signers to alice.
1010  env(signers(alice, 2, {{becky, 1}, {bogie, 1}}), sig(alie));
1011  env.close();
1012  int const signerListOwners{features[featureMultiSignReserve] ? 1 : 4};
1013  env.require(owners(alice, signerListOwners + 0));
1014 
1015  // Multisign a ttPAYMENT.
1016  auto const baseFee = env.current()->fees().base;
1017  std::uint32_t aliceSeq = env.seq(alice);
1018  env(pay(alice, env.master, XRP(1)),
1019  msig(becky, bogie),
1020  fee(3 * baseFee));
1021  env.close();
1022  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1023 
1024  // Multisign a ttACCOUNT_SET.
1025  aliceSeq = env.seq(alice);
1026  env(noop(alice), msig(becky, bogie), fee(3 * baseFee));
1027  env.close();
1028  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1029 
1030  // Multisign a ttREGULAR_KEY_SET.
1031  aliceSeq = env.seq(alice);
1032  Account const ace{"ace", KeyType::secp256k1};
1033  env(regkey(alice, ace), msig(becky, bogie), fee(3 * baseFee));
1034  env.close();
1035  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1036 
1037  // Multisign a ttTRUST_SET
1038  env(trust("alice", USD(100)),
1039  msig(becky, bogie),
1040  fee(3 * baseFee),
1041  require(lines("alice", 1)));
1042  env.close();
1043  env.require(owners(alice, signerListOwners + 1));
1044 
1045  // Multisign a ttOFFER_CREATE transaction.
1046  env(pay(gw, alice, USD(50)));
1047  env.close();
1048  env.require(balance(alice, USD(50)));
1049  env.require(balance(gw, alice["USD"](-50)));
1050 
1051  std::uint32_t const offerSeq = env.seq(alice);
1052  env(offer(alice, XRP(50), USD(50)),
1053  msig(becky, bogie),
1054  fee(3 * baseFee));
1055  env.close();
1056  env.require(owners(alice, signerListOwners + 2));
1057 
1058  // Now multisign a ttOFFER_CANCEL canceling the offer we just created.
1059  {
1060  aliceSeq = env.seq(alice);
1061  env(offer_cancel(alice, offerSeq),
1062  seq(aliceSeq),
1063  msig(becky, bogie),
1064  fee(3 * baseFee));
1065  env.close();
1066  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1067  env.require(owners(alice, signerListOwners + 1));
1068  }
1069 
1070  // Multisign a ttSIGNER_LIST_SET.
1071  env(signers(alice, 3, {{becky, 1}, {bogie, 1}, {demon, 1}}),
1072  msig(becky, bogie),
1073  fee(3 * baseFee));
1074  env.close();
1075  env.require(owners(alice, features[featureMultiSignReserve] ? 2 : 6));
1076  }
1077 
1078  void
1080  {
1081  testcase("Bad Signature Text");
1082 
1083  // Verify that the text returned for signature failures is correct.
1084  using namespace jtx;
1085 
1086  Env env{*this, features};
1087 
1088  // lambda that submits an STTx and returns the resulting JSON.
1089  auto submitSTTx = [&env](STTx const& stx) {
1090  Json::Value jvResult;
1091  jvResult[jss::tx_blob] = strHex(stx.getSerializer().slice());
1092  return env.rpc("json", "submit", to_string(jvResult));
1093  };
1094 
1095  Account const alice{"alice"};
1096  env.fund(XRP(1000), alice);
1097  env(signers(alice, 1, {{bogie, 1}, {demon, 1}}), sig(alice));
1098 
1099  auto const baseFee = env.current()->fees().base;
1100  {
1101  // Single-sign, but leave an empty SigningPubKey.
1102  JTx tx = env.jt(noop(alice), sig(alice));
1103  STTx local = *(tx.stx);
1104  local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey
1105  auto const info = submitSTTx(local);
1106  BEAST_EXPECT(
1107  info[jss::result][jss::error_exception] ==
1108  "fails local checks: Empty SigningPubKey.");
1109  }
1110  {
1111  // Single-sign, but invalidate the signature.
1112  JTx tx = env.jt(noop(alice), sig(alice));
1113  STTx local = *(tx.stx);
1114  // Flip some bits in the signature.
1115  auto badSig = local.getFieldVL(sfTxnSignature);
1116  badSig[20] ^= 0xAA;
1117  local.setFieldVL(sfTxnSignature, badSig);
1118  // Signature should fail.
1119  auto const info = submitSTTx(local);
1120  BEAST_EXPECT(
1121  info[jss::result][jss::error_exception] ==
1122  "fails local checks: Invalid signature.");
1123  }
1124  {
1125  // Single-sign, but invalidate the sequence number.
1126  JTx tx = env.jt(noop(alice), sig(alice));
1127  STTx local = *(tx.stx);
1128  // Flip some bits in the signature.
1129  auto seq = local.getFieldU32(sfSequence);
1130  local.setFieldU32(sfSequence, seq + 1);
1131  // Signature should fail.
1132  auto const info = submitSTTx(local);
1133  BEAST_EXPECT(
1134  info[jss::result][jss::error_exception] ==
1135  "fails local checks: Invalid signature.");
1136  }
1137  {
1138  // Multisign, but leave a nonempty sfSigningPubKey.
1139  JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(bogie));
1140  STTx local = *(tx.stx);
1141  local[sfSigningPubKey] = alice.pk(); // Insert sfSigningPubKey
1142  auto const info = submitSTTx(local);
1143  BEAST_EXPECT(
1144  info[jss::result][jss::error_exception] ==
1145  "fails local checks: Cannot both single- and multi-sign.");
1146  }
1147  {
1148  // Both multi- and single-sign with an empty SigningPubKey.
1149  JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(bogie));
1150  STTx local = *(tx.stx);
1151  local.sign(alice.pk(), alice.sk());
1152  local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey
1153  auto const info = submitSTTx(local);
1154  BEAST_EXPECT(
1155  info[jss::result][jss::error_exception] ==
1156  "fails local checks: Cannot both single- and multi-sign.");
1157  }
1158  {
1159  // Multisign but invalidate one of the signatures.
1160  JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(bogie));
1161  STTx local = *(tx.stx);
1162  // Flip some bits in the signature.
1163  auto& signer = local.peekFieldArray(sfSigners).back();
1164  auto badSig = signer.getFieldVL(sfTxnSignature);
1165  badSig[20] ^= 0xAA;
1166  signer.setFieldVL(sfTxnSignature, badSig);
1167  // Signature should fail.
1168  auto const info = submitSTTx(local);
1169  BEAST_EXPECT(
1170  info[jss::result][jss::error_exception].asString().find(
1171  "Invalid signature on account r") != std::string::npos);
1172  }
1173  {
1174  // Multisign with an empty signers array should fail.
1175  JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(bogie));
1176  STTx local = *(tx.stx);
1177  local.peekFieldArray(sfSigners).clear(); // Empty Signers array.
1178  auto const info = submitSTTx(local);
1179  BEAST_EXPECT(
1180  info[jss::result][jss::error_exception] ==
1181  "fails local checks: Invalid Signers array size.");
1182  }
1183  {
1184  // Multisign 9 (!ExpandedSignerList) | 33 (ExpandedSignerList) times
1185  // should fail.
1186  JTx tx = env.jt(
1187  noop(alice),
1188  fee(2 * baseFee),
1189 
1190  features[featureExpandedSignerList] ? msig(
1191  bogie,
1192  bogie,
1193  bogie,
1194  bogie,
1195  bogie,
1196  bogie,
1197  bogie,
1198  bogie,
1199  bogie,
1200  bogie,
1201  bogie,
1202  bogie,
1203  bogie,
1204  bogie,
1205  bogie,
1206  bogie,
1207  bogie,
1208  bogie,
1209  bogie,
1210  bogie,
1211  bogie,
1212  bogie,
1213  bogie,
1214  bogie,
1215  bogie,
1216  bogie,
1217  bogie,
1218  bogie,
1219  bogie,
1220  bogie,
1221  bogie,
1222  bogie,
1223  bogie)
1224  : msig(
1225  bogie,
1226  bogie,
1227  bogie,
1228  bogie,
1229  bogie,
1230  bogie,
1231  bogie,
1232  bogie,
1233  bogie));
1234  STTx local = *(tx.stx);
1235  auto const info = submitSTTx(local);
1236  BEAST_EXPECT(
1237  info[jss::result][jss::error_exception] ==
1238  "fails local checks: Invalid Signers array size.");
1239  }
1240  {
1241  // The account owner may not multisign for themselves.
1242  JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(alice));
1243  STTx local = *(tx.stx);
1244  auto const info = submitSTTx(local);
1245  BEAST_EXPECT(
1246  info[jss::result][jss::error_exception] ==
1247  "fails local checks: Invalid multisigner.");
1248  }
1249  {
1250  // No duplicate multisignatures allowed.
1251  JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(bogie, bogie));
1252  STTx local = *(tx.stx);
1253  auto const info = submitSTTx(local);
1254  BEAST_EXPECT(
1255  info[jss::result][jss::error_exception] ==
1256  "fails local checks: Duplicate Signers not allowed.");
1257  }
1258  {
1259  // Multisignatures must be submitted in sorted order.
1260  JTx tx = env.jt(noop(alice), fee(2 * baseFee), msig(bogie, demon));
1261  STTx local = *(tx.stx);
1262  // Unsort the Signers array.
1263  auto& signers = local.peekFieldArray(sfSigners);
1264  std::reverse(signers.begin(), signers.end());
1265  // Signature should fail.
1266  auto const info = submitSTTx(local);
1267  BEAST_EXPECT(
1268  info[jss::result][jss::error_exception] ==
1269  "fails local checks: Unsorted Signers array.");
1270  }
1271  }
1272 
1273  void
1275  {
1276  testcase("No Multisigners");
1277 
1278  using namespace jtx;
1279  Env env{*this, features};
1280  Account const alice{"alice", KeyType::ed25519};
1281  Account const becky{"becky", KeyType::secp256k1};
1282  env.fund(XRP(1000), alice, becky);
1283  env.close();
1284 
1285  auto const baseFee = env.current()->fees().base;
1286  env(noop(alice),
1287  msig(becky, demon),
1288  fee(3 * baseFee),
1290  }
1291 
1292  void
1294  {
1295  testcase("Multisigning multisigner");
1296 
1297  // Set up a signer list where one of the signers has both the
1298  // master disabled and no regular key (because that signer is
1299  // exclusively multisigning). That signer should no longer be
1300  // able to successfully sign the signer list.
1301 
1302  using namespace jtx;
1303  Env env{*this, features};
1304  Account const alice{"alice", KeyType::ed25519};
1305  Account const becky{"becky", KeyType::secp256k1};
1306  env.fund(XRP(1000), alice, becky);
1307  env.close();
1308 
1309  // alice sets up a signer list with becky as a signer.
1310  env(signers(alice, 1, {{becky, 1}}));
1311  env.close();
1312 
1313  // becky sets up her signer list.
1314  env(signers(becky, 1, {{bogie, 1}, {demon, 1}}));
1315  env.close();
1316 
1317  // Because becky has not (yet) disabled her master key, she can
1318  // multisign a transaction for alice.
1319  auto const baseFee = env.current()->fees().base;
1320  env(noop(alice), msig(becky), fee(2 * baseFee));
1321  env.close();
1322 
1323  // Now becky disables her master key.
1324  env(fset(becky, asfDisableMaster));
1325  env.close();
1326 
1327  // Since becky's master key is disabled she can no longer
1328  // multisign for alice.
1329  env(noop(alice),
1330  msig(becky),
1331  fee(2 * baseFee),
1333  env.close();
1334 
1335  // Becky cannot 2-level multisign for alice. 2-level multisigning
1336  // is not supported.
1337  env(noop(alice),
1338  msig(msig::Reg{becky, bogie}),
1339  fee(2 * baseFee),
1341  env.close();
1342 
1343  // Verify that becky cannot sign with a regular key that she has
1344  // not yet enabled.
1345  Account const beck{"beck", KeyType::ed25519};
1346  env(noop(alice),
1347  msig(msig::Reg{becky, beck}),
1348  fee(2 * baseFee),
1350  env.close();
1351 
1352  // Once becky gives herself the regular key, she can sign for alice
1353  // using that regular key.
1354  env(regkey(becky, beck), msig(demon), fee(2 * baseFee));
1355  env.close();
1356 
1357  env(noop(alice), msig(msig::Reg{becky, beck}), fee(2 * baseFee));
1358  env.close();
1359 
1360  // The presence of becky's regular key does not influence whether she
1361  // can 2-level multisign; it still won't work.
1362  env(noop(alice),
1363  msig(msig::Reg{becky, demon}),
1364  fee(2 * baseFee),
1366  env.close();
1367  }
1368 
1369  void
1371  {
1372  testcase("sign_for Hash");
1373 
1374  // Make sure that the "hash" field returned by the "sign_for" RPC
1375  // command matches the hash returned when that command is sent
1376  // through "submit_multisigned". Make sure that hash also locates
1377  // the transaction in the ledger.
1378  using namespace jtx;
1379  Account const alice{"alice", KeyType::ed25519};
1380 
1381  Env env(
1382  *this,
1384  cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
1385  return cfg;
1386  }),
1387  features);
1388  env.fund(XRP(1000), alice);
1389  env.close();
1390 
1391  env(signers(alice, 2, {{bogie, 1}, {ghost, 1}}));
1392  env.close();
1393 
1394  // Use sign_for to sign a transaction where alice pays 10 XRP to
1395  // masterpassphrase.
1396  auto const baseFee = env.current()->fees().base;
1397  Json::Value jvSig1;
1398  jvSig1[jss::account] = bogie.human();
1399  jvSig1[jss::secret] = bogie.name();
1400  jvSig1[jss::tx_json][jss::Account] = alice.human();
1401  jvSig1[jss::tx_json][jss::Amount] = 10000000;
1402  jvSig1[jss::tx_json][jss::Destination] = env.master.human();
1403  jvSig1[jss::tx_json][jss::Fee] = (3 * baseFee).jsonClipped();
1404  jvSig1[jss::tx_json][jss::Sequence] = env.seq(alice);
1405  jvSig1[jss::tx_json][jss::TransactionType] = jss::Payment;
1406 
1407  Json::Value jvSig2 = env.rpc("json", "sign_for", to_string(jvSig1));
1408  BEAST_EXPECT(jvSig2[jss::result][jss::status].asString() == "success");
1409 
1410  // Save the hash with one signature for use later.
1411  std::string const hash1 =
1412  jvSig2[jss::result][jss::tx_json][jss::hash].asString();
1413 
1414  // Add the next signature and sign again.
1415  jvSig2[jss::result][jss::account] = ghost.human();
1416  jvSig2[jss::result][jss::secret] = ghost.name();
1417  Json::Value jvSubmit =
1418  env.rpc("json", "sign_for", to_string(jvSig2[jss::result]));
1419  BEAST_EXPECT(
1420  jvSubmit[jss::result][jss::status].asString() == "success");
1421 
1422  // Save the hash with two signatures for use later.
1423  std::string const hash2 =
1424  jvSubmit[jss::result][jss::tx_json][jss::hash].asString();
1425  BEAST_EXPECT(hash1 != hash2);
1426 
1427  // Submit the result of the two signatures.
1428  Json::Value jvResult = env.rpc(
1429  "json", "submit_multisigned", to_string(jvSubmit[jss::result]));
1430  BEAST_EXPECT(
1431  jvResult[jss::result][jss::status].asString() == "success");
1432  BEAST_EXPECT(
1433  jvResult[jss::result][jss::engine_result].asString() ==
1434  "tesSUCCESS");
1435 
1436  // The hash from the submit should be the same as the hash from the
1437  // second signing.
1438  BEAST_EXPECT(
1439  hash2 == jvResult[jss::result][jss::tx_json][jss::hash].asString());
1440  env.close();
1441 
1442  // The transaction we just submitted should now be available and
1443  // validated.
1444  Json::Value jvTx = env.rpc("tx", hash2);
1445  BEAST_EXPECT(jvTx[jss::result][jss::status].asString() == "success");
1446  BEAST_EXPECT(jvTx[jss::result][jss::validated].asString() == "true");
1447  BEAST_EXPECT(
1448  jvTx[jss::result][jss::meta][sfTransactionResult.jsonName]
1449  .asString() == "tesSUCCESS");
1450  }
1451 
1452  void
1454  {
1455  testcase("Amendment Transition");
1456 
1457  // The OwnerCount associated with a SignerList changes once the
1458  // featureMultiSignReserve amendment goes live. Create a couple
1459  // of signer lists before and after the amendment goes live and
1460  // verify that the OwnerCount is managed properly for all of them.
1461  using namespace jtx;
1462  Account const alice{"alice", KeyType::secp256k1};
1463  Account const becky{"becky", KeyType::ed25519};
1464  Account const cheri{"cheri", KeyType::secp256k1};
1465  Account const daria{"daria", KeyType::ed25519};
1466 
1468  env.fund(XRP(1000), alice, becky, cheri, daria);
1469  env.close();
1470 
1471  // Give alice and becky signer lists before the amendment goes live.
1472  env(signers(alice, 1, {{bogie, 1}}));
1473  env(signers(
1474  becky,
1475  1,
1476  {{bogie, 1},
1477  {demon, 1},
1478  {ghost, 1},
1479  {haunt, 1},
1480  {jinni, 1},
1481  {phase, 1},
1482  {shade, 1},
1483  {spook, 1}}));
1484  env.close();
1485 
1486  env.require(owners(alice, 3));
1487  env.require(owners(becky, 10));
1488 
1489  // Enable the amendment.
1490  env.enableFeature(featureMultiSignReserve);
1491  env.close();
1492 
1493  // Give cheri and daria signer lists after the amendment goes live.
1494  env(signers(cheri, 1, {{bogie, 1}}));
1495  env(signers(
1496  daria,
1497  1,
1498  {{bogie, 1},
1499  {demon, 1},
1500  {ghost, 1},
1501  {haunt, 1},
1502  {jinni, 1},
1503  {phase, 1},
1504  {shade, 1},
1505  {spook, 1}}));
1506  env.close();
1507 
1508  env.require(owners(alice, 3));
1509  env.require(owners(becky, 10));
1510  env.require(owners(cheri, 1));
1511  env.require(owners(daria, 1));
1512 
1513  // Delete becky's signer list; her OwnerCount should drop to zero.
1514  // Replace alice's signer list; her OwnerCount should drop to one.
1515  env(signers(becky, jtx::none));
1516  env(signers(
1517  alice,
1518  1,
1519  {{bogie, 1},
1520  {demon, 1},
1521  {ghost, 1},
1522  {haunt, 1},
1523  {jinni, 1},
1524  {phase, 1},
1525  {shade, 1},
1526  {spook, 1}}));
1527  env.close();
1528 
1529  env.require(owners(alice, 1));
1530  env.require(owners(becky, 0));
1531  env.require(owners(cheri, 1));
1532  env.require(owners(daria, 1));
1533 
1534  // Delete the three remaining signer lists. Everybody's OwnerCount
1535  // should now be zero.
1536  env(signers(alice, jtx::none));
1537  env(signers(cheri, jtx::none));
1538  env(signers(daria, jtx::none));
1539  env.close();
1540 
1541  env.require(owners(alice, 0));
1542  env.require(owners(becky, 0));
1543  env.require(owners(cheri, 0));
1544  env.require(owners(daria, 0));
1545  }
1546 
1547  void
1549  {
1550  testcase("Signers With Tickets");
1551 
1552  using namespace jtx;
1553  Env env{*this, features};
1554  Account const alice{"alice", KeyType::ed25519};
1555  env.fund(XRP(2000), alice);
1556  env.close();
1557 
1558  // Create a few tickets that alice can use up.
1559  std::uint32_t aliceTicketSeq{env.seq(alice) + 1};
1560  env(ticket::create(alice, 20));
1561  env.close();
1562  std::uint32_t const aliceSeq = env.seq(alice);
1563 
1564  // Attach phantom signers to alice using a ticket.
1565  env(signers(alice, 1, {{bogie, 1}, {demon, 1}}),
1566  ticket::use(aliceTicketSeq++));
1567  env.close();
1568  env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1569  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1570 
1571  // This should work.
1572  auto const baseFee = env.current()->fees().base;
1573  env(noop(alice),
1574  msig(bogie, demon),
1575  fee(3 * baseFee),
1576  ticket::use(aliceTicketSeq++));
1577  env.close();
1578  env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1579  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1580 
1581  // Should also be able to remove the signer list using a ticket.
1582  env(signers(alice, jtx::none), ticket::use(aliceTicketSeq++));
1583  env.close();
1584  env.require(tickets(alice, env.seq(alice) - aliceTicketSeq));
1585  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1586  }
1587 
1588  void
1590  {
1591  if (!features[featureExpandedSignerList])
1592  return;
1593 
1594  testcase("Signers With Tags");
1595 
1596  using namespace jtx;
1597  Env env{*this, features};
1598  Account const alice{"alice", KeyType::ed25519};
1599  env.fund(XRP(1000), alice);
1600  env.close();
1601  uint8_t tag1[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
1602  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
1603  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
1604  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
1605 
1606  uint8_t tag2[] =
1607  "hello world some ascii 32b long"; // including 1 byte for NUL
1608 
1609  uint256 bogie_tag = ripple::base_uint<256>::fromVoid(tag1);
1610  uint256 demon_tag = ripple::base_uint<256>::fromVoid(tag2);
1611 
1612  // Attach phantom signers to alice and use them for a transaction.
1613  env(signers(alice, 1, {{bogie, 1, bogie_tag}, {demon, 1, demon_tag}}));
1614  env.close();
1615  env.require(owners(alice, features[featureMultiSignReserve] ? 1 : 4));
1616 
1617  // This should work.
1618  auto const baseFee = env.current()->fees().base;
1619  std::uint32_t aliceSeq = env.seq(alice);
1620  env(noop(alice), msig(bogie, demon), fee(3 * baseFee));
1621  env.close();
1622  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1623 
1624  // Either signer alone should work.
1625  aliceSeq = env.seq(alice);
1626  env(noop(alice), msig(bogie), fee(2 * baseFee));
1627  env.close();
1628  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1629 
1630  aliceSeq = env.seq(alice);
1631  env(noop(alice), msig(demon), fee(2 * baseFee));
1632  env.close();
1633  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1634 
1635  // Duplicate signers should fail.
1636  aliceSeq = env.seq(alice);
1637  env(noop(alice), msig(demon, demon), fee(3 * baseFee), ter(temINVALID));
1638  env.close();
1639  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1640 
1641  // A non-signer should fail.
1642  aliceSeq = env.seq(alice);
1643  env(noop(alice),
1644  msig(bogie, spook),
1645  fee(3 * baseFee),
1647  env.close();
1648  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1649 
1650  // Don't meet the quorum. Should fail.
1651  env(signers(alice, 2, {{bogie, 1}, {demon, 1}}));
1652  aliceSeq = env.seq(alice);
1653  env(noop(alice), msig(bogie), fee(2 * baseFee), ter(tefBAD_QUORUM));
1654  env.close();
1655  BEAST_EXPECT(env.seq(alice) == aliceSeq);
1656 
1657  // Meet the quorum. Should succeed.
1658  aliceSeq = env.seq(alice);
1659  env(noop(alice), msig(bogie, demon), fee(3 * baseFee));
1660  env.close();
1661  BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1662  }
1663 
1664  void
1666  {
1667  test_noReserve(features);
1668  test_signerListSet(features);
1669  test_phantomSigners(features);
1670  test_fee(features);
1671  test_misorderedSigners(features);
1672  test_masterSigners(features);
1673  test_regularSigners(features);
1675  test_heterogeneousSigners(features);
1676  test_keyDisable(features);
1677  test_regKey(features);
1678  test_txTypes(features);
1679  test_badSignatureText(features);
1680  test_noMultiSigners(features);
1681  test_multisigningMultisigner(features);
1682  test_signForHash(features);
1683  test_signersWithTickets(features);
1684  test_signersWithTags(features);
1685  }
1686 
1687  void
1688  run() override
1689  {
1690  using namespace jtx;
1691  auto const all = supported_amendments();
1692 
1693  // The reserve required on a signer list changes based on
1694  // featureMultiSignReserve. Limits on the number of signers
1695  // changes based on featureExpandedSignerList. Test both with and
1696  // without.
1699  testAll(all);
1701  }
1702 };
1703 
1704 BEAST_DEFINE_TESTSUITE(MultiSign, app, ripple);
1705 
1706 } // namespace test
1707 } // namespace ripple
ripple::test::MultiSign_test::haunt
const jtx::Account haunt
Definition: MultiSign_test.cpp:32
ripple::test::jtx::Account::name
std::string const & name() const
Return the name.
Definition: Account.h:82
ripple::test::jtx::noop
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::Blob
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition: Blob.h:30
ripple::test::MultiSign_test
Definition: MultiSign_test.cpp:26
std::string
STL class.
ripple::test::jtx::none
static const none_t none
Definition: tags.h:34
ripple::sfSigners
const SField sfSigners
ripple::test::MultiSign_test::acc32
const jtx::Account acc32
Definition: MultiSign_test.cpp:59
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::test::MultiSign_test::ghost
const jtx::Account ghost
Definition: MultiSign_test.cpp:31
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::test::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::MultiSign_test::test_misorderedSigners
void test_misorderedSigners(FeatureBitset features)
Definition: MultiSign_test.cpp:342
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::TxSearched::all
@ all
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
std::vector
STL class.
ripple::test::jtx::trust
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition: trust.cpp:30
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:132
ripple::test::MultiSign_test::acc12
const jtx::Account acc12
Definition: MultiSign_test.cpp:39
ripple::test::MultiSign_test::acc31
const jtx::Account acc31
Definition: MultiSign_test.cpp:58
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
ripple::test::jtx::JTx::stx
std::shared_ptr< STTx const > stx
Definition: JTx.h:50
ripple::test::jtx::offer_cancel
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
Definition: offer.cpp:45
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:63
ripple::test::MultiSign_test::test_signersWithTags
void test_signersWithTags(FeatureBitset features)
Definition: MultiSign_test.cpp:1589
ripple::test::MultiSign_test::acc21
const jtx::Account acc21
Definition: MultiSign_test.cpp:48
ripple::test::MultiSign_test::acc10
const jtx::Account acc10
Definition: MultiSign_test.cpp:37
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
ripple::featureMultiSignReserve
const uint256 featureMultiSignReserve
ripple::test::jtx::msig::Reg
Definition: multisign.h:66
ripple::test::MultiSign_test::test_multisigningMultisigner
void test_multisigningMultisigner(FeatureBitset features)
Definition: MultiSign_test.cpp:1293
std::reverse
T reverse(T... args)
ripple::STObject::setFieldVL
void setFieldVL(SField const &field, Blob const &)
Definition: STObject.cpp:695
ripple::STObject::getFieldVL
Blob getFieldVL(SField const &field) const
Definition: STObject.cpp:595
ripple::test::MultiSign_test::acc20
const jtx::Account acc20
Definition: MultiSign_test.cpp:47
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::test::MultiSign_test::test_signersWithTickets
void test_signersWithTickets(FeatureBitset features)
Definition: MultiSign_test.cpp:1548
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:136
ripple::test::jtx::msig
Set a multisignature on a JTx.
Definition: multisign.h:63
ripple::test::jtx::signer
A signer in a SignerList.
Definition: multisign.h:35
ripple::test::MultiSign_test::test_txTypes
void test_txTypes(FeatureBitset features)
Definition: MultiSign_test.cpp:990
ripple::tefBAD_QUORUM
@ tefBAD_QUORUM
Definition: TER.h:162
ripple::KeyType::ed25519
@ ed25519
ripple::base_uint< 256 >
ripple::test::jtx::ticket::use
Set a ticket sequence on a JTx.
Definition: ticket.h:47
ripple::test::MultiSign_test::acc26
const jtx::Account acc26
Definition: MultiSign_test.cpp:53
ripple::temBAD_QUORUM
@ temBAD_QUORUM
Definition: TER.h:114
ripple::test::MultiSign_test::acc30
const jtx::Account acc30
Definition: MultiSign_test.cpp:57
ripple::asfDisableMaster
constexpr std::uint32_t asfDisableMaster
Definition: TxFlags.h:77
ripple::STArray::clear
void clear()
Definition: STArray.h:260
ripple::tecNO_ALTERNATIVE_KEY
@ tecNO_ALTERNATIVE_KEY
Definition: TER.h:263
ripple::test::MultiSign_test::acc19
const jtx::Account acc19
Definition: MultiSign_test.cpp:46
ripple::featureExpandedSignerList
const uint256 featureExpandedSignerList
ripple::test::MultiSign_test::demon
const jtx::Account demon
Definition: MultiSign_test.cpp:30
ripple::STObject::peekFieldArray
STArray & peekFieldArray(SField const &field)
Definition: STObject.cpp:445
ripple::test::MultiSign_test::acc33
const jtx::Account acc33
Definition: MultiSign_test.cpp:60
ripple::tefMASTER_DISABLED
@ tefMASTER_DISABLED
Definition: TER.h:159
ripple::test::MultiSign_test::acc15
const jtx::Account acc15
Definition: MultiSign_test.cpp:42
ripple::temBAD_SIGNER
@ temBAD_SIGNER
Definition: TER.h:113
ripple::test::jtx::JTx
Execution context for applying a JSON transaction.
Definition: JTx.h:42
ripple::test::MultiSign_test::acc11
const jtx::Account acc11
Definition: MultiSign_test.cpp:38
ripple::test::MultiSign_test::acc16
const jtx::Account acc16
Definition: MultiSign_test.cpp:43
ripple::test::MultiSign_test::test_regularSigners
void test_regularSigners(FeatureBitset features)
Definition: MultiSign_test.cpp:422
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
ripple::test::MultiSign_test::test_fee
void test_fee(FeatureBitset features)
Definition: MultiSign_test.cpp:278
ripple::telINSUF_FEE_P
@ telINSUF_FEE_P
Definition: TER.h:56
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::test::MultiSign_test::acc22
const jtx::Account acc22
Definition: MultiSign_test.cpp:49
ripple::test::MultiSign_test::acc25
const jtx::Account acc25
Definition: MultiSign_test.cpp:52
ripple::test::MultiSign_test::test_amendmentTransition
void test_amendmentTransition()
Definition: MultiSign_test.cpp:1453
ripple::STTx
Definition: STTx.h:45
ripple::test::MultiSign_test::spook
const jtx::Account spook
Definition: MultiSign_test.cpp:36
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
std::uint32_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::test::MultiSign_test::test_signForHash
void test_signForHash(FeatureBitset features)
Definition: MultiSign_test.cpp:1370
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:207
ripple::test::MultiSign_test::acc13
const jtx::Account acc13
Definition: MultiSign_test.cpp:40
ripple::STTx::sign
void sign(PublicKey const &publicKey, SecretKey const &secretKey)
Definition: STTx.cpp:198
ripple::test::jtx::fclear
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
ripple::test::MultiSign_test::test_noReserve
void test_noReserve(FeatureBitset features)
Definition: MultiSign_test.cpp:64
ripple::test::MultiSign_test::acc23
const jtx::Account acc23
Definition: MultiSign_test.cpp:50
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::KeyType::secp256k1
@ secp256k1
ripple::test::MultiSign_test::test_regKey
void test_regKey(FeatureBitset features)
Definition: MultiSign_test.cpp:955
ripple::test::MultiSign_test::testAll
void testAll(FeatureBitset features)
Definition: MultiSign_test.cpp:1665
ripple::test::MultiSign_test::acc24
const jtx::Account acc24
Definition: MultiSign_test.cpp:51
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::tefNOT_MULTI_SIGNING
@ tefNOT_MULTI_SIGNING
Definition: TER.h:163
ripple::sfTxnSignature
const SF_VL sfTxnSignature
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::MultiSign_test::test_badSignatureText
void test_badSignatureText(FeatureBitset features)
Definition: MultiSign_test.cpp:1079
ripple::test::MultiSign_test::test_phantomSigners
void test_phantomSigners(FeatureBitset features)
Definition: MultiSign_test.cpp:215
ripple::test::MultiSign_test::run
void run() override
Definition: MultiSign_test.cpp:1688
ripple::test::MultiSign_test::test_heterogeneousSigners
void test_heterogeneousSigners(FeatureBitset features)
Definition: MultiSign_test.cpp:727
ripple::sfTransactionResult
const SF_UINT8 sfTransactionResult
ripple::test::MultiSign_test::shade
const jtx::Account shade
Definition: MultiSign_test.cpp:35
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::test::MultiSign_test::test_keyDisable
void test_keyDisable(FeatureBitset features)
Definition: MultiSign_test.cpp:874
ripple::test::MultiSign_test::test_regularSignersUsingSubmitMulti
void test_regularSignersUsingSubmitMulti(FeatureBitset features)
Definition: MultiSign_test.cpp:487
ripple::test::jtx::regkey
Json::Value regkey(Account const &account, disabled_t)
Disable the regular key.
Definition: regkey.cpp:28
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::base_uint::fromVoid
static base_uint fromVoid(void const *data)
Definition: base_uint.h:312
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:121
ripple::test::MultiSign_test::acc17
const jtx::Account acc17
Definition: MultiSign_test.cpp:44
ripple::test::MultiSign_test::acc18
const jtx::Account acc18
Definition: MultiSign_test.cpp:45
ripple::test::MultiSign_test::jinni
const jtx::Account jinni
Definition: MultiSign_test.cpp:33
ripple::FeatureBitset
Definition: Feature.h:113
ripple::test::MultiSign_test::acc28
const jtx::Account acc28
Definition: MultiSign_test.cpp:55
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:274
ripple::test::MultiSign_test::acc29
const jtx::Account acc29
Definition: MultiSign_test.cpp:56
ripple::STArray::back
STObject & back()
Definition: STArray.h:193
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::MultiSign_test::test_masterSigners
void test_masterSigners(FeatureBitset features)
Definition: MultiSign_test.cpp:367
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:85
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:559
ripple::test::MultiSign_test::acc14
const jtx::Account acc14
Definition: MultiSign_test.cpp:41
ripple::test::MultiSign_test::acc27
const jtx::Account acc27
Definition: MultiSign_test.cpp:54
ripple::test::MultiSign_test::test_signerListSet
void test_signerListSet(FeatureBitset features)
Definition: MultiSign_test.cpp:134
std::unique_ptr
STL class.
ripple::STObject::setFieldU32
void setFieldU32(SField const &field, std::uint32_t)
Definition: STObject.cpp:659
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::MultiSign_test::bogie
const jtx::Account bogie
Definition: MultiSign_test.cpp:29
ripple::test::MultiSign_test::phase
const jtx::Account phase
Definition: MultiSign_test.cpp:34
ripple::temBAD_WEIGHT
@ temBAD_WEIGHT
Definition: TER.h:115
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::temINVALID
@ temINVALID
Definition: TER.h:108
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:687
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::MultiSign_test::test_noMultiSigners
void test_noMultiSigners(FeatureBitset features)
Definition: MultiSign_test.cpp:1274
ripple::test::jtx::owner_count
Definition: owners.h:49
ripple::tefBAD_SIGNATURE
@ tefBAD_SIGNATURE
Definition: TER.h:161
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)