rippled
Loading...
Searching...
No Matches
LocalTxs.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/ledger/Ledger.h>
21#include <xrpld/app/ledger/LocalTxs.h>
22
23#include <xrpl/protocol/Indexes.h>
24
25/*
26 This code prevents scenarios like the following:
271) A client submits a transaction.
282) The transaction gets into the ledger this server
29 believes will be the consensus ledger.
303) The server builds a succeeding open ledger without the
31 transaction (because it's in the prior ledger).
324) The local consensus ledger is not the majority ledger
33 (due to network conditions, Byzantine fault, etcetera)
34 the majority ledger does not include the transaction.
355) The server builds a new open ledger that does not include
36 the transaction or have it in a prior ledger.
376) The client submits another transaction and gets a terPRE_SEQ
38 preliminary result.
397) The server does not relay that second transaction, at least
40 not yet.
41
42With this code, when step 5 happens, the first transaction will
43be applied to that open ledger so the second transaction will
44succeed normally at step 6. Transactions remain tracked and
45test-applied to all new open ledgers until seen in a fully-
46validated ledger
47*/
48
49namespace ripple {
50
51// This class wraps a pointer to a transaction along with
52// its expiration ledger. It also caches the issuing account.
54{
55public:
56 // The number of ledgers to hold a transaction is essentially
57 // arbitrary. It should be sufficient to allow the transaction to
58 // get into a fully-validated ledger.
59 static int const holdLedgers = 5;
60
62 : m_txn(txn)
63 , m_expire(index + holdLedgers)
64 , m_id(txn->getTransactionID())
65 , m_account(txn->getAccountID(sfAccount))
66 , m_seqProxy(txn->getSeqProxy())
67 {
68 if (txn->isFieldPresent(sfLastLedgerSequence))
69 m_expire =
70 std::min(m_expire, txn->getFieldU32(sfLastLedgerSequence) + 1);
71 }
72
73 uint256 const&
74 getID() const
75 {
76 return m_id;
77 }
78
81 {
82 return m_seqProxy;
83 }
84
85 bool
87 {
88 return i > m_expire;
89 }
90
92 getTX() const
93 {
94 return m_txn;
95 }
96
97 AccountID const&
98 getAccount() const
99 {
100 return m_account;
101 }
102
103private:
109};
110
111//------------------------------------------------------------------------------
112
113class LocalTxsImp : public LocalTxs
114{
115public:
116 LocalTxsImp() = default;
117
118 // Add a new transaction to the set of local transactions
119 void
121 override
122 {
124
125 m_txns.emplace_back(index, txn);
126 }
127
129 getTxSet() override
130 {
131 CanonicalTXSet tset(uint256{});
132
133 // Get the set of local transactions as a canonical
134 // set (so they apply in a valid order)
135 {
137
138 for (auto const& it : m_txns)
139 tset.insert(it.getTX());
140 }
141 return tset;
142 }
143
144 // Remove transactions that have either been accepted
145 // into a fully-validated ledger, are (now) impossible,
146 // or have expired
147 void
148 sweep(ReadView const& view) override
149 {
151
152 m_txns.remove_if([&view](auto const& txn) {
153 if (txn.isExpired(view.info().seq))
154 return true;
155 if (view.txExists(txn.getID()))
156 return true;
157
158 AccountID const acctID = txn.getAccount();
159 auto const sleAcct = view.read(keylet::account(acctID));
160
161 if (!sleAcct)
162 return false;
163
164 SeqProxy const acctSeq =
165 SeqProxy::sequence(sleAcct->getFieldU32(sfSequence));
166 SeqProxy const seqProx = txn.getSeqProxy();
167
168 if (seqProx.isSeq())
169 return acctSeq > seqProx; // Remove tefPAST_SEQ
170
171 if (seqProx.isTicket() && acctSeq.value() <= seqProx.value())
172 // Keep ticket from the future. Note, however, that the
173 // transaction will not be held indefinitely since LocalTxs
174 // will only hold a transaction for a maximum of 5 ledgers.
175 return false;
176
177 // Ticket should have been created by now. Remove if ticket
178 // does not exist.
179 return !view.exists(keylet::ticket(acctID, seqProx));
180 });
181 }
182
184 size() override
185 {
187
188 return m_txns.size();
189 }
190
191private:
194};
195
198{
199 return std::make_unique<LocalTxsImp>();
200}
201
202} // namespace ripple
Holds transactions which were deferred to the next pass of consensus.
std::shared_ptr< STTx const > m_txn
Definition: LocalTxs.cpp:104
AccountID m_account
Definition: LocalTxs.cpp:107
std::shared_ptr< STTx const > const & getTX() const
Definition: LocalTxs.cpp:92
LocalTx(LedgerIndex index, std::shared_ptr< STTx const > const &txn)
Definition: LocalTxs.cpp:61
LedgerIndex m_expire
Definition: LocalTxs.cpp:105
SeqProxy getSeqProxy() const
Definition: LocalTxs.cpp:80
SeqProxy m_seqProxy
Definition: LocalTxs.cpp:108
static int const holdLedgers
Definition: LocalTxs.cpp:59
uint256 const & getID() const
Definition: LocalTxs.cpp:74
bool isExpired(LedgerIndex i) const
Definition: LocalTxs.cpp:86
AccountID const & getAccount() const
Definition: LocalTxs.cpp:98
std::mutex m_lock
Definition: LocalTxs.cpp:192
void sweep(ReadView const &view) override
Definition: LocalTxs.cpp:148
void push_back(LedgerIndex index, std::shared_ptr< STTx const > const &txn) override
Definition: LocalTxs.cpp:120
std::list< LocalTx > m_txns
Definition: LocalTxs.cpp:193
CanonicalTXSet getTxSet() override
Definition: LocalTxs.cpp:129
std::size_t size() override
Definition: LocalTxs.cpp:184
A view into a ledger.
Definition: ReadView.h:52
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:56
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition: SeqProxy.h:76
constexpr bool isSeq() const
Definition: SeqProxy.h:88
constexpr std::uint32_t value() const
Definition: SeqProxy.h:82
constexpr bool isTicket() const
Definition: SeqProxy.h:94
T min(T... args)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:175
static ticket_t const ticket
Definition: Indexes.h:170
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::unique_ptr< LocalTxs > make_LocalTxs()
Definition: LocalTxs.cpp:197