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