18 #include <ripple/core/ConfigSections.h>
19 #include <ripple/protocol/Feature.h>
20 #include <ripple/protocol/jss.h>
42 testcase(
"No Reserve");
45 Env env{*
this, features};
54 auto const fee = env.current()->fees().base;
55 auto const smallSignersReserve = reserve1 ?
XRP(250) :
XRP(350);
56 env.fund(smallSignersReserve -
drops(1), alice);
58 env.require(
owners(alice, 0));
65 env.require(
owners(alice, 0));
72 env.require(
owners(alice, reserve1 ? 1 : 3));
77 auto const addReserveBigSigners = reserve1 ?
XRP(0) :
XRP(350);
78 env(
pay(env.master, alice, addReserveBigSigners +
fee -
drops(1)));
94 env.require(
owners(alice, reserve1 ? 1 : 3));
101 env.require(
owners(alice, reserve1 ? 1 : 10));
106 env.require(
owners(alice, 0));
112 testcase(
"SignerListSet");
115 Env env{*
this, features};
117 env.fund(
XRP(1000), alice);
179 env.require(
owners(alice, 0));
185 testcase(
"Phantom Signers");
188 Env env{*
this, features};
190 env.fund(
XRP(1000), alice);
194 env(signers(alice, 1, {{
bogie, 1}, {
demon, 1}}));
199 auto const baseFee = env.current()->fees().base;
203 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
206 aliceSeq = env.seq(alice);
209 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
211 aliceSeq = env.seq(alice);
214 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
217 aliceSeq = env.seq(alice);
220 BEAST_EXPECT(env.seq(alice) == aliceSeq);
223 aliceSeq = env.seq(alice);
229 BEAST_EXPECT(env.seq(alice) == aliceSeq);
232 env(signers(alice, 2, {{
bogie, 1}, {
demon, 1}}));
233 aliceSeq = env.seq(alice);
236 BEAST_EXPECT(env.seq(alice) == aliceSeq);
239 aliceSeq = env.seq(alice);
242 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
251 Env env{*
this, features};
253 env.fund(
XRP(1000), alice);
272 auto const baseFee = env.current()->fees().base;
277 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
280 aliceSeq = env.seq(alice);
283 fee((2 * baseFee) - 1),
287 BEAST_EXPECT(env.seq(alice) == aliceSeq);
290 aliceSeq = env.seq(alice);
296 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
299 aliceSeq = env.seq(alice);
302 fee((9 * baseFee) - 1),
306 BEAST_EXPECT(env.seq(alice) == aliceSeq);
312 testcase(
"Misordered Signers");
315 Env env{*
this, features};
317 env.fund(
XRP(1000), alice);
322 env(signers(alice, 1, {{
bogie, 1}, {
demon, 1}}));
327 std::reverse(phantoms.signers.begin(), phantoms.signers.end());
331 BEAST_EXPECT(env.seq(alice) == aliceSeq);
337 testcase(
"Master Signers");
340 Env env{*
this, features};
344 env.fund(
XRP(1000), alice, becky, cheri);
355 BEAST_EXPECT(env.seq(alice) == aliceSeq + 2);
358 env(signers(alice, 4, {{becky, 3}, {cheri, 4}}),
sig(alice));
363 auto const baseFee = env.current()->fees().base;
364 aliceSeq = env.seq(alice);
367 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
370 aliceSeq = env.seq(alice);
373 BEAST_EXPECT(env.seq(alice) == aliceSeq);
383 aliceSeq = env.seq(alice);
384 env(
noop(alice),
msig(becky, cheri),
fee(3 * baseFee));
386 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
392 testcase(
"Regular Signers");
395 Env env{*
this, features};
399 env.fund(
XRP(1000), alice, becky, cheri);
403 env(signers(alice, 1, {{becky, 1}, {cheri, 1}}),
sig(alice));
419 auto const baseFee = env.current()->fees().base;
423 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
426 aliceSeq = env.seq(alice);
432 BEAST_EXPECT(env.seq(alice) == aliceSeq);
435 aliceSeq = env.seq(alice);
438 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
440 aliceSeq = env.seq(alice);
443 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
446 aliceSeq = env.seq(alice);
451 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
457 testcase(
"Regular Signers Using submit_multisigned");
463 cfg->loadFromString(
"[" SECTION_SIGNING_SUPPORT
"]\ntrue");
470 env.
fund(
XRP(1000), alice, becky, cheri);
474 env(signers(alice, 2, {{becky, 1}, {cheri, 1}}),
sig(alice));
487 auto const baseFee = env.
current()->fees().base;
493 jv[jss::tx_json][jss::Account] = alice.human();
494 jv[jss::tx_json][jss::TransactionType] = jss::AccountSet;
495 jv[jss::tx_json][jss::Fee] = (8 * baseFee).jsonClipped();
496 jv[jss::tx_json][jss::Sequence] = env.
seq(alice);
497 jv[jss::tx_json][jss::SigningPubKey] =
"";
501 jv[jss::account] = cheri.human();
502 jv[jss::key_type] =
"ed25519";
503 jv[jss::passphrase] = cher.name();
506 jv[jss::account] = becky.human();
507 jv[jss::secret] = beck.name();
513 aliceSeq = env.
seq(alice);
517 env.
rpc(
"json",
"sign_for",
to_string(jv_one))[jss::result];
518 BEAST_EXPECT(jrr[jss::status] ==
"success");
523 jv_two[jss::tx_json] = jrr[jss::tx_json];
525 jrr = env.
rpc(
"json",
"sign_for",
to_string(jv_two))[jss::result];
526 BEAST_EXPECT(jrr[jss::status] ==
"success");
529 jv_submit[jss::tx_json] = jrr[jss::tx_json];
532 "submit_multisigned",
534 BEAST_EXPECT(jrr[jss::status] ==
"success");
536 BEAST_EXPECT(env.
seq(alice) == aliceSeq + 1);
541 aliceSeq = env.
seq(alice);
543 jv_one[jss::tx_json][jss::SigningPubKey] =
544 strHex(alice.pk().slice());
547 env.
rpc(
"json",
"sign_for",
to_string(jv_one))[jss::result];
548 BEAST_EXPECT(jrr[jss::status] ==
"error");
549 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
551 jrr[jss::error_message] ==
552 "When multi-signing 'tx_json.SigningPubKey' must be empty.");
557 aliceSeq = env.
seq(alice);
559 jv_one[jss::tx_json][jss::Fee] = -1;
562 env.
rpc(
"json",
"sign_for",
to_string(jv_one))[jss::result];
563 BEAST_EXPECT(jrr[jss::status] ==
"success");
568 jv_two[jss::tx_json] = jrr[jss::tx_json];
570 jrr = env.
rpc(
"json",
"sign_for",
to_string(jv_two))[jss::result];
571 BEAST_EXPECT(jrr[jss::status] ==
"success");
574 jv_submit[jss::tx_json] = jrr[jss::tx_json];
577 "submit_multisigned",
579 BEAST_EXPECT(jrr[jss::status] ==
"error");
580 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
582 jrr[jss::error_message] ==
583 "Invalid Fee field. Fees must be greater than zero.");
588 aliceSeq = env.
seq(alice);
590 jv_one[jss::tx_json][jss::Fee] =
591 alice[
"USD"](10).value().getFullText();
594 env.
rpc(
"json",
"sign_for",
to_string(jv_one))[jss::result];
595 BEAST_EXPECT(jrr[jss::status] ==
"success");
600 jv_two[jss::tx_json] = jrr[jss::tx_json];
602 jrr = env.
rpc(
"json",
"sign_for",
to_string(jv_two))[jss::result];
603 BEAST_EXPECT(jrr[jss::status] ==
"success");
606 jv_submit[jss::tx_json] = jrr[jss::tx_json];
609 "submit_multisigned",
611 BEAST_EXPECT(jrr[jss::status] ==
"error");
612 BEAST_EXPECT(jrr[jss::error] ==
"internal");
613 BEAST_EXPECT(jrr[jss::error_message] ==
"Internal error.");
618 aliceSeq = env.
seq(alice);
620 jv[jss::account] = cheri.human();
621 jv[jss::secret] = cheri.name();
622 auto jrr = env.
rpc(
"json",
"sign_for",
to_string(jv))[jss::result];
623 BEAST_EXPECT(jrr[jss::status] ==
"error");
624 BEAST_EXPECT(jrr[jss::error] ==
"masterDisabled");
626 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
632 aliceSeq = env.
seq(alice);
636 env.
rpc(
"json",
"sign_for",
to_string(jv_one))[jss::result];
637 BEAST_EXPECT(jrr[jss::status] ==
"success");
642 jv_two[jss::tx_json] = jrr[jss::tx_json];
643 jv_two[jss::account] = becky.human();
644 jv_two[jss::key_type] =
"ed25519";
645 jv_two[jss::passphrase] = becky.name();
646 jrr = env.
rpc(
"json",
"sign_for",
to_string(jv_two))[jss::result];
647 BEAST_EXPECT(jrr[jss::status] ==
"success");
650 jv_submit[jss::tx_json] = jrr[jss::tx_json];
653 "submit_multisigned",
655 BEAST_EXPECT(jrr[jss::status] ==
"success");
657 BEAST_EXPECT(env.
seq(alice) == aliceSeq + 1);
663 jv[jss::tx_json][jss::Account] =
"DEADBEEF";
665 auto jrr = env.
rpc(
"json",
"sign_for",
to_string(jv))[jss::result];
666 BEAST_EXPECT(jrr[jss::status] ==
"error");
667 BEAST_EXPECT(jrr[jss::error] ==
"srcActMalformed");
670 jv[jss::tx_json][jss::Account] = jimmy.human();
671 jrr = env.
rpc(
"json",
"sign_for",
to_string(jv))[jss::result];
672 BEAST_EXPECT(jrr[jss::status] ==
"error");
673 BEAST_EXPECT(jrr[jss::error] ==
"srcActNotFound");
677 aliceSeq = env.
seq(alice);
683 "json",
"submit_multisigned",
to_string(jv))[jss::result];
684 BEAST_EXPECT(jrr[jss::status] ==
"error");
685 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
687 jrr[jss::error_message] ==
688 "tx_json.Signers array may not be empty.");
690 BEAST_EXPECT(env.
seq(alice) == aliceSeq);
697 testcase(
"Heterogenious Signers");
700 Env env{*
this, features};
705 env.fund(
XRP(1000), alice, becky, cheri, daria);
726 env(signers(alice, 1, {{becky, 1}, {cheri, 1}, {daria, 1}, {
jinni, 1}}),
732 auto const baseFee = env.current()->fees().base;
736 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
738 aliceSeq = env.seq(alice);
741 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
743 aliceSeq = env.seq(alice);
746 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
748 aliceSeq = env.seq(alice);
751 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
753 aliceSeq = env.seq(alice);
756 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
759 aliceSeq = env.seq(alice);
764 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
778 aliceSeq = env.seq(alice);
783 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
786 aliceSeq = env.seq(alice);
791 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
809 aliceSeq = env.seq(alice);
822 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
825 aliceSeq = env.seq(alice);
831 BEAST_EXPECT(env.seq(alice) == aliceSeq);
836 env.require(
owners(alice, 0));
844 testcase(
"Key Disable");
847 Env env{*
this, features};
849 env.fund(
XRP(1000), alice);
883 env(signers(alice, 1, {{
bogie, 1}}),
sig(alie));
889 auto const baseFee = env.current()->fees().base;
902 env(signers(alice, 1, {{
bogie, 1}}),
sig(alice));
925 testcase(
"Regular Key");
928 Env env{*
this, features};
930 env.fund(
XRP(1000), alice);
946 env.fund(
XRP(1000), becky);
948 env(signers(becky, 1, {{alice, 1}}),
sig(becky));
960 testcase(
"Transaction Types");
963 Env env{*
this, features};
968 auto const USD = gw[
"USD"];
969 env.fund(
XRP(1000), alice, becky, zelda, gw);
978 env(signers(alice, 2, {{becky, 1}, {
bogie, 1}}),
sig(alie));
981 env.require(
owners(alice, signerListOwners + 0));
984 auto const baseFee = env.current()->fees().
base;
986 env(
pay(alice, env.master,
XRP(1)),
990 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
993 aliceSeq = env.seq(alice);
996 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
999 aliceSeq = env.seq(alice);
1003 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1006 env(
trust(
"alice", USD(100)),
1011 env.require(
owners(alice, signerListOwners + 1));
1014 env(
pay(gw, alice, USD(50)));
1016 env.require(
balance(alice, USD(50)));
1017 env.require(
balance(gw, alice[
"USD"](-50)));
1020 env(offer(alice,
XRP(50), USD(50)),
1024 env.require(
owners(alice, signerListOwners + 2));
1028 aliceSeq = env.seq(alice);
1030 cancelOffer[jss::Account] = alice.human();
1031 cancelOffer[jss::OfferSequence] = offerSeq;
1032 cancelOffer[jss::TransactionType] = jss::OfferCancel;
1038 BEAST_EXPECT(env.seq(alice) == aliceSeq + 1);
1039 env.require(
owners(alice, signerListOwners + 1));
1043 env(signers(alice, 3, {{becky, 1}, {
bogie, 1}, {
demon, 1}}),
1053 testcase(
"Bad Signature Text");
1056 using namespace jtx;
1058 Env env{*
this, features};
1061 auto submitSTTx = [&env](
STTx const& stx) {
1063 jvResult[jss::tx_blob] =
strHex(stx.getSerializer().slice());
1064 return env.rpc(
"json",
"submit",
to_string(jvResult));
1068 env.fund(
XRP(1000), alice);
1069 env(signers(alice, 1, {{
bogie, 1}, {
demon, 1}}),
sig(alice));
1071 auto const baseFee = env.current()->fees().base;
1077 auto const info = submitSTTx(local);
1079 info[jss::result][jss::error_exception] ==
1080 "fails local checks: Empty SigningPubKey.");
1091 auto const info = submitSTTx(local);
1093 info[jss::result][jss::error_exception] ==
1094 "fails local checks: Invalid signature.");
1104 auto const info = submitSTTx(local);
1106 info[jss::result][jss::error_exception] ==
1107 "fails local checks: Invalid signature.");
1114 auto const info = submitSTTx(local);
1116 info[jss::result][jss::error_exception] ==
1117 "fails local checks: Cannot both single- and multi-sign.");
1123 local.
sign(alice.pk(), alice.sk());
1125 auto const info = submitSTTx(local);
1127 info[jss::result][jss::error_exception] ==
1128 "fails local checks: Cannot both single- and multi-sign.");
1140 auto const info = submitSTTx(local);
1142 info[jss::result][jss::error_exception].asString().find(
1143 "Invalid signature on account r") != std::string::npos);
1150 auto const info = submitSTTx(local);
1152 info[jss::result][jss::error_exception] ==
1153 "fails local checks: Invalid Signers array size.");
1171 auto const info = submitSTTx(local);
1173 info[jss::result][jss::error_exception] ==
1174 "fails local checks: Invalid Signers array size.");
1180 auto const info = submitSTTx(local);
1182 info[jss::result][jss::error_exception] ==
1183 "fails local checks: Invalid multisigner.");
1189 auto const info = submitSTTx(local);
1191 info[jss::result][jss::error_exception] ==
1192 "fails local checks: Duplicate Signers not allowed.");
1202 auto const info = submitSTTx(local);
1204 info[jss::result][jss::error_exception] ==
1205 "fails local checks: Unsorted Signers array.");
1212 testcase(
"No Multisigners");
1214 using namespace jtx;
1215 Env env{*
this, features};
1218 env.fund(
XRP(1000), alice, becky);
1221 auto const baseFee = env.current()->fees().base;
1231 testcase(
"Multisigning multisigner");
1238 using namespace jtx;
1239 Env env{*
this, features};
1242 env.fund(
XRP(1000), alice, becky);
1246 env(signers(alice, 1, {{becky, 1}}));
1250 env(signers(becky, 1, {{
bogie, 1}, {
demon, 1}}));
1255 auto const baseFee = env.current()->fees().base;
1308 testcase(
"sign_for Hash");
1314 using namespace jtx;
1320 cfg->loadFromString(
"[" SECTION_SIGNING_SUPPORT
"]\ntrue");
1327 env(signers(alice, 2, {{
bogie, 1}, {
ghost, 1}}));
1332 auto const baseFee = env.
current()->fees().base;
1336 jvSig1[jss::tx_json][jss::Account] = alice.human();
1337 jvSig1[jss::tx_json][jss::Amount] = 10000000;
1338 jvSig1[jss::tx_json][jss::Destination] = env.
master.
human();
1339 jvSig1[jss::tx_json][jss::Fee] = (3 * baseFee).jsonClipped();
1340 jvSig1[jss::tx_json][jss::Sequence] = env.
seq(alice);
1341 jvSig1[jss::tx_json][jss::TransactionType] = jss::Payment;
1344 BEAST_EXPECT(jvSig2[jss::result][jss::status].asString() ==
"success");
1348 jvSig2[jss::result][jss::tx_json][jss::hash].
asString();
1351 jvSig2[jss::result][jss::account] =
ghost.
human();
1352 jvSig2[jss::result][jss::secret] =
ghost.
name();
1354 env.
rpc(
"json",
"sign_for",
to_string(jvSig2[jss::result]));
1356 jvSubmit[jss::result][jss::status].asString() ==
"success");
1360 jvSubmit[jss::result][jss::tx_json][jss::hash].
asString();
1361 BEAST_EXPECT(hash1 != hash2);
1365 "json",
"submit_multisigned",
to_string(jvSubmit[jss::result]));
1367 jvResult[jss::result][jss::status].asString() ==
"success");
1369 jvResult[jss::result][jss::engine_result].asString() ==
1375 hash2 == jvResult[jss::result][jss::tx_json][jss::hash].asString());
1381 BEAST_EXPECT(jvTx[jss::result][jss::status].asString() ==
"success");
1382 BEAST_EXPECT(jvTx[jss::result][jss::validated].asString() ==
"true");
1391 testcase(
"Amendment Transition");
1397 using namespace jtx;
1404 env.fund(
XRP(1000), alice, becky, cheri, daria);
1408 env(signers(alice, 1, {{
bogie, 1}}));
1422 env.require(
owners(alice, 3));
1423 env.require(
owners(becky, 10));
1430 env(signers(cheri, 1, {{
bogie, 1}}));
1444 env.require(
owners(alice, 3));
1445 env.require(
owners(becky, 10));
1446 env.require(
owners(cheri, 1));
1447 env.require(
owners(daria, 1));
1465 env.require(
owners(alice, 1));
1466 env.require(
owners(becky, 0));
1467 env.require(
owners(cheri, 1));
1468 env.require(
owners(daria, 1));
1477 env.require(
owners(alice, 0));
1478 env.require(
owners(becky, 0));
1479 env.require(
owners(cheri, 0));
1480 env.require(
owners(daria, 0));
1486 testcase(
"Signers With Tickets");
1488 using namespace jtx;
1489 Env env{*
this, features};
1491 env.fund(
XRP(2000), alice);
1499 env(ticket::create(alice, 20));
1504 env(signers(alice, 1, {{
bogie, 1}, {
demon, 1}}),
1507 env.require(
tickets(alice, env.seq(alice) - aliceTicketSeq));
1508 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1511 auto const baseFee = env.current()->fees().base;
1517 env.require(
tickets(alice, env.seq(alice) - aliceTicketSeq));
1518 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1523 env.require(
tickets(alice, env.seq(alice) - aliceTicketSeq));
1524 BEAST_EXPECT(env.seq(alice) == aliceSeq);
1552 using namespace jtx;