diff --git a/src/libxrpl/protocol/TxMeta.cpp b/src/libxrpl/protocol/TxMeta.cpp index 2083fc8eaf..2343a6a794 100644 --- a/src/libxrpl/protocol/TxMeta.cpp +++ b/src/libxrpl/protocol/TxMeta.cpp @@ -185,6 +185,18 @@ TxMeta::getAffectedAccounts() const { auto issuer = lim->getIssuer(); + if (issuer.isNonZero()) + list.insert(issuer); + } + } + else if (field.getFName() == sfMPTokenIssuanceID) + { + auto mptID = + dynamic_cast const*>(&field); + if (mptID != nullptr) + { + auto issuer = MPTIssue(mptID->value()).getIssuer(); + if (issuer.isNonZero()) list.insert(issuer); } diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index 947640495d..d0965cc8ff 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -99,40 +99,6 @@ class TxQPosNegFlows_test : public beast::unit_test::suite return calcMedFeeLevel(feeLevel, feeLevel); } - static std::unique_ptr - makeConfig( - std::map extraTxQ = {}, - std::map extraVoting = {}) - { - auto p = test::jtx::envconfig(); - auto& section = p->section("transaction_queue"); - section.set("ledgers_in_queue", "2"); - section.set("minimum_queue_size", "2"); - section.set("min_ledgers_to_compute_size_limit", "3"); - section.set("max_ledger_counts_to_store", "100"); - section.set("retry_sequence_percent", "25"); - section.set("normal_consensus_increase_percent", "0"); - - for (auto const& [k, v] : extraTxQ) - section.set(k, v); - - // Some tests specify different fee settings that are enabled by - // a FeeVote - if (!extraVoting.empty()) - { - auto& votingSection = p->section("voting"); - for (auto const& [k, v] : extraVoting) - { - votingSection.set(k, v); - } - - // In order for the vote to occur, we must run as a validator - p->section("validation_seed") - .legacy("shUwVw52ofnCUX5m7kPTKzJdr4HEH"); - } - return p; - } - std::size_t initFee( jtx::Env& env, diff --git a/src/test/jtx/envconfig.h b/src/test/jtx/envconfig.h index f22c5743e7..432ef28ff6 100644 --- a/src/test/jtx/envconfig.h +++ b/src/test/jtx/envconfig.h @@ -127,6 +127,11 @@ addGrpcConfigWithSecureGateway( std::unique_ptr, std::string const& secureGateway); +std::unique_ptr +makeConfig( + std::map extraTxQ = {}, + std::map extraVoting = {}); + } // namespace jtx } // namespace test } // namespace ripple diff --git a/src/test/jtx/impl/envconfig.cpp b/src/test/jtx/impl/envconfig.cpp index dd9c735465..624036196d 100644 --- a/src/test/jtx/impl/envconfig.cpp +++ b/src/test/jtx/impl/envconfig.cpp @@ -140,6 +140,39 @@ addGrpcConfigWithSecureGateway( return cfg; } +std::unique_ptr +makeConfig( + std::map extraTxQ, + std::map extraVoting) +{ + auto p = test::jtx::envconfig(); + auto& section = p->section("transaction_queue"); + section.set("ledgers_in_queue", "2"); + section.set("minimum_queue_size", "2"); + section.set("min_ledgers_to_compute_size_limit", "3"); + section.set("max_ledger_counts_to_store", "100"); + section.set("retry_sequence_percent", "25"); + section.set("normal_consensus_increase_percent", "0"); + + for (auto const& [k, v] : extraTxQ) + section.set(k, v); + + // Some tests specify different fee settings that are enabled by + // a FeeVote + if (!extraVoting.empty()) + { + auto& votingSection = p->section("voting"); + for (auto const& [k, v] : extraVoting) + { + votingSection.set(k, v); + } + + // In order for the vote to occur, we must run as a validator + p->section("validation_seed").legacy("shUwVw52ofnCUX5m7kPTKzJdr4HEH"); + } + return p; +} + } // namespace jtx } // namespace test } // namespace ripple diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index 6e25c26e58..82809b5c5b 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -18,9 +18,12 @@ //============================================================================== #include +#include #include +#include #include +#include #include #include @@ -753,6 +756,85 @@ class AccountTx_test : public beast::unit_test::suite } } + void + testMPT() + { + testcase("MPT"); + + using namespace test::jtx; + using namespace std::chrono_literals; + + auto cfg = makeConfig(); + cfg->FEES.reference_fee = 10; + Env env(*this, std::move(cfg)); + + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const carol{"carol"}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + // check the latest mpt-related txn is in alice's account history + auto const checkAliceAcctTx = [&](size_t size, + Json::StaticString txType) { + Json::Value params; + params[jss::account] = alice.human(); + params[jss::limit] = 100; + auto const jv = + env.rpc("json", "account_tx", to_string(params))[jss::result]; + + BEAST_EXPECT(jv[jss::transactions].size() == size); + auto const& tx0(jv[jss::transactions][0u][jss::tx]); + BEAST_EXPECT(tx0[jss::TransactionType] == txType); + + std::string const txHash{ + env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + BEAST_EXPECT(tx0[jss::hash] == txHash); + }; + + // alice creates issuance + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanClawback | tfMPTRequireAuth | tfMPTCanTransfer}); + + checkAliceAcctTx(3, jss::MPTokenIssuanceCreate); + + // bob creates a MPToken; + mptAlice.authorize({.account = bob}); + checkAliceAcctTx(4, jss::MPTokenAuthorize); + env.close(); + + // TODO: windows pipeline fails validation for the hardcoded ledger hash + // due to having different test config, it can be uncommented after + // figuring out what happened + // + // ledger hash should be fixed regardless any change to account history + // BEAST_EXPECT( + // to_string(env.closed()->info().hash) == + // "0BD507BB87D3C0E73B462485E6E381798A8C82FC49BF17FE39C60E08A1AF035D"); + + // alice authorizes bob + mptAlice.authorize({.account = alice, .holder = bob}); + checkAliceAcctTx(5, jss::MPTokenAuthorize); + + // carol creates a MPToken; + mptAlice.authorize({.account = carol}); + checkAliceAcctTx(6, jss::MPTokenAuthorize); + + // alice authorizes carol + mptAlice.authorize({.account = alice, .holder = carol}); + checkAliceAcctTx(7, jss::MPTokenAuthorize); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + checkAliceAcctTx(8, jss::Payment); + + // bob pays carol 10 tokens + mptAlice.pay(bob, carol, 10); + checkAliceAcctTx(9, jss::Payment); + } + public: void run() override @@ -761,6 +843,7 @@ public: std::bind_front(&AccountTx_test::testParameters, this)); testContents(); testAccountDelete(); + testMPT(); } }; BEAST_DEFINE_TESTSUITE(AccountTx, rpc, ripple);