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:
57 : m_txn(txn)
58 , m_expire(index + LocalTxs::holdLedgers)
59 , m_id(txn->getTransactionID())
60 , m_account(txn->getAccountID(sfAccount))
61 , m_seqProxy(txn->getSeqProxy())
62 {
63 if (txn->isFieldPresent(sfLastLedgerSequence))
64 m_expire =
65 std::min(m_expire, txn->getFieldU32(sfLastLedgerSequence) + 1);
66 }
67
68 uint256 const&
69 getID() const
70 {
71 return m_id;
72 }
73
76 {
77 return m_seqProxy;
78 }
79
80 bool
82 {
83 return i > m_expire;
84 }
85
87 getTX() const
88 {
89 return m_txn;
90 }
91
92 AccountID const&
93 getAccount() const
94 {
95 return m_account;
96 }
97
98private:
104};
105
106//------------------------------------------------------------------------------
107
108class LocalTxsImp : public LocalTxs
109{
110public:
111 LocalTxsImp() = default;
112
113 // Add a new transaction to the set of local transactions
114 void
116 override
117 {
119
120 m_txns.emplace_back(index, txn);
121 }
122
124 getTxSet() override
125 {
126 CanonicalTXSet tset(uint256{});
127
128 // Get the set of local transactions as a canonical
129 // set (so they apply in a valid order)
130 {
132
133 for (auto const& it : m_txns)
134 tset.insert(it.getTX());
135 }
136 return tset;
137 }
138
139 // Remove transactions that have either been accepted
140 // into a fully-validated ledger, are (now) impossible,
141 // or have expired
142 void
143 sweep(ReadView const& view) override
144 {
146
147 m_txns.remove_if([&view](auto const& txn) {
148 if (txn.isExpired(view.info().seq))
149 return true;
150 if (view.txExists(txn.getID()))
151 return true;
152
153 AccountID const acctID = txn.getAccount();
154 auto const sleAcct = view.read(keylet::account(acctID));
155
156 if (!sleAcct)
157 return false;
158
159 SeqProxy const acctSeq =
160 SeqProxy::sequence(sleAcct->getFieldU32(sfSequence));
161 SeqProxy const seqProx = txn.getSeqProxy();
162
163 if (seqProx.isSeq())
164 return acctSeq > seqProx; // Remove tefPAST_SEQ
165
166 if (seqProx.isTicket() && acctSeq.value() <= seqProx.value())
167 // Keep ticket from the future. Note, however, that the
168 // transaction will not be held indefinitely since LocalTxs
169 // will only hold a transaction for a maximum of 5 ledgers.
170 return false;
171
172 // Ticket should have been created by now. Remove if ticket
173 // does not exist.
174 return !view.exists(keylet::ticket(acctID, seqProx));
175 });
176 }
177
179 size() override
180 {
182
183 return m_txns.size();
184 }
185
186private:
189};
190
196
197} // namespace ripple
Holds transactions which were deferred to the next pass of consensus.
std::shared_ptr< STTx const > m_txn
Definition LocalTxs.cpp:99
AccountID m_account
Definition LocalTxs.cpp:102
std::shared_ptr< STTx const > const & getTX() const
Definition LocalTxs.cpp:87
LocalTx(LedgerIndex index, std::shared_ptr< STTx const > const &txn)
Definition LocalTxs.cpp:56
LedgerIndex m_expire
Definition LocalTxs.cpp:100
SeqProxy getSeqProxy() const
Definition LocalTxs.cpp:75
SeqProxy m_seqProxy
Definition LocalTxs.cpp:103
uint256 const & getID() const
Definition LocalTxs.cpp:69
bool isExpired(LedgerIndex i) const
Definition LocalTxs.cpp:81
AccountID const & getAccount() const
Definition LocalTxs.cpp:93
void sweep(ReadView const &view) override
Definition LocalTxs.cpp:143
void push_back(LedgerIndex index, std::shared_ptr< STTx const > const &txn) override
Definition LocalTxs.cpp:115
std::list< LocalTx > m_txns
Definition LocalTxs.cpp:188
CanonicalTXSet getTxSet() override
Definition LocalTxs.cpp:124
std::size_t size() override
Definition LocalTxs.cpp:179
A view into a ledger.
Definition ReadView.h:51
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 is_same_v
T min(T... args)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
static ticket_t const ticket
Definition Indexes.h:171
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::unique_ptr< LocalTxs > make_LocalTxs()
Definition LocalTxs.cpp:192