xrpld
Loading...
Searching...
No Matches
PaymentChannelCreate.cpp
1#include <xrpl/tx/transactors/payment_channel/PaymentChannelCreate.h>
2
3#include <xrpl/basics/chrono.h>
4#include <xrpl/beast/utility/Zero.h>
5#include <xrpl/core/ServiceRegistry.h>
6#include <xrpl/ledger/ApplyView.h>
7#include <xrpl/ledger/View.h>
8#include <xrpl/ledger/helpers/AccountRootHelpers.h>
9#include <xrpl/ledger/helpers/DirectoryHelpers.h>
10#include <xrpl/protocol/Feature.h>
11#include <xrpl/protocol/Indexes.h>
12#include <xrpl/protocol/Keylet.h>
13#include <xrpl/protocol/LedgerFormats.h>
14#include <xrpl/protocol/PublicKey.h>
15#include <xrpl/protocol/SField.h>
16#include <xrpl/protocol/STAmount.h>
17#include <xrpl/protocol/STLedgerEntry.h>
18#include <xrpl/protocol/STTx.h>
19#include <xrpl/protocol/TER.h>
20#include <xrpl/protocol/XRPAmount.h>
21#include <xrpl/tx/Transactor.h>
22#include <xrpl/tx/applySteps.h>
23
24#include <memory>
25
26namespace xrpl {
27
28/*
29 PaymentChannel
30
31 Payment channels permit off-ledger checkpoints of XRP payments flowing
32 in a single direction. A channel sequesters the owner's XRP in its own
33 ledger entry. The owner can authorize the recipient to claim up to a
34 given balance by giving the receiver a signed message (off-ledger). The
35 recipient can use this signed message to claim any unpaid balance while
36 the channel remains open. The owner can top off the line as needed. If
37 the channel has not paid out all its funds, the owner must wait out a
38 delay to close the channel to give the recipient a chance to supply any
39 claims. The recipient can close the channel at any time. Any transaction
40 that touches the channel after the expiration time will close the
41 channel. The total amount paid increases monotonically as newer claims
42 are issued. When the channel is closed any remaining balance is returned
43 to the owner. Channels are intended to permit intermittent off-ledger
44 settlement of ILP trust lines as balances get substantial. For
45 bidirectional channels, a payment channel can be used in each direction.
46*/
47
48//------------------------------------------------------------------------------
49
52{
53 return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()};
54}
55
58{
59 if (!isXRP(ctx.tx[sfAmount]) || (ctx.tx[sfAmount] <= beast::kZero))
60 return temBAD_AMOUNT;
61
62 if (ctx.tx[sfAccount] == ctx.tx[sfDestination])
63 return temDST_IS_SRC;
64
65 if (!publicKeyType(ctx.tx[sfPublicKey]))
66 return temMALFORMED;
67
68 return tesSUCCESS;
69}
70
71TER
73{
74 auto const account = ctx.tx[sfAccount];
75 auto const sle = ctx.view.read(keylet::account(account));
76 if (!sle)
77 return terNO_ACCOUNT;
78
79 // Check reserve and funds availability
80 {
81 auto const balance = (*sle)[sfBalance];
82 auto const reserve = ctx.view.fees().accountReserve((*sle)[sfOwnerCount] + 1);
83
84 if (balance < reserve)
86
87 if (balance < reserve + ctx.tx[sfAmount])
88 return tecUNFUNDED;
89 }
90
91 auto const dst = ctx.tx[sfDestination];
92
93 {
94 // Check destination account
95 auto const sled = ctx.view.read(keylet::account(dst));
96 if (!sled)
97 return tecNO_DST;
98
99 // Check if they have disallowed incoming payment channels
100 if (sled->isFlag(lsfDisallowIncomingPayChan))
101 return tecNO_PERMISSION;
102
103 if (sled->isFlag(lsfRequireDestTag) && !ctx.tx[~sfDestinationTag])
104 return tecDST_TAG_NEEDED;
105
106 // Pseudo-accounts cannot receive payment channels, other than native
107 // to their underlying ledger object - implemented in their respective
108 // transaction types. Note, this is not amendment-gated because all
109 // writes to pseudo-account discriminator fields **are** amendment
110 // gated, hence the behaviour of this check will always match the
111 // currently active amendments.
112 if (isPseudoAccount(sled))
113 return tecNO_PERMISSION;
114 }
115
116 return tesSUCCESS;
117}
118
119TER
121{
122 auto const account = ctx_.tx[sfAccount];
123 auto const sle = ctx_.view().peek(keylet::account(account));
124 if (!sle)
125 return tefINTERNAL; // LCOV_EXCL_LINE
126
127 if (ctx_.view().rules().enabled(fixPayChanCancelAfter))
128 {
129 auto const closeTime = ctx_.view().header().parentCloseTime;
130 if (ctx_.tx[~sfCancelAfter] && after(closeTime, ctx_.tx[sfCancelAfter]))
131 return tecEXPIRED;
132 }
133
134 auto const dst = ctx_.tx[sfDestination];
135
136 // Create PayChan in ledger.
137 //
138 // Note that we use the value from the sequence or ticket as the
139 // payChan sequence. For more explanation see comments in SeqProxy.h.
140 Keylet const payChanKeylet = keylet::payChannel(account, dst, ctx_.tx.getSeqValue());
141 auto const slep = std::make_shared<SLE>(payChanKeylet);
142
143 // Funds held in this channel
144 (*slep)[sfAmount] = ctx_.tx[sfAmount];
145 // Amount channel has already paid
146 (*slep)[sfBalance] = ctx_.tx[sfAmount].zeroed();
147 (*slep)[sfAccount] = account;
148 (*slep)[sfDestination] = dst;
149 (*slep)[sfSettleDelay] = ctx_.tx[sfSettleDelay];
150 (*slep)[sfPublicKey] = ctx_.tx[sfPublicKey];
151 (*slep)[~sfCancelAfter] = ctx_.tx[~sfCancelAfter];
152 (*slep)[~sfSourceTag] = ctx_.tx[~sfSourceTag];
153 (*slep)[~sfDestinationTag] = ctx_.tx[~sfDestinationTag];
154 if (ctx_.view().rules().enabled(fixIncludeKeyletFields))
155 {
156 (*slep)[sfSequence] = ctx_.tx.getSeqValue();
157 }
158
159 ctx_.view().insert(slep);
160
161 // Add PayChan to owner directory
162 {
163 auto const page = ctx_.view().dirInsert(
164 keylet::ownerDir(account), payChanKeylet, describeOwnerDir(account));
165 if (!page)
166 return tecDIR_FULL; // LCOV_EXCL_LINE
167 (*slep)[sfOwnerNode] = *page;
168 }
169
170 // Add PayChan to the recipient's owner directory
171 {
172 auto const page =
173 ctx_.view().dirInsert(keylet::ownerDir(dst), payChanKeylet, describeOwnerDir(dst));
174 if (!page)
175 return tecDIR_FULL; // LCOV_EXCL_LINE
176 (*slep)[sfDestinationNode] = *page;
177 }
178
179 // Deduct owner's balance, increment owner count
180 (*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
181 adjustOwnerCount(ctx_.view(), sle, 1, ctx_.journal);
182 ctx_.view().update(sle);
183
184 return tesSUCCESS;
185}
186
187void
189{
190 // No transaction-specific invariants yet (future work).
191}
192
193bool
195 STTx const&,
196 TER,
197 XRPAmount,
198 ReadView const&,
199 beast::Journal const&)
200{
201 // No transaction-specific invariants yet (future work).
202 return true;
203}
204} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
A view into a ledger.
Definition ReadView.h:31
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
std::shared_ptr< STLedgerEntry const > const & const_ref
ApplyContext & ctx_
Definition Transactor.h:116
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition applySteps.h:38
T make_shared(T... args)
Keylet payChannel(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition Indexes.cpp:378
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:357
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ terNO_ACCOUNT
Definition TER.h:209
bool isXRP(AccountID const &c)
Definition AccountID.h:70
@ tefINTERNAL
Definition TER.h:163
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:554
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
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:94
@ temMALFORMED
Definition TER.h:73
@ temBAD_AMOUNT
Definition TER.h:75
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecDIR_FULL
Definition TER.h:285
@ tecEXPIRED
Definition TER.h:312
@ tecINSUFFICIENT_RESERVE
Definition TER.h:305
@ tecNO_PERMISSION
Definition TER.h:303
@ tecDST_TAG_NEEDED
Definition TER.h:307
@ tecNO_DST
Definition TER.h:288
@ tecUNFUNDED
Definition TER.h:293
bool isPseudoAccount(SLE::const_pointer sleAcct, std::set< SField const * > const &pseudoFieldFilter={})
Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFil...
@ tesSUCCESS
Definition TER.h:240
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
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:61
ReadView const & view
Definition Transactor.h:64
State information when preflighting a tx.
Definition Transactor.h:18