rippled
Loading...
Searching...
No Matches
CreateTicket.cpp
1#include <xrpld/app/tx/detail/CreateTicket.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/protocol/Feature.h>
5#include <xrpl/protocol/Indexes.h>
6#include <xrpl/protocol/TxFlags.h>
7
8namespace xrpl {
9
10TxConsequences
12{
13 // Create TxConsequences identifying the number of sequences consumed.
14 return TxConsequences{ctx.tx, ctx.tx[sfTicketCount]};
15}
16
19{
20 if (std::uint32_t const count = ctx.tx[sfTicketCount]; count < minValidCount || count > maxValidCount)
21 return temINVALID_COUNT;
22
23 return tesSUCCESS;
24}
25
26TER
28{
29 auto const id = ctx.tx[sfAccount];
30 auto const sleAccountRoot = ctx.view.read(keylet::account(id));
31 if (!sleAccountRoot)
32 return terNO_ACCOUNT;
33
34 // Make sure the TicketCreate would not cause the account to own
35 // too many tickets.
36 std::uint32_t const curTicketCount = (*sleAccountRoot)[~sfTicketCount].value_or(0u);
37 std::uint32_t const addedTickets = ctx.tx[sfTicketCount];
38 std::uint32_t const consumedTickets = ctx.tx.getSeqProxy().isTicket() ? 1u : 0u;
39
40 // Note that unsigned integer underflow can't currently happen because
41 // o curTicketCount >= 0
42 // o addedTickets >= 1
43 // o consumedTickets <= 1
44 // So in the worst case addedTickets == consumedTickets and the
45 // computation yields curTicketCount.
46 if (curTicketCount + addedTickets - consumedTickets > maxTicketThreshold)
47 return tecDIR_FULL;
48
49 return tesSUCCESS;
50}
51
52TER
54{
55 SLE::pointer const sleAccountRoot = view().peek(keylet::account(account_));
56 if (!sleAccountRoot)
57 return tefINTERNAL; // LCOV_EXCL_LINE
58
59 // Each ticket counts against the reserve of the issuing account, but we
60 // check the starting balance because we want to allow dipping into the
61 // reserve to pay fees.
62 std::uint32_t const ticketCount = ctx_.tx[sfTicketCount];
63 {
64 XRPAmount const reserve = view().fees().accountReserve(sleAccountRoot->getFieldU32(sfOwnerCount) + ticketCount);
65
66 if (mPriorBalance < reserve)
68 }
69
70 beast::Journal viewJ{ctx_.app.journal("View")};
71
72 // The starting ticket sequence is the same as the current account
73 // root sequence. Before we got here to doApply(), the transaction
74 // machinery already incremented the account root sequence if that
75 // was appropriate.
76 std::uint32_t const firstTicketSeq = (*sleAccountRoot)[sfSequence];
77
78 // Sanity check that the transaction machinery really did already
79 // increment the account root Sequence.
80 if (std::uint32_t const txSeq = ctx_.tx[sfSequence]; txSeq != 0 && txSeq != (firstTicketSeq - 1))
81 return tefINTERNAL; // LCOV_EXCL_LINE
82
83 for (std::uint32_t i = 0; i < ticketCount; ++i)
84 {
85 std::uint32_t const curTicketSeq = firstTicketSeq + i;
86 Keylet const ticketKeylet = keylet::ticket(account_, curTicketSeq);
87 SLE::pointer sleTicket = std::make_shared<SLE>(ticketKeylet);
88
89 sleTicket->setAccountID(sfAccount, account_);
90 sleTicket->setFieldU32(sfTicketSequence, curTicketSeq);
91 view().insert(sleTicket);
92
93 auto const page = view().dirInsert(keylet::ownerDir(account_), ticketKeylet, describeOwnerDir(account_));
94
95 JLOG(j_.trace()) << "Creating ticket " << to_string(ticketKeylet.key) << ": " << (page ? "success" : "failure");
96
97 if (!page)
98 return tecDIR_FULL; // LCOV_EXCL_LINE
99
100 sleTicket->setFieldU64(sfOwnerNode, *page);
101 }
102
103 // Update the record of the number of Tickets this account owns.
104 std::uint32_t const oldTicketCount = (*(sleAccountRoot))[~sfTicketCount].value_or(0u);
105
106 sleAccountRoot->setFieldU32(sfTicketCount, oldTicketCount + ticketCount);
107
108 // Every added Ticket counts against the creator's reserve.
109 adjustOwnerCount(view(), sleAccountRoot, ticketCount, viewJ);
110
111 // TicketCreate is the only transaction that can cause an account root's
112 // Sequence field to increase by more than one. October 2018.
113 sleAccountRoot->setFieldU32(sfSequence, firstTicketSeq + ticketCount);
114
115 return tesSUCCESS;
116}
117
118} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:41
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
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:284
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
static TER preclaim(PreclaimContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
static constexpr std::uint32_t maxTicketThreshold
static constexpr std::uint32_t maxValidCount
TER doApply() override
Precondition: fee collection is likely.
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.
SeqProxy getSeqProxy() const
Definition STTx.cpp:193
constexpr bool isTicket() const
Definition SeqProxy.h:75
AccountID const account_
Definition Transactor.h:113
beast::Journal const j_
Definition Transactor.h:111
ApplyView & view()
Definition Transactor.h:129
XRPAmount mPriorBalance
Definition Transactor.h:114
ApplyContext & ctx_
Definition Transactor.h:109
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition applySteps.h:38
T is_same_v
static ticket_t const ticket
Definition Indexes.h:149
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:325
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:6
@ terNO_ACCOUNT
Definition TER.h:198
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:598
@ tefINTERNAL
Definition TER.h:154
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
@ temINVALID_COUNT
Definition TER.h:102
@ tecDIR_FULL
Definition TER.h:269
@ tecINSUFFICIENT_RESERVE
Definition TER.h:289
@ tesSUCCESS
Definition TER.h:226
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:54
ReadView const & view
Definition Transactor.h:57
State information when preflighting a tx.
Definition Transactor.h:16