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 <xrpl/basics/contract.h>
21#include <xrpl/ledger/detail/RawStateTable.h>
22
23namespace ripple {
24namespace detail {
25
27{
28private:
33 items_t::const_iterator iter1_;
34 items_t::const_iterator end1_;
35
36public:
37 sles_iter_impl(sles_iter_impl const&) = default;
38
40 items_t::const_iterator iter1,
41 items_t::const_iterator end1,
44 : iter0_(iter0), end0_(end0), iter1_(iter1), end1_(end1)
45 {
46 if (iter0_ != end0_)
47 sle0_ = *iter0_;
48 if (iter1_ != end1)
49 {
50 sle1_ = iter1_->second.sle;
51 skip();
52 }
53 }
54
56 copy() const override
57 {
59 }
60
61 bool
62 equal(base_type const& impl) const override
63 {
64 if (auto const p = dynamic_cast<sles_iter_impl const*>(&impl))
65 {
66 XRPL_ASSERT(
67 end1_ == p->end1_ && end0_ == p->end0_,
68 "ripple::detail::RawStateTable::equal : matching end "
69 "iterators");
70 return iter1_ == p->iter1_ && iter0_ == p->iter0_;
71 }
72
73 return false;
74 }
75
76 void
77 increment() override
78 {
79 XRPL_ASSERT(
80 sle1_ || sle0_,
81 "ripple::detail::RawStateTable::increment : either SLE is "
82 "non-null");
83
84 if (sle1_ && !sle0_)
85 {
86 inc1();
87 return;
88 }
89
90 if (sle0_ && !sle1_)
91 {
92 inc0();
93 return;
94 }
95
96 if (sle1_->key() == sle0_->key())
97 {
98 inc1();
99 inc0();
100 }
101 else if (sle1_->key() < sle0_->key())
102 {
103 inc1();
104 }
105 else
106 {
107 inc0();
108 }
109 skip();
110 }
111
113 dereference() const override
114 {
115 if (!sle1_)
116 return sle0_;
117 else if (!sle0_)
118 return sle1_;
119 if (sle1_->key() <= sle0_->key())
120 return sle1_;
121 return sle0_;
122 }
123
124private:
125 void
127 {
128 ++iter0_;
129 if (iter0_ == end0_)
130 sle0_ = nullptr;
131 else
132 sle0_ = *iter0_;
133 }
134
135 void
137 {
138 ++iter1_;
139 if (iter1_ == end1_)
140 sle1_ = nullptr;
141 else
142 sle1_ = iter1_->second.sle;
143 }
144
145 void
147 {
148 while (iter1_ != end1_ && iter1_->second.action == Action::erase &&
149 sle0_->key() == sle1_->key())
150 {
151 inc1();
152 inc0();
153 if (!sle0_)
154 return;
155 }
156 }
157};
158
159//------------------------------------------------------------------------------
160
161// Base invariants are checked by the base during apply()
162
163void
165{
167 for (auto const& elem : items_)
168 {
169 auto const& item = elem.second;
170 switch (item.action)
171 {
172 case Action::erase:
173 to.rawErase(item.sle);
174 break;
175 case Action::insert:
176 to.rawInsert(item.sle);
177 break;
178 case Action::replace:
179 to.rawReplace(item.sle);
180 break;
181 }
182 }
183}
184
185bool
186RawStateTable::exists(ReadView const& base, Keylet const& k) const
187{
188 XRPL_ASSERT(
189 k.key.isNonZero(),
190 "ripple::detail::RawStateTable::exists : nonzero key");
191 auto const iter = items_.find(k.key);
192 if (iter == items_.end())
193 return base.exists(k);
194 auto const& item = iter->second;
195 if (item.action == Action::erase)
196 return false;
197 if (!k.check(*item.sle))
198 return false;
199 return true;
200}
201
202/* This works by first calculating succ() on the parent,
203 then calculating succ() our internal list, and taking
204 the lower of the two.
205*/
206auto
208 ReadView const& base,
209 key_type const& key,
211{
212 std::optional<key_type> next = key;
213 items_t::const_iterator iter;
214 // Find base successor that is
215 // not also deleted in our list
216 do
217 {
218 next = base.succ(*next, last);
219 if (!next)
220 break;
221 iter = items_.find(*next);
222 } while (iter != items_.end() && iter->second.action == Action::erase);
223 // Find non-deleted successor in our list
224 for (iter = items_.upper_bound(key); iter != items_.end(); ++iter)
225 {
226 if (iter->second.action != Action::erase)
227 {
228 // Found both, return the lower key
229 if (!next || next > iter->first)
230 next = iter->first;
231 break;
232 }
233 }
234 // Nothing in our list, return
235 // what we got from the parent.
236 if (last && next >= last)
237 return std::nullopt;
238 return next;
239}
240
241void
243{
244 // The base invariant is checked during apply
245 auto const result = items_.emplace(
247 std::forward_as_tuple(sle->key()),
249 if (result.second)
250 return;
251 auto& item = result.first->second;
252 switch (item.action)
253 {
254 case Action::erase:
255 LogicError("RawStateTable::erase: already erased");
256 break;
257 case Action::insert:
258 items_.erase(result.first);
259 break;
260 case Action::replace:
261 item.action = Action::erase;
262 item.sle = sle;
263 break;
264 }
265}
266
267void
269{
270 auto const result = items_.emplace(
272 std::forward_as_tuple(sle->key()),
274 if (result.second)
275 return;
276 auto& item = result.first->second;
277 switch (item.action)
278 {
279 case Action::erase:
280 item.action = Action::replace;
281 item.sle = sle;
282 break;
283 case Action::insert:
284 LogicError("RawStateTable::insert: already inserted");
285 break;
286 case Action::replace:
287 LogicError("RawStateTable::insert: already exists");
288 break;
289 }
290}
291
292void
294{
295 auto const result = items_.emplace(
297 std::forward_as_tuple(sle->key()),
299 if (result.second)
300 return;
301 auto& item = result.first->second;
302 switch (item.action)
303 {
304 case Action::erase:
305 LogicError("RawStateTable::replace: was erased");
306 break;
307 case Action::insert:
308 case Action::replace:
309 item.sle = sle;
310 break;
311 }
312}
313
315RawStateTable::read(ReadView const& base, Keylet const& k) const
316{
317 auto const iter = items_.find(k.key);
318 if (iter == items_.end())
319 return base.read(k);
320 auto const& item = iter->second;
321 if (item.action == Action::erase)
322 return nullptr;
323 // Convert to SLE const
324 std::shared_ptr<SLE const> sle = item.sle;
325 if (!k.check(*sle))
326 return nullptr;
327 return sle;
328}
329
330void
332{
333 dropsDestroyed_ += fee;
334}
335
338{
340 items_.begin(), items_.end(), base.sles.begin(), base.sles.end());
341}
342
345{
347 items_.end(), items_.end(), base.sles.end(), base.sles.end());
348}
349
351RawStateTable::slesUpperBound(ReadView const& base, uint256 const& key) const
352{
354 items_.upper_bound(key),
355 items_.end(),
356 base.sles.upper_bound(key),
357 base.sles.end());
358}
359
360} // namespace detail
361} // namespace ripple
T begin(T... args)
Interface for ledger entry changes.
Definition RawView.h:34
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:51
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:245
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)