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:
Vinnie Falco
2015-07-04 10:55:07 -07:00
parent f3b172b0c9
commit 367c3a5bfc
116 changed files with 4392 additions and 3565 deletions

View File

@@ -1405,10 +1405,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\MetaView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\OpenLedger.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1449,8 +1445,6 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerToJson.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\MetaView.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\OpenLedger.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\OrderBookDB.cpp">
@@ -1467,18 +1461,10 @@
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\ledger\tests\common_ledger.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\tests\DeferredCredits.test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\tests\Ledger_test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\tests\MetaView_test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\TransactionStateSF.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1663,12 +1649,6 @@
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\paths\FindPaths.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\paths\impl\PaymentView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\paths\impl\PaymentView.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\paths\Node.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1881,8 +1861,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\tests\PathSet.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\tests\Taker.test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -2307,15 +2285,53 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\json\Writer.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\CachedView.h">
<ClInclude Include="..\..\src\ripple\ledger\ApplyView.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\DeferredCredits.h">
<ClInclude Include="..\..\src\ripple\ledger\ApplyViewImpl.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\ledger\impl\CachedView.cpp">
<ClInclude Include="..\..\src\ripple\ledger\CachedSLEs.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\CachingReadView.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\ApplyStateTable.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\ApplyViewBase.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\RawStateTable.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\ReadViewFwdRange.h">
</ClInclude>
<None Include="..\..\src\ripple\ledger\detail\ReadViewFwdRange.ipp">
</None>
<ClCompile Include="..\..\src\ripple\ledger\impl\ApplyStateTable.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\DeferredCredits.cpp">
<ClCompile Include="..\..\src\ripple\ledger\impl\ApplyViewBase.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\ApplyViewImpl.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\CachedSLEs.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\CachingReadView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\OpenView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\PaymentSandbox.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\RawStateTable.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
@@ -2323,8 +2339,26 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\ledger\SLECache.h">
<ClInclude Include="..\..\src\ripple\ledger\OpenView.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\PaymentSandbox.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\RawView.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\ReadView.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\Sandbox.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\tests\PathSet.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\ledger\tests\PaymentSandbox_test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\tests\View_test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\ledger\View.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\net\HTTPClient.h">

View File

@@ -271,9 +271,6 @@
<Filter Include="ripple\app\paths\cursor">
<UniqueIdentifier>{9AD8D049-10A8-704C-D51A-FAD55B1F235F}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\app\paths\impl">
<UniqueIdentifier>{38932157-7DA1-A9CC-CABC-2A3D9CACF188}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\app\paths\tests">
<UniqueIdentifier>{1025719B-6A8F-D9FB-A6BA-02B93756DE09}</UniqueIdentifier>
</Filter>
@@ -328,9 +325,15 @@
<Filter Include="ripple\ledger">
<UniqueIdentifier>{33BBF793-1734-8439-B367-C4A48AB37EFC}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\ledger\detail">
<UniqueIdentifier>{3F9EB11B-A89B-C878-201C-5F1113B3A6E8}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\ledger\impl">
<UniqueIdentifier>{EA35E0D0-6876-9DC8-10FA-1E6A0486C574}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\ledger\tests">
<UniqueIdentifier>{D5A85FA6-148D-DA25-5DAA-C59504C18F26}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\net">
<UniqueIdentifier>{6649BD29-BE86-723F-501A-045E39310112}</UniqueIdentifier>
</Filter>
@@ -2142,9 +2145,6 @@
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerTiming.cpp">
<Filter>ripple\app\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\MetaView.cpp">
<Filter>ripple\app\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\OpenLedger.cpp">
<Filter>ripple\app\ledger\impl</Filter>
</ClCompile>
@@ -2190,9 +2190,6 @@
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerToJson.h">
<Filter>ripple\app\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\MetaView.h">
<Filter>ripple\app\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\OpenLedger.h">
<Filter>ripple\app\ledger</Filter>
</ClInclude>
@@ -2211,15 +2208,9 @@
<ClInclude Include="..\..\src\ripple\app\ledger\tests\common_ledger.h">
<Filter>ripple\app\ledger\tests</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\ledger\tests\DeferredCredits.test.cpp">
<Filter>ripple\app\ledger\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\tests\Ledger_test.cpp">
<Filter>ripple\app\ledger\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\tests\MetaView_test.cpp">
<Filter>ripple\app\ledger\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\TransactionStateSF.cpp">
<Filter>ripple\app\ledger</Filter>
</ClCompile>
@@ -2397,12 +2388,6 @@
<ClInclude Include="..\..\src\ripple\app\paths\FindPaths.h">
<Filter>ripple\app\paths</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\paths\impl\PaymentView.cpp">
<Filter>ripple\app\paths\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\paths\impl\PaymentView.h">
<Filter>ripple\app\paths\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\paths\Node.cpp">
<Filter>ripple\app\paths</Filter>
</ClCompile>
@@ -2610,9 +2595,6 @@
<ClCompile Include="..\..\src\ripple\app\tx\tests\OfferStream.test.cpp">
<Filter>ripple\app\tx\tests</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\tests\PathSet.h">
<Filter>ripple\app\tx\tests</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\tests\Taker.test.cpp">
<Filter>ripple\app\tx\tests</Filter>
</ClCompile>
@@ -3024,24 +3006,84 @@
<ClInclude Include="..\..\src\ripple\json\Writer.h">
<Filter>ripple\json</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\CachedView.h">
<ClInclude Include="..\..\src\ripple\ledger\ApplyView.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\DeferredCredits.h">
<ClInclude Include="..\..\src\ripple\ledger\ApplyViewImpl.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\ledger\impl\CachedView.cpp">
<ClInclude Include="..\..\src\ripple\ledger\CachedSLEs.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\CachingReadView.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\ApplyStateTable.h">
<Filter>ripple\ledger\detail</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\ApplyViewBase.h">
<Filter>ripple\ledger\detail</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\RawStateTable.h">
<Filter>ripple\ledger\detail</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\detail\ReadViewFwdRange.h">
<Filter>ripple\ledger\detail</Filter>
</ClInclude>
<None Include="..\..\src\ripple\ledger\detail\ReadViewFwdRange.ipp">
<Filter>ripple\ledger\detail</Filter>
</None>
<ClCompile Include="..\..\src\ripple\ledger\impl\ApplyStateTable.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\DeferredCredits.cpp">
<ClCompile Include="..\..\src\ripple\ledger\impl\ApplyViewBase.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\ApplyViewImpl.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\CachedSLEs.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\CachingReadView.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\OpenView.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\PaymentSandbox.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\RawStateTable.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\impl\View.cpp">
<Filter>ripple\ledger\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\ledger\SLECache.h">
<ClInclude Include="..\..\src\ripple\ledger\OpenView.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\PaymentSandbox.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\RawView.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\ReadView.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\Sandbox.h">
<Filter>ripple\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\ledger\tests\PathSet.h">
<Filter>ripple\ledger\tests</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\ledger\tests\PaymentSandbox_test.cpp">
<Filter>ripple\ledger\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\ledger\tests\View_test.cpp">
<Filter>ripple\ledger\tests</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\ledger\View.h">
<Filter>ripple\ledger</Filter>
</ClInclude>

View File

@@ -20,7 +20,6 @@
#include <BeastConfig.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/ledger/AcceptedLedgerTx.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/protocol/JsonFields.h>
#include <ripple/protocol/types.h>
@@ -98,9 +97,7 @@ void AcceptedLedgerTx::buildJson ()
// If the offer create is not self funded then add the owner balance
if (account != amount.issue ().account)
{
CachedView const view(
*mLedger, getApp().getSLECache());
auto const ownerFunds = accountFunds(view,
auto const ownerFunds = accountFunds(*mLedger,
account, amount, fhIGNORE_FREEZE, getConfig());
mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText ();
}

View File

@@ -53,6 +53,62 @@
namespace ripple {
class Ledger::txs_iter_impl
: public txs_type::iter_base
{
private:
bool metadata_;
ReadView const* view_;
SHAMap::iterator iter_;
public:
txs_iter_impl() = delete;
txs_iter_impl& operator= (txs_iter_impl const&) = delete;
txs_iter_impl (txs_iter_impl const&) = default;
txs_iter_impl (bool metadata,
SHAMap::iterator iter,
ReadView const& view)
: metadata_ (metadata)
, view_ (&view)
, iter_ (iter)
{
}
std::unique_ptr<base_type>
copy() const override
{
return std::make_unique<
txs_iter_impl>(*this);
}
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_;
}
txs_type::value_type
dereference() const override
{
auto const item = *iter_;
if (metadata_)
return deserializeTxPlusMeta(*item);
return { deserializeTx(*item), nullptr };
}
};
//------------------------------------------------------------------------------
/* Create the "genesis" account root.
The genesis account root contains all the XRP
that will ever exist in the system.
@@ -94,12 +150,12 @@ Ledger::Ledger (RippleAddress const& masterPublicKey,
{
// first ledger
info_.seq = 1;
auto sle = makeGenesisAccount(
auto const sle = makeGenesisAccount(
calcAccountID(masterPublicKey),
balanceInDrops);
WriteLog (lsTRACE, Ledger)
<< "root account: " << sle->getJson(0);
unchecked_insert(std::move(sle));
rawInsert(sle);
stateMap_->flushDirty (hotACCOUNT_NODE, info_.seq);
}
@@ -192,6 +248,7 @@ Ledger::Ledger (bool /* dummy */,
info_.hash = prevLedger.info().hash + uint256(1);
prevLedger.updateHash ();
// VFALCO TODO Require callers to update the hash
mParentHash = prevLedger.getHash ();
assert (mParentHash.isNonZero ());
@@ -247,14 +304,13 @@ Ledger::~Ledger ()
void Ledger::setImmutable ()
{
// Updates the hash and marks the ledger and its maps immutable
// Force update, since this is the only
// place the hash transitions to valid
updateHash ();
mImmutable = true;
mImmutable = true;
if (txMap_)
txMap_->setImmutable ();
if (stateMap_)
stateMap_->setImmutable ();
}
@@ -941,12 +997,18 @@ Ledger::succ (uint256 const& key,
std::shared_ptr<SLE const>
Ledger::read (Keylet const& k) const
{
auto const& value =
if (k.key == zero)
{
assert(false);
return nullptr;
}
auto const& item =
stateMap_->peekItem(k.key);
if (! value)
if (! item)
return nullptr;
auto sle = std::make_shared<SLE>(
SerialIter{value->data(), value->size()}, value->key());
SerialIter{item->data(),
item->size()}, item->key());
if (! k.check(*sle))
return nullptr;
// VFALCO TODO Eliminate "immutable" runtime property
@@ -958,138 +1020,100 @@ Ledger::read (Keylet const& k) const
//------------------------------------------------------------------------------
class Ledger::tx_iterator_impl
: public BasicView::iterator_impl
{
private:
SHAMap::iterator iter_;
public:
explicit
tx_iterator_impl (SHAMap::iterator iter)
: iter_(iter)
{
}
std::unique_ptr<iterator_impl>
copy() const override
auto
Ledger::txsBegin() const ->
std::unique_ptr<txs_type::iter_base>
{
return std::make_unique<
tx_iterator_impl>(
iter_);
}
bool
equal (iterator_impl const& impl) const override
{
auto const& other = dynamic_cast<
tx_iterator_impl const&>(impl);
return iter_ == other.iter_;
}
void
increment() override
{
++iter_;
}
txs_type::value_type
dereference() const override
{
return deserializeTxPlusMeta(**iter_);
}
};
bool
Ledger::txEmpty() const
{
return txMap_->getHash().isZero();
txs_iter_impl>(closed(),
txMap_->begin(), *this);
}
auto
Ledger::txBegin() const ->
std::unique_ptr<iterator_impl>
Ledger::txsEnd() const ->
std::unique_ptr<txs_type::iter_base>
{
// Can't iterate open Ledger objects
// because they don't have the metadata!
assert(closed());
return std::make_unique<
tx_iterator_impl>(txMap_->begin());
txs_iter_impl>(closed(),
txMap_->end(), *this);
}
bool
Ledger::txExists (uint256 const& key) const
{
return txMap_->hasItem (key);
}
auto
Ledger::txEnd() const ->
std::unique_ptr<iterator_impl>
Ledger::txRead(
key_type const& key) const ->
tx_type
{
// Can't iterate open Ledger objects
// because they don't have the metadata!
assert(closed());
return std::make_unique<
tx_iterator_impl>(txMap_->end());
auto const& item =
txMap_->peekItem(key);
if (! item)
return {};
if (closed())
{
auto result =
deserializeTxPlusMeta(*item);
return { std::move(result.first),
std::move(result.second) };
}
return { deserializeTx(*item), nullptr };
}
auto
Ledger::digest (key_type const& key) const ->
boost::optional<digest_type>
{
digest_type digest;
// VFALCO Unfortunately this loads the item
// from the NodeStore needlessly.
if (! stateMap_->peekItem(key, digest))
return boost::none;
return digest;
}
//------------------------------------------------------------------------------
bool
Ledger::unchecked_erase(
uint256 const& key)
void
Ledger::rawErase(std::shared_ptr<SLE> const& sle)
{
return stateMap_->delItem(key);
if (! stateMap_->delItem(sle->key()))
LogicError("Ledger::rawErase: key not found");
}
void
Ledger::unchecked_insert(
std::shared_ptr<SLE>&& sle)
Ledger::rawInsert(std::shared_ptr<SLE> const& sle)
{
assert(! stateMap_->hasItem(sle->getIndex()));
Serializer ss;
sle->add(ss);
auto item = std::make_shared<
SHAMapItem const>(sle->key(),
std::move(ss));
// VFALCO NOTE addGiveItem should take ownership
auto const success =
stateMap_->addGiveItem(
std::move(item), false, false);
(void)success;
assert(success);
auto const ours = std::move(sle);
if (! stateMap_->addGiveItem(
std::move(item), false, false))
LogicError("Ledger::rawInsert: key already exists");
}
void
Ledger::unchecked_replace(
std::shared_ptr<SLE>&& sle)
Ledger::rawReplace(std::shared_ptr<SLE> const& sle)
{
assert(stateMap_->hasItem(sle->getIndex()));
Serializer ss;
sle->add(ss);
auto item = std::make_shared<
SHAMapItem const>(sle->key(),
std::move(ss));
// VFALCO NOTE updateGiveItem should take ownership
auto const success =
stateMap_->updateGiveItem(
std::move(item), false, false);
(void)success;
assert(success);
auto const ours = std::move(sle);
}
std::size_t
Ledger::txCount() const
{
// Always zero for closed ledgers.
return 0;
}
bool
Ledger::txExists (uint256 const& key) const
{
return txMap().hasItem (key);
if (! stateMap_->updateGiveItem(
std::move(item), false, false))
LogicError("Ledger::rawReplace: key not found");
}
void
Ledger::txInsert (uint256 const& key,
Ledger::rawTxInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData)
@@ -1123,17 +1147,6 @@ Ledger::txInsert (uint256 const& key,
touch();
}
std::vector<uint256>
Ledger::txList() const
{
std::vector<uint256> list;
for (auto const& item : *txMap_)
{
list.push_back(item->key());
}
return list;
}
std::shared_ptr<SLE>
Ledger::peek (Keylet const& k) const
{
@@ -1298,9 +1311,9 @@ void Ledger::updateSkipList ()
sle->setFieldV256 (sfHashes, STVector256 (hashes));
sle->setFieldU32 (sfLastLedgerSequence, prevIndex);
if (created)
unchecked_insert(std::move(sle));
rawInsert(sle);
else
unchecked_replace(std::move(sle));
rawReplace(sle);
}
// update record of past 256 ledger
@@ -1326,9 +1339,9 @@ void Ledger::updateSkipList ()
sle->setFieldV256 (sfHashes, STVector256 (hashes));
sle->setFieldU32 (sfLastLedgerSequence, prevIndex);
if (created)
unchecked_insert(std::move(sle));
rawInsert(sle);
else
unchecked_replace(std::move(sle));
rawReplace(sle);
}
/** Save, or arrange to save, a fully-validated ledger
@@ -1407,7 +1420,7 @@ void Ledger::deprecatedUpdateCachedFees() const
std::uint32_t reserveBase = getConfig ().FEE_ACCOUNT_RESERVE;
std::int64_t reserveIncrement = getConfig ().FEE_OWNER_RESERVE;
// VFALCO NOTE this doesn't go through the SLECache
// VFALCO NOTE this doesn't go through the CachedSLEs
auto const sle = this->read(keylet::fees());
if (sle)
{
@@ -1476,34 +1489,9 @@ std::vector<uint256> Ledger::getNeededAccountStateHashes (
//
//------------------------------------------------------------------------------
std::shared_ptr<SLE const>
cachedRead (Ledger const& ledger, uint256 const& key,
SLECache& cache, boost::optional<LedgerEntryType> type)
{
uint256 hash;
auto const& item =
ledger.stateMap().peekItem(key, hash);
if (! item)
return {};
if (auto const sle = cache.fetch(hash))
{
if (type && sle->getType() != type)
return {};
return sle;
}
SerialIter sit(make_Slice(item->peekData()));
auto sle = std::make_shared<SLE>(sit, item->key());
// VFALCO Should we still cache it if the type doesn't match?
if (type && sle->getType() != type)
return {};
sle->setImmutable ();
cache.canonicalize(hash, sle);
return sle;
}
boost::optional<uint256>
hashOfSeq (Ledger& ledger, LedgerIndex seq,
SLECache& cache, beast::Journal journal)
beast::Journal journal)
{
// Easy cases...
if (seq > ledger.seq())
@@ -1524,7 +1512,7 @@ hashOfSeq (Ledger& ledger, LedgerIndex seq,
if (diff <= 256)
{
auto const hashIndex = cachedRead(
ledger, getLedgerHashIndex(), cache);
ledger, getLedgerHashIndex());
if (hashIndex)
{
assert (hashIndex->getFieldU32 (sfLastLedgerSequence) ==
@@ -1555,7 +1543,7 @@ hashOfSeq (Ledger& ledger, LedgerIndex seq,
// in skiplist
auto const hashIndex = cachedRead(ledger,
getLedgerHashIndex(seq), cache);
getLedgerHashIndex(seq));
if (hashIndex)
{
auto const lastSeq =

View File

@@ -21,7 +21,6 @@
#define RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED
#include <ripple/app/ledger/TxMeta.h>
#include <ripple/ledger/SLECache.h>
#include <ripple/ledger/View.h>
#include <ripple/app/tx/Transaction.h>
#include <ripple/basics/CountedObject.h>
@@ -49,10 +48,6 @@ class SqliteStatement;
particular ledger. Most of the operations on a ledger are concerned
with the state map.
A View provides a structured interface to manipulate the state map in
a reversible way, with facilities to automatically produce metadata
when applying changes.
This can hold just the header, a partial set of data, or the entire set
of data. It all depends on what is in the corresponding SHAMap entry.
Various functions are provided to populate or depopulate the caches that
@@ -67,10 +62,13 @@ class SqliteStatement;
for locks.
3) Mutable ledgers cannot be shared.
@note Presented to clients as ReadView
*/
class Ledger
: public std::enable_shared_from_this <Ledger>
, public BasicView
, public DigestAwareReadView
, public TxsRawView
, public CountedObject <Ledger>
{
public:
@@ -112,13 +110,11 @@ public:
~Ledger();
//--------------------------------------------------------------------------
//
// BasicView
// ReadView
//
//--------------------------------------------------------------------------
ViewInfo const&
LedgerInfo const&
info() const
{
return info_;
@@ -140,45 +136,57 @@ public:
std::shared_ptr<SLE const>
read (Keylet const& k) const override;
bool
txEmpty() const override;
std::unique_ptr<txs_type::iter_base>
txsBegin() const override;
std::unique_ptr<iterator_impl>
txBegin() const override;
std::unique_ptr<iterator_impl>
txEnd() const override;
bool
unchecked_erase (uint256 const& key) override;
void
unchecked_insert (std::shared_ptr<SLE>&& sle) override;
void
unchecked_replace (std::shared_ptr<SLE>&& sle) override;
void
destroyCoins (std::uint64_t feeDrops) override
{
mTotCoins -= feeDrops;
}
std::size_t
txCount() const override;
std::unique_ptr<txs_type::iter_base>
txsEnd() const override;
bool
txExists (uint256 const& key) const override;
tx_type
txRead (key_type const& key) const override;
//
// DigestAwareReadView
//
boost::optional<digest_type>
digest (key_type const& key) const override;
//
// RawView
//
void
txInsert (uint256 const& key,
rawErase (std::shared_ptr<
SLE> const& sle) override;
void
rawInsert (std::shared_ptr<
SLE> const& sle) override;
void
rawReplace (std::shared_ptr<
SLE> const& sle) override;
void
rawDestroyXRP (std::uint64_t feeDrops) override
{
mTotCoins -= feeDrops;
}
//
// TxsRawView
//
void
rawTxInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData) override;
std::vector<uint256>
txList() const override;
//--------------------------------------------------------------------------
/** Hint that the contents have changed.
@@ -428,7 +436,7 @@ public:
getHashesByIndex (std::uint32_t minSeq, std::uint32_t maxSeq);
private:
class tx_iterator_impl;
class txs_iter_impl;
void saveValidatedLedgerAsync(Job&, bool current)
{
@@ -475,7 +483,7 @@ private:
std::mutex mutable mutex_;
Fees fees_;
ViewInfo info_;
LedgerInfo info_;
// Ripple cost of the reference transaction
std::uint64_t mutable mBaseFee = 0;
@@ -521,19 +529,16 @@ deserializeTxPlusMeta (SHAMapItem const& item);
std::tuple<Ledger::pointer, std::uint32_t, uint256>
loadLedgerHelper(std::string const& sqlSuffix);
/** SLE cache-aware deserialized state SLE fetch.
Effects:
If the key exists, the item is flattened
and added to the SLE cache.
The returned object may not be modified.
@param type An optional LedgerEntryType. If type is
engaged and the SLE's type does not match,
an empty shared_ptr is returned.
@return `empty` if the key is not present
*/
// DEPRECATED
inline
std::shared_ptr<SLE const>
cachedRead (Ledger const& ledger, uint256 const& key, SLECache& cache,
boost::optional<LedgerEntryType> type = boost::none);
cachedRead (ReadView const& ledger, uint256 const& key,
boost::optional<LedgerEntryType> type = boost::none)
{
if (type)
return ledger.read(Keylet(*type, key));
return ledger.read(keylet::unchecked(key));
}
/** Return the hash of a ledger by sequence.
The hash is retrieved by looking up the "skip list"
@@ -546,7 +551,7 @@ cachedRead (Ledger const& ledger, uint256 const& key, SLECache& cache,
*/
boost::optional<uint256>
hashOfSeq (Ledger& ledger, LedgerIndex seq,
SLECache& cache, beast::Journal journal);
beast::Journal journal);
/** Find a ledger index from which we could easily get the requested ledger

View File

@@ -80,10 +80,10 @@ public:
*/
void applyTransactions (
SHAMap const* set,
BasicView& applyView,
OpenView& view,
Ledger::ref checkLedger,
CanonicalTXSet& retriableTransactions,
bool enableTesting = false);
ApplyFlags flags);
} // ripple

