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