rippled
Loading...
Searching...
No Matches
CheckCreate.cpp
1#include <xrpl/ledger/View.h>
2#include <xrpl/ledger/helpers/AccountRootHelpers.h>
3#include <xrpl/ledger/helpers/DirectoryHelpers.h>
4#include <xrpl/ledger/helpers/RippleStateHelpers.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#include <xrpl/tx/transactors/check/CheckCreate.h>
10
11namespace xrpl {
12
15{
16 if (ctx.tx[sfAccount] == ctx.tx[sfDestination])
17 {
18 // They wrote a check to themselves.
19 JLOG(ctx.j.warn()) << "Malformed transaction: Check to self.";
20 return temREDUNDANT;
21 }
22
23 {
24 STAmount const sendMax{ctx.tx.getFieldAmount(sfSendMax)};
25 if (!isLegalNet(sendMax) || sendMax.signum() <= 0)
26 {
27 JLOG(ctx.j.warn()) << "Malformed transaction: bad sendMax amount: "
28 << sendMax.getFullText();
29 return temBAD_AMOUNT;
30 }
31
32 if (badCurrency() == sendMax.getCurrency())
33 {
34 JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
35 return temBAD_CURRENCY;
36 }
37 }
38
39 if (auto const optExpiry = ctx.tx[~sfExpiration])
40 {
41 if (*optExpiry == 0)
42 {
43 JLOG(ctx.j.warn()) << "Malformed transaction: bad expiration";
44 return temBAD_EXPIRATION;
45 }
46 }
47
48 return tesSUCCESS;
49}
50
51TER
53{
54 AccountID const dstId{ctx.tx[sfDestination]};
55 auto const sleDst = ctx.view.read(keylet::account(dstId));
56 if (!sleDst)
57 {
58 JLOG(ctx.j.warn()) << "Destination account does not exist.";
59 return tecNO_DST;
60 }
61
62 auto const flags = sleDst->getFlags();
63
64 // Check if the destination has disallowed incoming checks
65 if ((flags & lsfDisallowIncomingCheck) != 0u)
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) != 0u) && !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 =
104 ctx.view.read(keylet::line(srcId, issuerId, sendMax.getCurrency()));
105 if (sleTrust && sleTrust->isFlag((issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze))
106 {
107 JLOG(ctx.j.warn()) << "Creating a check for frozen trustline.";
108 return tecFROZEN;
109 }
110 }
111 if (issuerId != dstId)
112 {
113 // Check if dst froze the line.
114 auto const sleTrust =
115 ctx.view.read(keylet::line(issuerId, dstId, sendMax.getCurrency()));
116 if (sleTrust && sleTrust->isFlag((dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze))
117 {
118 JLOG(ctx.j.warn()) << "Creating a check for destination frozen trustline.";
119 return tecFROZEN;
120 }
121 }
122 }
123 }
124 if (hasExpired(ctx.view, ctx.tx[~sfExpiration]))
125 {
126 JLOG(ctx.j.warn()) << "Creating a check that has already expired.";
127 return tecEXPIRED;
128 }
129 return tesSUCCESS;
130}
131
132TER
134{
135 auto const sle = view().peek(keylet::account(account_));
136 if (!sle)
137 return tefINTERNAL; // LCOV_EXCL_LINE
138
139 // A check counts against the reserve of the issuing account, but we
140 // check the starting balance because we want to allow dipping into the
141 // reserve to pay fees.
142 {
143 STAmount const reserve{view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
144
145 if (preFeeBalance_ < reserve)
147 }
148
149 // Note that we use the value from the sequence or ticket as the
150 // Check sequence. For more explanation see comments in SeqProxy.h.
151 std::uint32_t const seq = ctx_.tx.getSeqValue();
152 Keylet const checkKeylet = keylet::check(account_, seq);
153 auto sleCheck = std::make_shared<SLE>(checkKeylet);
154
155 sleCheck->setAccountID(sfAccount, account_);
156 AccountID const dstAccountId = ctx_.tx[sfDestination];
157 sleCheck->setAccountID(sfDestination, dstAccountId);
158 sleCheck->setFieldU32(sfSequence, seq);
159 sleCheck->setFieldAmount(sfSendMax, ctx_.tx[sfSendMax]);
160 if (auto const srcTag = ctx_.tx[~sfSourceTag])
161 sleCheck->setFieldU32(sfSourceTag, *srcTag);
162 if (auto const dstTag = ctx_.tx[~sfDestinationTag])
163 sleCheck->setFieldU32(sfDestinationTag, *dstTag);
164 if (auto const invoiceId = ctx_.tx[~sfInvoiceID])
165 sleCheck->setFieldH256(sfInvoiceID, *invoiceId);
166 if (auto const expiry = ctx_.tx[~sfExpiration])
167 sleCheck->setFieldU32(sfExpiration, *expiry);
168
169 view().insert(sleCheck);
170
171 auto viewJ = ctx_.registry.get().getJournal("View");
172 // If it's not a self-send (and it shouldn't be), add Check to the
173 // destination's owner directory.
174 if (dstAccountId != account_)
175 {
176 auto const page = view().dirInsert(
177 keylet::ownerDir(dstAccountId), checkKeylet, describeOwnerDir(dstAccountId));
178
179 JLOG(j_.trace()) << "Adding Check to destination directory " << to_string(checkKeylet.key)
180 << ": " << (page ? "success" : "failure");
181
182 if (!page)
183 return tecDIR_FULL; // LCOV_EXCL_LINE
184
185 sleCheck->setFieldU64(sfDestinationNode, *page);
186 }
187
188 {
189 auto const page =
191
192 JLOG(j_.trace()) << "Adding Check to owner directory " << to_string(checkKeylet.key) << ": "
193 << (page ? "success" : "failure");
194
195 if (!page)
196 return tecDIR_FULL; // LCOV_EXCL_LINE
197
198 sleCheck->setFieldU64(sfOwnerNode, *page);
199 }
200 // If we succeeded, the new entry counts against the creator's reserve.
201 adjustOwnerCount(view(), sle, 1, viewJ);
202 return tesSUCCESS;
203}
204
205} // namespace xrpl
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
Stream warn() const
Definition Journal.h:313
STTx const & tx
std::reference_wrapper< ServiceRegistry > registry
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:289
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
TER doApply() override
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:456
void setAccountID(SField const &field, AccountID const &)
Definition STObject.cpp:771
AccountID getAccountID(SField const &field) const
Definition STObject.cpp:635
STAmount const & getFieldAmount(SField const &field) const
Definition STObject.cpp:649
std::uint32_t getSeqValue() const
Returns the first non-zero value of (Sequence, TicketSequence).
Definition STTx.cpp:211
AccountID const account_
Definition Transactor.h:116
beast::Journal const j_
Definition Transactor.h:114
ApplyView & view()
Definition Transactor.h:132
XRPAmount preFeeBalance_
Definition Transactor.h:117
ApplyContext & ctx_
Definition Transactor.h:112
T is_same_v
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:336
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition Indexes.cpp:301
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:165
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:602
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
Definition View.cpp:34
@ tefINTERNAL
Definition TER.h:153
bool isLegalNet(STAmount const &value)
Definition STAmount.h:584
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct, std::set< SField const * > const &pseudoFieldFilter={})
Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFil...
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Check if the issuer has the global freeze flag set.
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
@ 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
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:582
@ 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:57
ReadView const & view
Definition Transactor.h:60
beast::Journal const j
Definition Transactor.h:65
State information when preflighting a tx.
Definition Transactor.h:14
beast::Journal const j
Definition Transactor.h:21