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 (ctx.view.rules().enabled(featureDisallowIncoming) &&
66 return tecNO_PERMISSION;
67
68 // Pseudo-accounts cannot cash checks. Note, this is not amendment-gated
69 // because all writes to pseudo-account discriminator fields **are**
70 // amendment gated, hence the behaviour of this check will always match the
71 // currently active amendments.
72 if (isPseudoAccount(sleDst))
73 return tecNO_PERMISSION;
74
75 if ((flags & lsfRequireDestTag) && !ctx.tx.isFieldPresent(sfDestinationTag))
76 {
77 // The tag is basically account-specific information we don't
78 // understand, but we can require someone to fill it in.
79 JLOG(ctx.j.warn()) << "Malformed transaction: DestinationTag required.";
80 return tecDST_TAG_NEEDED;
81 }
82
83 {
84 STAmount const sendMax{ctx.tx[sfSendMax]};
85 if (!sendMax.native())
86 {
87 // The currency may not be globally frozen
88 AccountID const& issuerId{sendMax.getIssuer()};
89 if (isGlobalFrozen(ctx.view, issuerId))
90 {
91 JLOG(ctx.j.warn()) << "Creating a check for frozen asset";
92 return tecFROZEN;
93 }
94 // If this account has a trustline for the currency, that
95 // trustline may not be frozen.
96 //
97 // Note that we DO allow create check for a currency that the
98 // account does not yet have a trustline to.
99 AccountID const srcId{ctx.tx.getAccountID(sfAccount)};
100 if (issuerId != srcId)
101 {
102 // Check if the issuer froze the line
103 auto const sleTrust = ctx.view.read(
104 keylet::line(srcId, issuerId, sendMax.getCurrency()));
105 if (sleTrust &&
106 sleTrust->isFlag(
107 (issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze))
108 {
109 JLOG(ctx.j.warn())
110 << "Creating a check for frozen trustline.";
111 return tecFROZEN;
112 }
113 }
114 if (issuerId != dstId)
115 {
116 // Check if dst froze the line.
117 auto const sleTrust = ctx.view.read(
118 keylet::line(issuerId, dstId, sendMax.getCurrency()));
119 if (sleTrust &&
120 sleTrust->isFlag(
121 (dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze))
122 {
123 JLOG(ctx.j.warn())
124 << "Creating a check for destination frozen trustline.";
125 return tecFROZEN;
126 }
127 }
128 }
129 }
130 if (hasExpired(ctx.view, ctx.tx[~sfExpiration]))
131 {
132 JLOG(ctx.j.warn()) << "Creating a check that has already expired.";
133 return tecEXPIRED;
134 }
135 return tesSUCCESS;
136}
137
138TER
140{
141 auto const sle = view().peek(keylet::account(account_));
142 if (!sle)
143 return tefINTERNAL; // LCOV_EXCL_LINE
144
145 // A check counts against the reserve of the issuing account, but we
146 // check the starting balance because we want to allow dipping into the
147 // reserve to pay fees.
148 {
149 STAmount const reserve{
150 view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
151
152 if (mPriorBalance < reserve)
154 }
155
156 // Note that we use the value from the sequence or ticket as the
157 // Check sequence. For more explanation see comments in SeqProxy.h.
158 std::uint32_t const seq = ctx_.tx.getSeqValue();
159 Keylet const checkKeylet = keylet::check(account_, seq);
160 auto sleCheck = std::make_shared<SLE>(checkKeylet);
161
162 sleCheck->setAccountID(sfAccount, account_);
163 AccountID const dstAccountId = ctx_.tx[sfDestination];
164 sleCheck->setAccountID(sfDestination, dstAccountId);
165 sleCheck->setFieldU32(sfSequence, seq);
166 sleCheck->setFieldAmount(sfSendMax, ctx_.tx[sfSendMax]);
167 if (auto const srcTag = ctx_.tx[~sfSourceTag])
168 sleCheck->setFieldU32(sfSourceTag, *srcTag);
169 if (auto const dstTag = ctx_.tx[~sfDestinationTag])
170 sleCheck->setFieldU32(sfDestinationTag, *dstTag);
171 if (auto const invoiceId = ctx_.tx[~sfInvoiceID])
172 sleCheck->setFieldH256(sfInvoiceID, *invoiceId);
173 if (auto const expiry = ctx_.tx[~sfExpiration])
174 sleCheck->setFieldU32(sfExpiration, *expiry);
175
176 view().insert(sleCheck);
177
178 auto viewJ = ctx_.app.journal("View");
179 // If it's not a self-send (and it shouldn't be), add Check to the
180 // destination's owner directory.
181 if (dstAccountId != account_)
182 {
183 auto const page = view().dirInsert(
184 keylet::ownerDir(dstAccountId),
185 checkKeylet,
186 describeOwnerDir(dstAccountId));
187
188 JLOG(j_.trace()) << "Adding Check to destination directory "
189 << to_string(checkKeylet.key) << ": "
190 << (page ? "success" : "failure");
191
192 if (!page)
193 return tecDIR_FULL; // LCOV_EXCL_LINE
194
195 sleCheck->setFieldU64(sfDestinationNode, *page);
196 }
197
198 {
199 auto const page = view().dirInsert(
201 checkKeylet,
203
204 JLOG(j_.trace()) << "Adding Check to owner directory "
205 << to_string(checkKeylet.key) << ": "
206 << (page ? "success" : "failure");
207
208 if (!page)
209 return tecDIR_FULL; // LCOV_EXCL_LINE
210
211 sleCheck->setFieldU64(sfOwnerNode, *page);
212 }
213 // If we succeeded, the new entry counts against the creator's reserve.
214 adjustOwnerCount(view(), sle, 1, viewJ);
215 return tesSUCCESS;
216}
217
218} // 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.
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:111
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