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