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