From a2c41016b0169f516e9bfa301f59bc46f7f92cb3 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Wed, 18 Oct 2023 10:10:49 +0200 Subject: [PATCH] add ticket tests (#129) --- src/ripple/protocol/impl/TxFormats.cpp | 7 ++-- src/test/app/ClaimReward_test.cpp | 23 +++++++++++++ src/test/app/Import_test.cpp | 47 ++++++++++++++++++++++++++ src/test/app/Invoke_test.cpp | 23 +++++++++++++ src/test/app/SetHook_test.cpp | 30 ++++++++++++++-- src/test/app/URIToken_test.cpp | 3 +- 6 files changed, 127 insertions(+), 6 deletions(-) diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/ripple/protocol/impl/TxFormats.cpp index b9d9f0b4b..cee5ff634 100644 --- a/src/ripple/protocol/impl/TxFormats.cpp +++ b/src/ripple/protocol/impl/TxFormats.cpp @@ -198,7 +198,6 @@ TxFormats::TxFormats() {sfLedgerSequence, soeREQUIRED}, {sfActiveValidator, soeOPTIONAL}, {sfImportVLKey, soeOPTIONAL}, - }, commonFields); @@ -308,13 +307,15 @@ TxFormats::TxFormats() ttHOOK_SET, { {sfHooks, soeREQUIRED}, + {sfTicketSequence, soeOPTIONAL}, }, commonFields); add(jss::ClaimReward, ttCLAIM_REWARD, { - {sfIssuer, soeOPTIONAL} + {sfIssuer, soeOPTIONAL}, + {sfTicketSequence, soeOPTIONAL}, }, commonFields); @@ -380,6 +381,7 @@ TxFormats::TxFormats() { {sfBlob, soeREQUIRED}, {sfIssuer, soeOPTIONAL}, + {sfTicketSequence, soeOPTIONAL}, }, commonFields); @@ -390,6 +392,7 @@ TxFormats::TxFormats() {sfDestination, soeOPTIONAL}, {sfInvoiceID, soeOPTIONAL}, {sfDestinationTag, soeOPTIONAL}, + {sfTicketSequence, soeOPTIONAL}, }, commonFields); diff --git a/src/test/app/ClaimReward_test.cpp b/src/test/app/ClaimReward_test.cpp index f1308b724..52e6668d9 100644 --- a/src/test/app/ClaimReward_test.cpp +++ b/src/test/app/ClaimReward_test.cpp @@ -351,6 +351,28 @@ struct ClaimReward_test : public beast::unit_test::suite BEAST_EXPECT(expectNoRewards(env, alice) == true); } + void + testUsingTickets(FeatureBitset features) + { + testcase("using tickets"); + using namespace jtx; + using namespace std::literals::chrono_literals; + Env env{*this, features}; + auto const alice = Account("alice"); + auto const issuer = Account("issuer"); + env.fund(XRP(10000), alice, issuer); + std::uint32_t aliceTicketSeq{env.seq(alice) + 1}; + env(ticket::create(alice, 10)); + std::uint32_t const aliceSeq{env.seq(alice)}; + env.require(owners(alice, 10)); + + env(claim(alice, issuer), ticket::use(aliceTicketSeq++), ter(tesSUCCESS)); + + env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); + BEAST_EXPECT(env.seq(alice) == aliceSeq); + env.require(owners(alice, 9)); + } + void testWithFeats(FeatureBitset features) { @@ -358,6 +380,7 @@ struct ClaimReward_test : public beast::unit_test::suite testInvalidPreflight(features); testInvalidPreclaim(features); testValidNoHook(features); + testUsingTickets(features); } public: diff --git a/src/test/app/Import_test.cpp b/src/test/app/Import_test.cpp index 87c1c4bc3..e0562fc74 100644 --- a/src/test/app/Import_test.cpp +++ b/src/test/app/Import_test.cpp @@ -4415,6 +4415,52 @@ class Import_test : public beast::unit_test::suite } } + void + testUsingTickets(FeatureBitset features) + { + testcase("using tickets"); + + using namespace test::jtx; + using namespace std::literals; + + { + test::jtx::Env env{*this, makeNetworkVLConfig(21337, keys)}; + auto const feeDrops = env.current()->fees().base; + + // confirm total coins header + auto const initCoins = env.current()->info().drops; + BEAST_EXPECT(initCoins == 100'000'000'000'000'000); + + // burn 10'000 xrp + auto const master = Account("masterpassphrase"); + env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); + env.close(); + + // confirm total coins header + auto const burnCoins = env.current()->info().drops; + BEAST_EXPECT(burnCoins == initCoins - 10'000'000'000); + + auto const alice = Account("alice"); + env.fund(XRP(1000), alice); + env.close(); + + std::uint32_t aliceTicketSeq{env.seq(alice) + 1}; + env(ticket::create(alice, 10)); + std::uint32_t const aliceSeq{env.seq(alice)}; + env.require(owners(alice, 10)); + + env(import(alice, loadXpop(ImportTCAccountSet::w_seed)), + fee(feeDrops * 10), + ticket::use(aliceTicketSeq++), + ter(tesSUCCESS)); + env.close(); + + env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); + BEAST_EXPECT(env.seq(alice) == aliceSeq); + env.require(owners(alice, 9)); + } + } + void testAccountIndex(FeatureBitset features) { @@ -5581,6 +5627,7 @@ public: testSetRegularKey(features); testSetRegularKeyFlags(features); testSignersListSet(features); + testUsingTickets(features); testAccountIndex(features); testHookIssuer(features); testImportSequence(features); diff --git a/src/test/app/Invoke_test.cpp b/src/test/app/Invoke_test.cpp index b58c94e33..9ea94cf39 100644 --- a/src/test/app/Invoke_test.cpp +++ b/src/test/app/Invoke_test.cpp @@ -232,6 +232,28 @@ class Invoke_test : public beast::unit_test::suite } } + void + testUsingTickets(FeatureBitset features) + { + testcase("invoke using tickets"); + using namespace jtx; + using namespace std::literals::chrono_literals; + Env env{*this, features}; + auto const alice = Account("alice"); + env.fund(XRP(10000), alice); + std::uint32_t aliceTicketSeq{env.seq(alice) + 1}; + env(ticket::create(alice, 10)); + std::uint32_t const aliceSeq{env.seq(alice)}; + env.require(owners(alice, 10)); + + env(invoke(alice), ticket::use(aliceTicketSeq++), ter(tesSUCCESS)); + env(invoke(alice), ticket::use(aliceTicketSeq++), ter(tesSUCCESS)); + + env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); + BEAST_EXPECT(env.seq(alice) == aliceSeq); + env.require(owners(alice, 8)); + } + public: void run() override @@ -247,6 +269,7 @@ public: testInvalidPreflight(features); testInvalidPreclaim(features); testInvoke(features); + testUsingTickets(features); } }; diff --git a/src/test/app/SetHook_test.cpp b/src/test/app/SetHook_test.cpp index 39ba3fbaa..845fd104d 100644 --- a/src/test/app/SetHook_test.cpp +++ b/src/test/app/SetHook_test.cpp @@ -1540,6 +1540,32 @@ public: } } + void + testWithTickets() + { + testcase("with tickets"); + using namespace jtx; + + Env env{*this, supported_amendments()}; + + auto const alice = Account{"alice"}; + env.fund(XRP(10000), alice); + + std::uint32_t aliceTicketSeq{env.seq(alice) + 1}; + env(ticket::create(alice, 10)); + std::uint32_t const aliceSeq{env.seq(alice)}; + env.require(owners(alice, 10)); + + env(ripple::test::jtx::hook(alice, {{hso(accept_wasm)}}, 0), + HSFEE, + ticket::use(aliceTicketSeq++), + ter(tesSUCCESS)); + + env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); + BEAST_EXPECT(env.seq(alice) == aliceSeq); + env.require(owners(alice, 9 + 1)); + } + void testInferHookSetOperation() { @@ -11400,7 +11426,6 @@ public: void run() override { - // testTicketSetHook(); // RH TODO testHooksDisabled(); testTxStructure(); @@ -11411,6 +11436,7 @@ public: testDelete(); testInstall(); testCreate(); + testWithTickets(); testUpdate(); @@ -11644,7 +11670,7 @@ private: HASH_WASM(accept2); }; -BEAST_DEFINE_TESTSUITE(SetHook, tx, ripple); +BEAST_DEFINE_TESTSUITE(SetHook, app, ripple); } // namespace test } // namespace ripple #undef M diff --git a/src/test/app/URIToken_test.cpp b/src/test/app/URIToken_test.cpp index 025ffe4c8..df00a9c17 100644 --- a/src/test/app/URIToken_test.cpp +++ b/src/test/app/URIToken_test.cpp @@ -1444,10 +1444,9 @@ struct URIToken_test : public beast::unit_test::suite env(buy(bob, hexid, USD(1500)), ticket::use(bobTicketSeq++), ter(tecINSUFFICIENT_FUNDS)); - env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); + env.require(tickets(bob, env.seq(bob) - bobTicketSeq)); env(buy(bob, hexid, USD(1000)), ticket::use(bobTicketSeq++)); - env.require(tickets(bob, env.seq(bob) - bobTicketSeq)); BEAST_EXPECT(env.seq(bob) == bobSeq); BEAST_EXPECT(inOwnerDir(*env.current(), bob, tid));