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  // nothing to do
68  }
69  else if (app_.config().standalone())
70  update(ledger);
71  else
73  jtUPDATE_PF, "OrderBookDB::update", [this, ledger](Job&) {
74  update(ledger);
75  });
76 }
77 
78 void
80 {
81  hash_set<uint256> seen;
84  hash_set<Issue> XRPBooks;
85 
86  JLOG(j_.debug()) << "OrderBookDB::update>";
87 
88  if (app_.config().PATH_SEARCH_MAX == 0)
89  {
90  // pathfinding has been disabled
91  return;
92  }
93 
94  // walk through the entire ledger looking for orderbook entries
95  int books = 0;
96 
97  try
98  {
99  for (auto& sle : ledger->sles)
100  {
101  if (app_.isStopping())
102  {
103  JLOG(j_.info())
104  << "OrderBookDB::update exiting due to isStopping";
106  mSeq = 0;
107  return;
108  }
109 
110  if (sle->getType() == ltDIR_NODE &&
111  sle->isFieldPresent(sfExchangeRate) &&
112  sle->getFieldH256(sfRootIndex) == sle->key())
113  {
114  Book book;
115  book.in.currency = sle->getFieldH160(sfTakerPaysCurrency);
116  book.in.account = sle->getFieldH160(sfTakerPaysIssuer);
117  book.out.account = sle->getFieldH160(sfTakerGetsIssuer);
118  book.out.currency = sle->getFieldH160(sfTakerGetsCurrency);
119 
120  uint256 index = getBookBase(book);
121  if (seen.insert(index).second)
122  {
123  auto orderBook = std::make_shared<OrderBook>(index, book);
124  sourceMap[book.in].push_back(orderBook);
125  destMap[book.out].push_back(orderBook);
126  if (isXRP(book.out))
127  XRPBooks.insert(book.in);
128  ++books;
129  }
130  }
131  }
132  }
133  catch (SHAMapMissingNode const& mn)
134  {
135  JLOG(j_.info()) << "OrderBookDB::update: " << mn.what();
137  mSeq = 0;
138  return;
139  }
140 
141  JLOG(j_.debug()) << "OrderBookDB::update< " << books << " books found";
142  {
144 
145  mXRPBooks.swap(XRPBooks);
146  mSourceMap.swap(sourceMap);
147  mDestMap.swap(destMap);
148  }
150 }
151 
152 void
154 {
155  bool toXRP = isXRP(book.out);
157 
158  if (toXRP)
159  {
160  // We don't want to search through all the to-XRP or from-XRP order
161  // books!
162  for (auto ob : mSourceMap[book.in])
163  {
164  if (isXRP(ob->getCurrencyOut())) // also to XRP
165  return;
166  }
167  }
168  else
169  {
170  for (auto ob : mDestMap[book.out])
171  {
172  if (ob->getCurrencyIn() == book.in.currency &&
173  ob->getIssuerIn() == book.in.account)
174  {
175  return;
176  }
177  }
178  }
179  uint256 index = getBookBase(book);
180  auto orderBook = std::make_shared<OrderBook>(index, book);
181 
182  mSourceMap[book.in].push_back(orderBook);
183  mDestMap[book.out].push_back(orderBook);
184  if (toXRP)
185  mXRPBooks.insert(book.in);
186 }
187 
188 // return list of all orderbooks that want this issuerID and currencyID
191 {
193  auto it = mSourceMap.find(issue);
194  return it == mSourceMap.end() ? OrderBook::List() : it->second;
195 }
196 
197 int
199 {
201  auto it = mSourceMap.find(issue);
202  return it == mSourceMap.end() ? 0 : it->second.size();
203 }
204 
205 bool
207 {
209  return mXRPBooks.count(issue) > 0;
210 }
211 
214 {
216  auto ret = getBookListeners(book);
217 
218  if (!ret)
219  {
220  ret = std::make_shared<BookListeners>();
221 
222  mListeners[book] = ret;
223  assert(getBookListeners(book) == ret);
224  }
225 
226  return ret;
227 }
228 
231 {
234 
235  auto it0 = mListeners.find(book);
236  if (it0 != mListeners.end())
237  ret = it0->second;
238 
239  return ret;
240 }
241 
242 // Based on the meta, send the meta to the streams that are listening.
243 // We need to determine which streams a given meta effects.
244 void
246  std::shared_ptr<ReadView const> const& ledger,
247  const AcceptedLedgerTx& alTx,
248  Json::Value const& jvObj)
249 {
251  if (alTx.getResult() == tesSUCCESS)
252  {
253  // For this particular transaction, maintain the set of unique
254  // subscriptions that have already published it. This prevents sending
255  // the transaction multiple times if it touches multiple ltOFFER
256  // entries for the same book, or if it touches multiple books and a
257  // single client has subscribed to those books.
258  hash_set<std::uint64_t> havePublished;
259 
260  // Check if this is an offer or an offer cancel or a payment that
261  // consumes an offer.
262  // Check to see what the meta looks like.
263  for (auto& node : alTx.getMeta()->getNodes())
264  {
265  try
266  {
267  if (node.getFieldU16(sfLedgerEntryType) == ltOFFER)
268  {
269  SField const* field = nullptr;
270 
271  // We need a field that contains the TakerGets and TakerPays
272  // parameters.
273  if (node.getFName() == sfModifiedNode)
274  field = &sfPreviousFields;
275  else if (node.getFName() == sfCreatedNode)
276  field = &sfNewFields;
277  else if (node.getFName() == sfDeletedNode)
278  field = &sfFinalFields;
279 
280  if (field)
281  {
282  auto data = dynamic_cast<const STObject*>(
283  node.peekAtPField(*field));
284 
285  if (data && data->isFieldPresent(sfTakerPays) &&
286  data->isFieldPresent(sfTakerGets))
287  {
288  // determine the OrderBook
289  Book b{
290  data->getFieldAmount(sfTakerGets).issue(),
291  data->getFieldAmount(sfTakerPays).issue()};
292 
293  auto listeners = getBookListeners(b);
294  if (listeners)
295  {
296  listeners->publish(jvObj, havePublished);
297  }
298  }
299  }
300  }
301  }
302  catch (std::exception const&)
303  {
304  JLOG(j_.info())
305  << "Fields not found in OrderBookDB::processTxn";
306  }
307  }
308  }
309 }
310 
311 } // namespace ripple
ripple::Application
Definition: Application.h:103
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:165
ripple::jtUPDATE_PF
@ jtUPDATE_PF
Definition: Job.h:53
ripple::OrderBookDB::getBooksByTakerPays
OrderBook::List getBooksByTakerPays(Issue const &)
Definition: OrderBookDB.cpp:190
ripple::OrderBookDB::update
void update(std::shared_ptr< ReadView const > const &ledger)
Definition: OrderBookDB.cpp:79
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:167
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:206
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:198
ripple::OrderBookDB::processTxn
void processTxn(std::shared_ptr< ReadView const > const &ledger, const AcceptedLedgerTx &alTx, Json::Value const &jvObj)
Definition: OrderBookDB.cpp:245
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:286
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:87
ripple::sfExchangeRate
const SF_UINT64 sfExchangeRate
ripple::OrderBookDB::makeBookListeners
BookListeners::pointer makeBookListeners(Book const &)
Definition: OrderBookDB.cpp:213
ripple::AcceptedLedgerTx::getResult
TER getResult() const
Definition: AcceptedLedgerTx.h:98
ripple::LedgerMaster::newOrderBookDB
bool newOrderBookDB()
Definition: LedgerMaster.cpp:1566
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:230
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:153