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