rippled
OfferStream.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/tx/impl/OfferStream.h>
21 #include <ripple/basics/Log.h>
22 
23 namespace ripple {
24 
25 namespace {
26 bool
27 checkIssuers(ReadView const& view, Book const& book)
28 {
29  auto issuerExists = [](ReadView const& view, Issue const& iss) -> bool {
30  return isXRP(iss.account) || view.read(keylet::account(iss.account));
31  };
32  return issuerExists(view, book.in) && issuerExists(view, book.out);
33 }
34 } // namespace
35 
36 template <class TIn, class TOut>
38  ApplyView& view,
39  ApplyView& cancelView,
40  Book const& book,
42  StepCounter& counter,
43  beast::Journal journal)
44  : j_(journal)
45  , view_(view)
46  , cancelView_(cancelView)
47  , book_(book)
48  , validBook_(checkIssuers(view, book))
49  , expire_(when)
50  , tip_(view, book_)
51  , counter_(counter)
52 {
53  assert(validBook_);
54 }
55 
56 // Handle the case where a directory item with no corresponding ledger entry
57 // is found. This shouldn't happen but if it does we clean it up.
58 template<class TIn, class TOut>
59 void
61 {
62  // NIKB NOTE This should be using ApplyView::dirRemove, which would
63  // correctly remove the directory if its the last entry.
64  // Unfortunately this is a protocol breaking change.
65 
66  auto p = view.peek (keylet::page(tip_.dir()));
67 
68  if (p == nullptr)
69  {
70  JLOG(j_.error()) <<
71  "Missing directory " << tip_.dir() <<
72  " for offer " << tip_.index();
73  return;
74  }
75 
76  auto v (p->getFieldV256 (sfIndexes));
77  auto it (std::find (v.begin(), v.end(), tip_.index()));
78 
79  if (it == v.end())
80  {
81  JLOG(j_.error()) <<
82  "Missing offer " << tip_.index() <<
83  " for directory " << tip_.dir();
84  return;
85  }
86 
87  v.erase (it);
88  p->setFieldV256 (sfIndexes, v);
89  view.update (p);
90 
91  JLOG(j_.trace()) <<
92  "Missing offer " << tip_.index() <<
93  " removed from directory " << tip_.dir();
94 }
95 
96 static
98  AccountID const& id,
99  STAmount const& saDefault,
100  Issue const&,
101  FreezeHandling freezeHandling,
102  beast::Journal j)
103 {
104  return accountFunds (view, id, saDefault, freezeHandling, j);
105 }
106 
107 static
109  AccountID const& id,
110  IOUAmount const& amtDefault,
111  Issue const& issue,
112  FreezeHandling freezeHandling,
113  beast::Journal j)
114 {
115  if (issue.account == id)
116  // self funded
117  return amtDefault;
118 
119  return toAmount<IOUAmount> (
120  accountHolds (view, id, issue.currency, issue.account, freezeHandling, j));
121 }
122 
123 static
125  AccountID const& id,
126  XRPAmount const& amtDefault,
127  Issue const& issue,
128  FreezeHandling freezeHandling,
129  beast::Journal j)
130 {
131  return toAmount<XRPAmount> (
132  accountHolds (view, id, issue.currency, issue.account, freezeHandling, j));
133 }
134 
135 template<class TIn, class TOut>
136 bool
138 {
139  // Modifying the order or logic of these
140  // operations causes a protocol breaking change.
141 
142  if (!validBook_)
143  return false;
144 
145  for(;;)
146  {
147  ownerFunds_ = boost::none;
148  // BookTip::step deletes the current offer from the view before
149  // advancing to the next (unless the ledger entry is missing).
150  if (! tip_.step(j_))
151  return false;
152 
153  std::shared_ptr<SLE> entry = tip_.entry();
154 
155  // If we exceed the maximum number of allowed steps, we're done.
156  if (!counter_.step ())
157  return false;
158 
159  // Remove if missing
160  if (! entry)
161  {
162  erase (view_);
163  erase (cancelView_);
164  continue;
165  }
166 
167  // Remove if expired
168  using d = NetClock::duration;
169  using tp = NetClock::time_point;
170  if (entry->isFieldPresent (sfExpiration) &&
171  tp{d{(*entry)[sfExpiration]}} <= expire_)
172  {
173  JLOG(j_.trace()) <<
174  "Removing expired offer " << entry->key();
175  permRmOffer (entry->key());
176  continue;
177  }
178 
179  offer_ = TOffer<TIn, TOut> (entry, tip_.quality());
180 
181  auto const amount (offer_.amount());
182 
183  // Remove if either amount is zero
184  if (amount.empty())
185  {
186  JLOG(j_.warn()) <<
187  "Removing bad offer " << entry->key();
188  permRmOffer (entry->key());
189  offer_ = TOffer<TIn, TOut>{};
190  continue;
191  }
192 
193  // Calculate owner funds
194  ownerFunds_ = accountFundsHelper (view_, offer_.owner (), amount.out,
195  offer_.issueOut (), fhZERO_IF_FROZEN, j_);
196 
197  // Check for unfunded offer
198  if (*ownerFunds_ <= beast::zero)
199  {
200  // If the owner's balance in the pristine view is the same,
201  // we haven't modified the balance and therefore the
202  // offer is "found unfunded" versus "became unfunded"
203  auto const original_funds =
204  accountFundsHelper (cancelView_, offer_.owner (), amount.out,
205  offer_.issueOut (), fhZERO_IF_FROZEN, j_);
206 
207  if (original_funds == *ownerFunds_)
208  {
209  permRmOffer (entry->key());
210  JLOG(j_.trace()) <<
211  "Removing unfunded offer " << entry->key();
212  }
213  else
214  {
215  JLOG(j_.trace()) <<
216  "Removing became unfunded offer " << entry->key();
217  }
218  offer_ = TOffer<TIn, TOut>{};
219  continue;
220  }
221 
222  break;
223  }
224 
225  return true;
226 }
227 
228 void
229 OfferStream::permRmOffer (uint256 const& offerIndex)
230 {
231  offerDelete (cancelView_,
232  cancelView_.peek(keylet::offer(offerIndex)), j_);
233 }
234 
235 template<class TIn, class TOut>
237 {
238  permToRemove_.insert (offerIndex);
239 }
240 
245 
250 }
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
std::shared_ptr
STL class.
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:56
ripple::FlowOfferStream
Presents and consumes the offers in an order book.
Definition: OfferStream.h:167
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:287
ripple::ApplyView::peek
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
std::find
T find(T... args)
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:91
std::chrono::duration
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
beast::Journal::warn
Stream warn() const
Definition: Journal.h:302
ripple::ApplyView::update
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:41
ripple::FreezeHandling
FreezeHandling
Controls the treatment of frozen account balances.
Definition: View.h:53
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:150
ripple::erase
void erase(STObject &st, TypedField< U > const &f)
Remove a field in an STObject.
Definition: STExchange.h:201
ripple::base_uint
Definition: base_uint.h:65
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:871
ripple::keylet::account
static const account_t account
Definition: Indexes.h:116
ripple::TOfferStreamBase::TOfferStreamBase
TOfferStreamBase(ApplyView &view, ApplyView &cancelView, Book const &book, NetClock::time_point when, StepCounter &counter, beast::Journal journal)
Definition: OfferStream.cpp:37
ripple::STAmount
Definition: STAmount.h:42
beast::Journal::error
Stream error() const
Definition: Journal.h:307
std::chrono::time_point
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:121
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
ripple::sfIndexes
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
Definition: SField.h:473
ripple::sfExpiration
const SF_U32 sfExpiration(access, STI_UINT32, 10, "Expiration")
Definition: SField.h:346
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:133
ripple::TOfferStreamBase
Definition: OfferStream.h:36
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:186
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Book
Specifies an order book.
Definition: Book.h:32
ripple::accountFundsHelper
static STAmount accountFundsHelper(ReadView const &view, AccountID const &id, STAmount const &saDefault, Issue const &, FreezeHandling freezeHandling, beast::Journal j)
Definition: OfferStream.cpp:97
ripple::TOffer
Definition: Offer.h:50
ripple::Issue::account
AccountID account
Definition: Issue.h:38
ripple::XRPAmount
Definition: XRPAmount.h:46