From 9933daeba35afb8730fbe9f2c52857cc1280f4b3 Mon Sep 17 00:00:00 2001 From: Chenna Keshava Date: Thu, 1 Jun 2023 12:14:55 -0700 Subject: [PATCH] Strongly typed wrapper for Payment Channels ledger object This commit introduces implementation for the said wrapper. Occurences of PayChan keylet have been modified to indicate the new type. One function in PayChan_test.cpp:channelAndSle(...) uses the readSLE API. It has a dependency on inOwnerDir(...) function. This can be ported only after completion of the Directory ledger object wrapper. --- src/ripple/app/tx/impl/PayChan.cpp | 2 +- src/ripple/ledger/ApplyView.h | 2 +- src/ripple/protocol/Indexes.h | 2 +- src/ripple/protocol/Keylet.h | 15 +++++++++++++ src/ripple/protocol/PayChan.h | 33 ++++++++++++++++++++++++++++ src/ripple/protocol/impl/Indexes.cpp | 7 +++--- src/test/app/AccountDelete_test.cpp | 10 +++++---- src/test/app/PayChan_test.cpp | 6 +++-- 8 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/ripple/app/tx/impl/PayChan.cpp b/src/ripple/app/tx/impl/PayChan.cpp index 3d67291ae13..7e198024171 100644 --- a/src/ripple/app/tx/impl/PayChan.cpp +++ b/src/ripple/app/tx/impl/PayChan.cpp @@ -252,7 +252,7 @@ PayChanCreate::doApply() // // Note that we we use the value from the sequence or ticket as the // payChan sequence. For more explanation see comments in SeqProxy.h. - Keylet const payChanKeylet = + PayChanKeylet const payChanKeylet = keylet::payChan(account, dst, ctx_.tx.getSeqProxy().value()); auto const slep = std::make_shared(payChanKeylet); diff --git a/src/ripple/ledger/ApplyView.h b/src/ripple/ledger/ApplyView.h index f7578411a23..e75405e8e2d 100644 --- a/src/ripple/ledger/ApplyView.h +++ b/src/ripple/ledger/ApplyView.h @@ -343,7 +343,7 @@ class ApplyView : public ReadView std::optional dirInsert( Keylet const& directory, - Keylet const& key, + KeyletBase const& key, std::function const&)> const& describe) { return dirAdd(false, directory, key.key, describe); diff --git a/src/ripple/protocol/Indexes.h b/src/ripple/protocol/Indexes.h index e7170eff7cc..9b069bde92f 100644 --- a/src/ripple/protocol/Indexes.h +++ b/src/ripple/protocol/Indexes.h @@ -222,7 +222,7 @@ Keylet escrow(AccountID const& src, std::uint32_t seq) noexcept; /** A PaymentChannel */ -Keylet +PayChanKeylet payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept; /** NFT page keylets diff --git a/src/ripple/protocol/Keylet.h b/src/ripple/protocol/Keylet.h index c34b484a150..e4af321b364 100644 --- a/src/ripple/protocol/Keylet.h +++ b/src/ripple/protocol/Keylet.h @@ -95,6 +95,21 @@ static_assert(std::is_move_assignable_v); static_assert(std::is_nothrow_destructible_v); #endif +template +class PayChanImpl; + +struct PayChanKeylet final : public KeyletBase +{ + template + using TWrapped = PayChanImpl; + + using KeyletBase::check; + + explicit PayChanKeylet(uint256 const& key) : KeyletBase(ltPAYCHAN, key) + { + } +}; + template class AcctRootImpl; diff --git a/src/ripple/protocol/PayChan.h b/src/ripple/protocol/PayChan.h index 216835de270..02fe78a8b1f 100644 --- a/src/ripple/protocol/PayChan.h +++ b/src/ripple/protocol/PayChan.h @@ -27,6 +27,39 @@ namespace ripple { +template +class PayChanImpl final : public LedgerEntryWrapper +{ + using Base = LedgerEntryWrapper; + using SleT = typename Base::SleT; + using Base::wrapped_; + + // This constructor is private so only the factory functions can + // construct an PayChanImpl. + PayChanImpl(std::shared_ptr&& w) : Base(std::move(w)) + { + } + + // Friend declarations of factory functions. + // + // For classes that contain factories we must declare the entire class + // as a friend unless the class declaration is visible at this point. + friend class ReadView; + friend class ApplyView; + +public: + // Conversion operator from PayChanImpl to PayChanImpl. + operator PayChanImpl() const + { + return PayChanImpl( + std::const_pointer_cast>( + wrapped_)); + } +}; + +using PayChan = PayChanImpl; +using PayChanRd = PayChanImpl; + inline void serializePayChanAuthorization( Serializer& msg, diff --git a/src/ripple/protocol/impl/Indexes.cpp b/src/ripple/protocol/impl/Indexes.cpp index 2cc80ff41e6..0b1690e249a 100644 --- a/src/ripple/protocol/impl/Indexes.cpp +++ b/src/ripple/protocol/impl/Indexes.cpp @@ -320,12 +320,11 @@ escrow(AccountID const& src, std::uint32_t seq) noexcept return {ltESCROW, indexHash(LedgerNameSpace::ESCROW, src, seq)}; } -Keylet +PayChanKeylet payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept { - return { - ltPAYCHAN, - indexHash(LedgerNameSpace::XRP_PAYMENT_CHANNEL, src, dst, seq)}; + return PayChanKeylet( + indexHash(LedgerNameSpace::XRP_PAYMENT_CHANNEL, src, dst, seq)); } Keylet diff --git a/src/test/app/AccountDelete_test.cpp b/src/test/app/AccountDelete_test.cpp index 4e7acce070e..37529b3b7e0 100644 --- a/src/test/app/AccountDelete_test.cpp +++ b/src/test/app/AccountDelete_test.cpp @@ -405,7 +405,7 @@ class AccountDelete_test : public beast::unit_test::suite env(escrowCancel(becky, alice, escrowSeq)); env.close(); - Keylet const alicePayChanKey{ + PayChanKeylet const alicePayChanKey{ keylet::payChan(alice, becky, env.seq(alice))}; env(payChanCreate( @@ -426,7 +426,7 @@ class AccountDelete_test : public beast::unit_test::suite // Lambda to close a PayChannel. auto payChanClose = [](jtx::Account const& account, - Keylet const& payChanKeylet, + KeyletBase const& payChanKeylet, PublicKey const& pk) { Json::Value jv; jv[jss::TransactionType] = jss::PaymentChannelClaim; @@ -447,7 +447,8 @@ class AccountDelete_test : public beast::unit_test::suite // gw creates a PayChannel with alice as the destination. With the // amendment passed this should prevent alice from deleting her // account. - Keylet const gwPayChanKey{keylet::payChan(gw, alice, env.seq(gw))}; + PayChanKeylet const gwPayChanKey{ + keylet::payChan(gw, alice, env.seq(gw))}; env(payChanCreate(gw, alice, XRP(68), 4s, env.now() + 2s, alice.pk())); env.close(); @@ -492,7 +493,8 @@ class AccountDelete_test : public beast::unit_test::suite BEAST_EXPECT(env.closed()->exists(beckyAcctKey)); using namespace std::chrono_literals; - Keylet const payChanKey{keylet::payChan(alice, becky, env.seq(alice))}; + PayChanKeylet const payChanKey{ + keylet::payChan(alice, becky, env.seq(alice))}; auto const payChanXRP = XRP(37); env(payChanCreate( diff --git a/src/test/app/PayChan_test.cpp b/src/test/app/PayChan_test.cpp index c3e9002256c..65e9c891134 100644 --- a/src/test/app/PayChan_test.cpp +++ b/src/test/app/PayChan_test.cpp @@ -44,6 +44,8 @@ struct PayChan_test : public beast::unit_test::suite return k.key; } + // Keshava: Modify this function to use read() after keylet::ownerDir has + // been updated. inOwnerDir(...) has a dependency on ltDirNode. static std::pair> channelKeyAndSle( ReadView const& view, @@ -81,8 +83,8 @@ struct PayChan_test : public beast::unit_test::suite static bool channelExists(ReadView const& view, uint256 const& chan) { - auto const slep = view.readSLE(Keylet(ltPAYCHAN, chan)); - return bool(slep); + auto const slep = view.read(PayChanKeylet(chan)); + return slep.has_value(); } static STAmount