rippled
Loading...
Searching...
No Matches
PaymentChannelCreate.cpp
1#include <xrpl/basics/chrono.h>
2#include <xrpl/ledger/ApplyView.h>
3#include <xrpl/ledger/View.h>
4#include <xrpl/ledger/helpers/AccountRootHelpers.h>
5#include <xrpl/ledger/helpers/DirectoryHelpers.h>
6#include <xrpl/protocol/Feature.h>
7#include <xrpl/protocol/Indexes.h>
8#include <xrpl/protocol/PublicKey.h>
9#include <xrpl/protocol/XRPAmount.h>
10#include <xrpl/tx/transactors/payment_channel/PaymentChannelCreate.h>
11
12namespace xrpl {
13
14/*
15 PaymentChannel
16
17 Payment channels permit off-ledger checkpoints of XRP payments flowing
18 in a single direction. A channel sequesters the owner's XRP in its own
19 ledger entry. The owner can authorize the recipient to claim up to a
20 given balance by giving the receiver a signed message (off-ledger). The
21 recipient can use this signed message to claim any unpaid balance while
22 the channel remains open. The owner can top off the line as needed. If
23 the channel has not paid out all its funds, the owner must wait out a
24 delay to close the channel to give the recipient a chance to supply any
25 claims. The recipient can close the channel at any time. Any transaction
26 that touches the channel after the expiration time will close the
27 channel. The total amount paid increases monotonically as newer claims
28 are issued. When the channel is closed any remaining balance is returned
29 to the owner. Channels are intended to permit intermittent off-ledger
30 settlement of ILP trust lines as balances get substantial. For
31 bidirectional channels, a payment channel can be used in each direction.
32*/
33
34//------------------------------------------------------------------------------
35
36TxConsequences
38{
39 return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()};
40}
41
44{
45 if (!isXRP(ctx.tx[sfAmount]) || (ctx.tx[sfAmount] <= beast::zero))
46 return temBAD_AMOUNT;
47
48 if (ctx.tx[sfAccount] == ctx.tx[sfDestination])
49 return temDST_IS_SRC;
50
51 if (!publicKeyType(ctx.tx[sfPublicKey]))
52 return temMALFORMED;
53
54 return tesSUCCESS;
55}
56
57TER
59{
60 auto const account = ctx.tx[sfAccount];
61 auto const sle = ctx.view.read(keylet::account(account));
62 if (!sle)
63 return terNO_ACCOUNT;
64
65 // Check reserve and funds availability
66 {
67 auto const balance = (*sle)[sfBalance];
68 auto const reserve = ctx.view.fees().accountReserve((*sle)[sfOwnerCount] + 1);
69
70 if (balance < reserve)
72
73 if (balance < reserve + ctx.tx[sfAmount])
74 return tecUNFUNDED;
75 }
76
77 auto const dst = ctx.tx[sfDestination];
78
79 {
80 // Check destination account
81 auto const sled = ctx.view.read(keylet::account(dst));
82 if (!sled)
83 return tecNO_DST;
84
85 auto const flags = sled->getFlags();
86
87 // Check if they have disallowed incoming payment channels
88 if ((flags & lsfDisallowIncomingPayChan) != 0u)
89 return tecNO_PERMISSION;
90
91 if (((flags & lsfRequireDestTag) != 0u) && !ctx.tx[~sfDestinationTag])
92 return tecDST_TAG_NEEDED;
93
94 // Pseudo-accounts cannot receive payment channels, other than native
95 // to their underlying ledger object - implemented in their respective
96 // transaction types. Note, this is not amendment-gated because all
97 // writes to pseudo-account discriminator fields **are** amendment
98 // gated, hence the behaviour of this check will always match the
99 // currently active amendments.
100 if (isPseudoAccount(sled))
101 return tecNO_PERMISSION;
102 }
103
104 return tesSUCCESS;
105}
106
107TER
109{
110 auto const account = ctx_.tx[sfAccount];
111 auto const sle = ctx_.view().peek(keylet::account(account));
112 if (!sle)
113 return tefINTERNAL; // LCOV_EXCL_LINE
114
115 if (ctx_.view().rules().enabled(fixPayChanCancelAfter))
116 {
117 auto const closeTime = ctx_.view().header().parentCloseTime;
118 if (ctx_.tx[~sfCancelAfter] && after(closeTime, ctx_.tx[sfCancelAfter]))
119 return tecEXPIRED;
120 }
121
122 auto const dst = ctx_.tx[sfDestination];
123
124 // Create PayChan in ledger.
125 //
126 // Note that we we use the value from the sequence or ticket as the
127 // payChan sequence. For more explanation see comments in SeqProxy.h.
128 Keylet const payChanKeylet = keylet::payChan(account, dst, ctx_.tx.getSeqValue());
129 auto const slep = std::make_shared<SLE>(payChanKeylet);
130
131 // Funds held in this channel
132 (*slep)[sfAmount] = ctx_.tx[sfAmount];
133 // Amount channel has already paid
134 (*slep)[sfBalance] = ctx_.tx[sfAmount].zeroed();
135 (*slep)[sfAccount] = account;
136 (*slep)[sfDestination] = dst;
137 (*slep)[sfSettleDelay] = ctx_.tx[sfSettleDelay];
138 (*slep)[sfPublicKey] = ctx_.tx[sfPublicKey];
139 (*slep)[~sfCancelAfter] = ctx_.tx[~sfCancelAfter];
140 (*slep)[~sfSourceTag] = ctx_.tx[~sfSourceTag];
141 (*slep)[~sfDestinationTag] = ctx_.tx[~sfDestinationTag];
142 if (ctx_.view().rules().enabled(fixIncludeKeyletFields))
143 {
144 (*slep)[sfSequence] = ctx_.tx.getSeqValue();
145 }
146
147 ctx_.view().insert(slep);
148
149 // Add PayChan to owner directory
150 {
151 auto const page = ctx_.view().dirInsert(
152 keylet::ownerDir(account), payChanKeylet, describeOwnerDir(account));
153 if (!page)
154 return tecDIR_FULL; // LCOV_EXCL_LINE
155 (*slep)[sfOwnerNode] = *page;
156 }
157
158 // Add PayChan to the recipient's owner directory
159 {
160 auto const page =
161 ctx_.view().dirInsert(keylet::ownerDir(dst), payChanKeylet, describeOwnerDir(dst));
162 if (!page)
163 return tecDIR_FULL; // LCOV_EXCL_LINE
164 (*slep)[sfDestinationNode] = *page;
165 }
166
167 // Deduct owner's balance, increment owner count
168 (*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
170 ctx_.view().update(sle);
171
172 return tesSUCCESS;
173}
174
175} // namespace xrpl
STTx const & tx
beast::Journal const journal
ApplyView & view()
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
Definition ApplyView.h:289
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual LedgerHeader const & header() const =0
Returns information about the ledger.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:120
std::uint32_t getSeqValue() const
Returns the first non-zero value of (Sequence, TicketSequence).
Definition STTx.cpp:211
ApplyContext & ctx_
Definition Transactor.h:112
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition applySteps.h:38
T is_same_v
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:336
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition Indexes.cpp:357
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ terNO_ACCOUNT
Definition TER.h:197
bool isXRP(AccountID const &c)
Definition AccountID.h:70
@ tefINTERNAL
Definition TER.h:153
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct, std::set< SField const * > const &pseudoFieldFilter={})
Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFil...
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:523
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
@ temDST_IS_SRC
Definition TER.h:88
@ temMALFORMED
Definition TER.h:67
@ temBAD_AMOUNT
Definition TER.h:69
@ tecDIR_FULL
Definition TER.h:268
@ tecEXPIRED
Definition TER.h:295
@ tecINSUFFICIENT_RESERVE
Definition TER.h:288
@ tecNO_PERMISSION
Definition TER.h:286
@ tecDST_TAG_NEEDED
Definition TER.h:290
@ tecNO_DST
Definition TER.h:271
@ tecUNFUNDED
Definition TER.h:276
@ tesSUCCESS
Definition TER.h:225
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:19
NetClock::time_point parentCloseTime
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:57
ReadView const & view
Definition Transactor.h:60
State information when preflighting a tx.
Definition Transactor.h:14