xrpld
Loading...
Searching...
No Matches
LocalTxs.cpp
1#include <xrpld/app/ledger/LocalTxs.h>
2
3#include <xrpl/basics/base_uint.h>
4#include <xrpl/ledger/CanonicalTXSet.h>
5#include <xrpl/ledger/ReadView.h>
6#include <xrpl/protocol/AccountID.h>
7#include <xrpl/protocol/Indexes.h>
8#include <xrpl/protocol/Protocol.h>
9#include <xrpl/protocol/SField.h>
10#include <xrpl/protocol/STTx.h>
11#include <xrpl/protocol/SeqProxy.h>
12
13#include <algorithm>
14#include <cstddef>
15#include <list>
16#include <memory>
17#include <mutex>
18
19/*
20 This code prevents scenarios like the following:
211) A client submits a transaction.
222) The transaction gets into the ledger this server
23 believes will be the consensus ledger.
243) The server builds a succeeding open ledger without the
25 transaction (because it's in the prior ledger).
264) The local consensus ledger is not the majority ledger
27 (due to network conditions, Byzantine fault, etcetera)
28 the majority ledger does not include the transaction.
295) The server builds a new open ledger that does not include
30 the transaction or have it in a prior ledger.
316) The client submits another transaction and gets a terPRE_SEQ
32 preliminary result.
337) The server does not relay that second transaction, at least
34 not yet.
35
36With this code, when step 5 happens, the first transaction will
37be applied to that open ledger so the second transaction will
38succeed normally at step 6. Transactions remain tracked and
39test-applied to all new open ledgers until seen in a fully-
40validated ledger
41*/
42
43namespace xrpl {
44
45// This class wraps a pointer to a transaction along with
46// its expiration ledger. It also caches the issuing account.
48{
49public:
51 : txn_(txn)
52 , expire_(index + LocalTxs::kHoldLedgers)
53 , id_(txn->getTransactionID())
54 , account_(txn->getAccountID(sfAccount))
55 , seqProxy_(txn->getSeqProxy())
56 {
57 if (txn->isFieldPresent(sfLastLedgerSequence))
58 expire_ = std::min(expire_, txn->getFieldU32(sfLastLedgerSequence) + 1);
59 }
60
61 [[nodiscard]] uint256 const&
62 getID() const
63 {
64 return id_;
65 }
66
67 [[nodiscard]] SeqProxy
69 {
70 return seqProxy_;
71 }
72
73 [[nodiscard]] bool
75 {
76 return i > expire_;
77 }
78
79 [[nodiscard]] std::shared_ptr<STTx const> const&
80 getTX() const
81 {
82 return txn_;
83 }
84
85 [[nodiscard]] AccountID const&
86 getAccount() const
87 {
88 return account_;
89 }
90
91private:
97};
98
99//------------------------------------------------------------------------------
100
101class LocalTxsImp : public LocalTxs
102{
103public:
104 LocalTxsImp() = default;
105
106 // Add a new transaction to the set of local transactions
107 void
109 {
110 std::scoped_lock const lock(lock_);
111
112 txns_.emplace_back(index, txn);
113 }
114
116 getTxSet() override
117 {
118 CanonicalTXSet tset(uint256{});
119
120 // Get the set of local transactions as a canonical
121 // set (so they apply in a valid order)
122 {
123 std::scoped_lock const lock(lock_);
124
125 for (auto const& it : txns_)
126 tset.insert(it.getTX());
127 }
128 return tset;
129 }
130
131 // Remove transactions that have either been accepted
132 // into a fully-validated ledger, are (now) impossible,
133 // or have expired
134 void
135 sweep(ReadView const& view) override
136 {
137 std::scoped_lock const lock(lock_);
138
139 txns_.remove_if([&view](auto const& txn) {
140 if (txn.isExpired(view.header().seq))
141 return true;
142 if (view.txExists(txn.getID()))
143 return true;
144
145 AccountID const acctID = txn.getAccount();
146 auto const sleAcct = view.read(keylet::account(acctID));
147
148 if (!sleAcct)
149 return false;
150
151 SeqProxy const acctSeq = SeqProxy::rawSequence(sleAcct->getFieldU32(sfSequence));
152 SeqProxy const seqProx = txn.getSeqProxy();
153
154 if (seqProx.isSeq())
155 return acctSeq > seqProx; // Remove tefPAST_SEQ
156
157 if (seqProx.isTicket() && acctSeq.value() <= seqProx.value())
158 {
159 // Keep ticket from the future. Note, however, that the
160 // transaction will not be held indefinitely since LocalTxs
161 // will only hold a transaction for a maximum of 5 ledgers.
162 return false;
163 }
164
165 // Ticket should have been created by now. Remove if ticket
166 // does not exist.
167 return !view.exists(keylet::ticket(acctID, seqProx));
168 });
169 }
170
172 size() override
173 {
174 std::scoped_lock const lock(lock_);
175
176 return txns_.size();
177 }
178
179private:
182};
183
189
190} // namespace xrpl
Holds transactions which were deferred to the next pass of consensus.
void insert(std::shared_ptr< STTx const > txn)
LedgerIndex expire_
Definition LocalTxs.cpp:93
SeqProxy seqProxy_
Definition LocalTxs.cpp:96
AccountID const & getAccount() const
Definition LocalTxs.cpp:86
uint256 const & getID() const
Definition LocalTxs.cpp:62
LocalTx(LedgerIndex index, std::shared_ptr< STTx const > const &txn)
Definition LocalTxs.cpp:50
std::shared_ptr< STTx const > txn_
Definition LocalTxs.cpp:92
SeqProxy getSeqProxy() const
Definition LocalTxs.cpp:68
bool isExpired(LedgerIndex i) const
Definition LocalTxs.cpp:74
uint256 id_
Definition LocalTxs.cpp:94
std::shared_ptr< STTx const > const & getTX() const
Definition LocalTxs.cpp:80
AccountID account_
Definition LocalTxs.cpp:95
void sweep(ReadView const &view) override
Definition LocalTxs.cpp:135
LocalTxsImp()=default
std::mutex lock_
Definition LocalTxs.cpp:180
std::size_t size() override
Definition LocalTxs.cpp:172
void pushBack(LedgerIndex index, std::shared_ptr< STTx const > const &txn) override
Definition LocalTxs.cpp:108
std::list< LocalTx > txns_
Definition LocalTxs.cpp:181
CanonicalTXSet getTxSet() override
Definition LocalTxs.cpp:116
A view into a ledger.
Definition ReadView.h:41
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
virtual LedgerHeader const & header() const =0
Returns information about the ledger.
virtual bool txExists(key_type const &key) const =0
Returns true if a tx exists in the tx map.
A type that represents either a sequence value or a ticket value.
Definition SeqProxy.h:37
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:62
constexpr bool isTicket() const
Definition SeqProxy.h:92
constexpr std::uint32_t value() const
Definition SeqProxy.h:80
constexpr bool isSeq() const
Definition SeqProxy.h:86
T make_unique(T... args)
T min(T... args)
Keylet ticket(AccountID const &id, SeqProxy const &ticketSeq)
A ticket belonging to an account.
Definition Indexes.cpp:310
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:198
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::uint32_t LedgerIndex
A ledger index.
Definition Protocol.h:370
std::unique_ptr< LocalTxs > makeLocalTxs()
Definition LocalTxs.cpp:185
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
BaseUInt< 256 > uint256
Definition base_uint.h:580