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()) << "Missing directory " << tip_.dir() << " for offer "
71  << tip_.index();
72  return;
73  }
74 
75  auto v(p->getFieldV256(sfIndexes));
76  auto it(std::find(v.begin(), v.end(), tip_.index()));
77 
78  if (it == v.end())
79  {
80  JLOG(j_.error()) << "Missing offer " << tip_.index()
81  << " for directory " << tip_.dir();
82  return;
83  }
84 
85  v.erase(it);
86  p->setFieldV256(sfIndexes, v);
87  view.update(p);
88 
89  JLOG(j_.trace()) << "Missing offer " << tip_.index()
90  << " removed from directory " << tip_.dir();
91 }
92 
93 static STAmount
95  ReadView const& view,
96  AccountID const& id,
97  STAmount const& saDefault,
98  Issue const&,
99  FreezeHandling freezeHandling,
100  beast::Journal j)
101 {
102  return accountFunds(view, id, saDefault, freezeHandling, j);
103 }
104 
105 static IOUAmount
107  ReadView const& view,
108  AccountID const& id,
109  IOUAmount const& amtDefault,
110  Issue const& issue,
111  FreezeHandling freezeHandling,
112  beast::Journal j)
113 {
114  if (issue.account == id)
115  // self funded
116  return amtDefault;
117 
118  return toAmount<IOUAmount>(accountHolds(
119  view, id, issue.currency, issue.account, freezeHandling, j));
120 }
121 
122 static XRPAmount
124  ReadView const& view,
125  AccountID const& id,
126  XRPAmount const& amtDefault,
127  Issue const& issue,
128  FreezeHandling freezeHandling,
129  beast::Journal j)
130 {
131  return toAmount<XRPAmount>(accountHolds(
132  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()) << "Removing expired offer " << entry->key();
174  permRmOffer(entry->key());
175  continue;
176  }
177 
178  offer_ = TOffer<TIn, TOut>(entry, tip_.quality());
179 
180  auto const amount(offer_.amount());
181 
182  // Remove if either amount is zero
183  if (amount.empty())
184  {
185  JLOG(j_.warn()) << "Removing bad offer " << entry->key();
186  permRmOffer(entry->key());
187  offer_ = TOffer<TIn, TOut>{};
188  continue;
189  }
190 
191  // Calculate owner funds
192  ownerFunds_ = accountFundsHelper(
193  view_,
194  offer_.owner(),
195  amount.out,
196  offer_.issueOut(),
198  j_);
199 
200  // Check for unfunded offer
201  if (*ownerFunds_ <= beast::zero)
202  {
203  // If the owner's balance in the pristine view is the same,
204  // we haven't modified the balance and therefore the
205  // offer is "found unfunded" versus "became unfunded"
206  auto const original_funds = accountFundsHelper(
207  cancelView_,
208  offer_.owner(),
209  amount.out,
210  offer_.issueOut(),
212  j_);
213 
214  if (original_funds == *ownerFunds_)
215  {
216  permRmOffer(entry->key());
217  JLOG(j_.trace()) << "Removing unfunded offer " << entry->key();
218  }
219  else
220  {
221  JLOG(j_.trace())
222  << "Removing became unfunded offer " << entry->key();
223  }
224  offer_ = TOffer<TIn, TOut>{};
225  continue;
226  }
227 
228  break;
229  }
230 
231  return true;
232 }
233 
234 void
235 OfferStream::permRmOffer(uint256 const& offerIndex)
236 {
237  offerDelete(cancelView_, cancelView_.peek(keylet::offer(offerIndex)), j_);
238 }
239 
240 template <class TIn, class TOut>
241 void
243 {
244  permToRemove_.insert(offerIndex);
245 }
246 
251 
256 } // namespace ripple
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:53
ripple::FlowOfferStream
Presents and consumes the offers in an order book.
Definition: OfferStream.h:171
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
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:92
std::chrono::duration
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
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:140
ripple::erase
void erase(STObject &st, TypedField< U > const &f)
Remove a field in an STObject.
Definition: STExchange.h:171
ripple::base_uint
Definition: base_uint.h:63
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:121
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:896
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:333
std::chrono::time_point
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:118
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::sfIndexes
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
Definition: SField.h:493
ripple::sfExpiration
const SF_U32 sfExpiration(access, STI_UINT32, 10, "Expiration")
Definition: SField.h:362
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:136
ripple::TOfferStreamBase
Definition: OfferStream.h:36
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::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:94
ripple::TOffer
Definition: Offer.h:49
ripple::Issue::account
AccountID account
Definition: Issue.h:38
ripple::XRPAmount
Definition: XRPAmount.h:46