mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d). This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
343 lines
8.3 KiB
C++
343 lines
8.3 KiB
C++
#include <xrpl/basics/contract.h>
|
|
#include <xrpl/ledger/detail/RawStateTable.h>
|
|
|
|
namespace ripple {
|
|
namespace detail {
|
|
|
|
class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base
|
|
{
|
|
private:
|
|
std::shared_ptr<SLE const> sle0_;
|
|
ReadView::sles_type::iterator iter0_;
|
|
ReadView::sles_type::iterator end0_;
|
|
std::shared_ptr<SLE const> sle1_;
|
|
items_t::const_iterator iter1_;
|
|
items_t::const_iterator end1_;
|
|
|
|
public:
|
|
sles_iter_impl(sles_iter_impl const&) = default;
|
|
|
|
sles_iter_impl(
|
|
items_t::const_iterator iter1,
|
|
items_t::const_iterator end1,
|
|
ReadView::sles_type::iterator iter0,
|
|
ReadView::sles_type::iterator end0)
|
|
: iter0_(iter0), end0_(end0), iter1_(iter1), end1_(end1)
|
|
{
|
|
if (iter0_ != end0_)
|
|
sle0_ = *iter0_;
|
|
if (iter1_ != end1)
|
|
{
|
|
sle1_ = iter1_->second.sle;
|
|
skip();
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<base_type>
|
|
copy() const override
|
|
{
|
|
return std::make_unique<sles_iter_impl>(*this);
|
|
}
|
|
|
|
bool
|
|
equal(base_type const& impl) const override
|
|
{
|
|
if (auto const p = dynamic_cast<sles_iter_impl const*>(&impl))
|
|
{
|
|
XRPL_ASSERT(
|
|
end1_ == p->end1_ && end0_ == p->end0_,
|
|
"ripple::detail::RawStateTable::equal : matching end "
|
|
"iterators");
|
|
return iter1_ == p->iter1_ && iter0_ == p->iter0_;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
increment() override
|
|
{
|
|
XRPL_ASSERT(
|
|
sle1_ || sle0_,
|
|
"ripple::detail::RawStateTable::increment : either SLE is "
|
|
"non-null");
|
|
|
|
if (sle1_ && !sle0_)
|
|
{
|
|
inc1();
|
|
return;
|
|
}
|
|
|
|
if (sle0_ && !sle1_)
|
|
{
|
|
inc0();
|
|
return;
|
|
}
|
|
|
|
if (sle1_->key() == sle0_->key())
|
|
{
|
|
inc1();
|
|
inc0();
|
|
}
|
|
else if (sle1_->key() < sle0_->key())
|
|
{
|
|
inc1();
|
|
}
|
|
else
|
|
{
|
|
inc0();
|
|
}
|
|
skip();
|
|
}
|
|
|
|
value_type
|
|
dereference() const override
|
|
{
|
|
if (!sle1_)
|
|
return sle0_;
|
|
else if (!sle0_)
|
|
return sle1_;
|
|
if (sle1_->key() <= sle0_->key())
|
|
return sle1_;
|
|
return sle0_;
|
|
}
|
|
|
|
private:
|
|
void
|
|
inc0()
|
|
{
|
|
++iter0_;
|
|
if (iter0_ == end0_)
|
|
sle0_ = nullptr;
|
|
else
|
|
sle0_ = *iter0_;
|
|
}
|
|
|
|
void
|
|
inc1()
|
|
{
|
|
++iter1_;
|
|
if (iter1_ == end1_)
|
|
sle1_ = nullptr;
|
|
else
|
|
sle1_ = iter1_->second.sle;
|
|
}
|
|
|
|
void
|
|
skip()
|
|
{
|
|
while (iter1_ != end1_ && iter1_->second.action == Action::erase &&
|
|
sle0_->key() == sle1_->key())
|
|
{
|
|
inc1();
|
|
inc0();
|
|
if (!sle0_)
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Base invariants are checked by the base during apply()
|
|
|
|
void
|
|
RawStateTable::apply(RawView& to) const
|
|
{
|
|
to.rawDestroyXRP(dropsDestroyed_);
|
|
for (auto const& elem : items_)
|
|
{
|
|
auto const& item = elem.second;
|
|
switch (item.action)
|
|
{
|
|
case Action::erase:
|
|
to.rawErase(item.sle);
|
|
break;
|
|
case Action::insert:
|
|
to.rawInsert(item.sle);
|
|
break;
|
|
case Action::replace:
|
|
to.rawReplace(item.sle);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
RawStateTable::exists(ReadView const& base, Keylet const& k) const
|
|
{
|
|
XRPL_ASSERT(
|
|
k.key.isNonZero(),
|
|
"ripple::detail::RawStateTable::exists : nonzero key");
|
|
auto const iter = items_.find(k.key);
|
|
if (iter == items_.end())
|
|
return base.exists(k);
|
|
auto const& item = iter->second;
|
|
if (item.action == Action::erase)
|
|
return false;
|
|
if (!k.check(*item.sle))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/* This works by first calculating succ() on the parent,
|
|
then calculating succ() our internal list, and taking
|
|
the lower of the two.
|
|
*/
|
|
auto
|
|
RawStateTable::succ(
|
|
ReadView const& base,
|
|
key_type const& key,
|
|
std::optional<key_type> const& last) const -> std::optional<key_type>
|
|
{
|
|
std::optional<key_type> next = key;
|
|
items_t::const_iterator iter;
|
|
// Find base successor that is
|
|
// not also deleted in our list
|
|
do
|
|
{
|
|
next = base.succ(*next, last);
|
|
if (!next)
|
|
break;
|
|
iter = items_.find(*next);
|
|
} while (iter != items_.end() && iter->second.action == Action::erase);
|
|
// Find non-deleted successor in our list
|
|
for (iter = items_.upper_bound(key); iter != items_.end(); ++iter)
|
|
{
|
|
if (iter->second.action != Action::erase)
|
|
{
|
|
// Found both, return the lower key
|
|
if (!next || next > iter->first)
|
|
next = iter->first;
|
|
break;
|
|
}
|
|
}
|
|
// Nothing in our list, return
|
|
// what we got from the parent.
|
|
if (last && next >= last)
|
|
return std::nullopt;
|
|
return next;
|
|
}
|
|
|
|
void
|
|
RawStateTable::erase(std::shared_ptr<SLE> const& sle)
|
|
{
|
|
// The base invariant is checked during apply
|
|
auto const result = items_.emplace(
|
|
std::piecewise_construct,
|
|
std::forward_as_tuple(sle->key()),
|
|
std::forward_as_tuple(Action::erase, sle));
|
|
if (result.second)
|
|
return;
|
|
auto& item = result.first->second;
|
|
switch (item.action)
|
|
{
|
|
case Action::erase:
|
|
LogicError("RawStateTable::erase: already erased");
|
|
break;
|
|
case Action::insert:
|
|
items_.erase(result.first);
|
|
break;
|
|
case Action::replace:
|
|
item.action = Action::erase;
|
|
item.sle = sle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
RawStateTable::insert(std::shared_ptr<SLE> const& sle)
|
|
{
|
|
auto const result = items_.emplace(
|
|
std::piecewise_construct,
|
|
std::forward_as_tuple(sle->key()),
|
|
std::forward_as_tuple(Action::insert, sle));
|
|
if (result.second)
|
|
return;
|
|
auto& item = result.first->second;
|
|
switch (item.action)
|
|
{
|
|
case Action::erase:
|
|
item.action = Action::replace;
|
|
item.sle = sle;
|
|
break;
|
|
case Action::insert:
|
|
LogicError("RawStateTable::insert: already inserted");
|
|
break;
|
|
case Action::replace:
|
|
LogicError("RawStateTable::insert: already exists");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
RawStateTable::replace(std::shared_ptr<SLE> const& sle)
|
|
{
|
|
auto const result = items_.emplace(
|
|
std::piecewise_construct,
|
|
std::forward_as_tuple(sle->key()),
|
|
std::forward_as_tuple(Action::replace, sle));
|
|
if (result.second)
|
|
return;
|
|
auto& item = result.first->second;
|
|
switch (item.action)
|
|
{
|
|
case Action::erase:
|
|
LogicError("RawStateTable::replace: was erased");
|
|
break;
|
|
case Action::insert:
|
|
case Action::replace:
|
|
item.sle = sle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<SLE const>
|
|
RawStateTable::read(ReadView const& base, Keylet const& k) const
|
|
{
|
|
auto const iter = items_.find(k.key);
|
|
if (iter == items_.end())
|
|
return base.read(k);
|
|
auto const& item = iter->second;
|
|
if (item.action == Action::erase)
|
|
return nullptr;
|
|
// Convert to SLE const
|
|
std::shared_ptr<SLE const> sle = item.sle;
|
|
if (!k.check(*sle))
|
|
return nullptr;
|
|
return sle;
|
|
}
|
|
|
|
void
|
|
RawStateTable::destroyXRP(XRPAmount const& fee)
|
|
{
|
|
dropsDestroyed_ += fee;
|
|
}
|
|
|
|
std::unique_ptr<ReadView::sles_type::iter_base>
|
|
RawStateTable::slesBegin(ReadView const& base) const
|
|
{
|
|
return std::make_unique<sles_iter_impl>(
|
|
items_.begin(), items_.end(), base.sles.begin(), base.sles.end());
|
|
}
|
|
|
|
std::unique_ptr<ReadView::sles_type::iter_base>
|
|
RawStateTable::slesEnd(ReadView const& base) const
|
|
{
|
|
return std::make_unique<sles_iter_impl>(
|
|
items_.end(), items_.end(), base.sles.end(), base.sles.end());
|
|
}
|
|
|
|
std::unique_ptr<ReadView::sles_type::iter_base>
|
|
RawStateTable::slesUpperBound(ReadView const& base, uint256 const& key) const
|
|
{
|
|
return std::make_unique<sles_iter_impl>(
|
|
items_.upper_bound(key),
|
|
items_.end(),
|
|
base.sles.upper_bound(key),
|
|
base.sles.end());
|
|
}
|
|
|
|
} // namespace detail
|
|
} // namespace ripple
|