rippled
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 <ripple/app/ledger/Ledger.h>
21 #include <ripple/app/ledger/LocalTxs.h>
22 #include <ripple/app/main/Application.h>
23 #include <ripple/protocol/Indexes.h>
24 
25 /*
26  This code prevents scenarios like the following:
27 1) A client submits a transaction.
28 2) The transaction gets into the ledger this server
29  believes will be the consensus ledger.
30 3) The server builds a succeeding open ledger without the
31  transaction (because it's in the prior ledger).
32 4) 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.
35 5) The server builds a new open ledger that does not include
36  the transaction or have it in a prior ledger.
37 6) The client submits another transaction and gets a terPRE_SEQ
38  preliminary result.
39 7) The server does not relay that second transaction, at least
40  not yet.
41 
42 With this code, when step 5 happens, the first transaction will
43 be applied to that open ledger so the second transaction will
44 succeed normally at step 6. Transactions remain tracked and
45 test-applied to all new open ledgers until seen in a fully-
46 validated ledger
47 */
48 
49 namespace ripple {
50 
51 // This class wraps a pointer to a transaction along with
52 // its expiration ledger. It also caches the issuing account.
53 class LocalTx
54 {
55 public:
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 
79  SeqProxy
80  getSeqProxy() const
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 
103 private:
109 };
110 
111 //------------------------------------------------------------------------------
112 
113 class LocalTxsImp : public LocalTxs
114 {
115 public:
116  LocalTxsImp() = default;
117 
118  // Add a new transaction to the set of local transactions
119  void
121  override
122  {
123  std::lock_guard lock(m_lock);
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  {
136  std::lock_guard lock(m_lock);
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  {
150  std::lock_guard lock(m_lock);
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  {
186  std::lock_guard lock(m_lock);
187 
188  return m_txns.size();
189  }
190 
191 private:
194 };
195 
198 {
199  return std::make_unique<LocalTxsImp>();
200 }
201 
202 } // namespace ripple
ripple::ReadView::info
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
ripple::LocalTx::getAccount
AccountID const & getAccount() const
Definition: LocalTxs.cpp:98
ripple::LocalTxsImp::m_txns
std::list< LocalTx > m_txns
Definition: LocalTxs.cpp:193
std::shared_ptr
STL class.
ripple::LocalTx::isExpired
bool isExpired(LedgerIndex i) const
Definition: LocalTxs.cpp:86
std::list
STL class.
ripple::LocalTx::m_expire
LedgerIndex m_expire
Definition: LocalTxs.cpp:105
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::LocalTxsImp::sweep
void sweep(ReadView const &view) override
Definition: LocalTxs.cpp:148
ripple::SeqProxy::sequence
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition: SeqProxy.h:76
std::lock_guard
STL class.
ripple::LocalTxsImp::push_back
void push_back(LedgerIndex index, std::shared_ptr< STTx const > const &txn) override
Definition: LocalTxs.cpp:120
ripple::LocalTx::LocalTx
LocalTx(LedgerIndex index, std::shared_ptr< STTx const > const &txn)
Definition: LocalTxs.cpp:61
ripple::keylet::ticket
static const ticket_t ticket
Definition: Indexes.h:167
ripple::ReadView::txExists
virtual bool txExists(key_type const &key) const =0
Returns true if a tx exists in the tx map.
ripple::LocalTxsImp::m_lock
std::mutex m_lock
Definition: LocalTxs.cpp:192
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:83
ripple::CanonicalTXSet
Holds transactions which were deferred to the next pass of consensus.
Definition: CanonicalTXSet.h:38
ripple::SeqProxy::isSeq
constexpr bool isSeq() const
Definition: SeqProxy.h:88
ripple::LocalTx::m_seqProxy
SeqProxy m_seqProxy
Definition: LocalTxs.cpp:108
ripple::base_uint< 256 >
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::LocalTx::getTX
std::shared_ptr< STTx const > const & getTX() const
Definition: LocalTxs.cpp:92
ripple::ReadView::exists
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
ripple::LocalTxs
Definition: LocalTxs.h:33
std::uint32_t
ripple::LocalTx
Definition: LocalTxs.cpp:53
ripple::LocalTx::m_account
AccountID m_account
Definition: LocalTxs.cpp:107
ripple::LocalTx::getID
uint256 const & getID() const
Definition: LocalTxs.cpp:74
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::LocalTxsImp
Definition: LocalTxs.cpp:113
std::min
T min(T... args)
ripple::LocalTx::getSeqProxy
SeqProxy getSeqProxy() const
Definition: LocalTxs.cpp:80
ripple::SeqProxy::value
constexpr std::uint32_t value() const
Definition: SeqProxy.h:82
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:125
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::LocalTxsImp::size
std::size_t size() override
Definition: LocalTxs.cpp:184
ripple::LocalTx::m_id
uint256 m_id
Definition: LocalTxs.cpp:106
ripple::SeqProxy
A type that represents either a sequence value or a ticket value.
Definition: SeqProxy.h:55
std::mutex
STL class.
std::size_t
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::make_LocalTxs
std::unique_ptr< LocalTxs > make_LocalTxs()
Definition: LocalTxs.cpp:197
ripple::sfLastLedgerSequence
const SF_UINT32 sfLastLedgerSequence
ripple::LocalTxsImp::getTxSet
CanonicalTXSet getTxSet() override
Definition: LocalTxs.cpp:129
std::unique_ptr
STL class.
ripple::LocalTx::m_txn
std::shared_ptr< STTx const > m_txn
Definition: LocalTxs.cpp:104
ripple::LocalTxsImp::LocalTxsImp
LocalTxsImp()=default
ripple::LocalTx::holdLedgers
static const int holdLedgers
Definition: LocalTxs.cpp:59