rippled
OrderBookDB.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/LedgerMaster.h>
21 #include <ripple/app/ledger/OrderBookDB.h>
22 #include <ripple/app/main/Application.h>
23 #include <ripple/basics/Log.h>
24 #include <ripple/core/Config.h>
25 #include <ripple/core/JobQueue.h>
26 #include <ripple/protocol/Indexes.h>
27 
28 namespace ripple {
29 
31  : app_(app), mSeq(0), j_(app.journal("OrderBookDB"))
32 {
33 }
34 
35 void
37 {
39  mSeq = 0;
40 }
41 
42 void
44 {
45  {
47  auto seq = ledger->info().seq;
48 
49  // Do a full update every 256 ledgers
50  if (mSeq != 0)
51  {
52  if (seq == mSeq)
53  return;
54  if ((seq > mSeq) && ((seq - mSeq) < 256))
55  return;
56  if ((seq < mSeq) && ((mSeq - seq) < 16))
57  return;
58  }
59 
60  JLOG(j_.debug()) << "Advancing from " << mSeq << " to " << seq;
61 
62  mSeq = seq;
63  }
64 
65  if (app_.config().PATH_SEARCH_MAX != 0)
66  {
67  if (app_.config().standalone())
68  update(ledger);
69  else
71  jtUPDATE_PF, "OrderBookDB::update", [this, ledger](Job&) {
72  update(ledger);
73  });
74  }
75 }
76 
77 void
79 {
80  hash_set<uint256> seen;
83  hash_set<Issue> XRPBooks;
84 
85  JLOG(j_.debug()) << "OrderBookDB::update>";
86 
87  if (app_.config().PATH_SEARCH_MAX == 0)
88  {
89  // pathfinding has been disabled
90  return;
91  }
92 
93  // walk through the entire ledger looking for orderbook entries
94  int books = 0;
95 
96  try
97  {
98  for (auto& sle : ledger->sles)
99  {
100  if (app_.isStopping())
101  {
102  JLOG(j_.info())
103  << "OrderBookDB::update exiting due to isStopping";
105  mSeq = 0;
106  return;
107  }
108 
109  if (sle->getType() == ltDIR_NODE &&
110  sle->isFieldPresent(sfExchangeRate) &&
111  sle->getFieldH256(sfRootIndex) == sle->key())
112  {
113  Book book;
114  book.in.currency = sle->getFieldH160(sfTakerPaysCurrency);
115  book.in.account = sle->getFieldH160(sfTakerPaysIssuer);
116  book.out.account = sle->getFieldH160(sfTakerGetsIssuer);
117  book.out.currency = sle->getFieldH160(sfTakerGetsCurrency);
118 
119  uint256 index = getBookBase(book);
120  if (seen.insert(index).second)
121  {
122  auto orderBook = std::make_shared<OrderBook>(index, book);
123  sourceMap[book.in].push_back(orderBook);
124  destMap[book.out].push_back(orderBook);
125  if (isXRP(book.out))
126  XRPBooks.insert(book.in);
127  ++books;
128  }
129  }
130  }
131  }
132  catch (SHAMapMissingNode const& mn)
133  {
134  JLOG(j_.info()) << "OrderBookDB::update: " << mn.what();
136  mSeq = 0;
137  return;
138  }
139 
140  JLOG(j_.debug()) << "OrderBookDB::update< " << books << " books found";
141  {
143 
144  mXRPBooks.swap(XRPBooks);
145  mSourceMap.swap(sourceMap);
146  mDestMap.swap(destMap);
147  }
149 }
150 
151 void
153 {
154  bool toXRP = isXRP(book.out);
156 
157  if (toXRP)
158  {
159  // We don't want to search through all the to-XRP or from-XRP order
160  // books!
161  for (auto ob : mSourceMap[book.in])
162  {
163  if (isXRP(ob->getCurrencyOut())) // also to XRP
164  return;
165  }
166  }
167  else
168  {
169  for (auto ob : mDestMap[book.out])
170  {
171  if (ob->getCurrencyIn() == book.in.currency &&
172  ob->getIssuerIn() == book.in.account)
173  {
174  return;
175  }
176  }
177  }
178  uint256 index = getBookBase(book);
179  auto orderBook = std::make_shared<OrderBook>(index, book);
180 
181  mSourceMap[book.in].push_back(orderBook);
182  mDestMap[book.out].push_back(orderBook);
183  if (toXRP)
184  mXRPBooks.insert(book.in);
185 }
186 
187 // return list of all orderbooks that want this issuerID and currencyID
190 {
192  auto it = mSourceMap.find(issue);
193  return it == mSourceMap.end() ? OrderBook::List() : it->second;
194 }
195 
196 int
198 {
200  auto it = mSourceMap.find(issue);
201  return it == mSourceMap.end() ? 0 : it->second.size();
202 }
203 
204 bool
206 {
208  return mXRPBooks.count(issue) > 0;
209 }
210 
213 {
215  auto ret = getBookListeners(book);
216 
217  if (!ret)
218  {
219  ret = std::make_shared<BookListeners>();
220 
221  mListeners[book] = ret;
222  assert(getBookListeners(book) == ret);
223  }
224 
225  return ret;
226 }
227 
230 {
233 
234  auto it0 = mListeners.find(book);
235  if (it0 != mListeners.end())
236  ret = it0->second;
237 
238  return ret;
239 }
240 
241 // Based on the meta, send the meta to the streams that are listening.
242 // We need to determine which streams a given meta effects.
243 void
245  std::shared_ptr<ReadView const> const& ledger,
246  const AcceptedLedgerTx& alTx,
247  Json::Value const& jvObj)
248 {
250  if (alTx.getResult() == tesSUCCESS)
251  {
252  // For this particular transaction, maintain the set of unique
253  // subscriptions that have already published it. This prevents sending
254  // the transaction multiple times if it touches multiple ltOFFER
255  // entries for the same book, or if it touches multiple books and a
256  // single client has subscribed to those books.
257  hash_set<std::uint64_t> havePublished;
258 
259  // Check if this is an offer or an offer cancel or a payment that
260  // consumes an offer.
261  // Check to see what the meta looks like.
262  for (auto& node : alTx.getMeta()->getNodes())
263  {
264  try
265  {
266  if (node.getFieldU16(sfLedgerEntryType) == ltOFFER)
267  {
268  SField const* field = nullptr;
269 
270  // We need a field that contains the TakerGets and TakerPays
271  // parameters.
272  if (node.getFName() == sfModifiedNode)
273  field = &sfPreviousFields;
274  else if (node.getFName() == sfCreatedNode)
275  field = &sfNewFields;
276  else if (node.getFName() == sfDeletedNode)
277  field = &sfFinalFields;
278 
279  if (field)
280  {
281  auto data = dynamic_cast<const STObject*>(
282  node.peekAtPField(*field));
283 
284  if (data && data->isFieldPresent(sfTakerPays) &&
285  data->isFieldPresent(sfTakerGets))
286  {
287  // determine the OrderBook
288  Book b{
289  data->getFieldAmount(sfTakerGets).issue(),
290  data->getFieldAmount(sfTakerPays).issue()};
291 
292  auto listeners = getBookListeners(b);
293  if (listeners)
294  {
295  listeners->publish(jvObj, havePublished);
296  }
297  }
298  }
299  }
300  }
301  catch (std::exception const&)
302  {
303  JLOG(j_.info())
304  << "Fields not found in OrderBookDB::processTxn";
305  }
306  }
307  }
308 }
309 
310 } // namespace ripple
ripple::Application
Definition: Application.h:115
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
std::shared_ptr
STL class.
std::exception
STL class.
ripple::Book::out
Issue out
Definition: Book.h:36
ripple::sfTakerGetsCurrency
const SF_HASH160 sfTakerGetsCurrency
std::unordered_set
STL class.
ripple::OrderBookDB::j_
const beast::Journal j_
Definition: OrderBookDB.h:96
ripple::OrderBookDB::mLock
std::recursive_mutex mLock
Definition: OrderBookDB.h:88
ripple::getBookBase
uint256 getBookBase(Book const &book)
Definition: Indexes.cpp:79
std::vector
STL class.
std::unordered_map::find
T find(T... args)
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::OrderBook::List
std::vector< pointer > List
Definition: OrderBook.h:31
std::lock_guard
STL class.
ripple::OrderBookDB::mDestMap
IssueToOrderBook mDestMap
Definition: OrderBookDB.h:83
ripple::sfFinalFields
const SField sfFinalFields
ripple::Application::isStopping
virtual bool isStopping() const =0
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
ripple::jtUPDATE_PF
@ jtUPDATE_PF
Definition: Job.h:55
ripple::OrderBookDB::getBooksByTakerPays
OrderBook::List getBooksByTakerPays(Issue const &)
Definition: OrderBookDB.cpp:189
ripple::OrderBookDB::update
void update(std::shared_ptr< ReadView const > const &ledger)
Definition: OrderBookDB.cpp:78
ripple::OrderBookDB::invalidate
void invalidate()
Definition: OrderBookDB.cpp:36
ripple::sfDeletedNode
const SField sfDeletedNode
ripple::sfTakerGetsIssuer
const SF_HASH160 sfTakerGetsIssuer
ripple::Config::PATH_SEARCH_MAX
int PATH_SEARCH_MAX
Definition: Config.h:180
ripple::ltDIR_NODE
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
Definition: LedgerFormats.h:66
ripple::SHAMapMissingNode
Definition: SHAMapMissingNode.h:55
ripple::OrderBookDB::isBookToXRP
bool isBookToXRP(Issue const &)
Definition: OrderBookDB.cpp:205
ripple::base_uint< 256 >
ripple::sfTakerPays
const SF_AMOUNT sfTakerPays
ripple::ltOFFER
@ ltOFFER
A ledger object which describes an offer on the DEX.
Definition: LedgerFormats.h:92
ripple::OrderBookDB::getBookSize
int getBookSize(Issue const &)
Definition: OrderBookDB.cpp:197
ripple::OrderBookDB::processTxn
void processTxn(std::shared_ptr< ReadView const > const &ledger, const AcceptedLedgerTx &alTx, Json::Value const &jvObj)
Definition: OrderBookDB.cpp:244
ripple::AcceptedLedgerTx::getMeta
std::shared_ptr< TxMeta > const & getMeta() const
Definition: AcceptedLedgerTx.h:76
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::sfTakerPaysIssuer
const SF_HASH160 sfTakerPaysIssuer
ripple::sfNewFields
const SField sfNewFields
ripple::Application::config
virtual Config & config()=0
ripple::Config::standalone
bool standalone() const
Definition: Config.h:311
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::AcceptedLedgerTx
A transaction that is in a closed ledger.
Definition: AcceptedLedgerTx.h:50
ripple::sfModifiedNode
const SField sfModifiedNode
ripple::OrderBookDB::mSourceMap
IssueToOrderBook mSourceMap
Definition: OrderBookDB.h:80
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::sfTakerGets
const SF_AMOUNT sfTakerGets
ripple::OrderBookDB::setup
void setup(std::shared_ptr< ReadView const > const &ledger)
Definition: OrderBookDB.cpp:43
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
ripple::Job
Definition: Job.h:94
ripple::sfExchangeRate
const SF_UINT64 sfExchangeRate
ripple::OrderBookDB::makeBookListeners
BookListeners::pointer makeBookListeners(Book const &)
Definition: OrderBookDB.cpp:212
ripple::AcceptedLedgerTx::getResult
TER getResult() const
Definition: AcceptedLedgerTx.h:98
ripple::LedgerMaster::newOrderBookDB
bool newOrderBookDB()
Definition: LedgerMaster.cpp:1576
ripple::sfTakerPaysCurrency
const SF_HASH160 sfTakerPaysCurrency
ripple::OrderBookDB::mSeq
std::uint32_t mSeq
Definition: OrderBookDB.h:94
ripple::OrderBookDB::mListeners
BookToListenersMap mListeners
Definition: OrderBookDB.h:92
ripple::sfPreviousFields
const SField sfPreviousFields
std::unordered_map::swap
T swap(T... args)
ripple::OrderBookDB::getBookListeners
BookListeners::pointer getBookListeners(Book const &)
Definition: OrderBookDB.cpp:229
ripple::STObject
Definition: STObject.h:51
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
ripple::SField
Identifies fields.
Definition: SField.h:109
std::unordered_set::insert
T insert(T... args)
ripple::sfCreatedNode
const SField sfCreatedNode
ripple::OrderBookDB::OrderBookDB
OrderBookDB(Application &app)
Definition: OrderBookDB.cpp:30
ripple::sfRootIndex
const SF_HASH256 sfRootIndex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::OrderBookDB::mXRPBooks
hash_set< Issue > mXRPBooks
Definition: OrderBookDB.h:86
ripple::OrderBookDB::app_
Application & app_
Definition: OrderBookDB.h:77
ripple::Book
Specifies an order book.
Definition: Book.h:32
std::unordered_map::end
T end(T... args)
std::unordered_map
STL class.
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:217
ripple::Book::in
Issue in
Definition: Book.h:35
ripple::Issue::account
AccountID account
Definition: Issue.h:38
std::runtime_error::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::OrderBookDB::addOrderBook
void addOrderBook(Book const &)
Definition: OrderBookDB.cpp:152