rippled
Loading...
Searching...
No Matches
CreateCheck.cpp
1#include <xrpld/app/tx/detail/CreateCheck.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/ledger/View.h>
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/Indexes.h>
7#include <xrpl/protocol/TER.h>
8#include <xrpl/protocol/TxFlags.h>
9
10namespace ripple {
11
14{
15 if (ctx.tx[sfAccount] == ctx.tx[sfDestination])
16 {
17 // They wrote a check to themselves.
18 JLOG(ctx.j.warn()) << "Malformed transaction: Check to self.";
19 return temREDUNDANT;
20 }
21
22 {
23 STAmount const sendMax{ctx.tx.getFieldAmount(sfSendMax)};
24 if (!isLegalNet(sendMax) || sendMax.signum() <= 0)
25 {
26 JLOG(ctx.j.warn()) << "Malformed transaction: bad sendMax amount: "
27 << sendMax.getFullText();
28 return temBAD_AMOUNT;
29 }
30
31 if (badCurrency() == sendMax.getCurrency())
32 {
33 JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
34 return temBAD_CURRENCY;
35 }
36 }
37
38 if (auto const optExpiry = ctx.tx[~sfExpiration])
39 {
40 if (*optExpiry == 0)
41 {
42 JLOG(ctx.j.warn()) << "Malformed transaction: bad expiration";
43 return temBAD_EXPIRATION;
44 }
45 }
46
47 return tesSUCCESS;
48}
49
50TER
52{
53 AccountID const dstId{ctx.tx[sfDestination]};
54 auto const sleDst = ctx.view.read(keylet::account(dstId));
55 if (!sleDst)
56 {
57 JLOG(ctx.j.warn()) << "Destination account does not exist.";
58 return tecNO_DST;
59 }
60
61 auto const flags = sleDst->getFlags();
62
63 // Check if the destination has disallowed incoming checks
64 if (flags & lsfDisallowIncomingCheck)
65 return tecNO_PERMISSION;
66
67 // Pseudo-accounts cannot cash checks. Note, this is not amendment-gated
68 // because all writes to pseudo-account discriminator fields **are**
69 // amendment gated, hence the behaviour of this check will always match the
70 // currently active amendments.
71 if (isPseudoAccount(sleDst))
72 return tecNO_PERMISSION;
73
74 if ((flags & lsfRequireDestTag) && !ctx.tx.isFieldPresent(sfDestinationTag))
75 {
76 // The tag is basically account-specific information we don't
77 // understand, but we can require someone to fill it in.
78 JLOG(ctx.j.warn()) << "Malformed transaction: DestinationTag required.";
79 return tecDST_TAG_NEEDED;
80 }
81
82 {
83 STAmount const sendMax{ctx.tx[sfSendMax]};
84 if (!sendMax.native())
85 {
86 // The currency may not be globally frozen
87 AccountID const& issuerId{sendMax.getIssuer()};
88 if (isGlobalFrozen(ctx.view, issuerId))
89 {
90 JLOG(ctx.j.warn()) << "Creating a check for frozen asset";
91 return tecFROZEN;
92 }
93 // If this account has a trustline for the currency, that
94 // trustline may not be frozen.
95 //
96 // Note that we DO allow create check for a currency that the
97 // account does not yet have a trustline to.
98 AccountID const srcId{ctx.tx.getAccountID(sfAccount)};
99 if (issuerId != srcId)
100 {
101 // Check if the issuer froze the line
102 auto const sleTrust = ctx.view.read(
103 keylet::line(srcId, issuerId, sendMax.getCurrency()));
104 if (sleTrust &&
105 sleTrust->isFlag(
106 (issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze))
107 {
108 JLOG(ctx.j.warn())
109 << "Creating a check for frozen trustline.";
110 return tecFROZEN;
111 }
112 }
113 if (issuerId != dstId)
114 {
115 // Check if dst froze the line.
116 auto const sleTrust = ctx.view.read(
117 keylet::line(issuerId, dstId, sendMax.getCurrency()));
118 if (sleTrust &&
119 sleTrust->isFlag(
120 (dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze))
121 {
122 JLOG(ctx.j.warn())
123 << "Creating a check for destination frozen trustline.";
124 return tecFROZEN;
125 }
126 }
127 }
128 }
129 if (hasExpired(ctx.view, ctx.tx[~sfExpiration]))
130 {
131 JLOG(ctx.j.warn()) << "Creating a check that has already expired.";
132 return tecEXPIRED;
133 }
134 return tesSUCCESS;
135}
136
137TER
139{
140 auto const sle = view().peek(keylet::account(account_));
141 if (!sle)
142 return tefINTERNAL; // LCOV_EXCL_LINE
143
144 // A check counts against the reserve of the issuing account, but we
145 // check the starting balance because we want to allow dipping into the
146 // reserve to pay fees.
147 {
148 STAmount const reserve{
149 view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
150
151 if (mPriorBalance < reserve)
153 }
154
155 // Note that we use the value from the sequence or ticket as the
156 // Check sequence. For more explanation see comments in SeqProxy.h.
157 std::uint32_t const seq = ctx_.tx.getSeqValue();
158 Keylet const checkKeylet = keylet::check(account_, seq);
159 auto sleCheck = std::make_shared<SLE>(checkKeylet);
160
161 sleCheck->setAccountID(sfAccount, account_);
162 AccountID const dstAccountId = ctx_.tx[sfDestination];
163 sleCheck->setAccountID(sfDestination, dstAccountId);
164 sleCheck->setFieldU32(sfSequence, seq);
165 sleCheck->setFieldAmount(sfSendMax, ctx_.tx[sfSendMax]);
166 if (auto const srcTag = ctx_.tx[~sfSourceTag])
167 sleCheck->setFieldU32(sfSourceTag, *srcTag);
168 if (auto const dstTag = ctx_.tx[~sfDestinationTag])
169 sleCheck->setFieldU32(sfDestinationTag, *dstTag);
170 if (auto const invoiceId = ctx_.tx[~sfInvoiceID])
171 sleCheck->setFieldH256(sfInvoiceID, *invoiceId);
172 if (auto const expiry = ctx_.tx[~sfExpiration])
173 sleCheck->setFieldU32(sfExpiration, *expiry);
174
175 view().insert(sleCheck);
176
177 auto viewJ = ctx_.app.journal("View");
178 // If it's not a self-send (and it shouldn't be), add Check to the
179 // destination's owner directory.
180 if (dstAccountId != account_)
181 {
182 auto const page = view().dirInsert(
183 keylet::ownerDir(dstAccountId),
184 checkKeylet,
185 describeOwnerDir(dstAccountId));
186
187 JLOG(j_.trace()) << "Adding Check to destination directory "
188 << to_string(checkKeylet.key) << ": "
189 << (page ? "success" : "failure");
190
191 if (!page)
192 return tecDIR_FULL; // LCOV_EXCL_LINE
193
194 sleCheck->setFieldU64(sfDestinationNode, *page);
195 }
196
197 {
198 auto const page = view().dirInsert(
200 checkKeylet,
202
203 JLOG(j_.trace()) << "Adding Check to owner directory "
204 << to_string(checkKeylet.key) << ": "
205 << (page ? "success" : "failure");
206
207 if (!page)
208 return tecDIR_FULL; // LCOV_EXCL_LINE
209
210 sleCheck->setFieldU64(sfOwnerNode, *page);
211 }
212 // If we succeeded, the new entry counts against the creator's reserve.
213 adjustOwnerCount(view(), sle, 1, viewJ);
214 return tesSUCCESS;
215}
216
217} // namespace ripple
Stream trace() const
Severity stream access functions.
Definition Journal.h:303
Stream warn() const
Definition Journal.h:321
virtual beast::Journal journal(std::string const &name)=0
Application & app
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:300
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)
static TER preclaim(PreclaimContext const &ctx)
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.
AccountID getAccountID(SField const &field) const
Definition STObject.cpp:638
STAmount const & getFieldAmount(SField const &field) const
Definition STObject.cpp:652
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:465
void setAccountID(SField const &field, AccountID const &)
Definition STObject.cpp:774
std::uint32_t getSeqValue() const
Returns the first non-zero value of (Sequence, TicketSequence).
Definition STTx.cpp:212
AccountID const account_
Definition Transactor.h:128
ApplyView & view()
Definition Transactor.h:144
beast::Journal const j_
Definition Transactor.h:126
XRPAmount mPriorBalance
Definition Transactor.h:129
ApplyContext & ctx_
Definition Transactor.h:124
T is_same_v
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:225
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:355
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition Indexes.cpp:317
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
bool isLegalNet(STAmount const &value)
Definition STAmount.h:581
@ lsfRequireDestTag
@ lsfDisallowIncomingCheck
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition View.cpp:1013
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition View.cpp:1031
@ tefINTERNAL
Definition TER.h:154
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
Definition View.cpp:154
@ tecNO_DST
Definition TER.h:272
@ tecDIR_FULL
Definition TER.h:269
@ tecFROZEN
Definition TER.h:285
@ tecNO_PERMISSION
Definition TER.h:287
@ tecDST_TAG_NEEDED
Definition TER.h:291
@ tecINSUFFICIENT_RESERVE
Definition TER.h:289
@ tecEXPIRED
Definition TER.h:296
@ tesSUCCESS
Definition TER.h:226
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
Definition View.cpp:1099
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:590
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Definition View.cpp:163
@ temBAD_AMOUNT
Definition TER.h:70
@ temREDUNDANT
Definition TER.h:93
@ temBAD_CURRENCY
Definition TER.h:71
@ temBAD_EXPIRATION
Definition TER.h:72
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:20
uint256 key
Definition Keylet.h:21
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:16
beast::Journal const j
Definition Transactor.h:23