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/ledger/Ledger.h>
21#include <xrpld/app/tx/detail/CreateCheck.h>
22#include <xrpl/basics/Log.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/Indexes.h>
25#include <xrpl/protocol/STAccount.h>
26#include <xrpl/protocol/TER.h>
27#include <xrpl/protocol/TxFlags.h>
28
29namespace ripple {
30
33{
34 if (!ctx.rules.enabled(featureChecks))
35 return temDISABLED;
36
37 NotTEC const ret{preflight1(ctx)};
38 if (!isTesSuccess(ret))
39 return ret;
40
41 if (ctx.tx.getFlags() & tfUniversalMask)
42 {
43 // There are no flags (other than universal) for CreateCheck yet.
44 JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set.";
45 return temINVALID_FLAG;
46 }
47 if (ctx.tx[sfAccount] == ctx.tx[sfDestination])
48 {
49 // They wrote a check to themselves.
50 JLOG(ctx.j.warn()) << "Malformed transaction: Check to self.";
51 return temREDUNDANT;
52 }
53
54 {
55 STAmount const sendMax{ctx.tx.getFieldAmount(sfSendMax)};
56 if (!isLegalNet(sendMax) || sendMax.signum() <= 0)
57 {
58 JLOG(ctx.j.warn()) << "Malformed transaction: bad sendMax amount: "
59 << sendMax.getFullText();
60 return temBAD_AMOUNT;
61 }
62
63 if (badCurrency() == sendMax.getCurrency())
64 {
65 JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
66 return temBAD_CURRENCY;
67 }
68 }
69
70 if (auto const optExpiry = ctx.tx[~sfExpiration])
71 {
72 if (*optExpiry == 0)
73 {
74 JLOG(ctx.j.warn()) << "Malformed transaction: bad expiration";
75 return temBAD_EXPIRATION;
76 }
77 }
78
79 return preflight2(ctx);
80}
81
82TER
84{
85 AccountID const dstId{ctx.tx[sfDestination]};
86 auto const sleDst = ctx.view.read(keylet::account(dstId));
87 if (!sleDst)
88 {
89 JLOG(ctx.j.warn()) << "Destination account does not exist.";
90 return tecNO_DST;
91 }
92
93 auto const flags = sleDst->getFlags();
94
95 // Check if the destination has disallowed incoming checks
96 if (ctx.view.rules().enabled(featureDisallowIncoming) &&
98 return tecNO_PERMISSION;
99
100 // AMM can not cash the check
101 if (sleDst->isFieldPresent(sfAMMID))
102 return tecNO_PERMISSION;
103
104 if ((flags & lsfRequireDestTag) && !ctx.tx.isFieldPresent(sfDestinationTag))
105 {
106 // The tag is basically account-specific information we don't
107 // understand, but we can require someone to fill it in.
108 JLOG(ctx.j.warn()) << "Malformed transaction: DestinationTag required.";
109 return tecDST_TAG_NEEDED;
110 }
111
112 {
113 STAmount const sendMax{ctx.tx[sfSendMax]};
114 if (!sendMax.native())
115 {
116 // The currency may not be globally frozen
117 AccountID const& issuerId{sendMax.getIssuer()};
118 if (isGlobalFrozen(ctx.view, issuerId))
119 {
120 JLOG(ctx.j.warn()) << "Creating a check for frozen asset";
121 return tecFROZEN;
122 }
123 // If this account has a trustline for the currency, that
124 // trustline may not be frozen.
125 //
126 // Note that we DO allow create check for a currency that the
127 // account does not yet have a trustline to.
128 AccountID const srcId{ctx.tx.getAccountID(sfAccount)};
129 if (issuerId != srcId)
130 {
131 // Check if the issuer froze the line
132 auto const sleTrust = ctx.view.read(
133 keylet::line(srcId, issuerId, sendMax.getCurrency()));
134 if (sleTrust &&
135 sleTrust->isFlag(
136 (issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze))
137 {
138 JLOG(ctx.j.warn())
139 << "Creating a check for frozen trustline.";
140 return tecFROZEN;
141 }
142 }
143 if (issuerId != dstId)
144 {
145 // Check if dst froze the line.
146 auto const sleTrust = ctx.view.read(
147 keylet::line(issuerId, dstId, sendMax.getCurrency()));
148 if (sleTrust &&
149 sleTrust->isFlag(
150 (dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze))
151 {
152 JLOG(ctx.j.warn())
153 << "Creating a check for destination frozen trustline.";
154 return tecFROZEN;
155 }
156 }
157 }
158 }
159 if (hasExpired(ctx.view, ctx.tx[~sfExpiration]))
160 {
161 JLOG(ctx.j.warn()) << "Creating a check that has already expired.";
162 return tecEXPIRED;
163 }
164 return tesSUCCESS;
165}
166
167TER
169{
170 auto const sle = view().peek(keylet::account(account_));
171 if (!sle)
172 return tefINTERNAL;
173
174 // A check counts against the reserve of the issuing account, but we
175 // check the starting balance because we want to allow dipping into the
176 // reserve to pay fees.
177 {
178 STAmount const reserve{
179 view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
180
181 if (mPriorBalance < reserve)
183 }
184
185 // Note that we use the value from the sequence or ticket as the
186 // Check sequence. For more explanation see comments in SeqProxy.h.
187 std::uint32_t const seq = ctx_.tx.getSeqProxy().value();
188 Keylet const checkKeylet = keylet::check(account_, seq);
189 auto sleCheck = std::make_shared<SLE>(checkKeylet);
190
191 sleCheck->setAccountID(sfAccount, account_);
192 AccountID const dstAccountId = ctx_.tx[sfDestination];
193 sleCheck->setAccountID(sfDestination, dstAccountId);
194 sleCheck->setFieldU32(sfSequence, seq);
195 sleCheck->setFieldAmount(sfSendMax, ctx_.tx[sfSendMax]);
196 if (auto const srcTag = ctx_.tx[~sfSourceTag])
197 sleCheck->setFieldU32(sfSourceTag, *srcTag);
198 if (auto const dstTag = ctx_.tx[~sfDestinationTag])
199 sleCheck->setFieldU32(sfDestinationTag, *dstTag);
200 if (auto const invoiceId = ctx_.tx[~sfInvoiceID])
201 sleCheck->setFieldH256(sfInvoiceID, *invoiceId);
202 if (auto const expiry = ctx_.tx[~sfExpiration])
203 sleCheck->setFieldU32(sfExpiration, *expiry);
204
205 view().insert(sleCheck);
206
207 auto viewJ = ctx_.app.journal("View");
208 // If it's not a self-send (and it shouldn't be), add Check to the
209 // destination's owner directory.
210 if (dstAccountId != account_)
211 {
212 auto const page = view().dirInsert(
213 keylet::ownerDir(dstAccountId),
214 checkKeylet,
215 describeOwnerDir(dstAccountId));
216
217 JLOG(j_.trace()) << "Adding Check to destination directory "
218 << to_string(checkKeylet.key) << ": "
219 << (page ? "success" : "failure");
220
221 if (!page)
222 return tecDIR_FULL;
223
224 sleCheck->setFieldU64(sfDestinationNode, *page);
225 }
226
227 {
228 auto const page = view().dirInsert(
230 checkKeylet,
232
233 JLOG(j_.trace()) << "Adding Check to owner directory "
234 << to_string(checkKeylet.key) << ": "
235 << (page ? "success" : "failure");
236
237 if (!page)
238 return tecDIR_FULL;
239
240 sleCheck->setFieldU64(sfOwnerNode, *page);
241 }
242 // If we succeeded, the new entry counts against the creator's reserve.
243 adjustOwnerCount(view(), sle, 1, viewJ);
244 return tesSUCCESS;
245}
246
247} // namespace ripple
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
Stream warn() const
Definition: Journal.h:329
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:32
static TER preclaim(PreclaimContext const &ctx)
Definition: CreateCheck.cpp:83
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:122
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:621
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:635
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:454
void setAccountID(SField const &field, AccountID const &)
Definition: STObject.cpp:741
std::uint32_t getFlags() const
Definition: STObject.cpp:507
SeqProxy getSeqProxy() const
Definition: STTx.cpp:186
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:220
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:160
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:350
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:312
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:129
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:925
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
@ tefINTERNAL
Definition: TER.h:173
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
@ 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:629
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