View File

@@ -275,8 +275,7 @@ log_metadata_difference(Ledger::pointer builtLedger, Ledger::pointer validLedger
// Return list of leaves sorted by key
static
std::vector<std::shared_ptr<
SHAMapItem const>>
std::vector<std::shared_ptr<SHAMapItem const>>
leaves (SHAMap const& sm)
{
std::vector<std::shared_ptr<

View File

@@ -1,340 +0,0 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_METAVIEW_H_INCLUDED
#define RIPPLE_LEDGER_METAVIEW_H_INCLUDED
#include <ripple/ledger/View.h>
#include <ripple/app/ledger/TxMeta.h>
#include <ripple/basics/CountedObject.h>
#include <ripple/basics/UnorderedContainers.h>
#include <ripple/protocol/Keylet.h>
#include <ripple/protocol/Serializer.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/protocol/STTx.h>
#include <beast/utility/noexcept.h>
#include <boost/optional.hpp>
#include <functional>
#include <list>
#include <tuple>
#include <utility>
namespace ripple {
/** Shallow-copy construction tag.
When a MetaView is shallow-copied, the SLEs and
Serializers are shared between instances. It is
only safe to use BasicView interfaces, using
View members results in undefined behavior.
*/
struct shallow_copy_t {};
extern shallow_copy_t const shallow_copy;
/** Open ledger construction tag.
Views constructed with this tag will have the
rules of open ledgers applied during transaction
processing.
*/
struct open_ledger_t {};
extern open_ledger_t const open_ledger;
/** A MetaView can produce tx metadata and is attached to a parent.
It's a view into a ledger used while a transaction is processing.
The transaction manipulates the MetaView rather than the ledger
(because it's cheaper, can be checkpointed, and so on). When the
transaction finishes, the MetaView is committed into the ledger to make
the modifications. The transaction metadata is built from the LES too.
*/
class MetaView : public View
{
private:
enum Action
{
taaCACHED, // Unmodified.
taaMODIFY, // Modifed, must have previously been taaCACHED.
taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY.
taaCREATE, // Newly created.
};
using Item = std::pair<Action,
std::shared_ptr<SLE>>;
using Mods = hash_map<uint256,
std::shared_ptr<SLE>>;
// The SLEs and Serializers in here are
// shared between copy-constructed instances
using item_list = std::map<uint256, Item>;
// List of tx, key order
using tx_map = std::map<uint256,
std::pair<std::shared_ptr<
Serializer const>, std::shared_ptr<
Serializer const>>>;
// Note that this class needs to be
// somewhat light-weight copy constructible.
BasicView const& base_;
ViewFlags flags_ = tapNONE;
ViewInfo info_;
tx_map txs_;
item_list items_;
std::uint32_t destroyedCoins_ = 0;
boost::optional<STAmount> deliverAmount_;
std::shared_ptr<void const> hold_;
public:
MetaView() = delete;
MetaView(MetaView const&) = delete;
MetaView& operator= (MetaView const&) = delete;
/** Create a shallow copy of a MetaView.
Effects:
Duplicates the information in the
passed MetaView.
The SLEs and Serializers in the copy
are shared with the other view.
The copy has the same Info values.
It is only safe to use the BasicView modification
functions. Using View modification functions will
break invariants.
*/
// VFALCO Refactor to disallow at compile time,
// breaking invariants on a shallow copy.
//
MetaView (shallow_copy_t,
MetaView const& other);
/** Create a MetaView representing an open ledger.
Preconditions:
`prev` cannot represent an open ledger.
Effects:
The sequence number is set to the
sequence number of parent plus one.
The parentCloseTime is set to the
closeTime of parent.
If `hold` is not nullptr, retains
ownership of a copy of `hold` until
the MetaView is destroyed.
It is only safe to use the BasicView modification
functions. Using View modification functions will
break invariants.
@param parent A view representing the previous
ledger that this open ledger follows.
*/
MetaView (open_ledger_t,
BasicView const& parent,
std::shared_ptr<
void const> hold = nullptr);
/** Create a nested MetaView.
Effects:
The ViewInfo is copied from the base.
*/
MetaView (BasicView const& base,
ViewFlags flags, std::shared_ptr<
void const> hold = nullptr);
//--------------------------------------------------------------------------
//
// BasicView
//
//--------------------------------------------------------------------------
ViewInfo const&
info() const
{
return info_;
}
Fees const&
fees() const override
{
return base_.fees();
}
bool
exists (Keylet const& k) const override;
boost::optional<uint256>
succ (uint256 const& key, boost::optional<
uint256> last = boost::none) const override;
std::shared_ptr<SLE const>
read (Keylet const& k) const override;
virtual
bool
txEmpty() const override;
std::unique_ptr<iterator_impl>
txBegin() const override;
std::unique_ptr<iterator_impl>
txEnd() const override;
bool
unchecked_erase(
uint256 const& key) override;
void
unchecked_insert (
std::shared_ptr<SLE>&& sle) override;
void
unchecked_replace(
std::shared_ptr<SLE>&& sle) override;
void
destroyCoins (std::uint64_t feeDrops) override;
std::size_t
txCount() const override;
bool
txExists (uint256 const& key) const override;
void
txInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData) override;
std::vector<uint256>
txList() const override;
//--------------------------------------------------------------------------
//
// view
//
//--------------------------------------------------------------------------
ViewFlags
flags() const override
{
return flags_;
}
std::shared_ptr<SLE>
peek (Keylet const& k) override;
void
erase (std::shared_ptr<SLE> const& sle) override;
void
insert (std::shared_ptr<SLE> const& sle) override;
void
update (std::shared_ptr<SLE> const& sle) override;
//--------------------------------------------------------------------------
/** Apply changes to the base View.
`to` must contain contents identical to the
parent view passed upon construction, else
undefined behavior will result.
After a call to apply(), the only valid operation
on the object is a call to the destructor.
*/
void
apply (BasicView& to,
beast::Journal j = {});
/** Apply the results of a transaction to the base view.
`to` must contain contents identical to the
parent view passed upon construction, else
undefined behavior will result.
After a call to apply(), the only valid operation
on the object is a call to the destructor.
Effects:
The transaction is inserted to the tx map.
If the base view represents a closed ledger,
the transaction metadata is computed and
inserted with the transaction.
The metadata is computed by recording the
differences between the base view and the
modifications in this view.
@param view The view to apply to.
@param tx The transaction that was processed.
@param ter The result of applying the transaction.
@param j Where to log.
*/
void
apply (BasicView& to, STTx const& tx,
TER result, beast::Journal j);
// For diagnostics
Json::Value getJson (int) const;
void setDeliveredAmount (STAmount const& amt)
{
deliverAmount_ = amt;
}
private:
class tx_iterator_impl;
static
bool
threadTx (TxMeta& meta,
std::shared_ptr<SLE> const& to,
Mods& mods);
std::shared_ptr<SLE>
getForMod (uint256 const& key,
Mods& mods, beast::Journal j);
bool
threadTx (TxMeta& meta,
AccountID const& to, Mods& mods,
beast::Journal j);
bool
threadOwners (TxMeta& meta, std::shared_ptr<
SLE const> const& sle, Mods& mods,
beast::Journal j);
};
} // ripple
#endif

View File

@@ -21,10 +21,10 @@
#define RIPPLE_APP_LEDGER_OPENLEDGER_H_INCLUDED
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/ledger/CachedSLEs.h>
#include <ripple/ledger/OpenView.h>
#include <ripple/app/misc/CanonicalTXSet.h>
#include <ripple/app/misc/IHashRouter.h>
#include <ripple/basics/chrono.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/UnorderedContainers.h>
#include <ripple/core/Config.h>
@@ -45,48 +45,6 @@ namespace ripple {
using OrderedTxs = CanonicalTXSet;
namespace detail {
class CachedSLEs
{
public:
using key_type = uint256;
using value_type =
std::shared_ptr<SLE const>;
CachedSLEs (CachedSLEs const&) = delete;
CachedSLEs& operator= (CachedSLEs const&) = delete;
template <class Rep, class Period>
CachedSLEs (std::chrono::duration<
Rep, Period> const& timeToLive,
Stopwatch& clock)
: clock_ (clock)
, timeToLive_ (timeToLive)
, map_ (clock)
{
}
value_type
find (key_type const& key);
// `false` if the insert failed
std::pair<value_type, bool>
insert (key_type const& key,
value_type const& value);
private:
Stopwatch const& clock_;
Stopwatch::duration timeToLive_;
beast::aged_unordered_map<key_type,
value_type, Stopwatch::clock_type,
hardened_hash<strong_hash>
> map_;
};
} // detail
//------------------------------------------------------------------------------
/** Represents the open ledger. */
@@ -94,12 +52,11 @@ class OpenLedger
{
private:
beast::Journal j_;
CachedSLEs& cache_;
Config const& config_;
Stopwatch& clock_;
detail::CachedSLEs cache_;
std::mutex mutable modify_mutex_;
std::mutex mutable current_mutex_;
std::shared_ptr<MetaView const> current_;
std::shared_ptr<OpenView const> current_;
public:
OpenLedger() = delete;
@@ -110,12 +67,10 @@ public:
@param ledger A closed ledger
*/
// Although ledger is not const, we do not modify it.
explicit
OpenLedger (std::shared_ptr<
Ledger> const& ledger,
Config const& config,
Stopwatch& clock,
Ledger const> const& ledger,
Config const& config, CachedSLEs& cache,
beast::Journal journal);
/** Returns a view to the current open ledger.
@@ -128,7 +83,7 @@ public:
non-modifiable snapshot of the open ledger
at the time of the call.
*/
std::shared_ptr<BasicView const>
std::shared_ptr<ReadView const>
current() const;
/** Modify the open ledger
@@ -137,17 +92,16 @@ public:
Can be called concurrently from any thread.
`f` will be called as
bool(BasicView&)
bool(ReadView&)
If `f` returns `true`, the changes made in the
View will be published to the open ledger.
OpenView will be published to the open ledger.
@return `true` if a the open ledger was changed
@return `true` if the open view was changed
*/
// VFALCO This should take a `BasicView`
bool
modify (std::function<
bool(View&, beast::Journal)> const& f);
bool(OpenView&, beast::Journal)> const& f);
/** Accept a new ledger.
@@ -175,11 +129,11 @@ public:
@param ledger A new closed ledger
*/
// Although ledger is not const, we do not modify it.
void
accept(std::shared_ptr<Ledger> const& ledger,
accept(std::shared_ptr<Ledger const> const& ledger,
OrderedTxs const& locals, bool retriesFirst,
OrderedTxs& retries, IHashRouter& router,
OrderedTxs& retries, ApplyFlags flags,
IHashRouter& router,
std::string const& suffix = "");
/** Algorithm for applying transactions.
@@ -190,10 +144,10 @@ public:
template <class FwdRange>
static
void
apply (View& view, BasicView const& check,
apply (OpenView& view, ReadView const& check,
FwdRange const& txs, OrderedTxs& retries,
IHashRouter& router, Config const& config,
beast::Journal j);
ApplyFlags flags, IHashRouter& router,
Config const& config, beast::Journal j);
private:
enum Result
@@ -203,16 +157,16 @@ private:
retry
};
std::shared_ptr<MetaView>
std::shared_ptr<OpenView>
create (std::shared_ptr<
Ledger> const& ledger);
Ledger const> const& ledger);
static
Result
apply_one (View& view, std::shared_ptr<
apply_one (OpenView& view, std::shared_ptr<
STTx const> const& tx, bool retry,
IHashRouter& router, Config const& config,
beast::Journal j);
ApplyFlags flags, IHashRouter& router,
Config const& config, beast::Journal j);
public:
//--------------------------------------------------------------------------
@@ -230,10 +184,11 @@ public:
template <class FwdRange>
void
OpenLedger::apply (View& view,
BasicView const& check, FwdRange const& txs,
OrderedTxs& retries, IHashRouter& router,
Config const& config, beast::Journal j)
OpenLedger::apply (OpenView& view,
ReadView const& check, FwdRange const& txs,
OrderedTxs& retries, ApplyFlags flags,
IHashRouter& router, Config const& config,
beast::Journal j)
{
for (auto iter = txs.begin();
iter != txs.end(); ++iter)
@@ -246,7 +201,7 @@ OpenLedger::apply (View& view,
if (check.txExists(tx->getTransactionID()))
continue;
auto const result = apply_one(view,
tx, true, router, config, j);
tx, true, flags, router, config, j);
if (result == Result::retry)
retries.insert(tx);
}
@@ -266,7 +221,7 @@ OpenLedger::apply (View& view,
while (iter != retries.end())
{
switch (apply_one(view,
iter->second, retry,
iter->second, retry, flags,
router, config, j))
{
case Result::success:
@@ -305,7 +260,7 @@ std::string
debugTostr (SHAMap const& set);
std::string
debugTostr (std::shared_ptr<BasicView const> const& view);
debugTostr (std::shared_ptr<ReadView const> const& view);
} // ripple

View File

@@ -254,8 +254,7 @@ public:
boost::optional<LedgerHash> hash;
try
{
hash = hashOfSeq(*ledger, index,
getApp().getSLECache(), m_journal);
hash = hashOfSeq(*ledger, index, m_journal);
}
catch (SHAMapMissingNode &)
{

View File

@@ -22,7 +22,6 @@
#include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/ledger/LedgerTiming.h>
#include <ripple/app/ledger/LedgerToJson.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/app/ledger/OpenLedger.h>
#include <ripple/app/ledger/impl/DisputedTx.h>
#include <ripple/app/ledger/impl/LedgerConsensusImp.h>
@@ -990,12 +989,11 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
<< " last closed ledger";
{
MetaView accum(*newLCL, tapNONE);
OpenView accum(&*newLCL);
assert(accum.closed());
applyTransactions (set.get(), accum,
newLCL, retriableTransactions);
accum.apply(*newLCL,
deprecatedLogs().journal("LedgerConsensus"));
newLCL, retriableTransactions, tapNONE);
accum.apply(*newLCL);
}
// retriableTransactions will include any transactions that
@@ -1078,7 +1076,7 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
// Build new open ledger
auto newOL = std::make_shared<Ledger> (true, *newLCL);
MetaView accum(*newOL, tapNONE);
OpenView accum(&*newOL);
assert(accum.open());
// Apply disputed transactions that didn't get in
@@ -1126,8 +1124,8 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
if (anyDisputes)
{
applyTransactions (nullptr,
accum, newLCL, retriableTransactions);
applyTransactions (nullptr, accum,
newLCL, retriableTransactions, tapNONE);
}
{
@@ -1145,20 +1143,19 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
{
WriteLog (lsDEBUG, LedgerConsensus)
<< "Applying transactions from current open ledger";
applyTransactions (&oldOL->txMap(),
accum, newLCL, retriableTransactions);
applyTransactions (&oldOL->txMap(), accum,
newLCL, retriableTransactions, tapNONE);
}
for (auto const& item : localTx)
apply (accum, *item.second, tapNONE, getConfig(),
deprecatedLogs().journal("LedgerConsensus"));
accum.apply(*newOL,
deprecatedLogs().journal("LedgerConsensus"));
accum.apply(*newOL);
// We have a new Last Closed Ledger and new Open Ledger
ledgerMaster_.pushLedger (newLCL, newOL);
#if RIPPLE_OPEN_LEDGER
getApp().openLedger().accept(newLCL,
localTx, anyDisputes, retries,
localTx, anyDisputes, retries, tapNONE,
getApp().getHashRouter(), "consensus");
getApp().openLedger().verify(*newOL, "consensus after");
#endif
@@ -1757,28 +1754,18 @@ make_LedgerConsensus (ConsensusImp& consensus, int previousProposers,
*/
static
int
applyTransaction (BasicView& view,
applyTransaction (OpenView& view,
std::shared_ptr<STTx const> const& txn,
bool retryAssured,
bool enableTesting)
bool retryAssured, ApplyFlags flags)
{
// Returns false if the transaction has need not be retried.
ViewFlags parms = tapNONE;
if (enableTesting)
parms = parms | tapENABLE_TESTING;
if (retryAssured)
{
parms = static_cast<ViewFlags> (parms | tapRETRY);
}
flags = flags | tapRETRY;
if ((getApp().getHashRouter ().getFlags (txn->getTransactionID ())
& SF_SIGGOOD) == SF_SIGGOOD)
{
parms = static_cast<ViewFlags>
(parms | tapNO_CHECK_SIGN);
}
flags = flags | tapNO_CHECK_SIGN;
WriteLog (lsDEBUG, LedgerConsensus) << "TXN "
<< txn->getTransactionID ()
//<< (engine.view().open() ? " open" : " closed") // because of the optional in engine
@@ -1787,7 +1774,7 @@ applyTransaction (BasicView& view,
try
{
auto const result = apply(view, *txn, parms, getConfig(),
auto const result = apply(view, *txn, flags, getConfig(),
deprecatedLogs().journal("LedgerConsensus"));
if (result.second)
{
@@ -1818,10 +1805,10 @@ applyTransaction (BasicView& view,
void applyTransactions (
SHAMap const* set,
BasicView& applyView,
OpenView& view,
Ledger::ref checkLedger,
CanonicalTXSet& retriableTransactions,
bool enableTesting)
ApplyFlags flags)
{
if (set)
{
@@ -1847,7 +1834,7 @@ void applyTransactions (
if (txn)
{
if (applyTransaction(applyView, txn, true, enableTesting) ==
if (applyTransaction(view, txn, true, flags) ==
LedgerConsensusImp::resultRetry)
{
// On failure, stash the failed transaction for
@@ -1873,8 +1860,8 @@ void applyTransactions (
{
try
{
switch (applyTransaction (applyView,
it->second, certainRetry, enableTesting))
switch (applyTransaction (view,
it->second, certainRetry, flags))
{
case LedgerConsensusImp::resultSuccess:
it = retriableTransactions.erase (it);

View File

@@ -356,19 +356,13 @@ public:
int recovers = 0;
#if RIPPLE_OPEN_LEDGER
bool const openLedger = true;
#else
bool const openLedger = false;
#endif
if (openLedger)
{
getApp().openLedger().modify(
[&](View& view, beast::Journal j)
[&](OpenView& view, beast::Journal j)
{
bool any = false;
for (auto const& it : mHeldTransactions)
{
ViewFlags flags = tapNONE;
ApplyFlags flags = tapNONE;
if (getApp().getHashRouter().addSuppressionFlags (it.first.getTXID (), SF_SIGGOOD))
flags = flags | tapNO_CHECK_SIGN;
auto const result = apply(view,
@@ -378,19 +372,19 @@ public:
}
return any;
});
}
#endif
{
OpenView view(&*ledger);
for (auto const& it : mHeldTransactions)
{
try
{
ViewFlags tepFlags = tapNONE;
ApplyFlags tepFlags = tapNONE;
if (getApp().getHashRouter ().addSuppressionFlags (it.first.getTXID (), SF_SIGGOOD))
tepFlags = static_cast<ViewFlags> (tepFlags | tapNO_CHECK_SIGN);
tepFlags = static_cast<ApplyFlags> (tepFlags | tapNO_CHECK_SIGN);
auto const ret = apply(
*ledger, *it.second, tepFlags, getConfig(),
view, *it.second, tepFlags, getConfig(),
deprecatedLogs().journal("LedgerMaster"));
if (ret.second)
@@ -399,12 +393,8 @@ public:
// If a transaction is recovered but hasn't been relayed,
// it will become disputed in the consensus process, which
// will cause it to be relayed.
}
catch (...)
{
WriteLog (lsWARNING, LedgerMaster) << "Held transaction throws";
}
view.apply(*ledger);
}
CondLog (recovers != 0, lsINFO, LedgerMaster) << "Recovered " << recovers << " held transactions";
@@ -642,8 +632,7 @@ public:
{
try
{
hash = hashOfSeq(*ledger, lSeq,
getApp().getSLECache(), m_journal);
hash = hashOfSeq(*ledger, lSeq, m_journal);
}
catch (...)
{
@@ -973,8 +962,7 @@ public:
if (mHistLedger && (mHistLedger->getLedgerSeq() >= index))
{
ret = hashOfSeq(*mHistLedger, index,
getApp().getSLECache(), m_journal);
ret = hashOfSeq(*mHistLedger, index, m_journal);
if (! ret)
ret = walkHashBySeq (index, mHistLedger);
}
@@ -1164,8 +1152,7 @@ public:
Ledger::pointer ledger;
// This can throw
auto hash = hashOfSeq(*valLedger, seq,
getApp().getSLECache(), m_journal);
auto hash = hashOfSeq(*valLedger, seq, m_journal);
// VFALCO TODO Restructure this code so that zero is not used
if (! hash)
hash = zero; // kludge
@@ -1229,8 +1216,7 @@ public:
{
assert(desiredSeq < knownGoodLedger->getLedgerSeq());
auto hash = hashOfSeq(*knownGoodLedger, desiredSeq,
getApp().getSLECache(), m_journal);
auto hash = hashOfSeq(*knownGoodLedger, desiredSeq, m_journal);
// Not directly in the given ledger
if (! hash)
@@ -1238,15 +1224,13 @@ public:
std::uint32_t seq = (desiredSeq + 255) % 256;
assert(seq < desiredSeq);
hash = hashOfSeq(*knownGoodLedger,
seq, getApp().getSLECache(), m_journal);
hash = hashOfSeq(*knownGoodLedger, seq, m_journal);
if (hash)
{
auto l = getLedgerByHash(*hash);
if (l)
{
hash = hashOfSeq(*l, desiredSeq,
getApp().getSLECache(), m_journal);
hash = hashOfSeq(*l, desiredSeq, m_journal);
assert (hash);
}
}
@@ -1450,16 +1434,14 @@ public:
}
// See if the hash for the ledger we need is in the reference ledger
auto ledgerHash = hashOfSeq(*referenceLedger, index,
getApp().getSLECache(), m_journal);
auto ledgerHash = hashOfSeq(*referenceLedger, index, m_journal);
if (ledgerHash)
return *ledgerHash;
// The hash is not in the reference ledger. Get another ledger which can
// be located easily and should contain the hash.
LedgerIndex refIndex = getCandidateLedger(index);
auto const refHash = hashOfSeq(*referenceLedger, refIndex,
getApp().getSLECache(), m_journal);
auto const refHash = hashOfSeq(*referenceLedger, refIndex, m_journal);
assert(refHash);
if (refHash)
{
@@ -1470,8 +1452,7 @@ public:
{
try
{
ledgerHash = hashOfSeq(*ledger, index,
getApp().getSLECache(), m_journal);
ledgerHash = hashOfSeq(*ledger, index, m_journal);
}
catch(SHAMapMissingNode&)
{
@@ -1486,8 +1467,7 @@ public:
*refHash, refIndex, InboundLedger::fcGENERIC);
if (ledger)
{
ledgerHash = hashOfSeq(*ledger, index,
getApp().getSLECache(), m_journal);
ledgerHash = hashOfSeq(*ledger, index, m_journal);
assert (ledgerHash);
}
}
@@ -1508,8 +1488,7 @@ public:
try
{
auto const hash = hashOfSeq(*valid, index,
getApp().getSLECache(), m_journal);
auto const hash = hashOfSeq(*valid, index, m_journal);
if (hash)
return mLedgerHistory.getLedgerByHash (*hash);
}

View File

@@ -1,918 +0,0 @@
//------------------------------------------------------------------------------
/*
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/app/ledger/MetaView.h>
#include <ripple/basics/contract.h>
#include <ripple/protocol/Quality.h>
#include <ripple/app/main/Application.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/JsonFields.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/types.h>
namespace ripple {
// #define META_DEBUG
// VFALCO TODO Replace this macro with a documented language constant
//
/** Maximum number of entries in a directory page
A change would be protocol-breaking.
*/
#ifndef DIR_NODE_MAX
#define DIR_NODE_MAX 32
#endif
shallow_copy_t const shallow_copy {};
open_ledger_t const open_ledger {};
MetaView::MetaView (shallow_copy_t,
MetaView const& other)
: base_ (other.base_)
, flags_ (other.flags_)
, info_ (other.info_)
, txs_ (other.txs_)
, items_ (other.items_)
, destroyedCoins_(
other.destroyedCoins_)
, hold_(other.hold_)
{
}
MetaView::MetaView (open_ledger_t,
BasicView const& parent,
std::shared_ptr<
void const> hold)
: base_ (parent)
, flags_ (tapNONE)
, info_ (parent.info())
, hold_(std::move(hold))
{
assert(! parent.open());
info_.open = true;
info_.seq = parent.info().seq + 1;
info_.parentCloseTime =
parent.info().closeTime;
// Give clients a unique but
// meaningless hash for open ledgers.
info_.hash = parent.info().hash + uint256(1);
}
MetaView::MetaView (BasicView const& base,
ViewFlags flags, std::shared_ptr<
void const> hold)
: base_ (base)
, flags_ (flags)
, info_ (base.info())
, hold_(std::move(hold))
{
}
//------------------------------------------------------------------------------
bool
MetaView::exists (Keylet const& k) const
{
assert(k.key.isNonZero());
auto const iter = items_.find(k.key);
if (iter == items_.end())
return base_.exists(k);
if (iter->second.first == taaDELETE)
return false;
if (! k.check(*iter->second.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.
*/
boost::optional<uint256>
MetaView::succ (uint256 const& key,
boost::optional<uint256> last) const
{
boost::optional<uint256> next = key;
item_list::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 == taaDELETE);
// Find non-deleted successor in our list
for (iter = items_.upper_bound(key);
iter != items_.end (); ++iter)
{
if (iter->second.first != taaDELETE)
{
// 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>
MetaView::read (Keylet const& k) const
{
assert(k.key.isNonZero());
if (k.key.isZero())
return nullptr;
// VFALCO TODO Shouldn't we create taaCACHED
// items to optimize reads?
auto const iter = items_.find(k.key);
if (iter == items_.end())
{
auto const sle =
base_.read(k);
if (! sle)
return nullptr;
return sle;
}
if (iter->second.first == taaDELETE)
return nullptr;
auto const& sle =
iter->second.second;
if (! k.check(*sle))
return nullptr;
return sle;
}
//------------------------------------------------------------------------------
class MetaView::tx_iterator_impl
: public BasicView::iterator_impl
{
private:
bool metadata_;
tx_map::const_iterator iter_;
public:
explicit
tx_iterator_impl (bool metadata,
tx_map::const_iterator iter)
: metadata_(metadata)
, iter_(iter)
{
}
std::unique_ptr<iterator_impl>
copy() const override
{
return std::make_unique<
tx_iterator_impl>(
metadata_, iter_);
}
bool
equal (iterator_impl const& impl) const override
{
auto const& other = dynamic_cast<
tx_iterator_impl const&>(impl);
return iter_ == other.iter_;
}
void
increment() override
{
++iter_;
}
txs_type::value_type
dereference() const override
{
txs_type::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;
}
};
bool
MetaView::txEmpty() const
{
return txs_.empty();
}
auto
MetaView::txBegin() const ->
std::unique_ptr<iterator_impl>
{
return std::make_unique<
tx_iterator_impl>(
closed(), txs_.cbegin());
}
auto
MetaView::txEnd() const ->
std::unique_ptr<iterator_impl>
{
return std::make_unique<
tx_iterator_impl>(
closed(), txs_.cend());
}
//------------------------------------------------------------------------------
bool
MetaView::unchecked_erase (uint256 const& key)
{
auto const iter =
items_.lower_bound(key);
if (iter == items_.end() ||
iter->first != key)
{
assert(base_.exists(
keylet::unchecked(key)));
using namespace std;
items_.emplace_hint(iter, piecewise_construct,
forward_as_tuple(key), forward_as_tuple(
taaDELETE, make_shared<SLE>(
*base_.read(keylet::unchecked(key)))));
return true;
}
if (iter->second.first == taaCREATE)
{
items_.erase(iter);
return true;
}
assert(iter->second.first != taaDELETE);
iter->second.first = taaDELETE;
return true;
}
void
MetaView::unchecked_insert(
std::shared_ptr<SLE>&& sle)
{
auto const iter =
items_.lower_bound(sle->key());
if (iter == items_.end() ||
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(! base_.exists(Keylet{
sle->getType(), sle->key()}));
using namespace std;
items_.emplace_hint(iter, piecewise_construct,
forward_as_tuple(sle->key()),
forward_as_tuple(taaCREATE,
move(sle)));
return;
}
switch(iter->second.first)
{
case taaMODIFY:
throw std::runtime_error(
"insert after modify");
case taaCREATE:
throw std::runtime_error(
"insert after create");
case taaCACHED:
throw std::runtime_error(
"insert after peek");
case taaDELETE:
default:
break;
};
// VFALCO return Keylet from SLE
assert(base_.exists(
Keylet{sle->getType(), sle->key()}));
iter->second.first = taaMODIFY;
iter->second.second = std::move(sle);
}
void
MetaView::unchecked_replace (std::shared_ptr<SLE>&& sle)
{
auto const iter =
items_.lower_bound(sle->key());
if (iter == items_.end() ||
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(base_.exists(Keylet{
sle->getType(), sle->key()}));
using namespace std;
items_.emplace_hint(iter, piecewise_construct,
forward_as_tuple(sle->key()),
forward_as_tuple(taaMODIFY,
move(sle)));
return;
}
if (iter->second.first == taaDELETE)
throw std::runtime_error(
"replace after delete");
if (iter->second.first != taaCREATE)
iter->second.first = taaMODIFY;
iter->second.second = std::move(sle);
}
void
MetaView::destroyCoins (std::uint64_t feeDrops)
{
destroyedCoins_ += feeDrops;
}
std::size_t
MetaView::txCount() const
{
return base_.txCount() + txs_.size();
}
bool
MetaView::txExists (uint256 const& key) const
{
if (txs_.count(key) > 0)
return true;
return base_.txExists(key);
}
void
MetaView::txInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData)
{
if (base_.txExists(key) ||
! txs_.emplace(key,
std::make_pair(txn, metaData)).second)
LogicError("duplicate_tx: " + to_string(key));
}
std::vector<uint256>
MetaView::txList() const
{
std::vector<uint256> list;
list.reserve(txs_.size());
for (auto const& e : txs_)
list.push_back(e.first);
return list;
}
std::shared_ptr<SLE>
MetaView::peek (Keylet const& k)
{
assert(k.key.isNonZero());
if (k.key.isZero())
return nullptr;
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
iter = items_.emplace_hint (iter,
std::piecewise_construct,
std::forward_as_tuple(sle->getIndex()),
std::forward_as_tuple(taaCACHED,
std::make_shared<SLE>(*sle)));
return iter->second.second;
}
if (iter->second.first == taaDELETE)
return nullptr;
if (! k.check(*iter->second.second))
return nullptr;
return iter->second.second;
}
void
MetaView::erase (std::shared_ptr<SLE> const& sle)
{
auto const iter =
items_.find(sle->getIndex());
assert(iter != items_.end());
if (iter == items_.end())
return;
assert(iter->second.first != taaDELETE);
assert(iter->second.second == sle);
if (iter->second.first == taaDELETE)
return;
if (iter->second.first == taaCREATE)
{
items_.erase(iter);
return;
}
assert(iter->second.first == taaCACHED ||
iter->second.first == taaMODIFY);
iter->second.first = taaDELETE;
}
void
MetaView::insert (std::shared_ptr<SLE> const& sle)
{
auto const iter = items_.lower_bound(sle->key());
if (iter == items_.end() ||
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(! base_.exists(
Keylet{sle->getType(), sle->key()}));
items_.emplace_hint(iter, std::piecewise_construct,
std::forward_as_tuple(sle->getIndex()),
std::forward_as_tuple(taaCREATE, sle));
return;
}
switch(iter->second.first)
{
case taaMODIFY:
throw std::runtime_error(
"insert after modify");
case taaCREATE:
// This could be made to work (?)
throw std::runtime_error(
"insert after create");
case taaCACHED:
throw std::runtime_error(
"insert after copy");
default:
break;
}
// Existed in parent, deleted here
assert(base_.exists(
Keylet{sle->getType(), sle->key()}));
iter->second.first = taaMODIFY;
iter->second.second = sle;
}
void
MetaView::update (std::shared_ptr<SLE> const& sle)
{
auto const iter = items_.lower_bound(sle->key());
if (iter == items_.end() ||
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(base_.exists(
Keylet{sle->getType(), sle->key()}));
items_.emplace_hint(iter, std::piecewise_construct,
std::forward_as_tuple(sle->key()),
std::forward_as_tuple(taaMODIFY, sle));
return;
}
// VFALCO Should we throw?
assert(iter->second.second == sle);
if (iter->second.first == taaDELETE)
throw std::runtime_error(
"update after delete");
if (iter->second.first != taaCREATE)
iter->second.first = taaMODIFY;
}
//------------------------------------------------------------------------------
void MetaView::apply(
BasicView& to, beast::Journal j)
{
assert(&to == &base_);
assert(to.info().open == info_.open);
// Write back the account states
for (auto& item : items_)
{
// VFALCO TODO rvalue move the second, make
// sure the mNodes is not used after
// this function is called.
auto& sle = item.second.second;
switch (item.second.first)
{
case taaCACHED:
assert(to.exists(
Keylet(sle->getType(), item.first)));
break;
case taaCREATE:
// VFALCO Is this logging necessary anymore?
WriteLog (lsDEBUG, View) <<
"applyTransaction: taaCREATE: " << sle->getText ();
to.unchecked_insert(std::move(sle));
break;
case taaMODIFY:
{
WriteLog (lsDEBUG, View) <<
"applyTransaction: taaMODIFY: " << sle->getText ();
to.unchecked_replace(std::move(sle));
break;
}
case taaDELETE:
WriteLog (lsDEBUG, View) <<
"applyTransaction: taaDELETE: " << sle->getText ();
to.unchecked_erase(sle->key());
break;
}
}
// Write the transactions
for (auto& tx : txs_)
to.txInsert(tx.first,
tx.second.first,
tx.second.second);
to.destroyCoins(destroyedCoins_);
}
Json::Value MetaView::getJson (int) const
{
Json::Value ret (Json::objectValue);
Json::Value nodes (Json::arrayValue);
for (auto it = items_.begin (), end = items_.end (); it != end; ++it)
{
Json::Value entry (Json::objectValue);
entry[jss::node] = to_string (it->first);
switch (it->second.second->getType ())
{
case ltINVALID:
entry[jss::type] = "invalid";
break;
case ltACCOUNT_ROOT:
entry[jss::type] = "acccount_root";
break;
case ltDIR_NODE:
entry[jss::type] = "dir_node";
break;
case ltRIPPLE_STATE:
entry[jss::type] = "ripple_state";
break;
case ltNICKNAME:
entry[jss::type] = "nickname";
break;
case ltOFFER:
entry[jss::type] = "offer";
break;
default:
assert (false);
}
switch (it->second.first)
{
case taaCACHED:
entry[jss::action] = "cache";
break;
case taaMODIFY:
entry[jss::action] = "modify";
break;
case taaDELETE:
entry[jss::action] = "delete";
break;
case taaCREATE:
entry[jss::action] = "create";
break;
default:
assert (false);
}
nodes.append (entry);
}
ret[jss::nodes] = nodes;
// VFALCO The meta only exists during apply() now
//ret[jss::metaData] = meta.getJson (0);
return ret;
}
//------------------------------------------------------------------------------
void
MetaView::apply (BasicView& to,
STTx const& tx, TER ter, beast::Journal j)
{
auto const sTx =
std::make_shared<Serializer>();
tx.add(*sTx);
std::shared_ptr<Serializer> sMeta;
if (closed())
{
TxMeta meta;
// VFALCO Shouldn't TxMeta ctor do this?
meta.init (tx.getTransactionID(), seq());
if (deliverAmount_)
meta.setDeliveredAmount(
*deliverAmount_);
Mods newMod;
for (auto& it : items_)
{
auto type = &sfGeneric;
switch (it.second.first)
{
case taaMODIFY:
#ifdef META_DEBUG
JLOG(j.trace) << "modify " << it.first;
#endif
type = &sfModifiedNode;
break;
case taaDELETE:
#ifdef META_DEBUG
JLOG(j.trace) << "delete " << it.first;
#endif
type = &sfDeletedNode;
break;
case taaCREATE:
#ifdef META_DEBUG
JLOG(j.trace) << "insert " << it.first;
#endif
type = &sfCreatedNode;
break;
default: // ignore these
break;
}
if (type == &sfGeneric)
continue;
auto const origNode =
base_.read(keylet::unchecked(it.first));
auto curNode = it.second.second;
if ((type == &sfModifiedNode) && (*curNode == *origNode))
continue;
std::uint16_t nodeType = curNode
? curNode->getFieldU16 (sfLedgerEntryType)
: origNode->getFieldU16 (sfLedgerEntryType);
meta.setAffectedNode (it.first, *type, nodeType);
if (type == &sfDeletedNode)
{
assert (origNode && curNode);
threadOwners (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(it.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 (it.first).emplace_back (std::move(finals));
}
else if (type == &sfModifiedNode)
{
assert (curNode && origNode);
if (curNode->isThreadedType ()) // thread transaction to node it 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 (it.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 (it.first).emplace_back (std::move(finals));
}
else if (type == &sfCreatedNode) // if created, thread to owner(s)
{
assert (curNode && !origNode);
threadOwners (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 (it.first).emplace_back (std::move(news));
}
else
{
assert (false);
}
}
// add any new modified nodes to the modification set
for (auto& it : newMod)
update (it.second);
sMeta = std::make_shared<Serializer>();
meta.addRaw (*sMeta, ter, txCount());
// VFALCO For diagnostics do we want to show
// metadata even when the base view is open?
JLOG(j.trace) <<
"metadata " << meta.getJson (0);
}
txInsert (tx.getTransactionID(),
sTx, sMeta);
apply(to);
}
//------------------------------------------------------------------------------
bool
MetaView::threadTx (TxMeta& meta,
std::shared_ptr<SLE> const& to,
Mods& mods)
{
uint256 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>
MetaView::getForMod (uint256 const& key,
Mods& mods, beast::Journal j)
{
auto iter = items_.find (key);
if (iter != items_.end ())
{
if (iter->second.first == taaDELETE)
{
JLOG(j.fatal) <<
"Trying to thread to deleted node";
return nullptr;
}
if (iter->second.first == taaCACHED)
iter->second.first = taaMODIFY;
return iter->second.second;
}
{
auto miter = mods.find (key);
if (miter != mods.end ())
{
assert (miter->second);
return miter->second;
}
}
// VFALCO NOTE Should this be read() or peek()?
auto const csle = base_.read(
keylet::unchecked(key));
if (! csle)
return nullptr;
// Need to make a copy here
auto sle =
std::make_shared<SLE>(*csle);
mods.emplace(key, sle);
return sle;
}
bool
MetaView::threadTx (TxMeta& meta,
AccountID const& to, Mods& mods,
beast::Journal j)
{
auto const sle = getForMod(
keylet::account(to).key, mods, j);
#ifdef META_DEBUG
JLOG(j.trace) <<
"Thread to " << toBase58(to);
#endif
assert(sle);
if (! sle)
{
JLOG(j.fatal) <<
"Threading to non-existent account: " <<
toBase58(to);
return false;
}
return threadTx (meta, sle, mods);
}
bool
MetaView::threadOwners (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
#ifdef META_DEBUG
JLOG(j.trace) << "Thread to single owner";
#endif
return threadTx (meta, sle->getAccountID(
sfAccount), mods, j);
}
else if (sle->getType() == ltRIPPLE_STATE)
{
// thread to owner's accounts
#ifdef META_DEBUG
JLOG(j.trace) << "Thread to two owners";
#endif
return
threadTx (meta, sle->getFieldAmount(
sfLowLimit).getIssuer(), mods, j) &&
threadTx (meta, sle->getFieldAmount(
sfHighLimit).getIssuer(), mods, j);
}
return false;
}
} // ripple

View File

@@ -20,120 +20,23 @@
#include <BeastConfig.h>
#include <ripple/app/ledger/OpenLedger.h>
#include <ripple/app/tx/apply.h>
#include <ripple/ledger/CachingReadView.h>
#include <boost/range/adaptor/transformed.hpp>
namespace ripple {
namespace detail {
auto
CachedSLEs::find(
key_type const& key) ->
value_type
{
auto const iter =
map_.find(key);
if (iter == map_.end())
return nullptr;
map_.touch(iter);
return iter->second;
}
auto
CachedSLEs::insert(
key_type const& key,
value_type const& value) ->
std::pair<value_type, bool>
{
beast::expire(map_, timeToLive_);
auto const result =
map_.emplace(key, value);
if (result.second)
return { value, true };
return { result.first->second, false };
}
} // detail
//------------------------------------------------------------------------------
class CachedSLEView
: public BasicViewWrapper<Ledger&>
{
private:
detail::CachedSLEs& cache_;
std::mutex mutable mutex_;
std::shared_ptr<Ledger> ledger_;
public:
// Retains ownership of ledger
// for lifetime management.
CachedSLEView(
std::shared_ptr<Ledger> const& ledger,
detail::CachedSLEs& cache)
: BasicViewWrapper(*ledger)
, cache_ (cache)
, ledger_ (ledger)
{
}
std::shared_ptr<SLE const>
read (Keylet const& k) const override;
};
std::shared_ptr<SLE const>
CachedSLEView::read (Keylet const& k) const
{
key_type key;
auto const item =
view_.stateMap().peekItem(k.key, key);
if (! item)
return nullptr;
{
std::lock_guard<
std::mutex> lock(mutex_);
if (auto sle = cache_.find(key))
{
if(! k.check(*sle))
return nullptr;
return sle;
}
}
SerialIter sit(item->slice());
// VFALCO This should be <SLE const>
auto sle = std::make_shared<
SLE>(sit, item->key());
if (! k.check(*sle))
return nullptr;
// VFALCO TODO Eliminate "immutable" runtime property
sle->setImmutable ();
std::lock_guard<
std::mutex> lock(mutex_);
auto const result =
cache_.insert(key, sle);
if (! result.second)
return result.first;
// Need std::move to avoid a copy
// because return type is different
return std::move(sle);
}
//------------------------------------------------------------------------------
OpenLedger::OpenLedger(std::shared_ptr<
Ledger> const& ledger,
Config const& config,
Stopwatch& clock,
OpenLedger::OpenLedger(
std::shared_ptr<Ledger const> const& ledger,
Config const& config, CachedSLEs& cache,
beast::Journal journal)
: j_ (journal)
, cache_ (cache)
, config_ (config)
, clock_ (clock)
, cache_ (std::chrono::minutes(1), clock)
, current_ (create(ledger))
{
}
std::shared_ptr<BasicView const>
std::shared_ptr<ReadView const>
OpenLedger::current() const
{
std::lock_guard<
@@ -144,12 +47,12 @@ OpenLedger::current() const
bool
OpenLedger::modify (std::function<
bool(View&, beast::Journal)> const& f)
bool(OpenView&, beast::Journal)> const& f)
{
std::lock_guard<
std::mutex> lock1(modify_mutex_);
auto next = std::make_shared<
MetaView>(shallow_copy, *current_);
OpenView>(*current_);
auto const changed = f(*next, j_);
if (changed)
{
@@ -162,10 +65,11 @@ OpenLedger::modify (std::function<
}
void
OpenLedger::accept (std::shared_ptr<Ledger> const& ledger,
OpenLedger::accept (std::shared_ptr<
Ledger const> const& ledger,
OrderedTxs const& locals, bool retriesFirst,
OrderedTxs& retries, IHashRouter& router,
std::string const& suffix)
OrderedTxs& retries, ApplyFlags flags,
IHashRouter& router, std::string const& suffix)
{
JLOG(j_.error) <<
"accept ledger " << ledger->seq() << " " << suffix;
@@ -177,7 +81,7 @@ OpenLedger::accept (std::shared_ptr<Ledger> const& ledger,
std::vector<std::shared_ptr<
STTx const>>;
apply (*next, *ledger, empty{},
retries, router, config_, j_);
retries, flags, router, config_, j_);
}
// Block calls to modify, otherwise
// new tx going into the open ledger
@@ -195,11 +99,11 @@ OpenLedger::accept (std::shared_ptr<Ledger> const& ledger,
{
return p.first;
}),
retries, router, config_, j_);
retries, flags, router, config_, j_);
// Apply local tx
for (auto const& item : locals)
ripple::apply(*next, *item.second,
tapNONE, config_, j_);
flags, config_, j_);
// Switch to the new open view
std::lock_guard<
std::mutex> lock2(current_mutex_);
@@ -208,25 +112,23 @@ OpenLedger::accept (std::shared_ptr<Ledger> const& ledger,
//------------------------------------------------------------------------------
std::shared_ptr<MetaView>
std::shared_ptr<OpenView>
OpenLedger::create (std::shared_ptr<
Ledger> const& ledger)
Ledger const> const& ledger)
{
auto cache = std::make_shared<
CachedSLEView>(ledger, cache_);
return std::make_shared<
MetaView>(open_ledger,
*cache, cache);
return std::make_shared<OpenView>(
open_ledger, std::make_shared<
CachingReadView const>(ledger,
cache_));
}
auto
OpenLedger::apply_one (View& view,
OpenLedger::apply_one (OpenView& view,
std::shared_ptr<STTx const> const& tx,
bool retry, IHashRouter& router,
Config const& config, beast::Journal j) ->
Result
bool retry, ApplyFlags flags,
IHashRouter& router, Config const& config,
beast::Journal j) -> Result
{
auto flags = view.flags();
if (retry)
flags = flags | tapRETRY;
if ((router.getFlags(
@@ -246,16 +148,26 @@ OpenLedger::apply_one (View& view,
//------------------------------------------------------------------------------
static
std::vector<uint256>
txList (ReadView const& view)
{
std::vector<uint256> v;
for (auto const& item : view.txs)
v.push_back(item.first->getTransactionID());
std::sort(v.begin(), v.end());
return v;
}
bool
OpenLedger::verify (Ledger const& ledger,
std::string const& suffix) const
{
#if 1
std::lock_guard<
std::mutex> lock(modify_mutex_);
auto list1 = ledger.txList();
auto list2 = current_->txList();
std::sort(list1.begin(), list1.end());
std::sort(list2.begin(), list2.end());
auto list1 = txList(ledger);
auto list2 = txList(*current_);
if (list1 == list2)
return true;
JLOG(j_.error) <<
@@ -263,6 +175,9 @@ OpenLedger::verify (Ledger const& ledger,
list1.size() << " / " << list2.size() <<
" " << " MISMATCH " << suffix;
return false;
#else
return true;
#endif
}
//------------------------------------------------------------------------------
@@ -306,7 +221,7 @@ debugTostr (SHAMap const& set)
}
std::string
debugTostr (std::shared_ptr<BasicView const> const& view)
debugTostr (std::shared_ptr<ReadView const> const& view)
{
std::stringstream ss;
for(auto const& item : view->txs)

View File

@@ -22,6 +22,8 @@
namespace ripple {
namespace test {
#if 0
class Ledger_test : public beast::unit_test::suite
{
void test_genesisLedger (bool sign, KeyType keyType)
@@ -144,5 +146,7 @@ public:
BEAST_DEFINE_TESTSUITE(Ledger,ripple_app,ripple);
#endif
} // test
} // ripple

View File

@@ -27,6 +27,8 @@
#include <ripple/rpc/RipplePathFind.h>
#include <ripple/json/json_writer.h>
#if 0
namespace ripple {
namespace test {
@@ -561,6 +563,7 @@ Json::Value pathNode (OfferPathNode const& offer)
return result;
}
}
}
}
}
#endif

View File

@@ -52,6 +52,7 @@
#include <ripple/json/to_string.h>
#include <ripple/core/LoadFeeTrack.h>
#include <ripple/core/ConfigSections.h>
#include <ripple/ledger/CachedSLEs.h>
#include <ripple/net/SNTPClient.h>
#include <ripple/nodestore/Database.h>
#include <ripple/nodestore/DummyScheduler.h>
@@ -269,7 +270,7 @@ public:
NodeCache m_tempNodeCache;
std::unique_ptr <CollectorManager> m_collectorManager;
detail::AppFamily family_;
SLECache m_sleCache;
CachedSLEs cachedSLEs_;
LocalCredentials m_localCredentials;
std::unique_ptr <Resource::Manager> m_resourceManager;
@@ -349,8 +350,7 @@ public:
, family_ (*m_nodeStore, *m_collectorManager)
, m_sleCache ("LedgerEntryCache", 4096, 120, stopwatch(),
m_logs.journal("TaggedCache"))
, cachedSLEs_ (std::chrono::minutes(1), stopwatch())
, m_resourceManager (Resource::make_Manager (
m_collectorManager->collector(), m_logs.journal("Resource")))
@@ -560,9 +560,10 @@ public:
return *m_pathRequests;
}
SLECache& getSLECache ()
CachedSLEs&
cachedSLEs()
{
return m_sleCache;
return cachedSLEs_;
}
Validators::Manager& getValidators ()
@@ -804,8 +805,6 @@ public:
mValidations->tune (getConfig ().getSize (siValidationsSize), getConfig ().getSize (siValidationsAge));
m_nodeStore->tune (getConfig ().getSize (siNodeCacheSize), getConfig ().getSize (siNodeCacheAge));
m_ledgerMaster->tune (getConfig ().getSize (siLedgerSize), getConfig ().getSize (siLedgerAge));
m_sleCache.setTargetSize (getConfig ().getSize (siSLECacheSize));
m_sleCache.setTargetAge (getConfig ().getSize (siSLECacheAge));
family().treecache().setTargetSize (getConfig ().getSize (siTreeCacheSize));
family().treecache().setTargetAge (getConfig ().getSize (siTreeCacheAge));
@@ -1025,11 +1024,10 @@ public:
getTempNodeCache().sweep();
getValidations().sweep();
getInboundLedgers().sweep();
getSLECache().sweep();
AcceptedLedger::sweep();
family().treecache().sweep();
getOPs().sweepFetchPack();
cachedSLEs_.expire();
// VFALCO NOTE does the call to sweep() happen on another thread?
m_sweepTimer.setExpiration (getConfig ().getSize (siSweepInterval));
}
@@ -1072,13 +1070,13 @@ void ApplicationImp::startNewLedger ()
Ledger::pointer secondLedger = std::make_shared<Ledger> (true, std::ref (*firstLedger));
secondLedger->setClosed ();
secondLedger->setAccepted ();
m_networkOPs->setLastCloseTime (secondLedger->getCloseTimeNC ());
openLedger_.emplace(secondLedger, getConfig(),
cachedSLEs_, deprecatedLogs().journal("OpenLedger"));
m_ledgerMaster->pushLedger (secondLedger, std::make_shared<Ledger> (true, std::ref (*secondLedger)));
assert (secondLedger->exists(keylet::account(
calcAccountID(rootAddress))));
m_networkOPs->setLastCloseTime (secondLedger->getCloseTimeNC ());
openLedger_.emplace(secondLedger, getConfig(),
stopwatch(), deprecatedLogs().journal("OpenLedger"));
}
}
@@ -1329,6 +1327,8 @@ bool ApplicationImp::loadOldLedger (
m_ledgerMaster->switchLedgers (loadLedger, openLedger);
m_ledgerMaster->forceValid(loadLedger);
m_networkOPs->setLastCloseTime (loadLedger->getCloseTimeNC ());
openLedger_.emplace(loadLedger, getConfig(),
cachedSLEs_, deprecatedLogs().journal("OpenLedger"));
if (replay)
{
@@ -1349,7 +1349,7 @@ bool ApplicationImp::loadOldLedger (
txn->getJson(0);
Serializer s;
txn->getSTransaction()->add(s);
cur->txInsert(item->key(),
cur->rawTxInsert(item->key(),
std::make_shared<Serializer const>(
std::move(s)), nullptr);
getApp().getHashRouter().setFlag (item->key(), SF_SIGGOOD);

View File

@@ -23,7 +23,6 @@
#include <ripple/shamap/FullBelowCache.h>
#include <ripple/shamap/TreeNodeCache.h>
#include <ripple/basics/TaggedCache.h>
#include <ripple/ledger/SLECache.h>
#include <beast/utility/PropertyStream.h>
#include <beast/cxx14/memory.h> // <memory>
#include <mutex>
@@ -39,6 +38,7 @@ namespace RPC { class Manager; }
// VFALCO TODO Fix forward declares required for header dependency loops
class AmendmentTable;
class CachedSLEs;
class CollectorManager;
namespace shamap {
class Family;
@@ -97,7 +97,7 @@ public:
virtual JobQueue& getJobQueue () = 0;
virtual RPC::Manager& getRPCManager () = 0;
virtual NodeCache& getTempNodeCache () = 0;
virtual SLECache& getSLECache () = 0;
virtual CachedSLEs& cachedSLEs() = 0;
virtual Validators::Manager& getValidators () = 0;
virtual AmendmentTable& getAmendmentTable() = 0;
virtual IHashRouter& getHashRouter () = 0;

View File

@@ -24,8 +24,6 @@
#include <ripple/app/ledger/Consensus.h>
#include <ripple/app/ledger/LedgerConsensus.h>
#include <ripple/app/ledger/AcceptedLedger.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/app/ledger/InboundLedger.h>
#include <ripple/app/ledger/InboundLedgers.h>
#include <ripple/app/ledger/LedgerMaster.h>
@@ -999,9 +997,9 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
batchLock.unlock();
{
Ledger::pointer ledger;
std::shared_ptr<Ledger> newOL;
bool applied = false;
boost::optional<MetaView> accum;
boost::optional<OpenView> accum;
auto lock = beast::make_lock(getApp().getMasterMutex());
{
std::lock_guard <std::recursive_mutex> lock (
@@ -1010,11 +1008,11 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
auto const oldOL = m_ledgerMaster.getCurrentLedgerHolder().get();
getApp().openLedger().verify(*oldOL, "apply before");
#endif
ledger = m_ledgerMaster.getCurrentLedgerHolder().getMutable();
accum.emplace(*ledger, tapNONE);
newOL = m_ledgerMaster.getCurrentLedgerHolder().getMutable();
accum.emplace(&*newOL);
for (TransactionStatus& e : transactions)
{
ViewFlags flags = tapNONE;
ApplyFlags flags = tapNONE;
flags = flags | tapNO_CHECK_SIGN;
if (e.admin)
flags = flags | tapADMIN;
@@ -1035,7 +1033,7 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
auto const sle2 = getApp().openLedger().current()->read(keylet::account(e.transaction->getSTransaction()->getAccountID(sfAccount)));
// VFALCO Should do the loop inside modify()
getApp().openLedger().modify(
[&](View& view, beast::Journal j)
[&](OpenView& view, beast::Journal j)
{
auto const result = ripple::apply(
view, *e.transaction->getSTransaction(),
@@ -1051,20 +1049,19 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
if (applied)
{
accum->apply(*ledger,
deprecatedLogs().journal("NetworkOPs"));
accum->apply(*newOL);
#if RIPPLE_OPEN_LEDGER
getApp().openLedger().verify(*ledger, "apply after");
getApp().openLedger().verify(*newOL, "apply after");
#endif
ledger->setImmutable();
m_ledgerMaster.getCurrentLedgerHolder().set (ledger);
newOL->setImmutable();
m_ledgerMaster.getCurrentLedgerHolder().set (newOL);
}
for (TransactionStatus& e : transactions)
{
if (e.applied)
{
pubProposedTransaction (ledger,
pubProposedTransaction (newOL,
e.transaction->getSTransaction(), e.result);
}
@@ -1168,8 +1165,7 @@ Json::Value NetworkOPsImp::getOwnerInfo (
{
Json::Value jvObjects (Json::objectValue);
auto uRootIndex = getOwnerDirIndex (account);
auto sleNode = cachedRead(*lpLedger, uRootIndex,
getApp().getSLECache(), ltDIR_NODE);
auto sleNode = cachedRead(*lpLedger, uRootIndex, ltDIR_NODE);
if (sleNode)
{
std::uint64_t uNodeDir;
@@ -1178,8 +1174,7 @@ Json::Value NetworkOPsImp::getOwnerInfo (
{
for (auto const& uDirEntry : sleNode->getFieldV256 (sfIndexes))
{
auto sleCur = cachedRead(*lpLedger, uDirEntry,
getApp().getSLECache());
auto sleCur = cachedRead(*lpLedger, uDirEntry);
switch (sleCur->getType ())
{
@@ -1213,8 +1208,7 @@ Json::Value NetworkOPsImp::getOwnerInfo (
if (uNodeDir)
{
sleNode = cachedRead(*lpLedger, getDirNodeIndex(
uRootIndex, uNodeDir), getApp().getSLECache(),
ltDIR_NODE);
uRootIndex, uNodeDir), ltDIR_NODE);
assert (sleNode);
}
}
@@ -1474,21 +1468,21 @@ void NetworkOPsImp::switchLastClosedLedger (
#endif
// Apply tx in old open ledger to new
// open ledger. Then apply local tx.
MetaView accum(*newOL, tapNONE);
OpenView accum(&*newOL);
assert(accum.open());
auto const localTx = m_localTX->getTxSet();
{
auto retries = localTx;
applyTransactions (&oldOL->txMap(),
accum, newLCL, retries);
accum, newLCL, retries, tapNONE);
}
accum.apply(*newOL, m_journal);
accum.apply(*newOL);
#if RIPPLE_OPEN_LEDGER
auto retries = localTx;
getApp().openLedger().accept(
newLCL, OrderedTxs({}), false, retries,
getApp().getHashRouter(), "jump");
tapNONE, getApp().getHashRouter(), "jump");
getApp().openLedger().verify(
*newOL, "jump after");
#endif
@@ -2313,9 +2307,7 @@ Json::Value NetworkOPsImp::transJson(
// If the offer create is not self funded then add the owner balance
if (account != amount.issue ().account)
{
CachedView const view(
*lpCurrent, getApp().getSLECache());
auto const ownerFunds = accountFunds(view,
auto const ownerFunds = accountFunds(*lpCurrent,
account, amount, fhIGNORE_FREEZE, getConfig());
jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText ();
}
@@ -2719,8 +2711,7 @@ void NetworkOPsImp::getBookPage (
m_journal.trace << "getBookPage: uTipIndex=" << uTipIndex;
}
CachedView const view(
*lpLedger, getApp().getSLECache());
ReadView const& view = *lpLedger;
bool const bGlobalFreeze =
isGlobalFrozen(view, book.out.account) ||

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/protocol/STAmount.h>
#include <ripple/protocol/Indexes.h>
@@ -26,7 +26,7 @@ namespace ripple {
STAmount
creditLimit (
BasicView const& view,
ReadView const& view,
AccountID const& account,
AccountID const& issuer,
Currency const& currency)
@@ -49,7 +49,7 @@ creditLimit (
}
STAmount creditBalance (
BasicView const& view,
ReadView const& view,
AccountID const& account,
AccountID const& issuer,
Currency const& currency)

View File

@@ -33,7 +33,7 @@ namespace ripple {
@return The maximum amount that can be held.
*/
STAmount creditLimit (
BasicView const& view,
ReadView const& view,
AccountID const& account,
AccountID const& issuer,
Currency const& currency);
@@ -45,7 +45,7 @@ STAmount creditLimit (
@param currency the IOU to check.
*/
STAmount creditBalance (
BasicView const& view,
ReadView const& view,
AccountID const& account,
AccountID const& issuer,
Currency const& currency);

View File

@@ -20,8 +20,9 @@
#ifndef RIPPLE_APP_PATHS_NODEDIRECTORY_H_INCLUDED
#define RIPPLE_APP_PATHS_NODEDIRECTORY_H_INCLUDED
#include <ripple/app/ledger/MetaView.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/ledger/ApplyView.h>
namespace ripple {
@@ -53,7 +54,7 @@ public:
restartNeeded = true; // Restart at same quality.
}
bool initialize (Book const& book, View& view)
bool initialize (Book const& book, ApplyView& view)
{
if (current != zero)
return false;
@@ -85,7 +86,7 @@ public:
/** Advance to the next quality directory in the order book. */
// VFALCO Consider renaming this to `nextQuality` or something
Advance
advance (View& view)
advance (ApplyView& view)
{
if (!(advanceNeeded || restartNeeded))
return NO_ADVANCE;

View File

@@ -522,9 +522,8 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
if (valid)
{
boost::optional<PaymentView> sandbox;
sandbox.emplace(*cache->getLedger(),
tapNONE);
boost::optional<PaymentSandbox> sandbox;
sandbox.emplace(&*cache->getLedger(), tapNONE);
auto& sourceAccount = !isXRP (currIssuer.account)
? currIssuer.account
@@ -550,8 +549,7 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
m_journal.debug
<< iIdentifier << " Trying with an extra path element";
spsPaths.push_back (fullLiquidityPath);
sandbox.emplace(*cache->getLedger(),
tapNONE);
sandbox.emplace(&*cache->getLedger(), tapNONE);
rc = path::RippleCalc::rippleCalculate (
*sandbox,
saMaxAmount,

View File

@@ -31,7 +31,7 @@ namespace ripple {
Get the correct ledger to use.
*/
RippleLineCache::pointer PathRequests::getLineCache (
std::shared_ptr <BasicView const> const& ledger, bool authoritative)
std::shared_ptr <ReadView const> const& ledger, bool authoritative)
{
ScopedLockType sl (mLock);
@@ -49,7 +49,7 @@ RippleLineCache::pointer PathRequests::getLineCache (
return mLineCache;
}
void PathRequests::updateAll (std::shared_ptr <BasicView const> const& inLedger,
void PathRequests::updateAll (std::shared_ptr <ReadView const> const& inLedger,
Job::CancelCallback shouldCancel)
{
std::vector<PathRequest::wptr> requests;
@@ -192,7 +192,7 @@ void PathRequests::insertPathRequest (PathRequest::pointer const& req)
// Make a new-style path_find request
Json::Value PathRequests::makePathRequest(
std::shared_ptr <InfoSub> const& subscriber,
std::shared_ptr<BasicView const> const& inLedger,
std::shared_ptr<ReadView const> const& inLedger,
Json::Value const& requestJson)
{
PathRequest::pointer req = std::make_shared<PathRequest> (
@@ -221,7 +221,7 @@ Json::Value PathRequests::makePathRequest(
Json::Value PathRequests::makeLegacyPathRequest(
PathRequest::pointer& req,
std::function <void (void)> completion,
std::shared_ptr<BasicView const> const& inLedger,
std::shared_ptr<ReadView const> const& inLedger,
Json::Value const& request)
{
// This assignment must take place before the

View File

@@ -38,21 +38,21 @@ public:
mFull = collector->make_event ("pathfind_full");
}
void updateAll (std::shared_ptr<BasicView const> const& ledger,
void updateAll (std::shared_ptr<ReadView const> const& ledger,
Job::CancelCallback shouldCancel);
RippleLineCache::pointer getLineCache (
std::shared_ptr <BasicView const> const& ledger, bool authoritative);
std::shared_ptr <ReadView const> const& ledger, bool authoritative);
Json::Value makePathRequest (
std::shared_ptr <InfoSub> const& subscriber,
std::shared_ptr<BasicView const> const& ledger,
std::shared_ptr<ReadView const> const& ledger,
Json::Value const& request);
Json::Value makeLegacyPathRequest (
PathRequest::pointer& req,
std::function <void (void)> completion,
std::shared_ptr<BasicView const> const& inLedger,
std::shared_ptr<ReadView const> const& inLedger,
Json::Value const& request);
void reportFast (int milliseconds)

View File

@@ -20,10 +20,9 @@
#ifndef RIPPLE_APP_PATHS_PATHSTATE_H_INCLUDED
#define RIPPLE_APP_PATHS_PATHSTATE_H_INCLUDED
#include <ripple/app/ledger/MetaView.h>
#include <ripple/app/paths/Node.h>
#include <ripple/app/paths/Types.h>
#include <ripple/app/paths/impl/PaymentView.h>
#include <ripple/ledger/PaymentSandbox.h>
#include <boost/optional.hpp>
namespace ripple {
@@ -36,7 +35,7 @@ class PathState : public CountedObject <PathState>
using Ptr = std::shared_ptr<PathState>;
using List = std::vector<Ptr>;
PathState (PaymentView const& parent,
PathState (PaymentSandbox const& parent,
STAmount const& saSend,
STAmount const& saSendMax)
: mIndex (0)
@@ -104,13 +103,13 @@ class PathState : public CountedObject <PathState>
static bool lessPriority (PathState const& lhs, PathState const& rhs);
PaymentView&
PaymentSandbox&
view()
{
return *view_;
}
void resetView (PaymentView const& view)
void resetView (PaymentSandbox const& view)
{
view_.emplace(&view);
}
@@ -141,7 +140,7 @@ private:
Json::Value getJson () const;
private:
boost::optional<PaymentView> view_;
boost::optional<PaymentSandbox> view_;
int mIndex; // Index/rank amoung siblings.
std::uint64_t uQuality; // 0 = no quality/liquity left.

View File

@@ -23,7 +23,7 @@
#include <ripple/app/paths/Pathfinder.h>
#include <ripple/app/paths/RippleCalc.h>
#include <ripple/app/paths/RippleLineCache.h>
#include <ripple/app/paths/impl/PaymentView.h>
#include <ripple/ledger/PaymentSandbox.h>
#include <ripple/app/ledger/OrderBookDB.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
@@ -378,7 +378,7 @@ TER Pathfinder::getPathLiquidity (
path::RippleCalc::Input rcInput;
rcInput.defaultPathsAllowed = false;
PaymentView sandbox (*mLedger, tapNONE);
PaymentSandbox sandbox (&*mLedger, tapNONE);
try
{
@@ -443,7 +443,7 @@ void Pathfinder::computePathRanks (int maxPaths)
// Must subtract liquidity in default path from remaining amount.
try
{
PaymentView sandbox (*mLedger, tapNONE);
PaymentSandbox sandbox (&*mLedger, tapNONE);
path::RippleCalc::Input rcInput;
rcInput.partialPaymentAllowed = true;

View File

@@ -185,7 +185,7 @@ private:
been removed. */
STAmount mRemainingAmount;
std::shared_ptr <BasicView const> mLedger;
std::shared_ptr <ReadView const> mLedger;
LoadEvent::pointer m_loadEvent;
RippleLineCache::pointer mRLCache;

View File

@@ -22,6 +22,7 @@
#include <ripple/app/paths/RippleCalc.h>
#include <ripple/app/paths/cursor/PathCursor.h>
#include <ripple/basics/Log.h>
#include <ripple/ledger/View.h>
namespace ripple {
namespace path {
@@ -30,7 +31,7 @@ namespace {
static
TER
deleteOffers (View& view,
deleteOffers (ApplyView& view,
OfferSet const& offers)
{
for (auto& e: offers)
@@ -43,7 +44,7 @@ deleteOffers (View& view,
} // namespace
RippleCalc::Output RippleCalc::rippleCalculate (
PaymentView& view,
PaymentSandbox& view,
// Compute paths using this ledger entry set. Up to caller to actually
// apply to ledger.

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_APP_PATHS_RIPPLECALC_H_INCLUDED
#define RIPPLE_APP_PATHS_RIPPLECALC_H_INCLUDED
#include <ripple/app/paths/impl/PaymentView.h>
#include <ripple/ledger/PaymentSandbox.h>
#include <ripple/app/paths/PathState.h>
#include <ripple/protocol/STAmount.h>
#include <ripple/protocol/TER.h>
@@ -75,7 +75,7 @@ public:
static
Output
rippleCalculate(
PaymentView& view,
PaymentSandbox& view,
// Compute paths using this ledger entry set. Up to caller to actually
// apply to ledger.
@@ -101,7 +101,7 @@ public:
Input const* const pInputs = nullptr);
// The view we are currently working on
PaymentView& view;
PaymentSandbox& view;
// If the transaction fails to meet some constraint, still need to delete
// unfunded offers.
@@ -117,7 +117,7 @@ public:
private:
RippleCalc (
PaymentView& view_,
PaymentSandbox& view_,
STAmount const& saMaxAmountReq, // --> -1 = no limit.
STAmount const& saDstAmountReq,

View File

@@ -19,15 +19,16 @@
#include <BeastConfig.h>
#include <ripple/app/paths/RippleLineCache.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/ledger/OpenView.h>
namespace ripple {
RippleLineCache::RippleLineCache (std::shared_ptr <BasicView const> const& l)
RippleLineCache::RippleLineCache(
std::shared_ptr <ReadView const> const& ledger)
{
// We want the caching that MetaView provides
// We want the caching that OpenView provides
// And we need to own a shared_ptr to the input view
mLedger = std::make_shared <MetaView> (*l, tapNONE, l);
mLedger = std::make_shared<OpenView>(&*ledger, ledger);
}
RippleLineCache::RippleStateVector const&

View File

@@ -37,9 +37,10 @@ public:
using pointer = std::shared_ptr <RippleLineCache>;
using ref = pointer const&;
explicit RippleLineCache (std::shared_ptr <BasicView const> const& l);
explicit RippleLineCache (std::shared_ptr <ReadView const> const& l);
std::shared_ptr <BasicView const> const& getLedger () // VFALCO TODO const?
std::shared_ptr <ReadView const> const&
getLedger () // VFALCO TODO const?
{
return mLedger;
}
@@ -53,7 +54,7 @@ private:
LockType mLock;
ripple::hardened_hash<> hasher_;
std::shared_ptr <BasicView const> mLedger;
std::shared_ptr <ReadView const> mLedger;
struct AccountKey
{

View File

@@ -18,7 +18,6 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/paths/RippleState.h>
#include <ripple/protocol/STAmount.h>
@@ -73,7 +72,7 @@ Json::Value RippleState::getJson (int)
std::vector <RippleState::pointer>
getRippleStateItems (AccountID const& accountID,
BasicView const& view)
ReadView const& view)
{
std::vector <RippleState::pointer> items;
forEachItem(view, accountID,

View File

@@ -156,7 +156,7 @@ private:
std::vector <RippleState::pointer>
getRippleStateItems (AccountID const& accountID,
BasicView const& view);
ReadView const& view);
} // ripple

View File

@@ -92,7 +92,7 @@ private:
STAmount& saInFees) const;
// VFALCO TODO Rename this to view()
PaymentView&
PaymentSandbox&
view() const
{
return pathState_.view();

View File

@@ -20,6 +20,7 @@
#include <BeastConfig.h>
#include <ripple/app/paths/cursor/PathCursor.h>
#include <ripple/basics/Log.h>
#include <ripple/ledger/View.h>
#include <tuple>
namespace ripple {

View File

@@ -203,7 +203,7 @@ void rippleLiquidity (
static
std::uint32_t
rippleQuality (
BasicView const& view,
ReadView const& view,
AccountID const& destination,
AccountID const& source,
Currency const& currency,
@@ -237,7 +237,7 @@ rippleQuality (
std::uint32_t
quality_in (
BasicView const& view,
ReadView const& view,
AccountID const& uToAccountID,
AccountID const& uFromAccountID,
Currency const& currency)
@@ -248,7 +248,7 @@ quality_in (
std::uint32_t
quality_out (
BasicView const& view,
ReadView const& view,
AccountID const& uToAccountID,
AccountID const& uFromAccountID,
Currency const& currency)

View File

@@ -40,14 +40,14 @@ void rippleLiquidity (
std::uint32_t
quality_in (
BasicView const& view,
ReadView const& view,
AccountID const& uToAccountID,
AccountID const& uFromAccountID,
Currency const& currency);
std::uint32_t
quality_out (
BasicView const& view,
ReadView const& view,
AccountID const& uToAccountID,
AccountID const& uFromAccountID,
Currency const& currency);

View File

@@ -1,61 +0,0 @@
//------------------------------------------------------------------------------
/*
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/app/paths/impl/PaymentView.h>
#include <cassert>
namespace ripple {
STAmount
PaymentView::balanceHook (AccountID const& account,
AccountID const& issuer,
STAmount const& amount) const
{
if (pv_)
return tab_.adjustedBalance (
account, issuer, pv_->balanceHook (account, issuer, amount));
return tab_.adjustedBalance(
account, issuer, amount);
}
void
PaymentView::creditHook (AccountID const& from,
AccountID const& to,
STAmount const& amount)
{
tab_.credit(from, to, amount);
}
void
PaymentView::apply (BasicView& to)
{
assert(! pv_);
view_.apply(to);
}
void
PaymentView::apply (PaymentView& to)
{
assert(pv_ == &to);
view_.apply(to);
tab_.apply(to.tab_);
}
} // ripple

View File

@@ -1,119 +0,0 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_APP_PAYMENTVIEW_H_INCLUDED
#define RIPPLE_APP_PAYMENTVIEW_H_INCLUDED
#include <ripple/core/Config.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/ledger/View.h>
#include <ripple/ledger/DeferredCredits.h>
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <utility>
namespace ripple {
/** A View wrapper which makes credits unavailable to balances.
This is used for payments and pathfinding, so that consuming
liquidity from a path never causes portions of that path or
other paths to gain liquidity.
The behavior of certain free functions in the View API
will change via the balanceHook and creditHook overrides
of PaymentView.
*/
class PaymentView : public ViewWrapper<MetaView>
{
private:
DeferredCredits tab_;
PaymentView const* pv_ = nullptr;
public:
PaymentView (PaymentView const&) = delete;
PaymentView& operator= (PaymentView const&) = delete;
/** Construct contained MetaView from arguments */
template <class... Args>
explicit
PaymentView (Args&&... args)
: ViewWrapper (std::forward<Args>(args)...)
{
}
/** Construct on top of existing PaymentView.
The changes are pushed to the parent when
apply() is called.
@param parent A non-null pointer to the parent.
@note A pointer is used to prevent confusion
with copy construction.
*/
// VFALCO If we are constructing on top of a PaymentView,
// or a PaymentView-derived class, we MUST go through
// one of these constructors or invariants will be broken.
/** @{ */
explicit
PaymentView (PaymentView const* parent)
: ViewWrapper (*parent, parent->flags())
, pv_ (parent)
{
}
explicit
PaymentView (PaymentView* parent)
: ViewWrapper (*parent, parent->flags())
, pv_ (parent)
{
}
/** @} */
STAmount
balanceHook (AccountID const& account,
AccountID const& issuer,
STAmount const& amount) const override;
void
creditHook (AccountID const& from,
AccountID const& to,
STAmount const& amount) override;
/** Apply changes to the parent View.
`to` must contain contents identical to the parent
view passed upon construction, else undefined
behavior will result.
After a call to apply(), the only valid operation that
may be performed on this is a call to the destructor.
*/
/** @{ */
void
apply (BasicView& to);
void
apply (PaymentView& to);
/** @} */
};
} // ripple
#endif

View File

@@ -35,7 +35,7 @@ class Path_test : public beast::unit_test::suite
{
public:
Json::Value
findPath (std::shared_ptr<BasicView const> const& view,
findPath (std::shared_ptr<ReadView const> const& view,
Account const& src, Account const& dest,
std::vector<Issue> const& srcIssues,
STAmount const& saDstAmount)

View File

@@ -30,24 +30,19 @@
namespace ripple {
/** Apply a transaction to a BasicView.
/** Apply a transaction to a ReadView.
Throws:
Exceptions are thrown on broken invariants. Callers
should catch these exceptions to protect the ledger
and the running process.
std::logic_error
(any)
Does not throw. Exceptions generated during
tx application will return tefEXCEPTION.
@return A pair with the TER and a bool indicating
whether or not the transaction was applied.
*/
// VFALCO Some call sites use try/catch some don't.
std::pair<TER, bool>
apply (BasicView& view,
STTx const& tx, ViewFlags flags,
apply (OpenView& view,
STTx const& tx, ApplyFlags flags,
Config const& config,
beast::Journal journal);

View File

@@ -28,8 +28,8 @@
namespace ripple {
ApplyContext::ApplyContext(
BasicView& base, STTx const& tx_,
ViewFlags flags, Config const& config_,
OpenView& base, STTx const& tx_,
ApplyFlags flags, Config const& config_,
beast::Journal journal_)
: tx (tx_)
, config (config_)
@@ -37,13 +37,13 @@ ApplyContext::ApplyContext(
, base_ (base)
, flags_(flags)
{
view_.emplace(base_, flags_);
view_.emplace(&base_, flags_);
}
void
ApplyContext::discard()
{
view_.emplace(base_, flags_);
view_.emplace(&base_, flags_);
}
void

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_TX_APPLYCONTEXT_H_INCLUDED
#define RIPPLE_TX_APPLYCONTEXT_H_INCLUDED
#include <ripple/app/ledger/MetaView.h>
#include <ripple/ledger/ApplyViewImpl.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/STTx.h>
#include <beast/utility/Journal.h>
@@ -36,8 +36,8 @@ class ApplyContext
{
public:
explicit
ApplyContext (BasicView& base,
STTx const& tx, ViewFlags flags,
ApplyContext (OpenView& base,
STTx const& tx, ApplyFlags flags,
Config const& config,
beast::Journal = {});
@@ -45,23 +45,30 @@ public:
Config const& config;
beast::Journal const journal;
View&
ApplyView&
view()
{
return *view_;
}
View const&
ApplyView const&
view() const
{
return *view_;
}
// VFALCO Unfortunately this is necessary
RawView&
rawView()
{
return *view_;
}
/** Sets the DeliveredAmount field in the metadata */
void
deliverAmount (STAmount const& delivered)
deliver (STAmount const& amount)
{
view_->setDeliveredAmount(delivered);
view_->deliver(amount);
}
/** Discard changes and start fresh. */
@@ -72,11 +79,17 @@ public:
void
apply (TER);
void
destroyXRP (std::uint64_t feeDrops)
{
view_->rawDestroyXRP(feeDrops);
}
private:
BasicView& base_;
ViewFlags flags_;
OpenView& base_;
ApplyFlags flags_;
beast::Journal j_;
boost::optional<MetaView> view_;
boost::optional<ApplyViewImpl> view_;
};
} // ripple

View File

@@ -22,7 +22,7 @@
namespace ripple {
BookTip::BookTip (View& view, BookRef book)
BookTip::BookTip (ApplyView& view, BookRef book)
: view_ (view)
, m_valid (false)
, m_book (getBookBase (book))

View File

@@ -36,7 +36,7 @@ namespace ripple {
class BookTip
{
private:
View& view_;
ApplyView& view_;
bool m_valid;
uint256 m_book;
uint256 m_end;
@@ -47,7 +47,7 @@ private:
public:
/** Create the iterator. */
BookTip (View& view, BookRef book);
BookTip (ApplyView& view, BookRef book);
uint256 const&
dir() const noexcept

View File

@@ -22,6 +22,7 @@
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/ledger/View.h>
namespace ripple {

View File

@@ -21,6 +21,7 @@
#include <ripple/app/tx/impl/CancelTicket.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/ledger/View.h>
namespace ripple {

View File

@@ -25,6 +25,7 @@
#include <ripple/protocol/Quality.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
#include <ripple/ledger/Sandbox.h>
#include <beast/cxx14/memory.h>
#include <beast/utility/Journal.h>
#include <beast/utility/WrappedSink.h>
@@ -87,7 +88,7 @@ CreateOffer::checkAcceptAsset(IssueRef issue) const
}
bool
CreateOffer::dry_offer (View& view, Offer const& offer)
CreateOffer::dry_offer (ApplyView& view, Offer const& offer)
{
if (offer.fully_consumed ())
return true;
@@ -129,8 +130,8 @@ CreateOffer::select_path (
std::pair<TER, Amounts>
CreateOffer::bridged_cross (
Taker& taker,
View& view,
View& view_cancel,
ApplyView& view,
ApplyView& view_cancel,
Clock::time_point const when)
{
auto const& taker_amount = taker.original_offer ();
@@ -277,8 +278,8 @@ CreateOffer::bridged_cross (
std::pair<TER, Amounts>
CreateOffer::direct_cross (
Taker& taker,
View& view,
View& view_cancel,
ApplyView& view,
ApplyView& view_cancel,
Clock::time_point const when)
{
OfferStream offers (
@@ -377,8 +378,8 @@ CreateOffer::step_account (OfferStream& stream, Taker const& taker)
// Charges fees on top to taker.
std::pair<TER, Amounts>
CreateOffer::cross (
View& view,
View& cancel_view,
ApplyView& view,
ApplyView& cancel_view,
Amounts const& taker_amount)
{
Clock::time_point const when =
@@ -525,7 +526,7 @@ CreateOffer::preCheck ()
}
std::pair<TER, bool>
CreateOffer::applyGuts (View& view, View& view_cancel)
CreateOffer::applyGuts (ApplyView& view, ApplyView& view_cancel)
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
@@ -825,15 +826,15 @@ CreateOffer::doApply()
{
// This is the ledger view that we work against. Transactions are applied
// as we go on processing transactions.
MetaView view (ctx_.view(), ctx_.view().flags());
Sandbox view (&ctx_.view());
// This is a checkpoint with just the fees paid. If something goes wrong
// with this transaction, we roll back to this ledger.
MetaView viewCancel (ctx_.view(), ctx_.view().flags());
Sandbox viewCancel (&ctx_.view());
auto const result = applyGuts(view, viewCancel);
if (result.second)
view.apply(ctx_.view());
view.apply(ctx_.rawView());
else
viewCancel.apply(ctx_.view());
viewCancel.apply(ctx_.rawView());
return result.first;
}

View File

@@ -55,7 +55,7 @@ public:
preCheck () override;
std::pair<TER, bool>
applyGuts (View& view, View& view_cancel);
applyGuts (ApplyView& view, ApplyView& view_cancel);
TER
doApply() override;
@@ -66,7 +66,7 @@ private:
checkAcceptAsset(IssueRef issue) const;
bool
dry_offer (View& view, Offer const& offer);
dry_offer (ApplyView& view, Offer const& offer);
static
std::pair<bool, Quality>
@@ -77,15 +77,15 @@ private:
std::pair<TER, Amounts>
bridged_cross (
Taker& taker,
View& view,
View& view_cancel,
ApplyView& view,
ApplyView& view_cancel,
Clock::time_point const when);
std::pair<TER, Amounts>
direct_cross (
Taker& taker,
View& view,
View& view_cancel,
ApplyView& view,
ApplyView& view_cancel,
Clock::time_point const when);
// Step through the stream for as long as possible, skipping any offers
@@ -101,8 +101,8 @@ private:
// Charges fees on top to taker.
std::pair<TER, Amounts>
cross (
View& view,
View& cancel_view,
ApplyView& view,
ApplyView& cancel_view,
Amounts const& taker_amount);
static

View File

@@ -127,8 +127,7 @@ public:
if (ledger->txExists(txn.getID()))
return true;
auto const sle = cachedRead(*ledger,
keylet::account(txn.getAccount()).key,
getApp().getSLECache(), ltACCOUNT_ROOT);
keylet::account(txn.getAccount()).key, ltACCOUNT_ROOT);
if (! sle)
return false;
if (sle->getFieldU32 (sfSequence) > txn.getSeq ())

View File

@@ -96,7 +96,7 @@ public:
/** Adjusts the offer to indicate that we consumed some (or all) of it. */
void
consume (View& view,
consume (ApplyView& view,
Amounts const& consumed) const
{
if (consumed.in > m_amounts.in)

View File

@@ -22,7 +22,7 @@
namespace ripple {
OfferStream::OfferStream (View& view, View& view_cancel,
OfferStream::OfferStream (ApplyView& view, ApplyView& view_cancel,
BookRef book, Clock::time_point when,
Config const& config, beast::Journal journal)
: j_ (journal)
@@ -38,9 +38,9 @@ OfferStream::OfferStream (View& view, View& view_cancel,
// Handle the case where a directory item with no corresponding ledger entry
// is found. This shouldn't happen but if it does we clean it up.
void
OfferStream::erase (View& view)
OfferStream::erase (ApplyView& view)
{
// NIKB NOTE This should be using View::dirDelete, which would
// NIKB NOTE This should be using ApplyView::dirDelete, which would
// correctly remove the directory if its the last entry.
// Unfortunately this is a protocol breaking change.

View File

@@ -32,7 +32,7 @@ namespace ripple {
/** Presents and consumes the offers in an order book.
Two `View` objects accumulate changes to the ledger. `view`
Two `ApplyView` objects accumulate changes to the ledger. `view`
is applied when the calling transaction succeeds. If the calling
transaction fails, then `view_cancel` is applied.
@@ -51,8 +51,8 @@ class OfferStream
{
private:
beast::Journal j_;
std::reference_wrapper <View> m_view;
std::reference_wrapper <View> m_view_cancel;
std::reference_wrapper <ApplyView> m_view;
std::reference_wrapper <ApplyView> m_view_cancel;
Book m_book;
Clock::time_point m_when;
BookTip m_tip;
@@ -60,21 +60,21 @@ private:
Config const& config_;
void
erase (View& view);
erase (ApplyView& view);
public:
OfferStream (View& view, View& view_cancel,
OfferStream (ApplyView& view, ApplyView& view_cancel,
BookRef book, Clock::time_point when,
Config const& config,
beast::Journal journal);
View&
ApplyView&
view () noexcept
{
return m_view;
}
View&
ApplyView&
view_cancel () noexcept
{
return m_view_cancel;

View File

@@ -327,7 +327,7 @@ Payment::doApply ()
{
path::RippleCalc::Output rc;
{
PaymentView pv (view(), view().flags());
PaymentSandbox pv(&view());
rc = path::RippleCalc::rippleCalculate (
pv,
maxSourceAmount,
@@ -339,7 +339,7 @@ Payment::doApply ()
// VFALCO NOTE We might not need to apply, depending
// on the TER. But always applying *should*
// be safe.
pv.apply(view());
pv.apply(ctx_.rawView());
}
// TODO: is this right? If the amount is the correct amount, was
@@ -351,7 +351,7 @@ Payment::doApply ()
mTxn.getFieldAmount (sfDeliverMin))
rc.setResult (tecPATH_PARTIAL);
else
ctx_.deliverAmount (rc.actualAmountOut);
ctx_.deliver (rc.actualAmountOut);
}
terResult = rc.result ();

View File

@@ -24,6 +24,7 @@
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/Quality.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/ledger/View.h>
namespace ripple {

View File

@@ -23,6 +23,7 @@
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/ledger/View.h>
namespace ripple {

View File

@@ -515,7 +515,7 @@ BasicTaker::do_cross (
//==============================================================================
Taker::Taker (CrossType cross_type, View& view,
Taker::Taker (CrossType cross_type, ApplyView& view,
AccountID const& account, Amounts const& offer,
std::uint32_t flags, Config const& config,
beast::Journal journal)
@@ -773,7 +773,7 @@ Taker::cross (Offer const& leg1, Offer const& leg2)
std::uint32_t
Taker::calculateRate (
View const& view,
ApplyView const& view,
AccountID const& issuer,
AccountID const& account)
{

View File

@@ -244,7 +244,7 @@ public:
Taker () = delete;
Taker (Taker const&) = delete;
Taker (CrossType cross_type, View& view,
Taker (CrossType cross_type, ApplyView& view,
AccountID const& account, Amounts const& offer,
std::uint32_t flags, Config const& config,
beast::Journal journal);
@@ -289,7 +289,7 @@ public:
private:
static
std::uint32_t
calculateRate (View const& view,
calculateRate (ApplyView const& view,
AccountID const& issuer,
AccountID const& account);
@@ -312,7 +312,7 @@ private:
private:
// The underlying ledger entry we are dealing with
View& view_;
ApplyView& view_;
Config const& config_;

View File

@@ -101,7 +101,7 @@ TER Transactor::payFee ()
mSourceBalance -= saPaid;
sle->setFieldAmount (sfBalance, mSourceBalance);
// VFALCO Should we call view().destroyCoins() here as well?
// VFALCO Should we call view().rawDestroyXRP() here as well?
return tesSUCCESS;
}
@@ -329,7 +329,7 @@ struct GetSignerListResult
static
GetSignerListResult
getSignerList (AccountID signingForAcctID,
BasicView const& view, beast::Journal journal)
ReadView const& view, beast::Journal journal)
{
GetSignerListResult ret;
@@ -786,7 +786,7 @@ Transactor::operator()()
}
if (fee != zero)
view().destroyCoins (fee.mantissa ());
ctx_.destroyXRP (fee.mantissa ());
}
ctx_.apply(terResult);

View File

@@ -45,13 +45,13 @@ public:
std::pair<TER, bool>
operator()();
View&
ApplyView&
view()
{
return ctx_.view();
}
View const&
ApplyView const&
view() const
{
return ctx_.view();

View File

@@ -74,8 +74,8 @@ invoke (TxType type,
}
std::pair<TER, bool>
apply (BasicView& view,
STTx const& tx, ViewFlags flags,
apply (OpenView& view,
STTx const& tx, ApplyFlags flags,
Config const& config,
beast::Journal j)
{

View File

@@ -24,6 +24,8 @@
namespace ripple {
namespace test {
#if 0
class MultiSign_test : public beast::unit_test::suite
{
static std::uint64_t const xrp = std::mega::num;
@@ -1617,5 +1619,7 @@ public:
BEAST_DEFINE_TESTSUITE(MultiSign,ripple_app,ripple);
#endif
} // test
} // ripple

View File

@@ -21,7 +21,6 @@
#include <ripple/app/main/Application.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/basics/Log.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/test/jtx.h>
#include <ripple/test/jtx/Account.h>

View File

@@ -25,6 +25,8 @@
#include <ripple/protocol/TxFormats.h>
#include <ripple/protocol/TxFlags.h>
#if 0
namespace ripple {
namespace test {
@@ -429,3 +431,5 @@ getTicketsOnAccount (TestLedger& ledger, UserAccount const& acct)
} // test
} // ripple
#endif

View 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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED
#define RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
namespace ripple {
enum ApplyFlags
{
tapNONE = 0x00,
// Signature already checked
tapNO_CHECK_SIGN = 0x01,
// Enable supressed features for testing.
// This lets unit tests exercise code that
// is not turned on for production.
//
tapENABLE_TESTING = 0x02,
// This is not the transaction's last pass
// Transaction can be retried, soft failures allowed
tapRETRY = 0x20,
// Transaction came from a privileged source
tapADMIN = 0x400,
};
inline
ApplyFlags
operator|(ApplyFlags const& lhs,
ApplyFlags const& rhs)
{
return static_cast<ApplyFlags>(
static_cast<int>(lhs) |
static_cast<int>(rhs));
}
inline
ApplyFlags
operator&(ApplyFlags const& lhs,
ApplyFlags const& rhs)
{
return static_cast<ApplyFlags>(
static_cast<int>(lhs) &
static_cast<int>(rhs));
}
//------------------------------------------------------------------------------
/** Writeable view to a ledger, for applying a transaction.
This refinement of ReadView provides an interface where
the SLE can be "checked out" for modifications and put
back in an updated or removed state. Also added is an
interface to provide contextual information necessary
to calculate the results of transaction processing,
including the metadata if the view is later applied to
the parent (using an interface in the derived class).
The context info also includes values from the base
ledger such as sequence number and the network time.
This allows implementations to journal changes made to
the state items in a ledger, with the option to apply
those changes to the base or discard the changes without
affecting the base.
Typical usage is to call read() for non-mutating
operations.
For mutating operations the sequence is as follows:
// Add a new value
v.insert(sle);
// Check out a value for modification
sle = v.peek(k);
// Indicate that changes were made
v.update(sle)
// Or, erase the value
v.erase(sle)
The invariant is that insert, update, and erase may not
be called with any SLE which belongs to different view.
*/
class ApplyView
: public ReadView
{
public:
/** Returns the tx apply flags.
Flags can affect the outcome of transaction
processing. For example, transactions applied
to an open ledger generate "local" failures,
while transactions applied to the consensus
ledger produce hard failures (and claim a fee).
*/
virtual
ApplyFlags
flags() const = 0;
/** Prepare to modify the SLE associated with key.
Effects:
Gives the caller ownership of a modifiable
SLE associated with the specified key.
The returned SLE may be used in a subsequent
call to erase or update.
The SLE must not be passed to any other ApplyView.
@return `nullptr` if the key is not present
*/
virtual
std::shared_ptr<SLE>
peek (Keylet const& k) = 0;
/** Remove a peeked SLE.
Requirements:
`sle` was obtained from prior call to peek()
on this instance of the RawView.
Effects:
The key is no longer associated with the SLE.
*/
virtual
void
erase (std::shared_ptr<SLE> const& sle) = 0;
/** Insert a new state SLE
Requirements:
`sle` was not obtained from any calls to
peek() on any instances of RawView.
The SLE's key must not already exist.
Effects:
The key in the state map is associated
with the SLE.
The RawView acquires ownership of the shared_ptr.
@note The key is taken from the SLE
*/
virtual
void
insert (std::shared_ptr<SLE> const& sle) = 0;
/** Indicate changes to a peeked SLE
Requirements:
The SLE's key must exist.
`sle` was obtained from prior call to peek()
on this instance of the RawView.
Effects:
The SLE is updated
@note The key is taken from the SLE
*/
/** @{ */
virtual
void
update (std::shared_ptr<SLE> const& sle) = 0;
//--------------------------------------------------------------------------
// Called when a credit is made to an account
// This is required to support PaymentSandbox
virtual
void
creditHook (AccountID const& from,
AccountID const& to,
STAmount const& amount)
{
}
};
} // ripple
#endif

View File

@@ -0,0 +1,89 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_APPLYVIEWIMPL_H_INCLUDED
#define RIPPLE_LEDGER_APPLYVIEWIMPL_H_INCLUDED
#include <ripple/ledger/OpenView.h>
#include <ripple/ledger/detail/ApplyViewBase.h>
#include <ripple/protocol/STAmount.h>
#include <ripple/protocol/TER.h>
#include <boost/optional.hpp>
namespace ripple {
/** Editable, discardable view that can build metadata for one tx.
Iteration of the tx map is delegated to the base.
@note Presented as ApplyView to clients.
*/
class ApplyViewImpl
: public detail::ApplyViewBase
{
public:
ApplyViewImpl() = delete;
ApplyViewImpl (ApplyViewImpl const&) = delete;
ApplyViewImpl& operator= (ApplyViewImpl&&) = delete;
ApplyViewImpl& operator= (ApplyViewImpl const&) = delete;
#ifdef _MSC_VER
ApplyViewImpl (ApplyViewImpl&& other)
: ApplyViewBase (std::move(other))
, deliver_ (std::move(other.deliver_))
{
}
#else
ApplyViewImpl (ApplyViewImpl&&) = default;
#endif
ApplyViewImpl (ReadView const* base,
ApplyFlags flags);
/** Apply the transaction.
After a call to `apply`, the only valid
operation on this object is to call the
destructor.
*/
void
apply (OpenView& to,
STTx const& tx, TER ter,
beast::Journal j);
/** Set the amount of currency delivered.
This value is used when generating metadata
for payments, to set the DeliveredAmount field.
If the amount is not specified, the field is
excluded from the resulting metadata.
*/
void
deliver (STAmount const& amount)
{
deliver_ = amount;
}
private:
boost::optional<STAmount> deliver_;
};
} // ripple
#endif

View File

@@ -0,0 +1,115 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_CACHEDSLES_H_INCLUDED
#define RIPPLE_LEDGER_CACHEDSLES_H_INCLUDED
#include <ripple/basics/chrono.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <beast/container/aged_unordered_map.h>
#include <memory>
#include <mutex>
namespace ripple {
/** Caches SLEs by their digest. */
class CachedSLEs
{
public:
using digest_type = uint256;
using value_type =
std::shared_ptr<SLE const>;
CachedSLEs (CachedSLEs const&) = delete;
CachedSLEs& operator= (CachedSLEs const&) = delete;
template <class Rep, class Period>
CachedSLEs (std::chrono::duration<
Rep, Period> const& timeToLive,
Stopwatch& clock)
: clock_ (clock)
, timeToLive_ (timeToLive)
, map_ (clock)
{
}
/** Discard expired entries.
Needs to be called periodically.
*/
void
expire();
/** Fetch an item from the cache.
If the digest was not found, Handler
will be called with this signature:
std::shared_ptr<SLE const>(void)
*/
template <class Handler>
value_type
fetch (digest_type const& digest,
Handler const& h)
{
{
std::lock_guard<
std::mutex> lock(mutex_);
auto iter =
map_.find(digest);
if (iter != map_.end())
{
++hit_;
map_.touch(iter);
return iter->second;
}
}
auto sle = h();
if (! sle)
return nullptr;
std::lock_guard<
std::mutex> lock(mutex_);
++miss_;
auto const result =
map_.emplace(
digest, std::move(sle));
if (! result.second)
map_.touch(result.first);
return result.first->second;
}
/** Returns the fraction of cache hits. */
double
rate() const;
private:
std::size_t hit_ = 0;
std::size_t miss_ = 0;
Stopwatch const& clock_;
std::mutex mutable mutex_;
Stopwatch::duration timeToLive_;
beast::aged_unordered_map <digest_type,
value_type, Stopwatch::clock_type,
hardened_hash<strong_hash>> map_;
};
} // ripple
#endif

View File

@@ -0,0 +1,149 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_CACHINGREADVIEW_H_INCLUDED
#define RIPPLE_LEDGER_CACHINGREADVIEW_H_INCLUDED
#include <ripple/ledger/CachedSLEs.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/basics/hardened_hash.h>
#include <map>
#include <memory>
#include <mutex>
namespace ripple {
//------------------------------------------------------------------------------
/** ReadView that caches by key and hash. */
class CachingReadView
: public ReadView
{
private:
CachedSLEs& cache_;
std::mutex mutable mutex_;
DigestAwareReadView const& base_;
std::shared_ptr<void const> hold_;
std::unordered_map<key_type,
std::shared_ptr<SLE const>,
hardened_hash<>> mutable map_;
public:
CachingReadView() = delete;
CachingReadView (CachingReadView const&) = delete;
CachingReadView& operator= (CachingReadView const&) = delete;
CachingReadView(
DigestAwareReadView const* base,
CachedSLEs& cache,
std::shared_ptr<void const> hold);
CachingReadView (std::shared_ptr<
DigestAwareReadView const> const& base,
CachedSLEs& cache)
: CachingReadView (&*base, cache, base)
{
}
bool
exists (Keylet const& k) const override;
std::shared_ptr<SLE const>
read (Keylet const& k) const override;
LedgerInfo const&
info() const override
{
return base_.info();
}
Fees const&
fees() const override
{
return base_.fees();
}
boost::optional<key_type>
succ (key_type const& key, boost::optional<
key_type> last = boost::none) const override
{
return base_.succ(key, last);
}
std::unique_ptr<txs_type::iter_base>
txsBegin() const override
{
return base_.txsBegin();
}
std::unique_ptr<txs_type::iter_base>
txsEnd() const override
{
return base_.txsEnd();
}
bool
txExists(key_type const& key) const override
{
return base_.txExists(key);
}
tx_type
txRead (key_type const& key) const override
{
return base_.txRead(key);
}
};
//------------------------------------------------------------------------------
/** Wrap a DigestAwareReadView with a cache.
Effects:
Returns ownership of a base ReadView that is
wrapped in a thread-safe cache.
The returned ReadView gains a reference to
the base.
Postconditions:
The base object will not be destroyed before
the returned view is destroyed.
The caller is responsible for ensuring that the
`cache` object lifetime extends to the lifetime of
the returned object.
*/
inline
std::shared_ptr<ReadView const>
makeCached (std::shared_ptr<
DigestAwareReadView const> const& base,
CachedSLEs& cache)
{
return std::make_shared<
CachingReadView const>(
&*base, cache, base);
}
} // ripple
#endif

View File

@@ -1,70 +0,0 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_DEFERREDCREDITS_H_INCLUDED
#define RIPPLE_LEDGER_DEFERREDCREDITS_H_INCLUDED
#include <ripple/protocol/UintTypes.h>
#include <ripple/protocol/STAmount.h>
#include <map>
#include <tuple>
namespace ripple {
class DeferredCredits
{
private:
// lowAccount, highAccount
using Key = std::tuple<
AccountID, AccountID, Currency>;
// lowAccountCredits, highAccountCredits
using Value = std::tuple<
STAmount, STAmount>;
static
Key
makeKey (AccountID const& a1,
AccountID const& a2,
Currency const& c);
std::map<Key, Value> map_;
public:
// Get the adjusted balance of main for the
// balance between main and other.
STAmount
adjustedBalance (AccountID const& main,
AccountID const& other,
STAmount const& curBalance) const;
void credit (AccountID const& sender,
AccountID const& receiver,
STAmount const& amount);
void apply (DeferredCredits& to);
// VFALCO Is this needed?
// DEPRECATED
void clear ();
};
} // ripple
#endif

View File

@@ -0,0 +1,209 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_OPENVIEW_H_INCLUDED
#define RIPPLE_LEDGER_OPENVIEW_H_INCLUDED
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/ledger/detail/RawStateTable.h>
namespace ripple {
/** Open ledger construction tag.
Views constructed with this tag will have the
rules of open ledgers applied during transaction
processing.
*/
struct open_ledger_t {};
extern open_ledger_t const open_ledger;
//------------------------------------------------------------------------------
/** Writable ledger view that accumulates state and tx changes.
@note Presented as ReadView to clients.
*/
class OpenView
: public ReadView
, public TxsRawView
{
private:
class txs_iter_impl;
// List of tx, key order
using txs_map = std::map<key_type,
std::pair<std::shared_ptr<
Serializer const>, std::shared_ptr<
Serializer const>>>;
txs_map txs_;
LedgerInfo info_;
ReadView const* base_;
detail::RawStateTable items_;
std::shared_ptr<void const> hold_;
public:
OpenView() = delete;
OpenView& operator= (OpenView&&) = delete;
OpenView& operator= (OpenView const&) = delete;
#ifdef _MSC_VER
OpenView (OpenView&& other)
: ReadView (std::move(other))
, TxsRawView (std::move(other))
, txs_ (std::move(other.txs_))
, info_ (std::move(other.info_))
, base_ (std::move(other.base_))
, items_ (std::move(other.items_))
, hold_ (std::move(other.hold_))
{
}
#else
OpenView (OpenView&&) = default;
#endif
/** Construct a shallow copy.
Effects:
Creates a new object with a copy of
the modificaiton state table.
The objects managed by shared pointers are
not duplicated but shared between instances.
Since the SLEs are immutable, calls on the
RawView interface cannot break invariants.
*/
OpenView (OpenView const&) = default;
/** Construct an open ledger view.
Effects:
The sequence number is set to the
sequence number of parent plus one.
The parentCloseTime is set to the
closeTime of parent.
If `hold` is not nullptr, retains
ownership of a copy of `hold` until
the MetaView is destroyed.
The tx list starts empty and will contain
all newly inserted tx.
*/
/** @{ */
OpenView (open_ledger_t, ReadView const* base,
std::shared_ptr<void const> hold = nullptr);
OpenView (open_ledger_t, std::shared_ptr<
ReadView const> const& base)
: OpenView (open_ledger, &*base, base)
{
}
/** @} */
/** Construct a new last closed ledger.
Effects:
The LedgerInfo is copied from the base.
The tx list starts empty and will contain
all newly inserted tx.
*/
OpenView (ReadView const* base,
std::shared_ptr<void const> hold = nullptr);
/** Return the number of tx inserted since creation.
This is used to set the "apply ordinal"
when calculating transaction metadata.
*/
std::size_t
txCount() const;
/** Apply changes. */
void
apply (TxsRawView& to) const;
// ReadView
LedgerInfo const&
info() const override;
Fees const&
fees() const override;
bool
exists (Keylet const& k) const override;
boost::optional<key_type>
succ (key_type const& key, boost::optional<
key_type> last = boost::none) const override;
std::shared_ptr<SLE const>
read (Keylet const& k) const override;
std::unique_ptr<txs_type::iter_base>
txsBegin() const override;
std::unique_ptr<txs_type::iter_base>
txsEnd() const override;
bool
txExists (key_type const& key) const override;
tx_type
txRead (key_type const& key) const override;
// RawView
void
rawErase (std::shared_ptr<
SLE> const& sle) override;
void
rawInsert (std::shared_ptr<
SLE> const& sle) override;
void
rawReplace (std::shared_ptr<
SLE> const& sle) override;
void
rawDestroyXRP(
std::uint64_t feeDrops) override;
// TxsRawView
void
rawTxInsert (key_type const& key,
std::shared_ptr<Serializer const>
const& txn, std::shared_ptr<
Serializer const>
const& metaData) override;
};
} // ripple
#endif

View File

@@ -0,0 +1,181 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_PAYMENTSANDBOX_H_INCLUDED
#define RIPPLE_LEDGER_PAYMENTSANDBOX_H_INCLUDED
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/Sandbox.h>
#include <ripple/ledger/detail/ApplyViewBase.h>
#include <ripple/protocol/AccountID.h>
#include <map>
#include <utility>
namespace ripple {
namespace detail {
// VFALCO TODO Inline this implementation
// into the PaymentSandbox class itself
class DeferredCredits
{
public:
// Get the adjusted balance of main for the
// balance between main and other.
STAmount
adjustedBalance (AccountID const& main,
AccountID const& other,
STAmount const& curBalance) const;
void credit (AccountID const& sender,
AccountID const& receiver,
STAmount const& amount);
void apply (DeferredCredits& to);
// VFALCO Is this needed?
// DEPRECATED
void clear ();
private:
// lowAccount, highAccount
using Key = std::tuple<
AccountID, AccountID, Currency>;
// lowAccountCredits, highAccountCredits
using Value = std::tuple<
STAmount, STAmount>;
static
Key
makeKey (AccountID const& a1,
AccountID const& a2,
Currency const& c);
std::map<Key, Value> map_;
};
} // detail
//------------------------------------------------------------------------------
/** A wrapper which makes credits unavailable to balances.
This is used for payments and pathfinding, so that consuming
liquidity from a path never causes portions of that path or
other paths to gain liquidity.
The behavior of certain free functions in the ApplyView API
will change via the balanceHook and creditHook overrides
of PaymentSandbox.
@note Presented as ApplyView to clients
*/
class PaymentSandbox
: public detail::ApplyViewBase
{
public:
PaymentSandbox() = delete;
PaymentSandbox (PaymentSandbox const&) = delete;
PaymentSandbox& operator= (PaymentSandbox&&) = delete;
PaymentSandbox& operator= (PaymentSandbox const&) = delete;
#ifdef _MSC_VER
PaymentSandbox (PaymentSandbox&& other)
: ApplyViewBase (std::move(other))
, tab_ (std::move(other.tab_))
, ps_ (std::move(other.ps_))
{
}
#else
PaymentSandbox (PaymentSandbox&&) = default;
#endif
PaymentSandbox (ReadView const* base,
ApplyFlags flags)
: ApplyViewBase (base, flags)
{
}
PaymentSandbox (ApplyView const* base)
: ApplyViewBase (base, base->flags())
{
}
/** Construct on top of existing PaymentSandbox.
The changes are pushed to the parent when
apply() is called.
@param parent A non-null pointer to the parent.
@note A pointer is used to prevent confusion
with copy construction.
*/
// VFALCO If we are constructing on top of a PaymentSandbox,
// or a PaymentSandbox-derived class, we MUST go through
// one of these constructors or invariants will be broken.
/** @{ */
explicit
PaymentSandbox (PaymentSandbox const* base)
: ApplyViewBase (base, base->flags())
, ps_ (base)
{
}
explicit
PaymentSandbox (PaymentSandbox* base)
: ApplyViewBase (base, base->flags())
, ps_ (base)
{
}
/** @} */
STAmount
balanceHook (AccountID const& account,
AccountID const& issuer,
STAmount const& amount) const override;
void
creditHook (AccountID const& from,
AccountID const& to,
STAmount const& amount) override;
/** Apply changes to base view.
`to` must contain contents identical to the parent
view passed upon construction, else undefined
behavior will result.
*/
/** @{ */
void
apply (RawView& to);
void
apply (PaymentSandbox& to);
/** @} */
private:
detail::DeferredCredits tab_;
PaymentSandbox const* ps_ = nullptr;
};
} // ripple
#endif

116
src/ripple/ledger/RawView.h Normal file
View File

@@ -0,0 +1,116 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_RAWVIEW_H_INCLUDED
#define RIPPLE_LEDGER_RAWVIEW_H_INCLUDED
#include <ripple/ledger/ReadView.h>
#include <ripple/protocol/Serializer.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <boost/optional.hpp>
#include <cstdint>
#include <memory>
#include <utility>
namespace ripple {
/** Interface for ledger entry changes.
Subclasses allow raw modification of ledger entries.
*/
class RawView
{
public:
virtual ~RawView() = default;
/** Delete an existing state item.
The SLE is provided so the implementation
can calculate metadata.
*/
virtual
void
rawErase (std::shared_ptr<SLE> const& sle) = 0;
/** Unconditionally insert a state item.
Requirements:
The key must not already exist.
Effects:
The key is associated with the SLE.
@note The key is taken from the SLE
*/
virtual
void
rawInsert (std::shared_ptr<SLE> const& sle) = 0;
/** Unconditionally replace a state item.
Requirements:
The key must exist.
Effects:
The key is associated with the SLE.
@note The key is taken from the SLE
*/
virtual
void
rawReplace (std::shared_ptr<SLE> const& sle) = 0;
/** Destroy XRP.
This is used to pay for transaction fees.
*/
virtual
void
rawDestroyXRP (std::uint64_t feeDrops) = 0;
};
//------------------------------------------------------------------------------
/** Interface for changing ledger entries with transactions.
Allows raw modification of ledger entries and insertion
of transactions into the transaction map.
*/
class TxsRawView : public RawView
{
public:
/** Add a transaction to the tx map.
Closed ledgers must have metadata,
while open ledgers omit metadata.
*/
virtual
void
rawTxInsert (ReadView::key_type const& key,
std::shared_ptr<Serializer const>
const& txn, std::shared_ptr<
Serializer const> const& metaData) = 0;
};
} // ripple
#endif

View File

@@ -0,0 +1,295 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_READVIEW_H_INCLUDED
#define RIPPLE_LEDGER_READVIEW_H_INCLUDED
#include <ripple/ledger/detail/ReadViewFwdRange.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/Protocol.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/protocol/STTx.h>
#include <boost/optional.hpp>
#include <cassert>
#include <cstdint>
#include <memory>
namespace ripple {
/** Reflects the fee settings for a particular ledger.
The fees are always the same for any transactions applied
to a ledger. Changes to fees occur in between ledgers.
*/
struct Fees
{
std::uint64_t base = 0; // Reference tx cost (drops)
std::uint32_t units = 0; // Reference fee units
std::uint32_t reserve = 0; // Reserve base (drops)
std::uint32_t increment = 0; // Reserve increment (drops)
Fees() = default;
Fees (Fees const&) = default;
Fees& operator= (Fees const&) = default;
/** Returns the account reserve given the owner count, in drops.
The reserve is calculated as the reserve base plus
the reserve increment times the number of increments.
*/
std::uint64_t
accountReserve (std::size_t ownerCount) const
{
return reserve + ownerCount * increment;
}
};
//------------------------------------------------------------------------------
/** Information about the notional ledger backing the view. */
struct LedgerInfo
{
// Fields for all ledgers
bool open = true;
LedgerIndex seq = 0;
std::uint32_t parentCloseTime = 0;
// Fields for closed ledgers
// Closed means "tx set already determined"
uint256 hash = zero;
//uint256 txHash;
//uint256 stateHash;
//uint256 parentHash;
//std::uint64_t coins = 0;
//bool validated = false;
//int closeTimeRes = 0;
// For closed ledgers, the time the ledger
// closed. For open ledgers, the time the ledger
// will close if there's no transactions.
//
std::uint32_t closeTime = 0;
};
//------------------------------------------------------------------------------
/** A view into a ledger.
This interface provides read access to state
and transaction items. There is no checkpointing
or calculation of metadata.
*/
class ReadView
{
public:
using tx_type =
std::pair<std::shared_ptr<STTx const>,
std::shared_ptr<STObject const>>;
using key_type = uint256;
using mapped_type =
std::shared_ptr<SLE const>;
using sles_type = detail::ReadViewFwdRange<
std::shared_ptr<SLE const>>;
using txs_type =
detail::ReadViewFwdRange<tx_type>;
virtual ~ReadView() = default;
ReadView& operator= (ReadView&& other) = delete;
ReadView& operator= (ReadView const& other) = delete;
ReadView()
: txs(*this)
{
}
ReadView (ReadView const&)
: txs(*this)
{
}
ReadView (ReadView&& other)
: txs(*this)
{
}
/** Returns information about the ledger. */
virtual
LedgerInfo const&
info() const = 0;
/** Returns true if this reflects an open ledger. */
bool
open() const
{
return info().open;
}
/** Returns true if this reflects a closed ledger. */
bool
closed() const
{
return ! info().open;
}
/** Returns the close time of the previous ledger. */
std::uint32_t
parentCloseTime() const
{
return info().parentCloseTime;
}
/** Returns the sequence number of the base ledger. */
LedgerIndex
seq() const
{
return info().seq;
}
/** Returns the fees for the base ledger. */
virtual
Fees const&
fees() const = 0;
/** Determine if a state item exists.
@note This can be more efficient than calling read.
@return `true` if a SLE is associated with the
specified key.
*/
virtual
bool
exists (Keylet const& k) const = 0;
/** Return the key of the next state item.
This returns the key of the first state item
whose key is greater than the specified key. If
no such key is present, boost::none is returned.
If `last` is engaged, returns boost::none when
the key returned would be outside the open
interval (key, last).
*/
virtual
boost::optional<key_type>
succ (key_type const& key, boost::optional<
key_type> last = boost::none) const = 0;
/** Return the state item associated with a key.
Effects:
If the key exists, gives the caller ownership
of the non-modifiable corresponding SLE.
@note While the returned SLE is `const` from the
perspective of the caller, it can be changed
by other callers through raw operations.
@return `nullptr` if the key is not present or
if the type does not match.
*/
virtual
std::shared_ptr<SLE const>
read (Keylet const& k) const = 0;
// Called to adjust returned balances
// This is required to support PaymentSandbox
virtual
STAmount
balanceHook (AccountID const& account,
AccountID const& issuer,
STAmount const& amount) const
{
return amount;
}
// used by the implementation
virtual
std::unique_ptr<txs_type::iter_base>
txsBegin() const = 0;
// used by the implementation
virtual
std::unique_ptr<txs_type::iter_base>
txsEnd() const = 0;
/** Returns `true` if a tx exists in the tx map.
A tx exists in the map if it is part of the
base ledger, or if it is a newly inserted tx.
*/
virtual
bool
txExists (key_type const& key) const = 0;
/** Read a transaction from the tx map.
If the view represents an open ledger,
the metadata object will be empty.
@return A pair of nullptr if the
key is not found in the tx map.
*/
virtual
tx_type
txRead (key_type const& key) const = 0;
//
// Memberspaces
//
// The range of ledger entries
//sles_type sles;
// The range of transactions
txs_type txs;
};
//------------------------------------------------------------------------------
/** ReadView that associates keys with digests. */
class DigestAwareReadView
: public ReadView
{
public:
using digest_type = uint256;
/** Return the digest associated with the key.
@return boost::none if the item does not exist.
*/
virtual
boost::optional<digest_type>
digest (key_type const& key) const = 0;
};
// For now
using BasicView = ReadView;
} // ripple
#include <ripple/ledger/detail/ReadViewFwdRange.ipp>
#endif

View File

@@ -17,36 +17,54 @@
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_CACHEDVIEW_H_INCLUDED
#define RIPPLE_LEDGER_CACHEDVIEW_H_INCLUDED
#ifndef RIPPLE_LEDGER_SANDBOX_H_INCLUDED
#define RIPPLE_LEDGER_SANDBOX_H_INCLUDED
#include <ripple/app/ledger/Ledger.h>
#include <ripple/ledger/SLECache.h>
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/detail/ApplyViewBase.h>
namespace ripple {
/** Cache-aware view to a ledger */
class CachedView : public BasicViewWrapper<Ledger&>
{
private:
SLECache& cache_;
/** Discardable, editable view to a ledger.
public:
CachedView(CachedView const&) = delete;
CachedView& operator=(CachedView const&) = delete;
The sandbox inherits the flags of the base.
/** Wrap a ledger with a cache.
@note Only ledgers may be wrapped with a cache.
@note Presented as ApplyView to clients.
*/
CachedView (Ledger& ledger,
SLECache& cache)
: BasicViewWrapper(ledger)
, cache_(cache)
class Sandbox
: public detail::ApplyViewBase
{
public:
Sandbox() = delete;
Sandbox (Sandbox const&) = delete;
Sandbox& operator= (Sandbox&&) = delete;
Sandbox& operator= (Sandbox const&) = delete;
#ifdef _MSC_VER
Sandbox (Sandbox&& other)
: ApplyViewBase (std::move(other))
{
}
#else
Sandbox (Sandbox&&) = default;
#endif
Sandbox (ReadView const* base,
ApplyFlags flags)
: ApplyViewBase (base, flags)
{
}
std::shared_ptr<SLE const>
read (Keylet const& k) const override;
Sandbox (ApplyView const* base)
: Sandbox (base, base->flags())
{
}
void
apply (RawView& to)
{
items_.apply(to);
}
};
} // ripple

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_APPLYSTATETABLE_H_INCLUDED
#define RIPPLE_LEDGER_APPLYSTATETABLE_H_INCLUDED
#include <ripple/ledger/OpenView.h>
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/protocol/TER.h>
#include <beast/utility/Journal.h>
#include <memory>
// VFALCO TODO Move TxMeta to ripple/ledger/
#include <ripple/app/ledger/TxMeta.h>
namespace ripple {
namespace detail {
// Helper class that buffers modifications
class ApplyStateTable
{
public:
using key_type = ReadView::key_type;
private:
enum class Action
{
cache,
erase,
insert,
modify,
};
using items_t = std::map<key_type,
std::pair<Action, std::shared_ptr<SLE>>>;
items_t items_;
std::uint64_t dropsDestroyed_ = 0;
public:
ApplyStateTable() = default;
ApplyStateTable (ApplyStateTable const&) = delete;
ApplyStateTable& operator= (ApplyStateTable&&) = delete;
ApplyStateTable& operator= (ApplyStateTable const&) = delete;
#ifdef _MSC_VER
ApplyStateTable (ApplyStateTable&& other)
: items_ (std::move(other.items_))
, dropsDestroyed_ (std::move(other.dropsDestroyed_))
{
}
#else
ApplyStateTable (ApplyStateTable&&) = default;
#endif
void
apply (RawView& to) const;
void
apply (OpenView& to, STTx const& tx,
TER ter, boost::optional<
STAmount> const& deliver,
beast::Journal j);
bool
exists (ReadView const& base,
Keylet const& k) const;
boost::optional<key_type>
succ (ReadView const& base,
key_type const& key, boost::optional<
key_type> const& last) const;
std::shared_ptr<SLE const>
read (ReadView const& base,
Keylet const& k) const;
std::shared_ptr<SLE>
peek (ReadView const& base,
Keylet const& k);
void
erase (ReadView const& base,
std::shared_ptr<SLE> const& sle);
void
rawErase (ReadView const& base,
std::shared_ptr<SLE> const& sle);
void
insert(ReadView const& base,
std::shared_ptr<SLE> const& sle);
void
update(ReadView const& base,
std::shared_ptr<SLE> const& sle);
void
replace(ReadView const& base,
std::shared_ptr<SLE> const& sle);
void
destroyXRP (std::uint64_t feeDrops);
private:
using Mods = hash_map<key_type,
std::shared_ptr<SLE>>;
static
bool
threadTx (TxMeta& meta,
std::shared_ptr<SLE> const& to,
Mods& mods);
std::shared_ptr<SLE>
getForMod (ReadView const& base,
key_type const& key, Mods& mods,
beast::Journal j);
bool
threadTx (ReadView const& base, TxMeta& meta,
AccountID const& to, Mods& mods,
beast::Journal j);
bool
threadOwners (ReadView const& base,
TxMeta& meta, std::shared_ptr<
SLE const> const& sle, Mods& mods,
beast::Journal j);
};
} // detail
} // ripple
#endif

View File

@@ -0,0 +1,136 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_APPLYVIEWBASE_H_INCLUDED
#define RIPPLE_LEDGER_APPLYVIEWBASE_H_INCLUDED
#include <ripple/ledger/ApplyView.h>
#include <ripple/ledger/OpenView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/ledger/detail/ApplyStateTable.h>
namespace ripple {
namespace detail {
class ApplyViewBase
: public ApplyView
, public RawView
{
public:
ApplyViewBase() = delete;
ApplyViewBase (ApplyViewBase const&) = delete;
ApplyViewBase& operator= (ApplyViewBase&&) = delete;
ApplyViewBase& operator= (ApplyViewBase const&) = delete;
#ifdef _MSC_VER
ApplyViewBase (ApplyViewBase&& other)
: ApplyView (std::move(other))
, RawView (std::move(other))
, flags_ (std::move(other.flags_))
, base_ (std::move(other.base_))
, items_ (std::move(other.items_))
, dropsDestroyed_ (std::move(other.dropsDestroyed_))
{
}
#else
ApplyViewBase (ApplyViewBase&&) = default;
#endif
ApplyViewBase (ReadView const* base,
ApplyFlags flags);
// ReadView
LedgerInfo const&
info() const override;
Fees const&
fees() const override;
bool
exists (Keylet const& k) const override;
boost::optional<key_type>
succ (key_type const& key, boost::optional<
key_type> last = boost::none) const override;
std::shared_ptr<SLE const>
read (Keylet const& k) const override;
std::unique_ptr<txs_type::iter_base>
txsBegin() const override;
std::unique_ptr<txs_type::iter_base>
txsEnd() const override;
bool
txExists (key_type const& key) const override;
tx_type
txRead (key_type const& key) const override;
// ApplyView
ApplyFlags
flags() const override;
std::shared_ptr<SLE>
peek (Keylet const& k) override;
void
erase (std::shared_ptr<
SLE> const& sle) override;
void
insert (std::shared_ptr<
SLE> const& sle) override;
void
update (std::shared_ptr<
SLE> const& sle) override;
// RawView
void
rawErase (std::shared_ptr<
SLE> const& sle) override;
void
rawInsert (std::shared_ptr<
SLE> const& sle) override;
void
rawReplace (std::shared_ptr<
SLE> const& sle) override;
void
rawDestroyXRP (
std::uint64_t feeDrops) override;
protected:
ApplyFlags flags_;
ReadView const* base_;
detail::ApplyStateTable items_;
std::uint64_t dropsDestroyed_ = 0;
};
} // detail
} // ripple
#endif

View File

@@ -0,0 +1,98 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED
#define RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <map>
#include <utility>
namespace ripple {
namespace detail {
// Helper class that buffers raw modifications
class RawStateTable
{
public:
using key_type = ReadView::key_type;
RawStateTable() = default;
RawStateTable (RawStateTable const&) = default;
RawStateTable& operator= (RawStateTable&&) = delete;
RawStateTable& operator= (RawStateTable const&) = delete;
#ifdef _MSC_VER
RawStateTable (RawStateTable&& other)
: items_ (std::move(other.items_))
, dropsDestroyed_ (std::move(other.dropsDestroyed_))
{
}
#else
RawStateTable (RawStateTable&&) = default;
#endif
void
apply (RawView& to) const;
bool
exists (ReadView const& base,
Keylet const& k) const;
boost::optional<key_type>
succ (ReadView const& base,
key_type const& key, boost::optional<
key_type> const& last) const;
void
erase (std::shared_ptr<SLE> const& sle);
void
insert (std::shared_ptr<SLE> const& sle);
void
replace (std::shared_ptr<SLE> const& sle);
std::shared_ptr<SLE const>
read (ReadView const& base,
Keylet const& k) const;
void
destroyXRP (std::uint64_t feeDrops);
private:
enum class Action
{
erase,
insert,
replace,
};
using items_t = std::map<key_type,
std::pair<Action, std::shared_ptr<SLE>>>;
items_t items_;
std::uint64_t dropsDestroyed_ = 0;
};
} // detail
} // ripple
#endif

View File

@@ -0,0 +1,172 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_READVIEWFWDRANGE_H_INCLUDED
#define RIPPLE_LEDGER_READVIEWFWDRANGE_H_INCLUDED
#include <cstddef>
#include <iterator>
#include <memory>
#include <boost/optional.hpp>
namespace ripple {
class ReadView;
namespace detail {
// A type-erased ForwardIterator
//
template <class ValueType>
class ReadViewFwdIter
{
public:
using base_type = ReadViewFwdIter;
using value_type = ValueType;
ReadViewFwdIter() = default;
ReadViewFwdIter(ReadViewFwdIter const&) = default;
ReadViewFwdIter& operator=(ReadViewFwdIter const&) = default;
virtual
~ReadViewFwdIter() = default;
virtual
std::unique_ptr<ReadViewFwdIter>
copy() const = 0;
virtual
bool
equal (ReadViewFwdIter const& impl) const = 0;
virtual
void
increment() = 0;
virtual
value_type
dereference() const = 0;
};
// A range using type-erased ForwardIterator
//
template<class ValueType>
class ReadViewFwdRange
{
public:
using iter_base =
ReadViewFwdIter<ValueType>;
class iterator
{
public:
using value_type = ValueType;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type =
std::ptrdiff_t;
using iterator_category =
std::forward_iterator_tag;
iterator() = default;
iterator (iterator const& other);
iterator (iterator&& other);
// Used by the implementation
explicit
iterator (ReadView const* view,
std::unique_ptr<iter_base> impl);
iterator&
operator= (iterator const& other);
iterator&
operator= (iterator&& other);
bool
operator== (iterator const& other) const;
bool
operator!= (iterator const& other) const;
// Can throw
reference
operator*() const;
// Can throw
pointer
operator->() const;
iterator&
operator++();
iterator
operator++(int);
private:
ReadView const* view_ = nullptr;
std::unique_ptr<iter_base> impl_;
boost::optional<value_type> mutable cache_;
};
using const_iterator = iterator;
using value_type = ValueType;
ReadViewFwdRange() = delete;
ReadViewFwdRange (ReadViewFwdRange const&) = default;
ReadViewFwdRange& operator= (ReadViewFwdRange const&) = default;
/** Returns `true` if the range is empty. */
bool
empty() const;
/** Return iterator to the beginning of the range. */
iterator
begin() const;
/** Return iterator to one past the end of the range. */
iterator const&
end() const;
// VFALCO Otherwise causes errors on clang
//private:
// friend class ReadView;
explicit
ReadViewFwdRange (ReadView const& view)
: view_ (&view)
{
}
private:
ReadView const* view_;
boost::optional<iterator> mutable end_;
};
} // detail
} // ripple
#endif

View File

@@ -0,0 +1,166 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_READVIEWFWDRANGEINL_H_INCLUDED
#define RIPPLE_LEDGER_READVIEWFWDRANGEINL_H_INCLUDED
namespace ripple {
namespace detail {
template<class ValueType>
ReadViewFwdRange<ValueType>::iterator::iterator(
iterator const& other)
: view_ (other.view_)
, impl_ (other.impl_->copy())
, cache_ (other.cache_)
{
}
template<class ValueType>
ReadViewFwdRange<ValueType>::iterator::iterator(
iterator&& other)
: view_ (other.view_)
, impl_ (std::move(other.impl_))
, cache_ (std::move(other.cache_))
{
}
template<class ValueType>
ReadViewFwdRange<ValueType>::iterator::iterator(
ReadView const* view,
std::unique_ptr<iter_base> impl)
: view_ (view)
, impl_ (std::move(impl))
{
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::iterator::operator=(
iterator const& other) ->
iterator&
{
if (this == &other)
return *this;
view_ = other.view_;
impl_ = other.impl_->copy();
cache_ = other.cache_;
return *this;
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::iterator::operator=(
iterator&& other) ->
iterator&
{
view_ = other.view_;
impl_ = std::move(other.impl_);
cache_ = std::move(other.cache_);
return *this;
}
template<class ValueType>
bool
ReadViewFwdRange<ValueType>::iterator::operator==(
iterator const& other) const
{
assert(view_ == other.view_);
return impl_->equal(*other.impl_);
}
template<class ValueType>
bool
ReadViewFwdRange<ValueType>::iterator::operator!=(
iterator const& other) const
{
return ! (*this == other);
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::iterator::operator*() const ->
reference
{
if (! cache_)
cache_ = impl_->dereference();
return *cache_;
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::iterator::operator->() const ->
pointer
{
return &**this;
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::iterator::operator++() ->
iterator&
{
impl_->increment();
cache_ = boost::none;
return *this;
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::iterator::operator++(int) ->
iterator
{
iterator prev(view_,
impl_->copy());
prev.cache_ = std::move(cache_);
++(*this);
return prev;
}
//------------------------------------------------------------------------------
template<class ValueType>
bool
ReadViewFwdRange<ValueType>::empty() const
{
return begin() == end();
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::begin() const ->
iterator
{
return iterator(view_, view_->txsBegin());
}
template<class ValueType>
auto
ReadViewFwdRange<ValueType>::end() const ->
iterator const&
{
if (! end_)
end_.emplace(view_, view_->txsEnd());
return *end_;
}
} // detail
} // ripple
#endif

View 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

View 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

View File

@@ -17,21 +17,25 @@
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_SLECACHE_H_INCLUDED
#define RIPPLE_LEDGER_SLECACHE_H_INCLUDED
#include <ripple/basics/TaggedCache.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <BeastConfig.h>
#include <ripple/ledger/ApplyViewImpl.h>
#include <ripple/basics/contract.h>
namespace ripple {
/** STLedgerEntry cache.
This maps keys to the deserialized ledger entries,
to improve performance where the same item in
the ledger is accessed often.
*/
using SLECache = TaggedCache <uint256, STLedgerEntry>;
ApplyViewImpl::ApplyViewImpl(
ReadView const* base,
ApplyFlags flags)
: ApplyViewBase (base, flags)
{
}
#endif
void
ApplyViewImpl::apply (OpenView& to,
STTx const& tx, TER ter,
beast::Journal j)
{
items_.apply(to, tx, ter, deliver_, j);
}
} // ripple

View File

@@ -18,36 +18,45 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/protocol/Serializer.h>
#include <ripple/ledger/CachedSLEs.h>
#include <vector>
namespace ripple {
std::shared_ptr<SLE const>
CachedView::read (Keylet const& k) const
void
CachedSLEs::expire()
{
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))
std::vector<
std::shared_ptr<void const>> trash;
{
if(! k.check(*sle))
return nullptr;
return sle;
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);
}
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);
}
}
}
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

View 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

View 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

View File

@@ -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

View 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

View File

@@ -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)

View File

@@ -21,7 +21,6 @@
#include <ripple/app/ledger/tests/common_ledger.h>
#include <ripple/app/tx/impl/BookTip.h>
#include <ripple/basics/Log.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/test/jtx.h>

View File

@@ -18,14 +18,14 @@
//==============================================================================
#include <ripple/app/ledger/tests/common_ledger.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/app/paths/impl/PaymentView.h>
#include <ripple/app/tx/tests/PathSet.h>
#include <ripple/ledger/ApplyViewImpl.h>
#include <ripple/ledger/PaymentSandbox.h>
#include <ripple/ledger/tests/PathSet.h>
namespace ripple {
namespace test {
class DeferredCredits_test : public beast::unit_test::suite
class PaymentSandbox_test : public beast::unit_test::suite
{
/*
Create paths so one path funds another path.
@@ -118,46 +118,46 @@ class DeferredCredits_test : public beast::unit_test::suite
STAmount const toDebit (USD_gw1 (20));
{
// accountSend, no deferredCredits
MetaView les (*env.open(), tapNONE);
ApplyViewImpl av (&*env.open(), tapNONE);
auto const iss = USD_gw1.issue ();
auto const startingAmount = accountHolds (
les, alice, iss.currency, iss.account, fhIGNORE_FREEZE, getConfig ());
av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, getConfig ());
accountSend (les, gw1, alice, toCredit);
expect (accountHolds (les, alice, iss.currency, iss.account,
accountSend (av, gw1, alice, toCredit);
expect (accountHolds (av, alice, iss.currency, iss.account,
fhIGNORE_FREEZE, getConfig ()) ==
startingAmount + toCredit);
accountSend (les, alice, gw1, toDebit);
expect (accountHolds (les, alice, iss.currency, iss.account,
accountSend (av, alice, gw1, toDebit);
expect (accountHolds (av, alice, iss.currency, iss.account,
fhIGNORE_FREEZE, getConfig ()) ==
startingAmount + toCredit - toDebit);
}
{
// rippleCredit, no deferredCredits
MetaView les (*env.open(), tapNONE);
ApplyViewImpl av (&*env.open(), tapNONE);
auto const iss = USD_gw1.issue ();
auto const startingAmount = accountHolds (
les, alice, iss.currency, iss.account, fhIGNORE_FREEZE, getConfig ());
av, alice, iss.currency, iss.account, fhIGNORE_FREEZE, getConfig ());
rippleCredit (les, gw1, alice, toCredit, true);
expect (accountHolds (les, alice, iss.currency, iss.account,
rippleCredit (av, gw1, alice, toCredit, true);
expect (accountHolds (av, alice, iss.currency, iss.account,
fhIGNORE_FREEZE, getConfig ()) ==
startingAmount + toCredit);
rippleCredit (les, alice, gw1, toDebit, true);
expect (accountHolds (les, alice, iss.currency, iss.account,
rippleCredit (av, alice, gw1, toDebit, true);
expect (accountHolds (av, alice, iss.currency, iss.account,
fhIGNORE_FREEZE, getConfig ()) ==
startingAmount + toCredit - toDebit);
}
{
// accountSend, w/ deferredCredits
MetaView les (*env.open(), tapNONE);
PaymentView pv (les, tapNONE);
ApplyViewImpl av (&*env.open(), tapNONE);
PaymentSandbox pv (&av);
auto const iss = USD_gw1.issue ();
auto const startingAmount = accountHolds (
@@ -176,8 +176,8 @@ class DeferredCredits_test : public beast::unit_test::suite
{
// rippleCredit, w/ deferredCredits
MetaView les (*env.open(), tapNONE);
PaymentView pv (les, tapNONE);
ApplyViewImpl av (&*env.open(), tapNONE);
PaymentSandbox pv (&av);
auto const iss = USD_gw1.issue ();
auto const startingAmount = accountHolds (
@@ -191,8 +191,8 @@ class DeferredCredits_test : public beast::unit_test::suite
{
// redeemIOU, w/ deferredCredits
MetaView les (*env.open(), tapNONE);
PaymentView pv (les, tapNONE);
ApplyViewImpl av (&*env.open(), tapNONE);
PaymentSandbox pv (&av);
auto const iss = USD_gw1.issue ();
auto const startingAmount = accountHolds (
@@ -206,8 +206,8 @@ class DeferredCredits_test : public beast::unit_test::suite
{
// issueIOU, w/ deferredCredits
MetaView les (*env.open(), tapNONE);
PaymentView pv (les, tapNONE);
ApplyViewImpl av (&*env.open(), tapNONE);
PaymentSandbox pv (&av);
auto const iss = USD_gw1.issue ();
auto const startingAmount = accountHolds (
@@ -221,8 +221,8 @@ class DeferredCredits_test : public beast::unit_test::suite
{
// accountSend, w/ deferredCredits and stacked views
MetaView les (*env.open(), tapNONE);
PaymentView pv (les, tapNONE);
ApplyViewImpl av (&*env.open(), tapNONE);
PaymentSandbox pv (&av);
auto const iss = USD_gw1.issue ();
auto const startingAmount = accountHolds (
@@ -234,7 +234,7 @@ class DeferredCredits_test : public beast::unit_test::suite
startingAmount);
{
PaymentView pv2(&pv);
PaymentSandbox pv2(&pv);
expect (accountHolds (pv2, alice, iss.currency, iss.account,
fhIGNORE_FREEZE, getConfig ()) ==
startingAmount);
@@ -259,7 +259,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE (DeferredCredits, ledger, ripple);
BEAST_DEFINE_TESTSUITE (PaymentSandbox, ledger, ripple);
} // test
} // ripple

View File

@@ -20,14 +20,16 @@
#include <BeastConfig.h>
#include <ripple/test/jtx.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/app/paths/impl/PaymentView.h>
#include <ripple/ledger/ApplyViewImpl.h>
#include <ripple/ledger/OpenView.h>
#include <ripple/ledger/PaymentSandbox.h>
#include <ripple/ledger/Sandbox.h>
#include <beast/cxx14/type_traits.h> // <type_traits>
namespace ripple {
namespace test {
class MetaView_test
class View_test
: public beast::unit_test::suite
{
// Convert a small integer to a key
@@ -75,7 +77,7 @@ class MetaView_test
wipe (OpenLedger& openLedger)
{
openLedger.modify(
[](View& view, beast::Journal)
[](OpenView& view, beast::Journal)
{
// HACK!
boost::optional<uint256> next;
@@ -85,8 +87,8 @@ class MetaView_test
next = view.succ(*next);
if (! next)
break;
view.erase(view.peek(
keylet::unchecked(*next)));
view.rawErase(std::make_shared<SLE>(
*view.read(keylet::unchecked(*next))));
}
return true;
});
@@ -104,13 +106,14 @@ class MetaView_test
next = ledger.succ(*next);
if (! next)
break;
ledger.unchecked_erase(*next);
ledger.rawErase(std::make_shared<SLE>(
*ledger.read(keylet::unchecked(*next))));
}
}
// Test succ correctness
void
succ (BasicView const& v,
succ (ReadView const& v,
std::uint32_t id,
boost::optional<
std::uint32_t> answer)
@@ -139,7 +142,7 @@ class MetaView_test
std::remove_const_t<T>>(*sp);
}
// Exercise Ledger implementation of View
// Exercise Ledger implementation of ApplyView
void
testLedger()
{
@@ -149,26 +152,25 @@ class MetaView_test
std::make_shared<Ledger>(
master.pk(), 1000000000);
wipe(*ledger);
BasicView& v = *ledger;
ReadView& v = *ledger;
succ(v, 0, boost::none);
v.unchecked_insert(sle(1, 1));
ledger->rawInsert(sle(1, 1));
expect(v.exists(k(1)));
expect(seq(v.read(k(1))) == 1);
succ(v, 0, 1);
succ(v, 1, boost::none);
v.unchecked_insert(sle(2, 2));
ledger->rawInsert(sle(2, 2));
expect(seq(v.read(k(2))) == 2);
v.unchecked_insert(sle(3, 3));
ledger->rawInsert(sle(3, 3));
expect(seq(v.read(k(3))) == 3);
auto s = copy(v.read(k(2)));
seq(s, 4);
v.unchecked_replace(std::move(s));
ledger->rawReplace(std::move(s));
expect(seq(v.read(k(2))) == 4);
expect(v.unchecked_erase(k(2).key));
ledger->rawErase(sle(2));
expect(! v.exists(k(2)));
expect(v.exists(k(1)));
expect(v.exists(k(3)));
expect(! v.unchecked_erase(k(5).key));
}
void
@@ -178,7 +180,7 @@ class MetaView_test
Env env(*this);
wipe(env.openLedger);
auto const open = env.open();
MetaView v(*open, tapNONE);
ApplyViewImpl v(&*open, tapNONE);
succ(v, 0, boost::none);
v.insert(sle(1));
expect(v.exists(k(1)));
@@ -209,13 +211,13 @@ class MetaView_test
Env env(*this);
wipe(env.openLedger);
auto const open = env.open();
MetaView v0(*open, tapNONE);
v0.unchecked_insert(sle(1));
v0.unchecked_insert(sle(2));
v0.unchecked_insert(sle(4));
v0.unchecked_insert(sle(7));
ApplyViewImpl v0(&*open, tapNONE);
v0.insert(sle(1));
v0.insert(sle(2));
v0.insert(sle(4));
v0.insert(sle(7));
{
MetaView v1(v0, tapNONE);
Sandbox v1(&v0);
v1.insert(sle(3));
v1.insert(sle(5));
v1.insert(sle(6));
@@ -273,13 +275,13 @@ class MetaView_test
Env env(*this);
wipe(env.openLedger);
auto const open = env.open();
MetaView v0 (*open, tapNONE);
v0.unchecked_insert(sle(1, 1));
v0.unchecked_insert(sle(2, 2));
v0.unchecked_insert(sle(4, 4));
ApplyViewImpl v0 (&*open, tapNONE);
v0.rawInsert(sle(1, 1));
v0.rawInsert(sle(2, 2));
v0.rawInsert(sle(4, 4));
{
MetaView v1(v0, tapNONE);
Sandbox v1(&v0);
v1.erase(v1.peek(k(2)));
v1.insert(sle(3, 3));
auto s = v1.peek(k(4));
@@ -290,7 +292,7 @@ class MetaView_test
expect(seq(v1.read(k(3))) == 3);
expect(seq(v1.read(k(4))) == 5);
{
MetaView v2(v1, tapNONE);
Sandbox v2(&v1);
auto s = v2.peek(k(3));
seq(s, 6);
v2.update(s);
@@ -307,7 +309,7 @@ class MetaView_test
expect(seq(v1.read(k(4))) == 5);
{
MetaView v2(v1, tapNONE);
Sandbox v2(&v1);
auto s = v2.peek(k(3));
seq(s, 6);
v2.update(s);
@@ -339,42 +341,43 @@ class MetaView_test
Env env(*this);
wipe(env.openLedger);
auto const open = env.open();
MetaView v0(*open, tapNONE);
OpenView v0(open.get());
expect(v0.seq() != 98);
expect(v0.seq() == open->seq());
expect(v0.parentCloseTime() != 99);
expect(v0.parentCloseTime() ==
open->parentCloseTime());
expect(v0.flags() == tapNONE);
{
MetaView v1(shallow_copy, v0);
// shallow copy
OpenView v1(v0);
expect (v1.seq() == v0.seq());
expect (v1.parentCloseTime() ==
v1.parentCloseTime());
expect (v1.flags() == tapNONE);
MetaView v2(v1, tapNO_CHECK_SIGN);
ApplyViewImpl v2(&v1, tapNO_CHECK_SIGN);
expect(v2.parentCloseTime() ==
v1.parentCloseTime());
expect(v2.seq() == v1.seq());
expect(v2.flags() == tapNO_CHECK_SIGN);
MetaView v3(v2, tapNONE);
Sandbox v3(&v2);
expect(v3.seq() == v2.seq());
expect(v3.parentCloseTime() ==
v2.parentCloseTime());
expect(v3.flags() == tapNONE);
expect(v3.flags() == tapNO_CHECK_SIGN);
}
{
PaymentView v1(v0, tapNO_CHECK_SIGN);
expect(v1.seq() == v0.seq());
expect(v1.parentCloseTime() ==
v0.parentCloseTime());
expect(v1.flags() == tapNO_CHECK_SIGN);
PaymentView v2(&v1);
expect(v2.seq() == v1.seq());
ApplyViewImpl v1(&v0, tapNO_CHECK_SIGN);
PaymentSandbox v2(&v1);
expect(v2.seq() == v0.seq());
expect(v2.parentCloseTime() ==
v1.parentCloseTime());
expect(v2.flags() == v1.flags());
v0.parentCloseTime());
expect(v2.flags() == tapNO_CHECK_SIGN);
PaymentSandbox v3(&v2);
expect(v3.seq() == v2.seq());
expect(v3.parentCloseTime() ==
v2.parentCloseTime());
expect(v3.flags() == v2.flags());
}
}
}
@@ -385,7 +388,7 @@ class MetaView_test
using namespace jtx;
// Create a ledger with 1 item, put a
// MetaView on that, then another MetaView,
// ApplyView on that, then another ApplyView,
// erase the item, apply.
{
Account const master("master");
@@ -393,11 +396,11 @@ class MetaView_test
std::make_shared<Ledger>(
master.pk(), 1000000000);
wipe(*ledger);
BasicView& v0 = *ledger;
v0.unchecked_insert(sle(1));
MetaView v1(v0, tapNONE);
ledger->rawInsert(sle(1));
ReadView& v0 = *ledger;
ApplyViewImpl v1(&v0, tapNONE);
{
MetaView v2(v1, tapNONE);
Sandbox v2(&v1);
v2.erase(v2.peek(k(1)));
v2.apply(v1);
}
@@ -420,7 +423,7 @@ class MetaView_test
}
};
BEAST_DEFINE_TESTSUITE(MetaView,app,ripple);
BEAST_DEFINE_TESTSUITE(View,ledger,ripple);
} // test
} // ripple

View File

@@ -99,6 +99,10 @@ public:
STObject (const SOTemplate & type, SField const& name);
STObject (const SOTemplate & type, SerialIter & sit, SField const& name);
STObject (SerialIter& sit, SField const& name);
STObject (SerialIter&& sit, SField const& name)
: STObject(sit, name)
{
}
STObject& operator= (STObject const&) = default;
STObject& operator= (STObject&& other);

View File

@@ -59,8 +59,7 @@ Json::Value doAccountInfo (RPC::Context& context)
return jvAccepted;
auto const sleAccepted = cachedRead(*ledger,
keylet::account(accountID).key,
getApp().getSLECache(), ltACCOUNT_ROOT);
keylet::account(accountID).key, ltACCOUNT_ROOT);
if (sleAccepted)
{
@@ -68,8 +67,7 @@ Json::Value doAccountInfo (RPC::Context& context)
// See if there's a SignerEntries for this account.
uint256 const signerListIndex = getSignerListIndex (accountID);
auto const signerList = cachedRead(*ledger, signerListIndex,
getApp().getSLECache());
auto const signerList = cachedRead(*ledger, signerListIndex);
if (signerList)
{

View File

@@ -19,7 +19,6 @@
#include <BeastConfig.h>
#include <ripple/app/main/Application.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/rpc/impl/Tuning.h>
#include <ripple/app/paths/RippleState.h>
@@ -152,8 +151,7 @@ Json::Value doAccountLines (RPC::Context& context)
return RPC::expected_field_error (jss::marker, "string");
startAfter.SetHex (marker.asString ());
auto const sleLine = cachedRead(*ledger, startAfter,
getApp().getSLECache());
auto const sleLine = cachedRead(*ledger, startAfter);
if (sleLine == nullptr || sleLine->getType () != ltRIPPLE_STATE)
return rpcError (rpcINVALID_PARAMS);
@@ -181,9 +179,8 @@ Json::Value doAccountLines (RPC::Context& context)
}
{
CachedView const view(
*ledger, getApp().getSLECache());
if (! forEachItemAfter(view, accountID,
// VFALCO Needs a caching view here
if (! forEachItemAfter(*ledger, accountID,
startAfter, startHint, reserve,
[&visitData](std::shared_ptr<SLE const> const& sleCur)
{

View File

@@ -19,7 +19,6 @@
#include <BeastConfig.h>
#include <ripple/app/main/Application.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/rpc/impl/Tuning.h>
namespace ripple {
@@ -96,8 +95,7 @@ Json::Value doAccountOffers (RPC::Context& context)
return RPC::expected_field_error (jss::marker, "string");
startAfter.SetHex (marker.asString ());
auto const sleOffer = cachedRead (*ledger, startAfter,
getApp().getSLECache());
auto const sleOffer = cachedRead (*ledger, startAfter);
if (sleOffer == nullptr ||
sleOffer->getType () != ltOFFER ||
@@ -125,8 +123,6 @@ Json::Value doAccountOffers (RPC::Context& context)
}
{
CachedView const view(
*ledger, getApp().getSLECache());
if (! forEachItemAfter(*ledger, accountID,
startAfter, startHint, reserve,
[&offers](std::shared_ptr<SLE const> const& offer)

View File

@@ -19,7 +19,6 @@
#include <BeastConfig.h>
#include <ripple/app/main/Application.h>
#include <ripple/ledger/CachedView.h>
#include <ripple/rpc/impl/AccountFromString.h>
#include <ripple/rpc/impl/LookupLedger.h>
#include <ripple/app/paths/RippleState.h>
@@ -137,9 +136,7 @@ Json::Value doGatewayBalances (RPC::Context& context)
// Traverse the cold wallet's trust lines
{
CachedView const view(
*ledger, getApp().getSLECache());
forEachItem(view, accountID,
forEachItem(*ledger, accountID,
[&](std::shared_ptr<SLE const> const& sle)
{
auto rs = RippleState::makeItem (accountID, sle);

View File

@@ -21,6 +21,7 @@
#include <ripple/core/DatabaseCon.h>
#include <ripple/app/ledger/AcceptedLedger.h>
#include <ripple/app/ledger/InboundLedgers.h>
#include <ripple/ledger/CachedSLEs.h>
#include <ripple/basics/UptimeTimer.h>
#include <ripple/nodestore/Database.h>
@@ -72,7 +73,7 @@ Json::Value doGetCounts (RPC::Context& context)
ret[jss::historical_perminute] = static_cast<int>(
app.getInboundLedgers().fetchRate());
ret[jss::SLE_hit_rate] = app.getSLECache ().getHitRate ();
ret[jss::SLE_hit_rate] = app.cachedSLEs().rate();
ret[jss::node_hit_rate] = app.getNodeStore ().getCacheHitRate ();
ret[jss::ledger_hit_rate] = app.getLedgerMaster ().getCacheHitRate ();
ret[jss::AL_hit_rate] = AcceptedLedger::getCacheHitRate ();

View File

@@ -202,8 +202,7 @@ Json::Value doLedgerEntry (RPC::Context& context)
if (uNodeIndex.isNonZero ())
{
auto const sleNode = cachedRead(*lpLedger, uNodeIndex,
getApp().getSLECache());
auto const sleNode = cachedRead(*lpLedger, uNodeIndex);
if (context.params.isMember(jss::binary))
bNodeBinary = context.params[jss::binary].asBool();

Some files were not shown because too many files have changed in this diff Show More