mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Refactor View classes:
The View hierarchy of classes is reorganized to include new classes with member functions moved and renamed, to solve defects in the original design: OpenView accumulates raw state and tx changes and can be applied to the base. ApplyView accumulates changes for a single transaction, including metadata, and can be applied to an OpenView. The Sandbox allows changes with the option to apply or throw them out. The PaymentSandbox provides a sandbox with account credit deferral. Call sites are changed to use the class appropriate for the task.
This commit is contained in:
589
src/ripple/ledger/impl/ApplyStateTable.cpp
Normal file
589
src/ripple/ledger/impl/ApplyStateTable.cpp
Normal file
@@ -0,0 +1,589 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/detail/ApplyStateTable.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
void
|
||||
ApplyStateTable::apply (RawView& to) const
|
||||
{
|
||||
to.rawDestroyXRP(dropsDestroyed_);
|
||||
for (auto const& item : items_)
|
||||
{
|
||||
auto const& sle =
|
||||
item.second.second;
|
||||
switch(item.second.first)
|
||||
{
|
||||
case Action::cache:
|
||||
break;
|
||||
case Action::erase:
|
||||
to.rawErase(sle);
|
||||
break;
|
||||
case Action::insert:
|
||||
to.rawInsert(sle);
|
||||
break;
|
||||
case Action::modify:
|
||||
to.rawReplace(sle);
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ApplyStateTable::apply (OpenView& to,
|
||||
STTx const& tx, TER ter,
|
||||
boost::optional<STAmount> const& deliver,
|
||||
beast::Journal j)
|
||||
{
|
||||
// Build metadata and insert
|
||||
auto const sTx =
|
||||
std::make_shared<Serializer>();
|
||||
tx.add(*sTx);
|
||||
std::shared_ptr<Serializer> sMeta;
|
||||
if (to.closed())
|
||||
{
|
||||
TxMeta meta;
|
||||
// VFALCO Shouldn't TxMeta ctor do this?
|
||||
meta.init (tx.getTransactionID(), to.seq());
|
||||
if (deliver)
|
||||
meta.setDeliveredAmount(*deliver);
|
||||
Mods newMod;
|
||||
// VFALCO NOTE getForMod can insert items with
|
||||
// Action::cache during the loop.
|
||||
for (auto& item : items_)
|
||||
{
|
||||
SField const* type;
|
||||
switch (item.second.first)
|
||||
{
|
||||
default:
|
||||
case Action::cache:
|
||||
continue;
|
||||
case Action::erase:
|
||||
type = &sfDeletedNode;
|
||||
break;
|
||||
case Action::insert:
|
||||
type = &sfCreatedNode;
|
||||
break;
|
||||
case Action::modify:
|
||||
type = &sfModifiedNode;
|
||||
break;
|
||||
}
|
||||
auto const origNode =
|
||||
to.read(keylet::unchecked(item.first));
|
||||
auto curNode = item.second.second;
|
||||
if ((type == &sfModifiedNode) && (*curNode == *origNode))
|
||||
continue;
|
||||
std::uint16_t nodeType = curNode
|
||||
? curNode->getFieldU16 (sfLedgerEntryType)
|
||||
: origNode->getFieldU16 (sfLedgerEntryType);
|
||||
meta.setAffectedNode (item.first, *type, nodeType);
|
||||
if (type == &sfDeletedNode)
|
||||
{
|
||||
assert (origNode && curNode);
|
||||
threadOwners (to, meta, origNode, newMod, j);
|
||||
|
||||
STObject prevs (sfPreviousFields);
|
||||
for (auto const& obj : *origNode)
|
||||
{
|
||||
// go through the original node for
|
||||
// modified fields saved on modification
|
||||
if (obj.getFName().shouldMeta(
|
||||
SField::sMD_ChangeOrig) &&
|
||||
! curNode->hasMatchingEntry (obj))
|
||||
prevs.emplace_back (obj);
|
||||
}
|
||||
|
||||
if (!prevs.empty ())
|
||||
meta.getAffectedNode(item.first).emplace_back(std::move(prevs));
|
||||
|
||||
STObject finals (sfFinalFields);
|
||||
for (auto const& obj : *curNode)
|
||||
{
|
||||
// go through the final node for final fields
|
||||
if (obj.getFName().shouldMeta(
|
||||
SField::sMD_Always | SField::sMD_DeleteFinal))
|
||||
finals.emplace_back (obj);
|
||||
}
|
||||
|
||||
if (!finals.empty ())
|
||||
meta.getAffectedNode (item.first).emplace_back (std::move(finals));
|
||||
}
|
||||
else if (type == &sfModifiedNode)
|
||||
{
|
||||
assert (curNode && origNode);
|
||||
|
||||
if (curNode->isThreadedType ()) // thread transaction to node item modified
|
||||
threadTx (meta, curNode, newMod);
|
||||
|
||||
STObject prevs (sfPreviousFields);
|
||||
for (auto const& obj : *origNode)
|
||||
{
|
||||
// search the original node for values saved on modify
|
||||
if (obj.getFName ().shouldMeta (SField::sMD_ChangeOrig) && !curNode->hasMatchingEntry (obj))
|
||||
prevs.emplace_back (obj);
|
||||
}
|
||||
|
||||
if (!prevs.empty ())
|
||||
meta.getAffectedNode (item.first).emplace_back (std::move(prevs));
|
||||
|
||||
STObject finals (sfFinalFields);
|
||||
for (auto const& obj : *curNode)
|
||||
{
|
||||
// search the final node for values saved always
|
||||
if (obj.getFName ().shouldMeta (SField::sMD_Always | SField::sMD_ChangeNew))
|
||||
finals.emplace_back (obj);
|
||||
}
|
||||
|
||||
if (!finals.empty ())
|
||||
meta.getAffectedNode (item.first).emplace_back (std::move(finals));
|
||||
}
|
||||
else if (type == &sfCreatedNode) // if created, thread to owner(s)
|
||||
{
|
||||
assert (curNode && !origNode);
|
||||
threadOwners (to, meta, curNode, newMod, j);
|
||||
|
||||
if (curNode->isThreadedType ()) // always thread to self
|
||||
threadTx (meta, curNode, newMod);
|
||||
|
||||
STObject news (sfNewFields);
|
||||
for (auto const& obj : *curNode)
|
||||
{
|
||||
// save non-default values
|
||||
if (!obj.isDefault () &&
|
||||
obj.getFName().shouldMeta(
|
||||
SField::sMD_Create | SField::sMD_Always))
|
||||
news.emplace_back (obj);
|
||||
}
|
||||
|
||||
if (!news.empty ())
|
||||
meta.getAffectedNode (item.first).emplace_back (std::move(news));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
// add any new modified nodes to the modification set
|
||||
for (auto& mod : newMod)
|
||||
update (to, mod.second);
|
||||
|
||||
sMeta = std::make_shared<Serializer>();
|
||||
meta.addRaw (*sMeta, ter, to.txCount());
|
||||
|
||||
// VFALCO For diagnostics do we want to show
|
||||
// metadata even when the base view is open?
|
||||
JLOG(j.trace) <<
|
||||
"metadata " << meta.getJson (0);
|
||||
}
|
||||
to.rawTxInsert(
|
||||
tx.getTransactionID(),
|
||||
sTx, sMeta);
|
||||
apply(to);
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
bool
|
||||
ApplyStateTable::exists (ReadView const& base,
|
||||
Keylet const& k) const
|
||||
{
|
||||
auto const iter = items_.find(k.key);
|
||||
if (iter == items_.end())
|
||||
return base.exists(k);
|
||||
auto const& item = iter->second;
|
||||
auto const& sle = item.second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
return false;
|
||||
case Action::cache:
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
break;
|
||||
}
|
||||
if (! k.check(*sle))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyStateTable::succ (ReadView const& base,
|
||||
key_type const& key, boost::optional<
|
||||
key_type> const& last) const ->
|
||||
boost::optional<key_type>
|
||||
{
|
||||
boost::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.first == Action::erase);
|
||||
// Find non-deleted successor in our list
|
||||
for (iter = items_.upper_bound(key);
|
||||
iter != items_.end (); ++iter)
|
||||
{
|
||||
if (iter->second.first != 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 boost::none;
|
||||
return next;
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE const>
|
||||
ApplyStateTable::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;
|
||||
auto const& sle = item.second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
return nullptr;
|
||||
case Action::cache:
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
break;
|
||||
};
|
||||
if (! k.check(*sle))
|
||||
return nullptr;
|
||||
return sle;
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE>
|
||||
ApplyStateTable::peek (ReadView const& base,
|
||||
Keylet const& k)
|
||||
{
|
||||
auto iter = items_.lower_bound(k.key);
|
||||
if (iter == items_.end() ||
|
||||
iter->first != k.key)
|
||||
{
|
||||
auto const sle = base.read(k);
|
||||
if (! sle)
|
||||
return nullptr;
|
||||
// Make our own copy
|
||||
using namespace std;
|
||||
iter = items_.emplace_hint (iter,
|
||||
piecewise_construct,
|
||||
forward_as_tuple(sle->key()),
|
||||
forward_as_tuple(Action::cache,
|
||||
make_shared<SLE>(*sle)));
|
||||
return iter->second.second;
|
||||
}
|
||||
auto const& item = iter->second;
|
||||
auto const& sle = item.second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
return nullptr;
|
||||
case Action::cache:
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
break;
|
||||
};
|
||||
if (! k.check(*sle))
|
||||
return nullptr;
|
||||
return sle;
|
||||
}
|
||||
|
||||
void
|
||||
ApplyStateTable::erase(
|
||||
ReadView const& base,
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
auto const iter =
|
||||
items_.find(sle->key());
|
||||
if (iter == items_.end())
|
||||
LogicError("ApplyStateTable::erase: missing key");
|
||||
auto& item = iter->second;
|
||||
if (item.second != sle)
|
||||
LogicError("ApplyStateTable::erase: unknown SLE");
|
||||
switch(item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
LogicError("ApplyStateTable::erase: double erase");
|
||||
break;
|
||||
case Action::insert:
|
||||
items_.erase(iter);
|
||||
break;
|
||||
case Action::cache:
|
||||
case Action::modify:
|
||||
item.first = Action::erase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ApplyStateTable::rawErase (ReadView const& base,
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
using namespace std;
|
||||
auto const result = items_.emplace(
|
||||
piecewise_construct,
|
||||
forward_as_tuple(sle->key()),
|
||||
forward_as_tuple(Action::erase, sle));
|
||||
if (result.second)
|
||||
return;
|
||||
auto& item = result.first->second;
|
||||
switch(item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
LogicError("ApplyStateTable::rawErase: double erase");
|
||||
break;
|
||||
case Action::insert:
|
||||
items_.erase(result.first);
|
||||
break;
|
||||
case Action::cache:
|
||||
case Action::modify:
|
||||
item.first = Action::erase;
|
||||
item.second = sle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ApplyStateTable::insert (ReadView const& base,
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
auto const iter =
|
||||
items_.lower_bound(sle->key());
|
||||
if (iter == items_.end() ||
|
||||
iter->first != sle->key())
|
||||
{
|
||||
using namespace std;
|
||||
items_.emplace_hint(iter,
|
||||
piecewise_construct,
|
||||
forward_as_tuple(sle->key()),
|
||||
forward_as_tuple(Action::insert, sle));
|
||||
return;
|
||||
}
|
||||
auto& item = iter->second;
|
||||
switch(item.first)
|
||||
{
|
||||
case Action::cache:
|
||||
LogicError("ApplyStateTable::insert: already cached");
|
||||
case Action::insert:
|
||||
LogicError("ApplyStateTable::insert: already inserted");
|
||||
case Action::modify:
|
||||
LogicError("ApplyStateTable::insert: already modified");
|
||||
case Action::erase:
|
||||
break;
|
||||
}
|
||||
item.first = Action::modify;
|
||||
item.second = sle;
|
||||
}
|
||||
|
||||
void
|
||||
ApplyStateTable::replace (ReadView const& base,
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
auto const iter =
|
||||
items_.lower_bound(sle->key());
|
||||
if (iter == items_.end() ||
|
||||
iter->first != sle->key())
|
||||
{
|
||||
using namespace std;
|
||||
items_.emplace_hint(iter, piecewise_construct,
|
||||
forward_as_tuple(sle->key()),
|
||||
forward_as_tuple(Action::modify, sle));
|
||||
return;
|
||||
}
|
||||
auto& item = iter->second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
LogicError("ApplyStateTable::replace: already erased");
|
||||
case Action::cache:
|
||||
item.first = Action::modify;
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
break;
|
||||
}
|
||||
item.second = sle;
|
||||
}
|
||||
|
||||
void
|
||||
ApplyStateTable::update (ReadView const& base,
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
auto const iter =
|
||||
items_.find(sle->key());
|
||||
if (iter == items_.end())
|
||||
LogicError("ApplyStateTable::update: missing key");
|
||||
auto& item = iter->second;
|
||||
if (item.second != sle)
|
||||
LogicError("ApplyStateTable::update: unknown SLE");
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
LogicError("ApplyStateTable::update: erased");
|
||||
break;
|
||||
case Action::cache:
|
||||
item.first = Action::modify;
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ApplyStateTable::destroyXRP(std::uint64_t feeDrops)
|
||||
{
|
||||
dropsDestroyed_ += feeDrops;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
ApplyStateTable::threadTx (TxMeta& meta,
|
||||
std::shared_ptr<SLE> const& to,
|
||||
Mods& mods)
|
||||
{
|
||||
key_type prevTxID;
|
||||
std::uint32_t prevLgrID;
|
||||
if (! to->thread(meta.getTxID(),
|
||||
meta.getLgrSeq(), prevTxID, prevLgrID))
|
||||
return false;
|
||||
if (prevTxID.isZero () ||
|
||||
TxMeta::thread(
|
||||
meta.getAffectedNode(to,
|
||||
sfModifiedNode), prevTxID,
|
||||
prevLgrID))
|
||||
return true;
|
||||
assert (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE>
|
||||
ApplyStateTable::getForMod (ReadView const& base,
|
||||
key_type const& key, Mods& mods, beast::Journal j)
|
||||
{
|
||||
auto iter = items_.find (key);
|
||||
if (iter != items_.end ())
|
||||
{
|
||||
auto const& item = iter->second;
|
||||
if (item.first == Action::erase)
|
||||
{
|
||||
// VFALCO We need to think about throwing
|
||||
// an exception or calling LogicError
|
||||
JLOG(j.fatal) <<
|
||||
"Trying to thread to deleted node";
|
||||
return nullptr;
|
||||
}
|
||||
return item.second;
|
||||
}
|
||||
{
|
||||
auto miter = mods.find (key);
|
||||
if (miter != mods.end ())
|
||||
{
|
||||
assert (miter->second);
|
||||
return miter->second;
|
||||
}
|
||||
}
|
||||
auto sle = peek(base,
|
||||
keylet::unchecked(key));
|
||||
if (! sle)
|
||||
{
|
||||
// VFALCO We need to think about throwing
|
||||
// an exception or calling LogicError
|
||||
JLOG(j.fatal) <<
|
||||
"ApplyStateTable::getForMod: key not found";
|
||||
return nullptr;
|
||||
}
|
||||
mods.emplace(key, sle);
|
||||
return sle;
|
||||
}
|
||||
|
||||
bool
|
||||
ApplyStateTable::threadTx (ReadView const& base,
|
||||
TxMeta& meta, AccountID const& to,
|
||||
Mods& mods, beast::Journal j)
|
||||
{
|
||||
auto const sle = getForMod(
|
||||
base, keylet::account(to).key, mods, j);
|
||||
assert(sle);
|
||||
if (! sle)
|
||||
{
|
||||
// VFALCO We need to think about throwing
|
||||
// an exception or calling LogicError
|
||||
JLOG(j.fatal) <<
|
||||
"Threading to non-existent account: " <<
|
||||
toBase58(to);
|
||||
return false;
|
||||
}
|
||||
|
||||
return threadTx (meta, sle, mods);
|
||||
}
|
||||
|
||||
bool
|
||||
ApplyStateTable::threadOwners (ReadView const& base,
|
||||
TxMeta& meta, std::shared_ptr<
|
||||
SLE const> const& sle, Mods& mods,
|
||||
beast::Journal j)
|
||||
{
|
||||
// thread new or modified sle to owner or owners
|
||||
// VFALCO Why not isFieldPresent?
|
||||
if (sle->getType() != ltACCOUNT_ROOT &&
|
||||
sle->getFieldIndex(sfAccount) != -1)
|
||||
{
|
||||
// thread to owner's account
|
||||
return threadTx (base, meta, sle->getAccountID(
|
||||
sfAccount), mods, j);
|
||||
}
|
||||
else if (sle->getType() == ltRIPPLE_STATE)
|
||||
{
|
||||
// thread to owner's accounts
|
||||
return
|
||||
threadTx (base, meta, sle->getFieldAmount(
|
||||
sfLowLimit).getIssuer(), mods, j) &&
|
||||
threadTx (base, meta, sle->getFieldAmount(
|
||||
sfHighLimit).getIssuer(), mods, j);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ripple
|
||||
163
src/ripple/ledger/impl/ApplyViewBase.cpp
Normal file
163
src/ripple/ledger/impl/ApplyViewBase.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/detail/ApplyViewBase.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
ApplyViewBase::ApplyViewBase(
|
||||
ReadView const* base,
|
||||
ApplyFlags flags)
|
||||
: flags_ (flags)
|
||||
, base_ (base)
|
||||
{
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
LedgerInfo const&
|
||||
ApplyViewBase::info() const
|
||||
{
|
||||
return base_->info();
|
||||
}
|
||||
|
||||
Fees const&
|
||||
ApplyViewBase::fees() const
|
||||
{
|
||||
return base_->fees();
|
||||
}
|
||||
|
||||
bool
|
||||
ApplyViewBase::exists (Keylet const& k) const
|
||||
{
|
||||
return items_.exists(*base_, k);
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::succ (key_type const& key,
|
||||
boost::optional<key_type> last) const ->
|
||||
boost::optional<key_type>
|
||||
{
|
||||
return items_.succ(*base_, key, last);
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE const>
|
||||
ApplyViewBase::read (Keylet const& k) const
|
||||
{
|
||||
return items_.read(*base_, k);
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::txsBegin() const ->
|
||||
std::unique_ptr<txs_type::iter_base>
|
||||
{
|
||||
return base_->txsBegin();
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::txsEnd() const ->
|
||||
std::unique_ptr<txs_type::iter_base>
|
||||
{
|
||||
return base_->txsEnd();
|
||||
}
|
||||
|
||||
bool
|
||||
ApplyViewBase::txExists (key_type const& key) const
|
||||
{
|
||||
return base_->txExists(key);
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::txRead(
|
||||
key_type const& key) const ->
|
||||
tx_type
|
||||
{
|
||||
return base_->txRead(key);
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
ApplyFlags
|
||||
ApplyViewBase::flags() const
|
||||
{
|
||||
return flags_;
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE>
|
||||
ApplyViewBase::peek (Keylet const& k)
|
||||
{
|
||||
return items_.peek(*base_, k);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyViewBase::erase(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.erase(*base_, sle);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyViewBase::insert(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.insert(*base_, sle);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyViewBase::update(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.update(*base_, sle);
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
void
|
||||
ApplyViewBase::rawErase(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.rawErase(*base_, sle);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyViewBase::rawInsert(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.insert(*base_, sle);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyViewBase::rawReplace(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.replace(*base_, sle);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyViewBase::rawDestroyXRP(
|
||||
std::uint64_t feeDrops)
|
||||
{
|
||||
items_.destroyXRP(feeDrops);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ripple
|
||||
@@ -18,36 +18,24 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/CachedView.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/ledger/ApplyViewImpl.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::shared_ptr<SLE const>
|
||||
CachedView::read (Keylet const& k) const
|
||||
ApplyViewImpl::ApplyViewImpl(
|
||||
ReadView const* base,
|
||||
ApplyFlags flags)
|
||||
: ApplyViewBase (base, flags)
|
||||
{
|
||||
uint256 hash;
|
||||
// get hash since SLECache needs to know
|
||||
auto const item =
|
||||
view_.stateMap().peekItem(k.key, hash);
|
||||
if (! item)
|
||||
return nullptr;
|
||||
if (auto sle = cache_.fetch(hash))
|
||||
{
|
||||
if(! k.check(*sle))
|
||||
return nullptr;
|
||||
return sle;
|
||||
}
|
||||
SerialIter sit(make_Slice(item->peekData()));
|
||||
auto sle = std::make_shared<SLE>(sit, item->key());
|
||||
if (! k.check(*sle))
|
||||
return nullptr;
|
||||
// VFALCO TODO Eliminate "immutable" runtime property
|
||||
sle->setImmutable ();
|
||||
cache_.canonicalize(hash, sle);
|
||||
// need move otherwise makes a copy
|
||||
// because return type is different
|
||||
return std::move(sle);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyViewImpl::apply (OpenView& to,
|
||||
STTx const& tx, TER ter,
|
||||
beast::Journal j)
|
||||
{
|
||||
items_.apply(to, tx, ter, deliver_, j);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
62
src/ripple/ledger/impl/CachedSLEs.cpp
Normal file
62
src/ripple/ledger/impl/CachedSLEs.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/CachedSLEs.h>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
void
|
||||
CachedSLEs::expire()
|
||||
{
|
||||
std::vector<
|
||||
std::shared_ptr<void const>> trash;
|
||||
{
|
||||
auto const expireTime =
|
||||
map_.clock().now() - timeToLive_;
|
||||
std::lock_guard<
|
||||
std::mutex> lock(mutex_);
|
||||
for (auto iter = map_.chronological.begin();
|
||||
iter != map_.chronological.end(); ++iter)
|
||||
{
|
||||
if (iter.when() > expireTime)
|
||||
break;
|
||||
if (iter->second.unique())
|
||||
{
|
||||
trash.emplace_back(
|
||||
std::move(iter->second));
|
||||
iter = map_.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
CachedSLEs::rate() const
|
||||
{
|
||||
std::lock_guard<
|
||||
std::mutex> lock(mutex_);
|
||||
auto const tot = hit_ + miss_;
|
||||
if (tot == 0)
|
||||
return 0;
|
||||
return double(hit_) / tot;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
78
src/ripple/ledger/impl/CachingReadView.cpp
Normal file
78
src/ripple/ledger/impl/CachingReadView.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/CachingReadView.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
CachingReadView::CachingReadView(
|
||||
DigestAwareReadView const* base,
|
||||
CachedSLEs& cache,
|
||||
std::shared_ptr<void const> hold)
|
||||
: cache_ (cache)
|
||||
, base_ (*base)
|
||||
, hold_ (hold)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CachingReadView::exists (Keylet const& k) const
|
||||
{
|
||||
return read(k) != nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE const>
|
||||
CachingReadView::read (Keylet const& k) const
|
||||
{
|
||||
{
|
||||
std::lock_guard<
|
||||
std::mutex> lock(mutex_);
|
||||
auto const iter = map_.find(k.key);
|
||||
if (iter != map_.end())
|
||||
{
|
||||
if (! k.check(*iter->second))
|
||||
return nullptr;
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
auto const digest =
|
||||
base_.digest(k.key);
|
||||
if (! digest)
|
||||
return nullptr;
|
||||
auto sle = cache_.fetch(*digest,
|
||||
[&]() { return base_.read(k); });
|
||||
std::lock_guard<
|
||||
std::mutex> lock(mutex_);
|
||||
auto const iter =
|
||||
map_.find(k.key);
|
||||
if (iter == map_.end())
|
||||
{
|
||||
map_.emplace(k.key, sle);
|
||||
return sle;
|
||||
}
|
||||
if (! k.check(*iter->second))
|
||||
LogicError("CachingReadView::read: wrong type");
|
||||
return iter->second;
|
||||
|
||||
}
|
||||
|
||||
} // ripple
|
||||
253
src/ripple/ledger/impl/OpenView.cpp
Normal file
253
src/ripple/ledger/impl/OpenView.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
open_ledger_t const open_ledger {};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class OpenView::txs_iter_impl
|
||||
: public txs_type::iter_base
|
||||
{
|
||||
private:
|
||||
bool metadata_;
|
||||
txs_map::const_iterator iter_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
txs_iter_impl (bool metadata,
|
||||
txs_map::const_iterator iter)
|
||||
: metadata_(metadata)
|
||||
, iter_(iter)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<base_type>
|
||||
copy() const override
|
||||
{
|
||||
return std::make_unique<
|
||||
txs_iter_impl>(
|
||||
metadata_, iter_);
|
||||
}
|
||||
|
||||
bool
|
||||
equal (base_type const& impl) const override
|
||||
{
|
||||
auto const& other = dynamic_cast<
|
||||
txs_iter_impl const&>(impl);
|
||||
return iter_ == other.iter_;
|
||||
}
|
||||
|
||||
void
|
||||
increment() override
|
||||
{
|
||||
++iter_;
|
||||
}
|
||||
|
||||
value_type
|
||||
dereference() const override
|
||||
{
|
||||
value_type result;
|
||||
{
|
||||
SerialIter sit(
|
||||
iter_->second.first->slice());
|
||||
result.first = std::make_shared<
|
||||
STTx const>(sit);
|
||||
}
|
||||
if (metadata_)
|
||||
{
|
||||
SerialIter sit(
|
||||
iter_->second.second->slice());
|
||||
result.second = std::make_shared<
|
||||
STObject const>(sit, sfMetadata);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
OpenView::OpenView (open_ledger_t,
|
||||
ReadView const* base,
|
||||
std::shared_ptr<void const> hold)
|
||||
: info_ (base->info())
|
||||
, base_ (base)
|
||||
, hold_ (std::move(hold))
|
||||
{
|
||||
info_.open = true;
|
||||
info_.seq = base_->info().seq + 1;
|
||||
info_.parentCloseTime = base_->info().closeTime;
|
||||
}
|
||||
|
||||
OpenView::OpenView (ReadView const* base,
|
||||
std::shared_ptr<void const> hold)
|
||||
: info_ (base->info())
|
||||
, base_ (base)
|
||||
, hold_ (std::move(hold))
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t
|
||||
OpenView::txCount() const
|
||||
{
|
||||
return txs_.size();
|
||||
}
|
||||
|
||||
void
|
||||
OpenView::apply (TxsRawView& to) const
|
||||
{
|
||||
items_.apply(to);
|
||||
for (auto const& item : txs_)
|
||||
to.rawTxInsert (item.first,
|
||||
item.second.first,
|
||||
item.second.second);
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
LedgerInfo const&
|
||||
OpenView::info() const
|
||||
{
|
||||
return info_;
|
||||
}
|
||||
|
||||
Fees const&
|
||||
OpenView::fees() const
|
||||
{
|
||||
return base_->fees();
|
||||
}
|
||||
|
||||
bool
|
||||
OpenView::exists (Keylet const& k) const
|
||||
{
|
||||
return items_.exists(*base_, k);
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::succ (key_type const& key,
|
||||
boost::optional<key_type> last) const ->
|
||||
boost::optional<key_type>
|
||||
{
|
||||
return items_.succ(*base_, key, last);
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE const>
|
||||
OpenView::read (Keylet const& k) const
|
||||
{
|
||||
return items_.read(*base_, k);
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::txsBegin() const ->
|
||||
std::unique_ptr<txs_type::iter_base>
|
||||
{
|
||||
return std::make_unique<
|
||||
txs_iter_impl>(
|
||||
closed(), txs_.cbegin());
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::txsEnd() const ->
|
||||
std::unique_ptr<txs_type::iter_base>
|
||||
{
|
||||
return std::make_unique<
|
||||
txs_iter_impl>(
|
||||
closed(), txs_.cend());
|
||||
}
|
||||
|
||||
bool
|
||||
OpenView::txExists (key_type const& key) const
|
||||
{
|
||||
return txs_.find(key) != txs_.end();
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::txRead (key_type const& key) const ->
|
||||
tx_type
|
||||
{
|
||||
auto const iter = txs_.find(key);
|
||||
if (iter == txs_.end())
|
||||
return base_->txRead(key);
|
||||
auto const& item = iter->second;
|
||||
auto stx = std::make_shared<STTx const
|
||||
>(SerialIter{ item.first->slice() });
|
||||
decltype(tx_type::second) sto;
|
||||
if (item.second)
|
||||
sto = std::make_shared<STObject const>(
|
||||
SerialIter{ item.second->slice() },
|
||||
sfMetadata);
|
||||
else
|
||||
sto = nullptr;
|
||||
return { std::move(stx), std::move(sto) };
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
void
|
||||
OpenView::rawErase(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.erase(sle);
|
||||
}
|
||||
|
||||
void
|
||||
OpenView::rawInsert(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.insert(sle);
|
||||
}
|
||||
|
||||
void
|
||||
OpenView::rawReplace(
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
items_.replace(sle);
|
||||
}
|
||||
|
||||
void
|
||||
OpenView::rawDestroyXRP(
|
||||
std::uint64_t feeDrops)
|
||||
{
|
||||
items_.destroyXRP(feeDrops);
|
||||
// VFALCO Deduct from info_.totalDrops ?
|
||||
// What about child views?
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
void
|
||||
OpenView::rawTxInsert (key_type const& key,
|
||||
std::shared_ptr<Serializer const>
|
||||
const& txn, std::shared_ptr<
|
||||
Serializer const>
|
||||
const& metaData)
|
||||
{
|
||||
auto const result = txs_.emplace (key,
|
||||
std::make_pair(txn, metaData));
|
||||
if (! result.second)
|
||||
LogicError("rawTxInsert: duplicate TX id" +
|
||||
to_string(key));
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -18,11 +18,13 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/DeferredCredits.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/PaymentSandbox.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
auto
|
||||
DeferredCredits::makeKey (AccountID const& a1,
|
||||
AccountID const& a2, Currency const& c) ->
|
||||
@@ -34,50 +36,12 @@ DeferredCredits::makeKey (AccountID const& a1,
|
||||
return std::make_tuple(a2, a1, c);
|
||||
}
|
||||
|
||||
template <class TMap>
|
||||
void maybeLogCredit (AccountID const& sender,
|
||||
AccountID const& receiver,
|
||||
STAmount const& amount,
|
||||
TMap const& adjMap)
|
||||
{
|
||||
using std::get;
|
||||
|
||||
if (!ShouldLog (lsTRACE, DeferredCredits))
|
||||
return;
|
||||
|
||||
// write the balances to the log
|
||||
std::stringstream str;
|
||||
str << "assetXfer: " << sender << ", " << receiver << ", " << amount;
|
||||
if (!adjMap.empty ())
|
||||
{
|
||||
str << " : ";
|
||||
}
|
||||
for (auto i = adjMap.begin (), e = adjMap.end ();
|
||||
i != e; ++i)
|
||||
{
|
||||
if (i != adjMap.begin ())
|
||||
{
|
||||
str << ", ";
|
||||
}
|
||||
auto const& k(i->first);
|
||||
auto const& v(i->second);
|
||||
str << to_string (get<0> (k)) << " | " <<
|
||||
to_string (get<1> (k)) << " | " <<
|
||||
get<1> (v).getFullText () << " | " <<
|
||||
get<0> (v).getFullText ();
|
||||
}
|
||||
WriteLog (lsTRACE, DeferredCredits) << str.str ();
|
||||
}
|
||||
|
||||
void DeferredCredits::credit (AccountID const& sender,
|
||||
AccountID const& receiver,
|
||||
STAmount const& amount)
|
||||
{
|
||||
using std::get;
|
||||
|
||||
WriteLog (lsTRACE, DeferredCredits)
|
||||
<< "credit: " << sender << ", " << receiver << ", " << amount;
|
||||
|
||||
assert (sender != receiver);
|
||||
assert (!amount.negative ());
|
||||
|
||||
@@ -108,7 +72,6 @@ void DeferredCredits::credit (AccountID const& sender,
|
||||
else
|
||||
get<0> (v) += amount;
|
||||
}
|
||||
maybeLogCredit (sender, receiver, amount, map_);
|
||||
}
|
||||
|
||||
// Get the adjusted balance of main for the
|
||||
@@ -135,10 +98,6 @@ STAmount DeferredCredits::adjustedBalance (AccountID const& main,
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog (lsTRACE, DeferredCredits)
|
||||
<< "adjustedBalance: " << main << ", " <<
|
||||
other << ", " << curBalance << ", " << result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -163,5 +122,41 @@ void DeferredCredits::clear ()
|
||||
map_.clear ();
|
||||
}
|
||||
|
||||
} // ripple
|
||||
} // detail
|
||||
|
||||
STAmount
|
||||
PaymentSandbox::balanceHook (AccountID const& account,
|
||||
AccountID const& issuer,
|
||||
STAmount const& amount) const
|
||||
{
|
||||
if (ps_)
|
||||
return tab_.adjustedBalance (
|
||||
account, issuer, ps_->balanceHook (account, issuer, amount));
|
||||
return tab_.adjustedBalance(
|
||||
account, issuer, amount);
|
||||
}
|
||||
|
||||
void
|
||||
PaymentSandbox::creditHook (AccountID const& from,
|
||||
AccountID const& to,
|
||||
STAmount const& amount)
|
||||
{
|
||||
tab_.credit(from, to, amount);
|
||||
}
|
||||
|
||||
void
|
||||
PaymentSandbox::apply (RawView& to)
|
||||
{
|
||||
assert(! ps_);
|
||||
items_.apply(to);
|
||||
}
|
||||
|
||||
void
|
||||
PaymentSandbox::apply (PaymentSandbox& to)
|
||||
{
|
||||
assert(ps_ == &to);
|
||||
items_.apply(to);
|
||||
tab_.apply(to.tab_);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
214
src/ripple/ledger/impl/RawStateTable.cpp
Normal file
214
src/ripple/ledger/impl/RawStateTable.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/detail/RawStateTable.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
// 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.first)
|
||||
{
|
||||
case Action::erase:
|
||||
to.rawErase(item.second);
|
||||
break;
|
||||
case Action::insert:
|
||||
to.rawInsert(item.second);
|
||||
break;
|
||||
case Action::replace:
|
||||
to.rawReplace(item.second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RawStateTable::exists (ReadView const& base,
|
||||
Keylet const& k) const
|
||||
{
|
||||
assert(k.key.isNonZero());
|
||||
auto const iter = items_.find(k.key);
|
||||
if (iter == items_.end())
|
||||
return base.exists(k);
|
||||
auto const& item = iter->second;
|
||||
if (item.first == Action::erase)
|
||||
return false;
|
||||
if (! k.check(*item.second))
|
||||
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, boost::optional<
|
||||
key_type> const& last) const ->
|
||||
boost::optional<key_type>
|
||||
{
|
||||
boost::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.first == Action::erase);
|
||||
// Find non-deleted successor in our list
|
||||
for (iter = items_.upper_bound(key);
|
||||
iter != items_.end (); ++iter)
|
||||
{
|
||||
if (iter->second.first != 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 boost::none;
|
||||
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.first)
|
||||
{
|
||||
case Action::erase:
|
||||
LogicError("RawStateTable::erase: already erased");
|
||||
break;
|
||||
case Action::insert:
|
||||
items_.erase(result.first);
|
||||
break;
|
||||
case Action::replace:
|
||||
item.first = Action::erase;
|
||||
item.second = 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.first)
|
||||
{
|
||||
case Action::erase:
|
||||
item.first = Action::replace;
|
||||
item.second = 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.first)
|
||||
{
|
||||
case Action::erase:
|
||||
LogicError("RawStateTable::replace: was erased");
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::replace:
|
||||
item.second = 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.first == Action::erase)
|
||||
return nullptr;
|
||||
// Convert to SLE const
|
||||
std::shared_ptr<
|
||||
SLE const> sle = item.second;
|
||||
if (! k.check(*sle))
|
||||
return nullptr;
|
||||
return sle;
|
||||
}
|
||||
|
||||
void
|
||||
RawStateTable::destroyXRP(std::uint64_t feeDrops)
|
||||
{
|
||||
dropsDestroyed_ += feeDrops;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ripple
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/protocol/Quality.h>
|
||||
@@ -40,7 +41,7 @@ namespace ripple {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Fees
|
||||
getFees (BasicView const& view,
|
||||
getFees (ReadView const& view,
|
||||
Config const& config)
|
||||
{
|
||||
Fees f;
|
||||
@@ -72,7 +73,7 @@ getFees (BasicView const& view,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
isGlobalFrozen (BasicView const& view,
|
||||
isGlobalFrozen (ReadView const& view,
|
||||
AccountID const& issuer)
|
||||
{
|
||||
// VFALCO Perhaps this should assert
|
||||
@@ -89,7 +90,7 @@ isGlobalFrozen (BasicView const& view,
|
||||
// the specified issuer or does the freeze flag prohibit it?
|
||||
static
|
||||
bool
|
||||
isFrozen (BasicView const& view, AccountID const& account,
|
||||
isFrozen (ReadView const& view, AccountID const& account,
|
||||
Currency const& currency, AccountID const& issuer)
|
||||
{
|
||||
if (isXRP (currency))
|
||||
@@ -112,7 +113,7 @@ isFrozen (BasicView const& view, AccountID const& account,
|
||||
}
|
||||
|
||||
STAmount
|
||||
accountHolds (BasicView const& view,
|
||||
accountHolds (ReadView const& view,
|
||||
AccountID const& account, Currency const& currency,
|
||||
AccountID const& issuer, FreezeHandling zeroIfFrozen,
|
||||
Config const& config)
|
||||
@@ -172,7 +173,7 @@ accountHolds (BasicView const& view,
|
||||
}
|
||||
|
||||
STAmount
|
||||
accountFunds (BasicView const& view, AccountID const& id,
|
||||
accountFunds (ReadView const& view, AccountID const& id,
|
||||
STAmount const& saDefault, FreezeHandling freezeHandling,
|
||||
Config const& config)
|
||||
{
|
||||
@@ -201,7 +202,7 @@ accountFunds (BasicView const& view, AccountID const& id,
|
||||
}
|
||||
|
||||
void
|
||||
forEachItem (BasicView const& view, AccountID const& id,
|
||||
forEachItem (ReadView const& view, AccountID const& id,
|
||||
std::function<void(std::shared_ptr<SLE const> const&)> f)
|
||||
{
|
||||
auto const root = keylet::ownerDir(id);
|
||||
@@ -223,7 +224,7 @@ forEachItem (BasicView const& view, AccountID const& id,
|
||||
}
|
||||
|
||||
bool
|
||||
forEachItemAfter (BasicView const& view, AccountID const& id,
|
||||
forEachItemAfter (ReadView const& view, AccountID const& id,
|
||||
uint256 const& after, std::uint64_t const hint,
|
||||
unsigned int limit, std::function<
|
||||
bool (std::shared_ptr<SLE const> const&)> f)
|
||||
@@ -295,7 +296,7 @@ forEachItemAfter (BasicView const& view, AccountID const& id,
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
rippleTransferRate (BasicView const& view,
|
||||
rippleTransferRate (ReadView const& view,
|
||||
AccountID const& issuer)
|
||||
{
|
||||
auto const sle = view.read(keylet::account(issuer));
|
||||
@@ -308,7 +309,7 @@ rippleTransferRate (BasicView const& view,
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
rippleTransferRate (BasicView const& view,
|
||||
rippleTransferRate (ReadView const& view,
|
||||
AccountID const& uSenderID,
|
||||
AccountID const& uReceiverID,
|
||||
AccountID const& issuer)
|
||||
@@ -322,7 +323,7 @@ rippleTransferRate (BasicView const& view,
|
||||
}
|
||||
|
||||
bool
|
||||
dirIsEmpty (BasicView const& view,
|
||||
dirIsEmpty (ReadView const& view,
|
||||
Keylet const& k)
|
||||
{
|
||||
auto const sleNode = view.read(k);
|
||||
@@ -335,7 +336,7 @@ dirIsEmpty (BasicView const& view,
|
||||
}
|
||||
|
||||
bool
|
||||
cdirFirst (BasicView const& view,
|
||||
cdirFirst (ReadView const& view,
|
||||
uint256 const& uRootIndex, // --> Root of directory.
|
||||
std::shared_ptr<SLE const>& sleNode, // <-> current node
|
||||
unsigned int& uDirEntry, // <-- next entry
|
||||
@@ -348,7 +349,7 @@ cdirFirst (BasicView const& view,
|
||||
}
|
||||
|
||||
bool
|
||||
cdirNext (BasicView const& view,
|
||||
cdirNext (ReadView const& view,
|
||||
uint256 const& uRootIndex, // --> Root of directory
|
||||
std::shared_ptr<SLE const>& sleNode, // <-> current node
|
||||
unsigned int& uDirEntry, // <-> next entry
|
||||
@@ -394,7 +395,7 @@ cdirNext (BasicView const& view,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
adjustOwnerCount (View& view,
|
||||
adjustOwnerCount (ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sle,
|
||||
int amount)
|
||||
{
|
||||
@@ -431,7 +432,7 @@ adjustOwnerCount (View& view,
|
||||
}
|
||||
|
||||
bool
|
||||
dirFirst (View& view,
|
||||
dirFirst (ApplyView& view,
|
||||
uint256 const& uRootIndex, // --> Root of directory.
|
||||
std::shared_ptr<SLE>& sleNode, // <-> current node
|
||||
unsigned int& uDirEntry, // <-- next entry
|
||||
@@ -444,7 +445,7 @@ dirFirst (View& view,
|
||||
}
|
||||
|
||||
bool
|
||||
dirNext (View& view,
|
||||
dirNext (ApplyView& view,
|
||||
uint256 const& uRootIndex, // --> Root of directory
|
||||
std::shared_ptr<SLE>& sleNode, // <-> current node
|
||||
unsigned int& uDirEntry, // <-> next entry
|
||||
@@ -484,7 +485,7 @@ dirNext (View& view,
|
||||
}
|
||||
|
||||
TER
|
||||
dirAdd (View& view,
|
||||
dirAdd (ApplyView& view,
|
||||
std::uint64_t& uNodeDir,
|
||||
uint256 const& uRootIndex, // VFALCO Should be Keylet
|
||||
uint256 const& uLedgerIndex,
|
||||
@@ -578,7 +579,7 @@ dirAdd (View& view,
|
||||
|
||||
// Ledger must be in a state for this to work.
|
||||
TER
|
||||
dirDelete (View& view,
|
||||
dirDelete (ApplyView& view,
|
||||
const bool bKeepRoot, // --> True, if we never completely clean up, after we overflow the root node.
|
||||
const std::uint64_t& uNodeDir, // --> Node containing entry.
|
||||
uint256 const& uRootIndex, // --> The index of the base of the directory. Nodes are based off of this.
|
||||
@@ -765,7 +766,7 @@ dirDelete (View& view,
|
||||
}
|
||||
|
||||
TER
|
||||
trustCreate (View& view,
|
||||
trustCreate (ApplyView& view,
|
||||
const bool bSrcHigh,
|
||||
AccountID const& uSrcAccountID,
|
||||
AccountID const& uDstAccountID,
|
||||
@@ -881,7 +882,7 @@ trustCreate (View& view,
|
||||
}
|
||||
|
||||
TER
|
||||
trustDelete (View& view,
|
||||
trustDelete (ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sleRippleState,
|
||||
AccountID const& uLowAccountID,
|
||||
AccountID const& uHighAccountID)
|
||||
@@ -923,7 +924,7 @@ trustDelete (View& view,
|
||||
}
|
||||
|
||||
TER
|
||||
offerDelete (View& view,
|
||||
offerDelete (ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
if (! sle)
|
||||
@@ -957,7 +958,7 @@ offerDelete (View& view,
|
||||
// - Create trust line of needed.
|
||||
// --> bCheckIssuer : normally require issuer to be involved.
|
||||
TER
|
||||
rippleCredit (View& view,
|
||||
rippleCredit (ApplyView& view,
|
||||
AccountID const& uSenderID, AccountID const& uReceiverID,
|
||||
STAmount const& saAmount, bool bCheckIssuer)
|
||||
{
|
||||
@@ -1099,7 +1100,7 @@ rippleCredit (View& view,
|
||||
// Calculate the fee needed to transfer IOU assets between two parties.
|
||||
static
|
||||
STAmount
|
||||
rippleTransferFee (BasicView const& view,
|
||||
rippleTransferFee (ReadView const& view,
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
AccountID const& issuer,
|
||||
@@ -1130,7 +1131,7 @@ rippleTransferFee (BasicView const& view,
|
||||
// <-- saActual: Amount actually cost. Sender pay's fees.
|
||||
static
|
||||
TER
|
||||
rippleSend (View& view,
|
||||
rippleSend (ApplyView& view,
|
||||
AccountID const& uSenderID, AccountID const& uReceiverID,
|
||||
STAmount const& saAmount, STAmount& saActual)
|
||||
{
|
||||
@@ -1176,7 +1177,7 @@ rippleSend (View& view,
|
||||
}
|
||||
|
||||
TER
|
||||
accountSend (View& view,
|
||||
accountSend (ApplyView& view,
|
||||
AccountID const& uSenderID, AccountID const& uReceiverID,
|
||||
STAmount const& saAmount)
|
||||
{
|
||||
@@ -1284,7 +1285,7 @@ accountSend (View& view,
|
||||
static
|
||||
bool
|
||||
updateTrustLine (
|
||||
View& view,
|
||||
ApplyView& view,
|
||||
SLE::pointer state,
|
||||
bool bSenderHigh,
|
||||
AccountID const& sender,
|
||||
@@ -1334,7 +1335,7 @@ updateTrustLine (
|
||||
}
|
||||
|
||||
TER
|
||||
issueIOU (View& view,
|
||||
issueIOU (ApplyView& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount, Issue const& issue)
|
||||
{
|
||||
@@ -1406,7 +1407,7 @@ issueIOU (View& view,
|
||||
}
|
||||
|
||||
TER
|
||||
redeemIOU (View& view,
|
||||
redeemIOU (ApplyView& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
Issue const& issue)
|
||||
@@ -1475,7 +1476,7 @@ redeemIOU (View& view,
|
||||
}
|
||||
|
||||
TER
|
||||
transferXRP (View& view,
|
||||
transferXRP (ApplyView& view,
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
STAmount const& amount)
|
||||
|
||||
Reference in New Issue
Block a user