rippled
Loading...
Searching...
No Matches
RawStateTable.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 <xrpld/ledger/detail/RawStateTable.h>
21
22#include <xrpl/basics/contract.h>
23
24namespace ripple {
25namespace detail {
26
28{
29private:
34 items_t::const_iterator iter1_;
35 items_t::const_iterator end1_;
36
37public:
38 sles_iter_impl(sles_iter_impl const&) = default;
39
41 items_t::const_iterator iter1,
42 items_t::const_iterator end1,
45 : iter0_(iter0), end0_(end0), iter1_(iter1), end1_(end1)
46 {
47 if (iter0_ != end0_)
48 sle0_ = *iter0_;
49 if (iter1_ != end1)
50 {
51 sle1_ = iter1_->second.sle;
52 skip();
53 }
54 }
55
57 copy() const override
58 {
60 }
61
62 bool
63 equal(base_type const& impl) const override
64 {
65 if (auto const p = dynamic_cast<sles_iter_impl const*>(&impl))
66 {
67 XRPL_ASSERT(
68 end1_ == p->end1_ && end0_ == p->end0_,
69 "ripple::detail::RawStateTable::equal : matching end "
70 "iterators");
71 return iter1_ == p->iter1_ && iter0_ == p->iter0_;
72 }
73
74 return false;
75 }
76
77 void
78 increment() override
79 {
80 XRPL_ASSERT(
81 sle1_ || sle0_,
82 "ripple::detail::RawStateTable::increment : either SLE is "
83 "non-null");
84
85 if (sle1_ && !sle0_)
86 {
87 inc1();
88 return;
89 }
90
91 if (sle0_ && !sle1_)
92 {
93 inc0();
94 return;
95 }
96
97 if (sle1_->key() == sle0_->key())
98 {
99 inc1();
100 inc0();
101 }
102 else if (sle1_->key() < sle0_->key())
103 {
104 inc1();
105 }
106 else
107 {
108 inc0();
109 }
110 skip();
111 }
112
114 dereference() const override
115 {
116 if (!sle1_)
117 return sle0_;
118 else if (!sle0_)
119 return sle1_;
120 if (sle1_->key() <= sle0_->key())
121 return sle1_;
122 return sle0_;
123 }
124
125private:
126 void
128 {
129 ++iter0_;
130 if (iter0_ == end0_)
131 sle0_ = nullptr;
132 else
133 sle0_ = *iter0_;
134 }
135
136 void
138 {
139 ++iter1_;
140 if (iter1_ == end1_)
141 sle1_ = nullptr;
142 else
143 sle1_ = iter1_->second.sle;
144 }
145
146 void
148 {
149 while (iter1_ != end1_ && iter1_->second.action == Action::erase &&
150 sle0_->key() == sle1_->key())
151 {
152 inc1();
153 inc0();
154 if (!sle0_)
155 return;
156 }
157 }
158};
159
160//------------------------------------------------------------------------------
161
162// Base invariants are checked by the base during apply()
163
164void
166{
168 for (auto const& elem : items_)
169 {
170 auto const& item = elem.second;
171 switch (item.action)
172 {
173 case Action::erase:
174 to.rawErase(item.sle);
175 break;
176 case Action::insert:
177 to.rawInsert(item.sle);
178 break;
179 case Action::replace:
180 to.rawReplace(item.sle);
181 break;
182 }
183 }
184}
185
186bool
187RawStateTable::exists(ReadView const& base, Keylet const& k) const
188{
189 XRPL_ASSERT(
190 k.key.isNonZero(),
191 "ripple::detail::RawStateTable::exists : nonzero key");
192 auto const iter = items_.find(k.key);
193 if (iter == items_.end())
194 return base.exists(k);
195 auto const& item = iter->second;
196 if (item.action == Action::erase)
197 return false;
198 if (!k.check(*item.sle))
199 return false;
200 return true;
201}
202
203/* This works by first calculating succ() on the parent,
204 then calculating succ() our internal list, and taking
205 the lower of the two.
206*/
207auto
209 ReadView const& base,
210 key_type const& key,
212{
213 std::optional<key_type> next = key;
214 items_t::const_iterator iter;
215 // Find base successor that is
216 // not also deleted in our list
217 do
218 {
219 next = base.succ(*next, last);
220 if (!next)
221 break;
222 iter = items_.find(*next);
223 } while (iter != items_.end() && iter->second.action == Action::erase);
224 // Find non-deleted successor in our list
225 for (iter = items_.upper_bound(key); iter != items_.end(); ++iter)
226 {
227 if (iter->second.action != Action::erase)
228 {
229 // Found both, return the lower key
230 if (!next || next > iter->first)
231 next = iter->first;
232 break;
233 }
234 }
235 // Nothing in our list, return
236 // what we got from the parent.
237 if (last && next >= last)
238 return std::nullopt;
239 return next;
240}
241
242void
244{
245 // The base invariant is checked during apply
246 auto const result = items_.emplace(
248 std::forward_as_tuple(sle->key()),
250 if (result.second)
251 return;
252 auto& item = result.first->second;
253 switch (item.action)
254 {
255 case Action::erase:
256 LogicError("RawStateTable::erase: already erased");
257 break;
258 case Action::insert:
259 items_.erase(result.first);
260 break;
261 case Action::replace:
262 item.action = Action::erase;
263 item.sle = sle;
264 break;
265 }
266}
267
268void
270{
271 auto const result = items_.emplace(
273 std::forward_as_tuple(sle->key()),
275 if (result.second)
276 return;
277 auto& item = result.first->second;
278 switch (item.action)
279 {
280 case Action::erase:
281 item.action = Action::replace;
282 item.sle = sle;
283 break;
284 case Action::insert:
285 LogicError("RawStateTable::insert: already inserted");
286 break;
287 case Action::replace:
288 LogicError("RawStateTable::insert: already exists");
289 break;
290 }
291}
292
293void
295{
296 auto const result = items_.emplace(
298 std::forward_as_tuple(sle->key()),
300 if (result.second)
301 return;
302 auto& item = result.first->second;
303 switch (item.action)
304 {
305 case Action::erase:
306 LogicError("RawStateTable::replace: was erased");
307 break;
308 case Action::insert:
309 case Action::replace:
310 item.sle = sle;
311 break;
312 }
313}
314
316RawStateTable::read(ReadView const& base, Keylet const& k) const
317{
318 auto const iter = items_.find(k.key);
319 if (iter == items_.end())
320 return base.read(k);
321 auto const& item = iter->second;
322 if (item.action == Action::erase)
323 return nullptr;
324 // Convert to SLE const
325 std::shared_ptr<SLE const> sle = item.sle;
326 if (!k.check(*sle))
327 return nullptr;
328 return sle;
329}
330
331void
333{
334 dropsDestroyed_ += fee;
335}
336
339{
341 items_.begin(), items_.end(), base.sles.begin(), base.sles.end());
342}
343
346{
348 items_.end(), items_.end(), base.sles.end(), base.sles.end());
349}
350
352RawStateTable::slesUpperBound(ReadView const& base, uint256 const& key) const
353{
355 items_.upper_bound(key),
356 items_.end(),
357 base.sles.upper_bound(key),
358 base.sles.end());
359}
360
361} // namespace detail
362} // namespace ripple
T begin(T... args)
Interface for ledger entry changes.
Definition RawView.h:35
virtual void rawInsert(std::shared_ptr< SLE > const &sle)=0
Unconditionally insert a state item.
virtual void rawDestroyXRP(XRPAmount const &fee)=0
Destroy XRP.
virtual void rawReplace(std::shared_ptr< SLE > const &sle)=0
Unconditionally replace a state item.
virtual void rawErase(std::shared_ptr< SLE > const &sle)=0
Delete an existing state item.
A view into a ledger.
Definition ReadView.h:52
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
sles_type sles
Iterable range of ledger state items.
Definition ReadView.h:246
bool isNonZero() const
Definition base_uint.h:545
sles_iter_impl(items_t::const_iterator iter1, items_t::const_iterator end1, ReadView::sles_type::iterator iter0, ReadView::sles_type::iterator end0)
sles_iter_impl(sles_iter_impl const &)=default
std::unique_ptr< base_type > copy() const override
bool equal(base_type const &impl) const override
std::optional< key_type > succ(ReadView const &base, key_type const &key, std::optional< key_type > const &last) const
void destroyXRP(XRPAmount const &fee)
bool exists(ReadView const &base, Keylet const &k) const
void apply(RawView &to) const
std::unique_ptr< ReadView::sles_type::iter_base > slesUpperBound(ReadView const &base, uint256 const &key) const
std::shared_ptr< SLE const > read(ReadView const &base, Keylet const &k) const
std::unique_ptr< ReadView::sles_type::iter_base > slesBegin(ReadView const &base) const
std::unique_ptr< ReadView::sles_type::iter_base > slesEnd(ReadView const &base) const
T emplace(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
T forward_as_tuple(T... args)
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
T piecewise_construct
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:39
bool check(STLedgerEntry const &) const
Returns true if the SLE matches the type.
Definition Keylet.cpp:28
uint256 key
Definition Keylet.h:40
iterator upper_bound(key_type const &key) const
Definition ReadView.cpp:41
iterator begin() const
Definition ReadView.cpp:29
T upper_bound(T... args)