rippled
Loading...
Searching...
No Matches
CreateCheck.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2017 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/tx/detail/CreateCheck.h>
21#include <xrpld/ledger/View.h>
22#include <xrpl/basics/Log.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/Indexes.h>
25#include <xrpl/protocol/TER.h>
26#include <xrpl/protocol/TxFlags.h>
27
28namespace ripple {
29
32{
33 if (!ctx.rules.enabled(featureChecks))
34 return temDISABLED;
35
36 NotTEC const ret{preflight1(ctx)};
37 if (!isTesSuccess(ret))
38 return ret;
39
40 if (ctx.tx.getFlags() & tfUniversalMask)
41 {
42 // There are no flags (other than universal) for CreateCheck yet.
43 JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set.";
44 return temINVALID_FLAG;
45 }
46 if (ctx.tx[sfAccount] == ctx.tx[sfDestination])
47 {
48 // They wrote a check to themselves.
49 JLOG(ctx.j.warn()) << "Malformed transaction: Check to self.";
50 return temREDUNDANT;
51 }
52
53 {
54 STAmount const sendMax{ctx.tx.getFieldAmount(sfSendMax)};
55 if (!isLegalNet(sendMax) || sendMax.signum() <= 0)
56 {
57 JLOG(ctx.j.warn()) << "Malformed transaction: bad sendMax amount: "
58 << sendMax.getFullText();
59 return temBAD_AMOUNT;
60 }
61
62 if (badCurrency() == sendMax.getCurrency())
63 {
64 JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
65 return temBAD_CURRENCY;
66 }
67 }
68
69 if (auto const optExpiry = ctx.tx[~sfExpiration])
70 {
71 if (*optExpiry == 0)
72 {
73 JLOG(ctx.j.warn()) << "Malformed transaction: bad expiration";
74 return temBAD_EXPIRATION;
75 }
76 }
77
78 return preflight2(ctx);
79}
80
81TER
83{
84 AccountID const dstId{ctx.tx[sfDestination]};
85 auto const sleDst = ctx.view.read(keylet::account(dstId));
86 if (!sleDst)
87 {
88 JLOG(ctx.j.warn()) << "Destination account does not exist.";
89 return tecNO_DST;
90 }
91
92 auto const flags = sleDst->getFlags();
93
94 // Check if the destination has disallowed incoming checks
95 if (ctx.view.rules().enabled(featureDisallowIncoming) &&
97 return tecNO_PERMISSION;
98
99 // AMM can not cash the check
100 if (sleDst->isFieldPresent(sfAMMID))
101 return tecNO_PERMISSION;
102
103 if ((flags & lsfRequireDestTag) && !ctx.tx.isFieldPresent(sfDestinationTag))
104 {
105 // The tag is basically account-specific information we don't
106 // understand, but we can require someone to fill it in.
107 JLOG(ctx.j.warn()) << "Malformed transaction: DestinationTag required.";
108 return tecDST_TAG_NEEDED;
109 }
110
111 {
112 STAmount const sendMax{ctx.tx[sfSendMax]};
113 if (!sendMax.native())
114 {
115 // The currency may not be globally frozen
116 AccountID const& issuerId{sendMax.getIssuer()};
117 if (isGlobalFrozen(ctx.view, issuerId))
118 {
119 JLOG(ctx.j.warn()) << "Creating a check for frozen asset";
120 return tecFROZEN;
121 }
122 // If this account has a trustline for the currency, that
123 // trustline may not be frozen.
124 //
125 // Note that we DO allow create check for a currency that the
126 // account does not yet have a trustline to.
127 AccountID const srcId{ctx.tx.getAccountID(sfAccount)};
128 if (issuerId != srcId)
129 {
130 // Check if the issuer froze the line
131 auto const sleTrust = ctx.view.read(
132 keylet::line(srcId, issuerId, sendMax.getCurrency()));
133 if (sleTrust &&
134 sleTrust->isFlag(
135 (issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze))
136 {
137 JLOG(ctx.j.warn())
138 << "Creating a check for frozen trustline.";
139 return tecFROZEN;
140 }
141 }
142 if (issuerId != dstId)
143 {
144 // Check if dst froze the line.
145 auto const sleTrust = ctx.view.read(
146 keylet::line(issuerId, dstId, sendMax.getCurrency()));
147 if (sleTrust &&
148 sleTrust->isFlag(
149 (dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze))
150 {
151 JLOG(ctx.j.warn())
152 << "Creating a check for destination frozen trustline.";
153 return tecFROZEN;
154 }
155 }
156 }
157 }
158 if (hasExpired(ctx.view, ctx.tx[~sfExpiration]))
159 {
160 JLOG(ctx.j.warn()) << "Creating a check that has already expired.";
161 return tecEXPIRED;
162 }
163 return tesSUCCESS;
164}
165
166TER
168{
169 auto const sle = view().peek(keylet::account(account_));
170 if (!sle)
171 return tefINTERNAL;
172
173 // A check counts against the reserve of the issuing account, but we
174 // check the starting balance because we want to allow dipping into the
175 // reserve to pay fees.
176 {
177 STAmount const reserve{
178 view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
179
180 if (mPriorBalance < reserve)
182 }
183
184 // Note that we use the value from the sequence or ticket as the
185 // Check sequence. For more explanation see comments in SeqProxy.h.
186 std::uint32_t const seq = ctx_.tx.getSeqProxy().value();
187 Keylet const checkKeylet = keylet::check(account_, seq);
188 auto sleCheck = std::make_shared<SLE>(checkKeylet);
189
190 sleCheck->setAccountID(sfAccount, account_);
191 AccountID const dstAccountId = ctx_.tx[sfDestination];
192 sleCheck->setAccountID(sfDestination, dstAccountId);
193 sleCheck->setFieldU32(sfSequence, seq);
194 sleCheck->setFieldAmount(sfSendMax, ctx_.tx[sfSendMax]);
195 if (auto const srcTag = ctx_.tx[~sfSourceTag])
196 sleCheck->setFieldU32(sfSourceTag, *srcTag);
197 if (auto const dstTag = ctx_.tx[~sfDestinationTag])
198 sleCheck->setFieldU32(sfDestinationTag, *dstTag);
199 if (auto const invoiceId = ctx_.tx[~sfInvoiceID])
200 sleCheck->setFieldH256(sfInvoiceID, *invoiceId);
201 if (auto const expiry = ctx_.tx[~sfExpiration])
202 sleCheck->setFieldU32(sfExpiration, *expiry);
203
204 view().insert(sleCheck);
205
206 auto viewJ = ctx_.app.journal("View");
207 // If it's not a self-send (and it shouldn't be), add Check to the
208 // destination's owner directory.
209 if (dstAccountId != account_)
210 {
211 auto const page = view().dirInsert(
212 keylet::ownerDir(dstAccountId),
213 checkKeylet,
214 describeOwnerDir(dstAccountId));
215
216 JLOG(j_.trace()) << "Adding Check to destination directory "
217 << to_string(checkKeylet.key) << ": "
218 << (page ? "success" : "failure");
219
220 if (!page)
221 return tecDIR_FULL;
222
223 sleCheck->setFieldU64(sfDestinationNode, *page);
224 }
225
226 {
227 auto const page = view().dirInsert(
229 checkKeylet,
231
232 JLOG(j_.trace()) << "Adding Check to owner directory "
233 << to_string(checkKeylet.key) << ": "
234 << (page ? "success" : "failure");
235
236 if (!page)
237 return tecDIR_FULL;
238
239 sleCheck->setFieldU64(sfOwnerNode, *page);
240 }
241 // If we succeeded, the new entry counts against the creator's reserve.
242 adjustOwnerCount(view(), sle, 1, viewJ);
243 return tesSUCCESS;
244}
245
246} // namespace ripple
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
Stream warn() const
Definition: Journal.h:340
virtual beast::Journal journal(std::string const &name)=0
Application & app
Definition: ApplyContext.h:47
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:314
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
TER doApply() override
static NotTEC preflight(PreflightContext const &ctx)
Definition: CreateCheck.cpp:31
static TER preclaim(PreclaimContext const &ctx)
Definition: CreateCheck.cpp:82
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
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:130
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:651
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:665
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:484
void setAccountID(SField const &field, AccountID const &)
Definition: STObject.cpp:771
std::uint32_t getFlags() const
Definition: STObject.cpp:537
SeqProxy getSeqProxy() const
Definition: STTx.cpp:213
constexpr std::uint32_t value() const
Definition: SeqProxy.h:82
AccountID const account_
Definition: Transactor.h:91
ApplyView & view()
Definition: Transactor.h:107
beast::Journal const j_
Definition: Transactor.h:89
XRPAmount mPriorBalance
Definition: Transactor.h:92
ApplyContext & ctx_
Definition: Transactor.h:88
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:235
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:175
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:365
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:327
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:133
bool isLegalNet(STAmount const &value)
Definition: STAmount.h:581
@ lsfRequireDestTag
@ lsfHighFreeze
@ lsfDisallowIncomingCheck
@ lsfLowFreeze
bool isTesSuccess(TER x)
Definition: TER.h:656
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:924
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:81
@ tefINTERNAL
Definition: TER.h:173
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:185
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:133
@ tecNO_DST
Definition: TER.h:277
@ tecDIR_FULL
Definition: TER.h:274
@ tecFROZEN
Definition: TER.h:290
@ tecNO_PERMISSION
Definition: TER.h:292
@ tecDST_TAG_NEEDED
Definition: TER.h:296
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:294
@ tecEXPIRED
Definition: TER.h:301
@ tesSUCCESS
Definition: TER.h:242
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:62
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
Definition: View.cpp:164
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:173
@ temBAD_AMOUNT
Definition: TER.h:89
@ temREDUNDANT
Definition: TER.h:112
@ temBAD_CURRENCY
Definition: TER.h:90
@ temBAD_EXPIRATION
Definition: TER.h:91
@ temINVALID_FLAG
Definition: TER.h:111
@ temDISABLED
Definition: TER.h:114
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: protocol/Fees.h:49
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:39
uint256 key
Definition: Keylet.h:40
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:53
ReadView const & view
Definition: Transactor.h:56
beast::Journal const j
Definition: Transactor.h:60
State information when preflighting a tx.
Definition: Transactor.h:32
beast::Journal const j
Definition: Transactor.h:38