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_seq(txn->getSequence())
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 
80  getSeq() const
81  {
82  return m_seq;
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 
142  return tset;
143  }
144 
145  // Remove transactions that have either been accepted
146  // into a fully-validated ledger, are (now) impossible,
147  // or have expired
148  void
149  sweep(ReadView const& view) override
150  {
151  std::lock_guard lock(m_lock);
152 
153  m_txns.remove_if([&view](auto const& txn) {
154  if (txn.isExpired(view.info().seq))
155  return true;
156  if (view.txExists(txn.getID()))
157  return true;
158 
160  view.read(keylet::account(txn.getAccount()));
161  if (!sle)
162  return false;
163  return sle->getFieldU32(sfSequence) > txn.getSeq();
164  });
165  }
166 
168  size() override
169  {
170  std::lock_guard lock(m_lock);
171 
172  return m_txns.size();
173  }
174 
175 private:
178 };
179 
182 {
183  return std::make_unique<LocalTxsImp>();
184 }
185 
186 } // 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::LocalTx::getSeq
std::uint32_t getSeq() const
Definition: LocalTxs.cpp:80
ripple::LocalTxsImp::m_txns
std::list< LocalTx > m_txns
Definition: LocalTxs.cpp:177
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_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
Definition: SField.h:356
ripple::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:480
ripple::LocalTxsImp::sweep
void sweep(ReadView const &view) override
Definition: LocalTxs.cpp:149
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::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:176
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:88
ripple::CanonicalTXSet
Holds transactions which were deferred to the next pass of consensus.
Definition: CanonicalTXSet.h:36
ripple::LocalTx::m_seq
std::uint32_t m_seq
Definition: LocalTxs.cpp:108
ripple::base_uint< 256 >
ripple::sfLastLedgerSequence
const SF_U32 sfLastLedgerSequence(access, STI_UINT32, 27, "LastLedgerSequence")
Definition: SField.h:380
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:121
ripple::LocalTx::getTX
std::shared_ptr< STTx const > const & getTX() const
Definition: LocalTxs.cpp:92
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::ReadView
A view into a ledger.
Definition: ReadView.h:188
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:168
ripple::LocalTx::m_id
uint256 m_id
Definition: LocalTxs.cpp:106
std::mutex
STL class.
std::size_t
ripple::make_LocalTxs
std::unique_ptr< LocalTxs > make_LocalTxs()
Definition: LocalTxs.cpp:181
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