xrpld
Loading...
Searching...
No Matches
PaymentChannelClaim.cpp
1#include <xrpl/tx/transactors/payment_channel/PaymentChannelClaim.h>
2
3#include <xrpl/beast/utility/Zero.h>
4#include <xrpl/beast/utility/instrumentation.h>
5#include <xrpl/ledger/ApplyView.h>
6#include <xrpl/ledger/helpers/CredentialHelpers.h>
7#include <xrpl/ledger/helpers/PaymentChannelHelpers.h>
8#include <xrpl/protocol/AccountID.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/Keylet.h>
12#include <xrpl/protocol/LedgerFormats.h>
13#include <xrpl/protocol/PayChan.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/Serializer.h>
20#include <xrpl/protocol/TER.h>
21#include <xrpl/protocol/TxFlags.h>
22#include <xrpl/protocol/XRPAmount.h>
23#include <xrpl/tx/Transactor.h>
24
25#include <cstdint>
26#include <optional>
27
28namespace xrpl {
29
30bool
32{
33 return !ctx.tx.isFieldPresent(sfCredentialIDs) || ctx.rules.enabled(featureCredentials);
34}
35
38{
39 return tfPaymentChannelClaimMask;
40}
41
44{
45 if (ctx.rules.enabled(fixCleanup3_2_0) && ctx.tx[sfChannel] == beast::kZero)
46 return temMALFORMED;
47
48 auto const bal = ctx.tx[~sfBalance];
49 if (bal && (!isXRP(*bal) || *bal <= beast::kZero))
50 return temBAD_AMOUNT;
51
52 auto const amt = ctx.tx[~sfAmount];
53 if (amt && (!isXRP(*amt) || *amt <= beast::kZero))
54 return temBAD_AMOUNT;
55
56 if (bal && amt && *bal > *amt)
57 return temBAD_AMOUNT;
58
59 {
60 if (ctx.tx.isFlag(tfClose) && ctx.tx.isFlag(tfRenew))
61 return temMALFORMED;
62 }
63
64 if (auto const sig = ctx.tx[~sfSignature])
65 {
66 if (!(ctx.tx[~sfPublicKey] && bal))
67 return temMALFORMED;
68
69 // Check the signature
70 // The signature isn't needed if txAccount == src, but if it's
71 // present, check it
72
73 auto const reqBalance = bal->xrp();
74 auto const authAmt = amt ? amt->xrp() : reqBalance;
75
76 if (reqBalance > authAmt)
77 return temBAD_AMOUNT;
78
79 Keylet const k(ltPAYCHAN, ctx.tx[sfChannel]);
80 if (!publicKeyType(ctx.tx[sfPublicKey]))
81 return temMALFORMED;
82
83 PublicKey const pk(ctx.tx[sfPublicKey]);
84 Serializer msg;
85 serializePayChanAuthorization(msg, k.key, authAmt);
86 if (!verify(pk, msg.slice(), *sig))
87 return temBAD_SIGNATURE;
88 }
89
90 if (auto const err = credentials::checkFields(ctx.tx, ctx.j); !isTesSuccess(err))
91 return err;
92
93 return tesSUCCESS;
94}
95
96TER
98{
99 if (!ctx.view.rules().enabled(featureCredentials))
100 return Transactor::preclaim(ctx);
101
102 if (auto const err = credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j);
103 !isTesSuccess(err))
104 return err;
105
106 return tesSUCCESS;
107}
108
109TER
111{
112 Keylet const k(ltPAYCHAN, ctx_.tx[sfChannel]);
113 auto const slep = ctx_.view().peek(k);
114 if (!slep)
115 return tecNO_TARGET;
116
117 AccountID const src = (*slep)[sfAccount];
118 AccountID const dst = (*slep)[sfDestination];
119 AccountID const txAccount = ctx_.tx[sfAccount];
120
121 auto const curExpiration = (*slep)[~sfExpiration];
122 if (isChannelExpired(ctx_.view(), (*slep)[~sfCancelAfter]) ||
123 isChannelExpired(ctx_.view(), curExpiration))
124 {
125 return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.get().getJournal("View"));
126 }
127
128 if (txAccount != src && txAccount != dst)
129 return tecNO_PERMISSION;
130
131 if (ctx_.tx[~sfBalance])
132 {
133 auto const chanBalance = slep->getFieldAmount(sfBalance).xrp();
134 auto const chanFunds = slep->getFieldAmount(sfAmount).xrp();
135 auto const reqBalance = ctx_.tx[sfBalance].xrp();
136
137 if (txAccount == dst && !ctx_.tx[~sfSignature])
138 {
139 return ctx_.view().rules().enabled(fixCleanup3_2_0) ? TER{tecNO_PERMISSION}
141 }
142
143 if (ctx_.tx[~sfSignature])
144 {
145 PublicKey const pk((*slep)[sfPublicKey]);
146 if (ctx_.tx[sfPublicKey] != pk)
147 {
148 return ctx_.view().rules().enabled(fixCleanup3_2_0) ? TER{tecNO_PERMISSION}
150 }
151 }
152
153 if (reqBalance > chanFunds)
154 return tecUNFUNDED_PAYMENT;
155
156 if (reqBalance <= chanBalance)
157 {
158 // nothing requested
159 return tecUNFUNDED_PAYMENT;
160 }
161
162 auto const sled = ctx_.view().peek(keylet::account(dst));
163 if (!sled)
164 return tecNO_DST;
165
166 if (auto err =
167 verifyDepositPreauth(ctx_.tx, ctx_.view(), txAccount, dst, sled, ctx_.journal);
168 !isTesSuccess(err))
169 return err;
170
171 (*slep)[sfBalance] = ctx_.tx[sfBalance];
172 XRPAmount const reqDelta = reqBalance - chanBalance;
173 XRPL_ASSERT(
174 reqDelta >= beast::kZero, "xrpl::PaymentChannelClaim::doApply : minimum balance delta");
175 (*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta;
176 ctx_.view().update(sled);
177 ctx_.view().update(slep);
178 }
179
180 if (ctx_.tx.isFlag(tfRenew))
181 {
182 if (src != txAccount)
183 return tecNO_PERMISSION;
184 (*slep)[~sfExpiration] = std::nullopt;
185 ctx_.view().update(slep);
186 }
187
188 if (ctx_.tx.isFlag(tfClose))
189 {
190 // Channel will close immediately if dry or the receiver closes
191 if (dst == txAccount || (*slep)[sfBalance] == (*slep)[sfAmount])
192 return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.get().getJournal("View"));
193
194 auto const settleExpiration = saturatingAdd(
195 ctx_.view().rules(),
196 ctx_.view().header().parentCloseTime.time_since_epoch().count(),
197 (*slep)[sfSettleDelay]);
198
199 if (!curExpiration || *curExpiration > settleExpiration)
200 {
201 (*slep)[~sfExpiration] = settleExpiration;
202 ctx_.view().update(slep);
203 }
204 }
205
206 return tesSUCCESS;
207}
208
209void
211{
212 // No transaction-specific invariants yet (future work).
213}
214
215bool
217 STTx const&,
218 TER,
219 XRPAmount,
220 ReadView const&,
221 beast::Journal const&)
222{
223 // No transaction-specific invariants yet (future work).
224 return true;
225}
226} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
static bool checkExtraFeatures(PreflightContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
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 public key.
Definition PublicKey.h:42
A view into a ledger.
Definition ReadView.h:31
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:171
std::shared_ptr< STLedgerEntry const > const & const_ref
bool isFlag(std::uint32_t) const
Definition STObject.cpp:501
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:454
Slice slice() const noexcept
Definition Serializer.h:44
static TER preclaim(PreclaimContext const &ctx)
Definition Transactor.h:224
ApplyContext & ctx_
Definition Transactor.h:116
NotTEC checkFields(STTx const &tx, beast::Journal j)
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
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
bool isChannelExpired(ApplyView const &view, std::optional< std::uint32_t > timeField)
Determine whether a payment channel time field represents an expired time.
TER closeChannel(SLE::ref slep, ApplyView &view, uint256 const &key, beast::Journal j)
Close a payment channel and return its remaining funds to the channel owner.
bool isXRP(AccountID const &c)
Definition AccountID.h:70
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
void serializePayChanAuthorization(Serializer &msg, uint256 const &key, XRPAmount const &amt)
Definition PayChan.h:11
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
uint32_t saturatingAdd(Rules const &rules, uint32_t const lhs, uint32_t const rhs)
Add two uint32_t values with saturation at UINT32_MAX.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
@ temMALFORMED
Definition TER.h:73
@ temBAD_AMOUNT
Definition TER.h:75
@ temBAD_SIGNATURE
Definition TER.h:91
@ temBAD_SIGNER
Definition TER.h:101
bool isTesSuccess(TER x) noexcept
Definition TER.h:663
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecUNFUNDED_PAYMENT
Definition TER.h:283
@ tecNO_TARGET
Definition TER.h:302
@ tecNO_PERMISSION
Definition TER.h:303
@ tecNO_DST
Definition TER.h:288
@ tesSUCCESS
Definition TER.h:240
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, SLE::const_ref sleDst, beast::Journal j)
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:19
uint256 key
Definition Keylet.h:20
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:61
ReadView const & view
Definition Transactor.h:64
beast::Journal const j
Definition Transactor.h:69
State information when preflighting a tx.
Definition Transactor.h:18
beast::Journal const j
Definition Transactor.h:25