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