rippled
Loading...
Searching...
No Matches
LocalTxs.cpp
1#include <xrpld/app/ledger/Ledger.h>
2#include <xrpld/app/ledger/LocalTxs.h>
3
4#include <xrpl/protocol/Indexes.h>
5
6/*
7 This code prevents scenarios like the following:
81) A client submits a transaction.
92) The transaction gets into the ledger this server
10 believes will be the consensus ledger.
113) The server builds a succeeding open ledger without the
12 transaction (because it's in the prior ledger).
134) The local consensus ledger is not the majority ledger
14 (due to network conditions, Byzantine fault, etcetera)
15 the majority ledger does not include the transaction.
165) The server builds a new open ledger that does not include
17 the transaction or have it in a prior ledger.
186) The client submits another transaction and gets a terPRE_SEQ
19 preliminary result.
207) The server does not relay that second transaction, at least
21 not yet.
22
23With this code, when step 5 happens, the first transaction will
24be applied to that open ledger so the second transaction will
25succeed normally at step 6. Transactions remain tracked and
26test-applied to all new open ledgers until seen in a fully-
27validated ledger
28*/
29
30namespace ripple {
31
32// This class wraps a pointer to a transaction along with
33// its expiration ledger. It also caches the issuing account.
35{
36public:
38 : m_txn(txn)
39 , m_expire(index + LocalTxs::holdLedgers)
40 , m_id(txn->getTransactionID())
41 , m_account(txn->getAccountID(sfAccount))
42 , m_seqProxy(txn->getSeqProxy())
43 {
44 if (txn->isFieldPresent(sfLastLedgerSequence))
45 m_expire =
46 std::min(m_expire, txn->getFieldU32(sfLastLedgerSequence) + 1);
47 }
48
49 uint256 const&
50 getID() const
51 {
52 return m_id;
53 }
54
57 {
58 return m_seqProxy;
59 }
60
61 bool
63 {
64 return i > m_expire;
65 }
66
68 getTX() const
69 {
70 return m_txn;
71 }
72
73 AccountID const&
74 getAccount() const
75 {
76 return m_account;
77 }
78
79private:
85};
86
87//------------------------------------------------------------------------------
88
89class LocalTxsImp : public LocalTxs
90{
91public:
92 LocalTxsImp() = default;
93
94 // Add a new transaction to the set of local transactions
95 void
97 override
98 {
100
101 m_txns.emplace_back(index, txn);
102 }
103
105 getTxSet() override
106 {
107 CanonicalTXSet tset(uint256{});
108
109 // Get the set of local transactions as a canonical
110 // set (so they apply in a valid order)
111 {
113
114 for (auto const& it : m_txns)
115 tset.insert(it.getTX());
116 }
117 return tset;
118 }
119
120 // Remove transactions that have either been accepted
121 // into a fully-validated ledger, are (now) impossible,
122 // or have expired
123 void
124 sweep(ReadView const& view) override
125 {
127
128 m_txns.remove_if([&view](auto const& txn) {
129 if (txn.isExpired(view.info().seq))
130 return true;
131 if (view.txExists(txn.getID()))
132 return true;
133
134 AccountID const acctID = txn.getAccount();
135 auto const sleAcct = view.read(keylet::account(acctID));
136
137 if (!sleAcct)
138 return false;
139
140 SeqProxy const acctSeq =
141 SeqProxy::sequence(sleAcct->getFieldU32(sfSequence));
142 SeqProxy const seqProx = txn.getSeqProxy();
143
144 if (seqProx.isSeq())
145 return acctSeq > seqProx; // Remove tefPAST_SEQ
146
147 if (seqProx.isTicket() && acctSeq.value() <= seqProx.value())
148 // Keep ticket from the future. Note, however, that the
149 // transaction will not be held indefinitely since LocalTxs
150 // will only hold a transaction for a maximum of 5 ledgers.
151 return false;
152
153 // Ticket should have been created by now. Remove if ticket
154 // does not exist.
155 return !view.exists(keylet::ticket(acctID, seqProx));
156 });
157 }
158
160 size() override
161 {
163
164 return m_txns.size();
165 }
166
167private:
170};
171
177
178} // namespace ripple
Holds transactions which were deferred to the next pass of consensus.
std::shared_ptr< STTx const > m_txn
Definition LocalTxs.cpp:80
AccountID m_account
Definition LocalTxs.cpp:83
std::shared_ptr< STTx const > const & getTX() const
Definition LocalTxs.cpp:68
LocalTx(LedgerIndex index, std::shared_ptr< STTx const > const &txn)
Definition LocalTxs.cpp:37
LedgerIndex m_expire
Definition LocalTxs.cpp:81
SeqProxy getSeqProxy() const
Definition LocalTxs.cpp:56
SeqProxy m_seqProxy
Definition LocalTxs.cpp:84
uint256 const & getID() const
Definition LocalTxs.cpp:50
bool isExpired(LedgerIndex i) const
Definition LocalTxs.cpp:62
AccountID const & getAccount() const
Definition LocalTxs.cpp:74
void sweep(ReadView const &view) override
Definition LocalTxs.cpp:124
void push_back(LedgerIndex index, std::shared_ptr< STTx const > const &txn) override
Definition LocalTxs.cpp:96
std::list< LocalTx > m_txns
Definition LocalTxs.cpp:169
CanonicalTXSet getTxSet() override
Definition LocalTxs.cpp:105
std::size_t size() override
Definition LocalTxs.cpp:160
A view into a ledger.
Definition ReadView.h:32
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual LedgerInfo const & info() 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 sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:57
constexpr bool isSeq() const
Definition SeqProxy.h:69
constexpr std::uint32_t value() const
Definition SeqProxy.h:63
constexpr bool isTicket() const
Definition SeqProxy.h:75
T is_same_v
T min(T... args)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
static ticket_t const ticket
Definition Indexes.h:152
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::unique_ptr< LocalTxs > make_LocalTxs()
Definition LocalTxs.cpp:173