Refactor View, MetaView, and tx processing:

This tidies up the View interface and makes transaction
application a free function, with the removal of the
TransactionEngine class. A new class ApplyContext provides
all the state information needed to apply a Transactor. The
Transactor is refactored to perform all the processing
activities previously part of TransactionEngine.

The calculation of metadata from a MetaView is improved.
A new apply function performs all the steps for calculating
and inserting metadata into the tx map.

Transaction processing code path is passed a Config instead
of retrieving the global, and uses the Journal supplied in
the call to apply() consistently.

To support transaction processing and RPC operations, a
new POD type ViewInfo is added which consolidates static
information about open and closed ledgers, such as the ledger
sequence number or the closing times. Ledger and MetaView are
refactored to use this info.

The ViewInfo now contains the "open ledger" setting. The
tapOPEN_LEDGER ViewFlag is removed. The view property of
being an open ledger is obtained from the base or by using
the MetaView constructor which presents a closed ledger as
an open one.

View, MetaView:

* Fix missing includes
* Add apply free function
* Use Journal in TransactionEngine
* Use BasicView in TransactionEngine
* inline NetworkOPs::batchApply
* Add shallow_copy, open_ledger MetaView ctor tags
* Add ViewInfo with open flag, seq, close times
* Make parent_ a reference
* Tidy up ctor arguments and base_ name
* Remove tapOPEN_LEDGER
* add assert to MetaView::apply
* ViewInfo comment
* Throw, pass Journal in txInsert
* Add BasicView::txCount

TransactionEngine:

* Add apply
* Make TransactionEngine private
* Refactor MetaView::apply and apply()
* Rename to TxMeta
* Refactor treatment of metadata in MetaView, TransactionEngine
* Rename to ApplyContext
* Use ApplyContext& in Transactor
* Pass Config in ApplyContext
* Declare Transactor classes in headers
* Use view flags in Transactor
This commit is contained in:
Vinnie Falco
2015-06-26 17:14:06 -07:00
parent b11b9939f4
commit f96ac3db67
71 changed files with 4229 additions and 3615 deletions

View File

@@ -1409,6 +1409,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\TxMeta.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\ledger\InboundLedger.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\InboundLedgers.h">
@@ -1475,6 +1479,8 @@
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\ledger\TransactionStateSF.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\TxMeta.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\main\Application.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1719,6 +1725,18 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\apply.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\apply.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\ApplyContext.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\ApplyContext.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\BookTip.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1729,22 +1747,32 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CancelOffer.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\CancelTicket.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CancelTicket.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\Change.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\Change.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\CreateOffer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateOffer.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\CreateTicket.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateTicket.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\InboundTransactions.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1765,22 +1793,32 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\Payment.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetAccount.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetAccount.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetRegularKey.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetRegularKey.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetSignerList.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetSignerList.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetTrust.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetTrust.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SignerEntries.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1801,18 +1839,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\TransactionEngine.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\TransactionMaster.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\TransactionMeta.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\Transactor.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -1849,12 +1879,8 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\tx\TransactionAcquire.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\tx\TransactionEngine.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\tx\TransactionMaster.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\tx\TransactionMeta.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\base_uint.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\BasicConfig.h">
@@ -1869,6 +1895,8 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\CheckLibraryVersions.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\contract.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\CountedObject.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\DecayingSample.h">

View File

@@ -2145,6 +2145,9 @@
<ClCompile Include="..\..\src\ripple\app\ledger\impl\MetaView.cpp">
<Filter>ripple\app\ledger\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\ledger\impl\TxMeta.cpp">
<Filter>ripple\app\ledger\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\ledger\InboundLedger.h">
<Filter>ripple\app\ledger</Filter>
</ClInclude>
@@ -2217,6 +2220,9 @@
<ClInclude Include="..\..\src\ripple\app\ledger\TransactionStateSF.h">
<Filter>ripple\app\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\ledger\TxMeta.h">
<Filter>ripple\app\ledger</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\main\Application.cpp">
<Filter>ripple\app\main</Filter>
</ClCompile>
@@ -2454,6 +2460,18 @@
<ClCompile Include="..\..\src\ripple\app\tests\Regression_test.cpp">
<Filter>ripple\app\tests</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\apply.h">
<Filter>ripple\app\tx</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\apply.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\ApplyContext.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\ApplyContext.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\BookTip.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
@@ -2463,18 +2481,33 @@
<ClCompile Include="..\..\src\ripple\app\tx\impl\CancelOffer.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CancelOffer.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\CancelTicket.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CancelTicket.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\Change.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\Change.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\CreateOffer.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateOffer.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\CreateTicket.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateTicket.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\InboundTransactions.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
@@ -2493,18 +2526,33 @@
<ClCompile Include="..\..\src\ripple\app\tx\impl\Payment.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\Payment.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetAccount.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetAccount.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetRegularKey.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetRegularKey.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetSignerList.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetSignerList.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SetTrust.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\tx\impl\SetTrust.h">
<Filter>ripple\app\tx\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\app\tx\impl\SignerEntries.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
@@ -2523,15 +2571,9 @@
<ClCompile Include="..\..\src\ripple\app\tx\impl\TransactionAcquire.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\TransactionEngine.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\TransactionMaster.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\TransactionMeta.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\app\tx\impl\Transactor.cpp">
<Filter>ripple\app\tx\impl</Filter>
</ClCompile>
@@ -2568,15 +2610,9 @@
<ClInclude Include="..\..\src\ripple\app\tx\TransactionAcquire.h">
<Filter>ripple\app\tx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\tx\TransactionEngine.h">
<Filter>ripple\app\tx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\tx\TransactionMaster.h">
<Filter>ripple\app\tx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\app\tx\TransactionMeta.h">
<Filter>ripple\app\tx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\base_uint.h">
<Filter>ripple\basics</Filter>
</ClInclude>
@@ -2598,6 +2634,9 @@
<ClInclude Include="..\..\src\ripple\basics\CheckLibraryVersions.h">
<Filter>ripple\basics</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\contract.h">
<Filter>ripple\basics</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\CountedObject.h">
<Filter>ripple\basics</Filter>
</ClInclude>

View File

@@ -36,7 +36,7 @@ AcceptedLedgerTx::AcceptedLedgerTx (Ledger::ref ledger, SerialIter& sit)
mTxn = std::make_shared<STTx> (std::ref (txnIt));
mRawMeta = sit.getVL ();
mMeta = std::make_shared<TransactionMetaSet> (mTxn->getTransactionID (),
mMeta = std::make_shared<TxMeta> (mTxn->getTransactionID (),
ledger->getLedgerSeq (), mRawMeta);
mAffected = mMeta->getAffectedAccounts ();
mResult = mMeta->getResultTER ();
@@ -44,7 +44,7 @@ AcceptedLedgerTx::AcceptedLedgerTx (Ledger::ref ledger, SerialIter& sit)
}
AcceptedLedgerTx::AcceptedLedgerTx (Ledger::ref ledger,
STTx::ref txn, TransactionMetaSet::ref met)
STTx::ref txn, TxMeta::ref met)
: mLedger (ledger)
, mTxn (txn)
, mMeta (met)

View File

@@ -53,14 +53,14 @@ public:
public:
AcceptedLedgerTx (Ledger::ref ledger, SerialIter& sit);
AcceptedLedgerTx (Ledger::ref ledger, STTx::ref,
TransactionMetaSet::ref);
TxMeta::ref);
AcceptedLedgerTx (Ledger::ref ledger, STTx::ref, TER result);
STTx::ref getTxn () const
{
return mTxn;
}
TransactionMetaSet::ref getMeta () const
TxMeta::ref getMeta () const
{
return mMeta;
}
@@ -105,7 +105,7 @@ public:
private:
Ledger::pointer mLedger;
STTx::pointer mTxn;
TransactionMetaSet::pointer mMeta;
TxMeta::pointer mMeta;
TER mResult;
boost::container::flat_set<AccountID> mAffected;
Blob mRawMeta;

View File

@@ -19,6 +19,7 @@
#include <BeastConfig.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/basics/contract.h>
#include <ripple/app/ledger/AcceptedLedger.h>
#include <ripple/app/ledger/InboundLedgers.h>
#include <ripple/app/ledger/LedgerMaster.h>
@@ -81,9 +82,6 @@ makeGenesisAccount (AccountID const& id,
Ledger::Ledger (RippleAddress const& masterPublicKey,
std::uint64_t balanceInDrops)
: mTotCoins (balanceInDrops)
, seq_ (1) // First Ledger
, mCloseTime (0)
, mParentCloseTime (0)
, mCloseResolution (ledgerDefaultTimeResolution)
, mCloseFlags (0)
, mImmutable (false)
@@ -94,13 +92,15 @@ Ledger::Ledger (RippleAddress const& masterPublicKey,
// VFALCO Needs audit
, fees_(getFees(*this, getConfig()))
{
// first ledger
info_.seq = 1;
auto sle = makeGenesisAccount(
calcAccountID(masterPublicKey),
balanceInDrops);
WriteLog (lsTRACE, Ledger)
<< "root account: " << sle->getJson(0);
unchecked_insert(std::move(sle));
stateMap_->flushDirty (hotACCOUNT_NODE, seq_);
stateMap_->flushDirty (hotACCOUNT_NODE, info_.seq);
}
Ledger::Ledger (uint256 const& parentHash,
@@ -117,9 +117,6 @@ Ledger::Ledger (uint256 const& parentHash,
, mTransHash (transHash)
, mAccountHash (accountHash)
, mTotCoins (totCoins)
, seq_ (ledgerSeq)
, mCloseTime (closeTime)
, mParentCloseTime (parentCloseTime)
, mCloseResolution (closeResolution)
, mCloseFlags (closeFlags)
, mImmutable (true)
@@ -131,6 +128,10 @@ Ledger::Ledger (uint256 const& parentHash,
// VFALCO Needs audit
, fees_(getFees(*this, getConfig()))
{
info_.seq = ledgerSeq;
info_.parentCloseTime = parentCloseTime;
info_.closeTime = closeTime;
updateHash ();
loaded = true;
@@ -157,12 +158,8 @@ Ledger::Ledger (Ledger const& ledger,
bool isMutable)
: mParentHash (ledger.mParentHash)
, mTotCoins (ledger.mTotCoins)
, seq_ (ledger.seq_)
, mCloseTime (ledger.mCloseTime)
, mParentCloseTime (ledger.mParentCloseTime)
, mCloseResolution (ledger.mCloseResolution)
, mCloseFlags (ledger.mCloseFlags)
, mClosed (ledger.mClosed)
, mValidated (ledger.mValidated)
, mAccepted (ledger.mAccepted)
, mImmutable (!isMutable)
@@ -170,16 +167,15 @@ Ledger::Ledger (Ledger const& ledger,
, stateMap_ (ledger.stateMap_->snapShot (isMutable))
// VFALCO Needs audit
, fees_(getFees(*this, getConfig()))
, info_ (ledger.info_)
{
updateHash ();
}
// Create a new ledger that follows this one
// Create a new open ledger that follows this one
Ledger::Ledger (bool /* dummy */,
Ledger& prevLedger)
: mTotCoins (prevLedger.mTotCoins)
, seq_ (prevLedger.seq_ + 1)
, mParentCloseTime (prevLedger.mCloseTime)
, mCloseResolution (prevLedger.mCloseResolution)
, mCloseFlags (0)
, mImmutable (false)
@@ -189,6 +185,10 @@ Ledger::Ledger (bool /* dummy */,
// VFALCO Needs audit
, fees_(getFees(*this, getConfig()))
{
info_.open = true;
info_.seq = prevLedger.info_.seq + 1;
info_.parentCloseTime =
prevLedger.info_.closeTime;
prevLedger.updateHash ();
mParentHash = prevLedger.getHash ();
@@ -196,16 +196,17 @@ Ledger::Ledger (bool /* dummy */,
assert (mParentHash.isNonZero ());
mCloseResolution = getNextLedgerTimeResolution (prevLedger.mCloseResolution,
prevLedger.getCloseAgree (), seq_);
prevLedger.getCloseAgree (), info_.seq);
if (prevLedger.mCloseTime == 0)
if (prevLedger.info_.closeTime == 0)
{
mCloseTime = roundCloseTime (
info_.closeTime = roundCloseTime (
getApp().getOPs ().getCloseTimeNC (), mCloseResolution);
}
else
{
mCloseTime = prevLedger.mCloseTime + mCloseResolution;
info_.closeTime =
prevLedger.info_.closeTime + mCloseResolution;
}
}
@@ -220,9 +221,6 @@ Ledger::Ledger (void const* data,
Ledger::Ledger (std::uint32_t ledgerSeq, std::uint32_t closeTime)
: mTotCoins (0)
, seq_ (ledgerSeq)
, mCloseTime (closeTime)
, mParentCloseTime (0)
, mCloseResolution (ledgerDefaultTimeResolution)
, mCloseFlags (0)
, mImmutable (false)
@@ -235,6 +233,9 @@ Ledger::Ledger (std::uint32_t ledgerSeq, std::uint32_t closeTime)
// VFALCO Needs audit
, fees_(getFees(*this, getConfig()))
{
info_.seq = ledgerSeq;
info_.parentCloseTime = 0;
info_.closeTime = closeTime;
}
//------------------------------------------------------------------------------
@@ -275,13 +276,13 @@ void Ledger::updateHash()
// VFALCO This has to match addRaw
mHash = sha512Half(
HashPrefix::ledgerMaster,
std::uint32_t(seq_),
std::uint32_t(info_.seq),
std::uint64_t(mTotCoins),
mParentHash,
mTransHash,
mAccountHash,
std::uint32_t(mParentCloseTime),
std::uint32_t(mCloseTime),
std::uint32_t(info_.parentCloseTime),
std::uint32_t(info_.closeTime),
std::uint8_t(mCloseResolution),
std::uint8_t(mCloseFlags));
mValidHash = true;
@@ -292,13 +293,13 @@ void Ledger::setRaw (SerialIter& sit, bool hasPrefix)
if (hasPrefix)
sit.get32 ();
seq_ = sit.get32 ();
info_.seq = sit.get32 ();
mTotCoins = sit.get64 ();
mParentHash = sit.get256 ();
mTransHash = sit.get256 ();
mAccountHash = sit.get256 ();
mParentCloseTime = sit.get32 ();
mCloseTime = sit.get32 ();
info_.parentCloseTime = sit.get32 ();
info_.closeTime = sit.get32 ();
mCloseResolution = sit.get8 ();
mCloseFlags = sit.get8 ();
updateHash ();
@@ -310,13 +311,13 @@ void Ledger::setRaw (SerialIter& sit, bool hasPrefix)
void Ledger::addRaw (Serializer& s) const
{
s.add32 (seq_);
s.add32 (info_.seq);
s.add64 (mTotCoins);
s.add256 (mParentHash);
s.add256 (mTransHash);
s.add256 (mAccountHash);
s.add32 (mParentCloseTime);
s.add32 (mCloseTime);
s.add32 (info_.parentCloseTime);
s.add32 (info_.closeTime);
s.add8 (mCloseResolution);
s.add8 (mCloseFlags);
}
@@ -326,8 +327,9 @@ void Ledger::setAccepted (
{
// Used when we witnessed the consensus. Rounds the close time, updates the
// hash, and sets the ledger accepted and immutable.
assert (mClosed && !mAccepted);
mCloseTime = correctCloseTime ? roundCloseTime (closeTime, closeResolution)
assert (closed() && !mAccepted);
info_.closeTime = correctCloseTime
? roundCloseTime (closeTime, closeResolution)
: closeTime;
mCloseResolution = closeResolution;
mCloseFlags = correctCloseTime ? 0 : sLCF_NoConsensusTime;
@@ -338,9 +340,10 @@ void Ledger::setAccepted (
void Ledger::setAccepted ()
{
// used when we acquired the ledger
// FIXME assert(mClosed && (mCloseTime != 0) && (mCloseResolution != 0));
// FIXME assert(closed() && (info_.closeTime != 0) && (mCloseResolution != 0));
if ((mCloseFlags & sLCF_NoConsensusTime) == 0)
mCloseTime = roundCloseTime (mCloseTime, mCloseResolution);
info_.closeTime = roundCloseTime(
info_.closeTime, mCloseResolution);
mAccepted = true;
setImmutable ();
@@ -396,7 +399,7 @@ getTransaction (Ledger const& ledger,
bool
getTransaction (Ledger const& ledger,
uint256 const& txID, Transaction::pointer& txn,
TransactionMetaSet::pointer& meta,
TxMeta::pointer& meta,
TransactionMaster& cache)
{
SHAMapTreeNode::TNType type;
@@ -428,7 +431,7 @@ getTransaction (Ledger const& ledger,
else
it.getVL (); // skip transaction
meta = std::make_shared<TransactionMetaSet> (
meta = std::make_shared<TxMeta> (
txID, ledger.seq(), it.getVL ());
}
else
@@ -442,7 +445,7 @@ getTransaction (Ledger const& ledger,
}
bool getTransactionMeta (Ledger const& ledger,
uint256 const& txID, TransactionMetaSet::pointer& meta)
uint256 const& txID, TxMeta::pointer& meta)
{
SHAMapTreeNode::TNType type;
auto const item =
@@ -456,7 +459,7 @@ bool getTransactionMeta (Ledger const& ledger,
SerialIter it (item->slice());
it.getVL (); // skip transaction
meta = std::make_shared<TransactionMetaSet> (txID, ledger.seq(), it.getVL ());
meta = std::make_shared<TxMeta> (txID, ledger.seq(), it.getVL ());
return true;
}
@@ -506,7 +509,7 @@ bool Ledger::saveValidatedLedger (bool current)
WriteLog (lsFATAL, Ledger) << "sAL: " << getAccountHash ()
<< " != " << stateMap_->getHash ();
WriteLog (lsFATAL, Ledger) << "saveAcceptedLedger: seq="
<< seq_ << ", current=" << current;
<< info_.seq << ", current=" << current;
assert (false);
}
@@ -529,7 +532,7 @@ bool Ledger::saveValidatedLedger (bool current)
catch (...)
{
WriteLog (lsWARNING, Ledger) << "An accepted ledger was missing nodes";
getApp().getLedgerMaster().failedSave(seq_, mHash);
getApp().getLedgerMaster().failedSave(info_.seq, mHash);
// Clients can now trust the database for information about this
// ledger sequence.
getApp().pendingSaves().erase(getLedgerSeq());
@@ -538,7 +541,7 @@ bool Ledger::saveValidatedLedger (bool current)
{
auto db = getApp().getLedgerDB ().checkoutDb();
*db << boost::str (deleteLedger % seq_);
*db << boost::str (deleteLedger % info_.seq);
}
{
@@ -604,7 +607,7 @@ bool Ledger::saveValidatedLedger (bool current)
}
else
WriteLog (lsWARNING, Ledger)
<< "Transaction in ledger " << seq_
<< "Transaction in ledger " << info_.seq
<< " affects no accounts";
*db <<
@@ -621,9 +624,9 @@ bool Ledger::saveValidatedLedger (bool current)
// TODO(tom): ARG!
*db << boost::str (addLedger %
to_string (getHash ()) % seq_ % to_string (mParentHash) %
beast::lexicalCastThrow <std::string> (mTotCoins) % mCloseTime %
mParentCloseTime % mCloseResolution % mCloseFlags %
to_string (getHash ()) % info_.seq % to_string (mParentHash) %
beast::lexicalCastThrow <std::string> (mTotCoins) % info_.closeTime %
info_.parentCloseTime % mCloseResolution % mCloseFlags %
to_string (mAccountHash) % to_string (mTransHash));
}
@@ -875,13 +878,13 @@ bool Ledger::isAcquiringAS (void) const
boost::posix_time::ptime Ledger::getCloseTime () const
{
return ptFromSeconds (mCloseTime);
return ptFromSeconds (info_.closeTime);
}
void Ledger::setCloseTime (boost::posix_time::ptime ptm)
{
assert (!mImmutable);
mCloseTime = iToSeconds (ptm);
info_.closeTime = iToSeconds (ptm);
}
//------------------------------------------------------------------------------
@@ -969,55 +972,50 @@ Ledger::unchecked_replace(
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);
}
bool
void
Ledger::txInsert (uint256 const& key,
std::shared_ptr<Serializer const> const& txn,
std::shared_ptr<Serializer const> const& metaData)
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData)
{
if (metaData)
{
// low-level - just add to table
Serializer s (txn->getDataLength () + metaData->getDataLength () + 16);
Serializer s(txn->getDataLength () +
metaData->getDataLength () + 16);
s.addVL (txn->peekData ());
s.addVL (metaData->peekData ());
auto item = std::make_shared<
SHAMapItem const> (key, std::move(s));
// VFALCO Should just terminate the app
// with a fatal error here.
if (! txMap().addGiveItem (std::move(item), true, true))
{
WriteLog (lsFATAL, Ledger)
<< "Attempt to add transaction+MD to ledger that already had it";
return false;
}
auto const temp = std::move(*metaData);
if (! txMap().addGiveItem
(std::move(item), true, true))
LogicError("duplicate_tx: " + to_string(key));
}
else
{
// low-level - just add to table
auto item = std::make_shared<
SHAMapItem const> (key, txn->peekData ());
if (! txMap().addGiveItem (std::move(item), true, false))
{
WriteLog (lsWARNING, Ledger)
<< "Attempt to add transaction to ledger that already had it";
return false;
}
SHAMapItem const>(key, txn->peekData());
if (! txMap().addGiveItem(
std::move(item), true, false))
LogicError("duplicate_tx: " + to_string(key));
}
// VFALCO TODO We could touch only the txMap
touch();
return true;
}
std::vector<uint256>
@@ -1074,7 +1072,7 @@ void Ledger::visitStateItems (std::function<void (SLE::ref)> function) const
if (mHash.isNonZero ())
{
getApp().getInboundLedgers().acquire(
mHash, seq_, InboundLedger::fcGENERIC);
mHash, info_.seq, InboundLedger::fcGENERIC);
}
throw;
}
@@ -1164,10 +1162,10 @@ bool Ledger::assertSane ()
// VFALCO TODO Document this skip list concept
void Ledger::updateSkipList ()
{
if (seq_ == 0) // genesis ledger has no previous ledger
if (info_.seq == 0) // genesis ledger has no previous ledger
return;
std::uint32_t prevIndex = seq_ - 1;
std::uint32_t prevIndex = info_.seq - 1;
// update record of every 256th ledger
if ((prevIndex & 0xff) == 0)
@@ -1287,6 +1285,7 @@ qualityDirDescriber (
sle->setFieldU64 (sfExchangeRate, uRate);
if (isNew)
{
// VFALCO NO! This shouldn't be done here!
getApp().getOrderBookDB().addOrderBook(
{{uTakerPaysCurrency, uTakerPaysIssuer},
{uTakerGetsCurrency, uTakerGetsIssuer}});

View File

@@ -20,16 +20,16 @@
#ifndef RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED
#define RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED
#include <ripple/shamap/SHAMap.h>
#include <ripple/app/tx/Transaction.h>
#include <ripple/app/tx/TransactionMeta.h>
#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>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/basics/CountedObject.h>
#include <ripple/protocol/Serializer.h>
#include <ripple/protocol/Book.h>
#include <ripple/shamap/SHAMap.h>
#include <beast/utility/Journal.h>
#include <boost/optional.hpp>
#include <mutex>
@@ -118,24 +118,18 @@ public:
//
//--------------------------------------------------------------------------
ViewInfo const&
info() const
{
return info_;
}
Fees const&
fees() const override
{
return fees_;
}
LedgerIndex
seq() const override
{
return seq_;
}
std::uint32_t
time() const override
{
return mParentCloseTime;
}
bool
exists (Keylet const& k) const override;
@@ -161,10 +155,13 @@ public:
mTotCoins -= feeDrops;
}
std::size_t
txCount() const override;
bool
txExists (uint256 const& key) const override;
bool
void
txInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
@@ -187,9 +184,9 @@ public:
mValidHash = false;
}
void setClosed ()
void setClosed()
{
mClosed = true;
info_.open = false;
}
void setValidated()
@@ -204,10 +201,10 @@ public:
void setImmutable ();
// VFALCO Rename to closed
// DEPRECATED use closed()
bool isClosed () const
{
return mClosed;
return closed();
}
bool isAccepted () const
@@ -225,10 +222,13 @@ public:
return mImmutable;
}
// Indicates that all ledger entries
// are available locally. For example,
// all in the NodeStore and memory.
void setFull ()
{
txMap_->setLedgerSeq (seq_);
stateMap_->setLedgerSeq (seq_);
txMap_->setLedgerSeq (info_.seq);
stateMap_->setLedgerSeq (info_.seq);
}
// ledger signature operations
@@ -266,20 +266,22 @@ public:
mTotCoins = totCoins;
}
// DEPRECATED
std::uint32_t getCloseTimeNC () const
{
return mCloseTime;
return info_.closeTime;
}
// DEPRECATED Use parentCloseTime()
std::uint32_t getParentCloseTimeNC () const
{
return mParentCloseTime;
return info_.parentCloseTime;
}
// DEPRECATED
// DEPRECATED Use seq()
std::uint32_t getLedgerSeq () const
{
return seq_;
return info_.seq;
}
int getCloseResolution () const
@@ -293,10 +295,10 @@ public:
}
// close time functions
void setCloseTime (std::uint32_t ct)
void setCloseTime (std::uint32_t when)
{
assert (!mImmutable);
mCloseTime = ct;
info_.closeTime = when;
}
void setCloseTime (boost::posix_time::ptime);
@@ -383,6 +385,7 @@ public:
return mBaseFee;
}
// DEPRECATED use fees()
std::uint64_t getReserve (int increments) const
{
// Returns the required reserve in drops
@@ -391,6 +394,7 @@ public:
+ mReserveBase;
}
// DEPRECATED use fees()
std::uint64_t getReserveInc () const
{
deprecatedUpdateCachedFees ();
@@ -444,20 +448,12 @@ private:
uint256 mTransHash;
uint256 mAccountHash;
std::uint64_t mTotCoins;
std::uint32_t seq_;
// when this ledger closed
std::uint32_t mCloseTime;
// when the previous ledger closed
std::uint32_t mParentCloseTime;
// the resolution for this ledger close time (2-120 seconds)
int mCloseResolution;
// flags indicating how this ledger close took place
std::uint32_t mCloseFlags;
bool mClosed = false;
bool mValidated = false;
bool mValidHash = false;
bool mAccepted = false;
@@ -470,6 +466,7 @@ private:
std::mutex mutable mutex_;
Fees fees_;
ViewInfo info_;
// Ripple cost of the reference transaction
std::uint64_t mutable mBaseFee = 0;
@@ -561,13 +558,13 @@ getTransaction (Ledger const& ledger,
bool
getTransaction (Ledger const& ledger,
uint256 const& transID, Transaction::pointer & txn,
TransactionMetaSet::pointer & txMeta,
TxMeta::pointer & txMeta,
TransactionMaster& cache);
bool
getTransactionMeta (Ledger const&,
uint256 const& transID,
TransactionMetaSet::pointer & txMeta);
TxMeta::pointer & txMeta);
// VFALCO NOTE This is called from only one place
bool

View File

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

View File

@@ -133,7 +133,7 @@ static
void
log_one(Ledger::pointer ledger, uint256 const& tx, char const* msg)
{
TransactionMetaSet::pointer metaData;
TxMeta::pointer metaData;
getTransactionMeta(*ledger, tx, metaData);
if (metaData != nullptr)
@@ -154,9 +154,9 @@ void
log_metadata_difference(Ledger::pointer builtLedger, Ledger::pointer validLedger,
uint256 const& tx)
{
TransactionMetaSet::pointer validMetaData;
TxMeta::pointer validMetaData;
getTransactionMeta(*validLedger, tx, validMetaData);
TransactionMetaSet::pointer builtMetaData;
TxMeta::pointer builtMetaData;
getTransactionMeta(*builtLedger, tx, builtMetaData);
assert(validMetaData != nullptr || builtMetaData != nullptr);

View File

@@ -166,7 +166,7 @@ void fillJson (Object& json, LedgerFill const& fill)
SerialIter tsit (make_Slice(vl));
STTx txn (tsit);
TransactionMetaSet meta (
TxMeta meta (
item->getTag (), ledger.getLedgerSeq(), sit.getVL ());
auto&& txJson = appendObject (txns);

View File

@@ -20,13 +20,14 @@
#ifndef RIPPLE_LEDGER_METAVIEW_H_INCLUDED
#define RIPPLE_LEDGER_METAVIEW_H_INCLUDED
#include <ripple/app/tx/TransactionMeta.h>
#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 <list>
@@ -35,6 +36,25 @@
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.
@@ -70,122 +90,88 @@ private:
// Note that this class needs to be
// somewhat light-weight copy constructible.
BasicView const* parent_;
BasicView const& base_;
ViewFlags flags_ = tapNONE;
LedgerIndex seq_;
std::uint32_t time_; // should be Clock::time_point
ViewInfo info_;
tx_list txs_;
item_list items_;
TransactionMetaSet meta_;
std::uint32_t destroyedCoins_ = 0;
boost::optional<STAmount> deliverAmount_;
public:
MetaView() = delete;
MetaView(MetaView const&) = delete;
MetaView& operator= (MetaView const&) = delete;
/** Create a shallow copy of a MetaView.
The SLEs and Serializers in the created copy
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.
The seq, time, and flags are copied from `other`.
@note This is used to apply new transactions to
the open MetaView.
*/
// VFALCO Refactor to disallow at compile time,
// breaking invariants on a shallow copy.
//
MetaView (MetaView const& other) = default;
MetaView (shallow_copy_t,
MetaView const& other);
/** Create a MetaView with a BasicView as its parent.
/** Create a MetaView representing an open ledger.
Preconditions:
`prev` cannot represent an open ledger.
Effects:
The sequence number and time are set
from the passed parameters.
The sequence number is set to the
sequence number of parent plus one.
The parentCloseTime is set to the
closeTime of parent.
It is only safe to use the BasicView modification
functions. Using View modification functions will
break invariants.
@note This is for converting a closed ledger
into an open ledger.
@note A pointer is used to prevent confusion
with copy construction.
@param parent A view representing the previous
ledger that this open ledger follows.
*/
// VFALCO Refactor to disallow at compile time,
// breaking invariants on a shallow copy.
//
MetaView (BasicView const* parent,
LedgerIndex seq, std::uint32_t time,
MetaView (open_ledger_t,
BasicView const& parent);
/** Create a nested MetaView.
Effects:
The ViewInfo is copied from the base.
*/
MetaView (BasicView const& base,
ViewFlags flags);
/** Create a MetaView with a BasicView as its parent.
Effects:
The sequence number and time are inherited
from the parent.
The MetaSet is prepared to produce metadata
for a transaction with the specified key.
@note This is for applying a particular transaction
and computing its metadata, or for applying
a transaction without extracting metadata. For
example, to calculate changes in a sandbox
and then throw the sandbox away.
@note A pointer is used to prevent confusion
with copy construction.
*/
MetaView (BasicView const* parent,
ViewFlags flags,
boost::optional<uint256
> const& key = boost::none);
/** Create a MetaView with a View as its parent.
Effects:
The sequence number, time, and flags
are inherited from the parent.
@note This is for stacking view for the purpose of
performing calculations or applying to an
underlying MetaView associated with a particular
transation.
@note A pointer is used to prevent confusion
with copy construction.
*/
MetaView (View const* parent);
//--------------------------------------------------------------------------
//
// BasicView
//
//--------------------------------------------------------------------------
ViewInfo const&
info() const
{
return info_;
}
Fees const&
fees() const override
{
return parent_->fees();
}
LedgerIndex
seq() const override
{
return seq_;
}
std::uint32_t
time() const override
{
return time_;
return base_.fees();
}
bool
@@ -213,10 +199,13 @@ public:
void
destroyCoins (std::uint64_t feeDrops) override;
std::size_t
txCount() const override;
bool
txExists (uint256 const& key) const override;
bool
void
txInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
@@ -251,44 +240,77 @@ public:
//--------------------------------------------------------------------------
/** Apply changes to the parent View.
/** Apply changes to the base View.
`to` must contain contents identical to the parent
view passed upon construction, else undefined
behavior will result.
`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.
After a call to apply(), the only valid operation
on the object is a call to the destructor.
*/
void
apply (BasicView& to);
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 calcRawMeta (Serializer&, TER result, std::uint32_t index);
void setDeliveredAmount (STAmount const& amt)
{
meta_.setDeliveredAmount (amt);
deliverAmount_ = amt;
}
private:
static
bool
threadTx (TxMeta& meta,
std::shared_ptr<SLE> const& to,
Mods& mods);
std::shared_ptr<SLE>
getForMod (uint256 const& key,
Mods& mods);
Mods& mods, beast::Journal j);
bool
threadTx (AccountID const& to,
Mods& mods);
threadTx (TxMeta& meta,
AccountID const& to, Mods& mods,
beast::Journal j);
bool
threadTx (std::shared_ptr<SLE> const& to,
Mods& mods);
bool
threadOwners (std::shared_ptr<
SLE const> const& sle, Mods& mods);
threadOwners (TxMeta& meta, std::shared_ptr<
SLE const> const& sle, Mods& mods,
beast::Journal j);
};
} // ripple

View File

@@ -28,26 +28,27 @@
namespace ripple {
class TransactionMetaSet
// VFALCO Move to ripple/app/ledger/detail, rename to TxMeta
class TxMeta
{
public:
using pointer = std::shared_ptr<TransactionMetaSet>;
using pointer = std::shared_ptr<TxMeta>;
using ref = const pointer&;
private:
struct CtorHelper{};
template<class T>
TransactionMetaSet (uint256 const& txID, std::uint32_t ledger, T const& data,
TxMeta (uint256 const& txID, std::uint32_t ledger, T const& data,
CtorHelper);
public:
TransactionMetaSet ()
TxMeta ()
: mLedger (0)
, mIndex (static_cast<std::uint32_t> (-1))
, mResult (255)
{
}
TransactionMetaSet (uint256 const& txID, std::uint32_t ledger, std::uint32_t index)
TxMeta (uint256 const& txID, std::uint32_t ledger, std::uint32_t index)
: mTransactionID (txID)
, mLedger (ledger)
, mIndex (static_cast<std::uint32_t> (-1))
@@ -55,15 +56,15 @@ public:
{
}
TransactionMetaSet (uint256 const& txID, std::uint32_t ledger, Blob const&);
TransactionMetaSet (uint256 const& txID, std::uint32_t ledger, std::string const&);
TxMeta (uint256 const& txID, std::uint32_t ledger, Blob const&);
TxMeta (uint256 const& txID, std::uint32_t ledger, std::string const&);
void init (uint256 const& transactionID, std::uint32_t ledger);
void clear ()
{
mNodes.clear ();
}
void swap (TransactionMetaSet&) noexcept;
void swap (TxMeta&) noexcept;
uint256 const& getTxID ()
{

View File

@@ -22,6 +22,7 @@
#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/impl/DisputedTx.h>
#include <ripple/app/ledger/impl/LedgerConsensusImp.h>
#include <ripple/app/main/Application.h>
@@ -31,7 +32,7 @@
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/misc/Validations.h>
#include <ripple/app/tx/TransactionAcquire.h>
#include <ripple/app/tx/TransactionEngine.h>
#include <ripple/app/tx/apply.h>
#include <ripple/basics/CountedObject.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
@@ -979,15 +980,27 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
// Build the new last closed ledger
auto newLCL = std::make_shared<Ledger> (false, *mPreviousLedger);
newLCL->setClosed (); // so applyTransactions sees a closed ledger
// Set up to write SHAMap changes to our database,
// perform updates, extract changes
WriteLog (lsDEBUG, LedgerConsensus)
<< "Applying consensus set transactions to the"
<< " last closed ledger";
applyTransactions (set.get(), newLCL, newLCL, retriableTransactions, false);
{
MetaView accum(*newLCL, tapNONE);
assert(accum.closed());
applyTransactions (set.get(), accum,
newLCL, retriableTransactions);
accum.apply(*newLCL,
deprecatedLogs().journal("LedgerConsensus"));
}
// retriableTransactions will include any transactions that
// made it into the consensus set but failed during application
// to the ledger.
newLCL->updateSkipList ();
newLCL->setClosed ();
int asf = newLCL->stateMap().flushDirty (
hotACCOUNT_NODE, newLCL->getLedgerSeq());
@@ -1057,8 +1070,20 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
// Build new open ledger
auto newOL = std::make_shared<Ledger> (true, *newLCL);
MetaView accum(*newOL, tapNONE);
assert(accum.open());
// Apply disputed transactions that didn't get in
//
// The first crack of transactions to get into the new
// open ledger goes to transactions proposed by a validator
// we trust but not included in the consensus set.
//
// These are done first because they are the most likely
// to receive agreement during consensus. They are also
// ordered logically "sooner" than transactions not mentioned
// in the previous consensus round.
//
bool anyDisputes = false;
for (auto& it : mDisputes)
{
@@ -1075,6 +1100,7 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
auto txn = std::make_shared<STTx>(sit);
retriableTransactions.push_back (txn);
anyDisputes = true;
}
catch (...)
@@ -1087,7 +1113,8 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
if (anyDisputes)
{
applyTransactions (nullptr, newOL, newLCL, retriableTransactions, true);
applyTransactions (nullptr,
accum, newLCL, retriableTransactions);
}
{
@@ -1102,17 +1129,16 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
WriteLog (lsDEBUG, LedgerConsensus)
<< "Applying transactions from current open ledger";
applyTransactions (&oldOL->txMap(),
newOL, newLCL, retriableTransactions, true);
accum, newLCL, retriableTransactions);
}
// Apply local transactions
TransactionEngine engine (newOL);
for (auto it : m_localTX.getTxSet ())
{
try
{
engine.applyTransaction (*it.second, tapOPEN_LEDGER);
apply (accum, *it.second, tapNONE, getConfig(),
deprecatedLogs().journal("LedgerConsensus"));
}
catch (...)
{
@@ -1123,6 +1149,9 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
}
}
accum.apply(*newOL,
deprecatedLogs().journal("LedgerConsensus"));
// We have a new Last Closed Ledger and new Open Ledger
ledgerMaster_.pushLedger (newLCL, newOL);
}
@@ -1715,20 +1744,18 @@ make_LedgerConsensus (ConsensusImp& consensus, int previousProposers,
@param engine The transaction engine containing the ledger.
@param txn The transaction to be applied to ledger.
@param openLedger true if ledger is open
@param retryAssured true if the transaction should be retried on failure.
@return One of resultSuccess, resultFail or resultRetry.
*/
static
int applyTransaction (
TransactionEngine& engine,
std::shared_ptr<STTx const> const& txn,
bool openLedger,
int
applyTransaction (BasicView& view,
STTx const& txn,
bool retryAssured,
bool enableTesting)
{
// Returns false if the transaction has need not be retried.
ViewFlags parms = openLedger ? tapOPEN_LEDGER : tapNONE;
ViewFlags parms = tapNONE;
if (enableTesting)
parms = parms | tapENABLE_TESTING;
@@ -1738,21 +1765,22 @@ int applyTransaction (
parms = static_cast<ViewFlags> (parms | tapRETRY);
}
if ((getApp().getHashRouter ().getFlags (txn->getTransactionID ())
if ((getApp().getHashRouter ().getFlags (txn.getTransactionID ())
& SF_SIGGOOD) == SF_SIGGOOD)
{
parms = static_cast<ViewFlags>
(parms | tapNO_CHECK_SIGN);
}
WriteLog (lsDEBUG, LedgerConsensus) << "TXN "
<< txn->getTransactionID ()
<< (openLedger ? " open" : " closed")
<< txn.getTransactionID ()
//<< (engine.view().open() ? " open" : " closed") // because of the optional in engine
<< (retryAssured ? "/retry" : "/final");
WriteLog (lsTRACE, LedgerConsensus) << txn->getJson (0);
WriteLog (lsTRACE, LedgerConsensus) << txn.getJson (0);
try
{
auto result = engine.applyTransaction (*txn, parms);
auto const result = apply(view, txn, parms, getConfig(),
deprecatedLogs().journal("LedgerConsensus"));
if (result.second)
{
@@ -1783,14 +1811,11 @@ int applyTransaction (
void applyTransactions (
SHAMap const* set,
Ledger::ref applyLedger,
BasicView& applyView,
Ledger::ref checkLedger,
CanonicalTXSet& retriableTransactions,
bool openLgr,
bool enableTesting)
{
TransactionEngine engine (applyLedger);
if (set)
{
for (auto const item : *set)
@@ -1805,9 +1830,11 @@ void applyTransactions (
try
{
SerialIter sit (item->slice());
auto txn = std::make_shared<STTx>(sit);
auto const txn =
std::make_shared<STTx const>(sit);
if (applyTransaction (engine, txn, openLgr, true, enableTesting) == LedgerConsensusImp::resultRetry)
if (applyTransaction(applyView, *txn, true, enableTesting) ==
LedgerConsensusImp::resultRetry)
{
// On failure, stash the failed transaction for
// later retry.
@@ -1836,8 +1863,8 @@ void applyTransactions (
{
try
{
switch (applyTransaction (engine, it->second,
openLgr, certainRetry, enableTesting))
switch (applyTransaction (applyView,
*it->second, certainRetry, enableTesting))
{
case LedgerConsensusImp::resultSuccess:
it = retriableTransactions.erase (it);

View File

@@ -24,6 +24,7 @@
#include <ripple/app/ledger/OrderBookDB.h>
#include <ripple/app/ledger/PendingSaves.h>
#include <ripple/app/ledger/impl/LedgerCleaner.h>
#include <ripple/app/tx/apply.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/IHashRouter.h>
#include <ripple/app/misc/NetworkOPs.h>
@@ -31,7 +32,6 @@
#include <ripple/app/misc/SHAMapStore.h>
#include <ripple/app/misc/Validations.h>
#include <ripple/app/paths/PathRequests.h>
#include <ripple/app/tx/TransactionEngine.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/RangeSet.h>
#include <ripple/core/LoadFeeTrack.h>
@@ -352,20 +352,20 @@ public:
// Start with a mutable snapshot of the open ledger
auto const ledger =
mCurrentLedger.getMutable();
TransactionEngine engine (ledger);
int recovers = 0;
for (auto const& it : mHeldTransactions)
{
try
{
ViewFlags tepFlags = tapOPEN_LEDGER;
ViewFlags tepFlags = tapNONE;
if (getApp().getHashRouter ().addSuppressionFlags (it.first.getTXID (), SF_SIGGOOD))
tepFlags = static_cast<ViewFlags> (tepFlags | tapNO_CHECK_SIGN);
auto ret = engine.applyTransaction (*it.second, tepFlags);
auto const ret = apply(
*ledger, *it.second, tepFlags, getConfig(),
deprecatedLogs().journal("LedgerMaster"));
if (ret.second)
++recovers;

View File

@@ -18,10 +18,11 @@
//==============================================================================
#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/app/ledger/MetaView.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/json/to_string.h>
@@ -42,34 +43,39 @@ namespace ripple {
#define DIR_NODE_MAX 32
#endif
MetaView::MetaView (BasicView const* parent,
LedgerIndex seq, std::uint32_t time,
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_)
{
}
MetaView::MetaView (open_ledger_t,
BasicView const& parent)
: base_ (parent)
, flags_ (tapNONE)
, info_ (parent.info())
{
assert(! parent.open());
info_.open = true;
info_.seq = parent.info().seq + 1;
info_.parentCloseTime =
parent.info().closeTime;
}
MetaView::MetaView (BasicView const& base,
ViewFlags flags)
: parent_ (parent)
: base_ (base)
, flags_ (flags)
, seq_ (parent->seq())
, time_ (parent->time())
{
}
MetaView::MetaView (BasicView const* parent,
ViewFlags flags, boost::optional<
uint256> const& key)
: parent_ (parent)
, flags_ (flags)
, seq_ (parent->seq())
, time_ (parent->time())
{
// VFALCO This needs to be refactored
if (key)
meta_.init (*key, seq_);
}
MetaView::MetaView (View const* parent)
: parent_ (parent)
, flags_ (parent->flags())
, seq_ (parent->seq())
, time_ (parent->time())
, info_ (base.info())
{
}
@@ -81,7 +87,7 @@ MetaView::exists (Keylet const& k) const
assert(k.key.isNonZero());
auto const iter = items_.find(k.key);
if (iter == items_.end())
return parent_->exists(k);
return base_.exists(k);
if (iter->second.first == taaDELETE)
return false;
if (! k.check(*iter->second.second))
@@ -99,11 +105,11 @@ MetaView::succ (uint256 const& key,
{
boost::optional<uint256> next = key;
item_list::const_iterator iter;
// Find parent successor that is
// Find base successor that is
// not also deleted in our list
do
{
next = parent_->succ(*next, last);
next = base_.succ(*next, last);
if (! next)
break;
iter = items_.find(*next);
@@ -141,7 +147,7 @@ MetaView::read (Keylet const& k) const
if (iter == items_.end())
{
auto const sle =
parent_->read(k);
base_.read(k);
if (! sle)
return nullptr;
return sle;
@@ -163,13 +169,13 @@ MetaView::unchecked_erase (uint256 const& key)
if (iter == items_.end() ||
iter->first != key)
{
assert(parent_->exists(
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>(
*parent_->read(keylet::unchecked(key)))));
*base_.read(keylet::unchecked(key)))));
return true;
}
if (iter->second.first == taaCREATE)
@@ -192,7 +198,7 @@ MetaView::unchecked_insert(
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(! parent_->exists(Keylet{
assert(! base_.exists(Keylet{
sle->getType(), sle->key()}));
using namespace std;
items_.emplace_hint(iter, piecewise_construct,
@@ -217,7 +223,7 @@ MetaView::unchecked_insert(
break;
};
// VFALCO return Keylet from SLE
assert(parent_->exists(
assert(base_.exists(
Keylet{sle->getType(), sle->key()}));
iter->second.first = taaMODIFY;
iter->second.second = std::move(sle);
@@ -232,7 +238,7 @@ MetaView::unchecked_replace (std::shared_ptr<SLE>&& sle)
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(parent_->exists(Keylet{
assert(base_.exists(Keylet{
sle->getType(), sle->key()}));
using namespace std;
items_.emplace_hint(iter, piecewise_construct,
@@ -255,29 +261,33 @@ 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 parent_->txExists(key);
return base_.txExists(key);
}
bool
void
MetaView::txInsert (uint256 const& key,
std::shared_ptr<Serializer const> const& txn,
std::shared_ptr<Serializer const> const& metaData)
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData)
{
bool already = txs_.count(key);
if (! already)
already = parent_->txExists(key);
if (already)
return false;
if (txs_.count(key) ||
base_.txExists(key))
LogicError("duplicate_tx: " + to_string(key));
txs_.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(
txn, metaData));
return true;
}
std::vector<uint256>
@@ -301,7 +311,7 @@ MetaView::peek (Keylet const& k)
iter->first != k.key)
{
auto const sle =
parent_->read(k);
base_.read(k);
if (! sle)
return nullptr;
// Make our own copy
@@ -349,7 +359,7 @@ MetaView::insert (std::shared_ptr<SLE> const& sle)
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(! parent_->exists(
assert(! base_.exists(
Keylet{sle->getType(), sle->key()}));
items_.emplace_hint(iter, std::piecewise_construct,
std::forward_as_tuple(sle->getIndex()),
@@ -372,7 +382,7 @@ MetaView::insert (std::shared_ptr<SLE> const& sle)
break;
}
// Existed in parent, deleted here
assert(parent_->exists(
assert(base_.exists(
Keylet{sle->getType(), sle->key()}));
iter->second.first = taaMODIFY;
iter->second.second = sle;
@@ -386,7 +396,7 @@ MetaView::update (std::shared_ptr<SLE> const& sle)
iter->first != sle->key())
{
// VFALCO return Keylet from SLE
assert(parent_->exists(
assert(base_.exists(
Keylet{sle->getType(), sle->key()}));
items_.emplace_hint(iter, std::piecewise_construct,
std::forward_as_tuple(sle->key()),
@@ -404,9 +414,11 @@ MetaView::update (std::shared_ptr<SLE> const& sle)
//------------------------------------------------------------------------------
void MetaView::apply (BasicView& to)
void MetaView::apply(
BasicView& to, beast::Journal j)
{
assert(&to == parent_);
assert(&to == &base_);
assert(to.info().open == info_.open);
// Write back the account states
for (auto& item : items_)
{
@@ -521,23 +533,212 @@ Json::Value MetaView::getJson (int) const
ret[jss::nodes] = nodes;
ret[jss::metaData] = meta_.getJson (0);
// 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)
Mods& mods, beast::Journal j)
{
auto iter = items_.find (key);
if (iter != items_.end ())
{
if (iter->second.first == taaDELETE)
{
WriteLog (lsFATAL, View) <<
JLOG(j.fatal) <<
"Trying to thread to deleted node";
return nullptr;
}
@@ -554,7 +755,7 @@ MetaView::getForMod (uint256 const& key,
}
}
// VFALCO NOTE Should this be read() or peek()?
auto const csle = parent_->read(
auto const csle = base_.read(
keylet::unchecked(key));
if (! csle)
return nullptr;
@@ -566,50 +767,33 @@ MetaView::getForMod (uint256 const& key,
}
bool
MetaView::threadTx (AccountID const& to,
Mods& mods)
MetaView::threadTx (TxMeta& meta,
AccountID const& to, Mods& mods,
beast::Journal j)
{
auto const sle = getForMod(
keylet::account(to).key, mods);
keylet::account(to).key, mods, j);
#ifdef META_DEBUG
WriteLog (lsTRACE, View) <<
JLOG(j.trace) <<
"Thread to " << toBase58(to);
#endif
assert(sle);
if (! sle)
{
WriteLog (lsFATAL, View) <<
JLOG(j.fatal) <<
"Threading to non-existent account: " <<
toBase58(to);
return false;
}
return threadTx (sle, mods);
return threadTx (meta, sle, mods);
}
bool
MetaView::threadTx(
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 () ||
TransactionMetaSet::thread(
meta_.getAffectedNode(to,
sfModifiedNode), prevTxID,
prevLgrID))
return true;
assert (false);
return false;
}
bool
MetaView::threadOwners(std::shared_ptr<
SLE const> const& sle, Mods& mods)
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?
@@ -618,163 +802,24 @@ MetaView::threadOwners(std::shared_ptr<
{
// thread to owner's account
#ifdef META_DEBUG
WriteLog (lsTRACE, View) << "Thread to single owner";
JLOG(j.trace) << "Thread to single owner";
#endif
return threadTx (sle->getAccountID(sfAccount), mods);
return threadTx (meta, sle->getAccountID(
sfAccount), mods, j);
}
else if (sle->getType() == ltRIPPLE_STATE)
{
// thread to owner's accounts
#ifdef META_DEBUG
WriteLog (lsTRACE, View) << "Thread to two owners";
JLOG(j.trace) << "Thread to two owners";
#endif
return
threadTx(sle->getFieldAmount(sfLowLimit).getIssuer(), mods) &&
threadTx(sle->getFieldAmount(sfHighLimit).getIssuer(), mods);
threadTx (meta, sle->getFieldAmount(
sfLowLimit).getIssuer(), mods, j) &&
threadTx (meta, sle->getFieldAmount(
sfHighLimit).getIssuer(), mods, j);
}
return false;
}
void
MetaView::calcRawMeta (Serializer& s,
TER result, std::uint32_t index)
{
// calculate the raw meta data and return it. This must be called before the set is committed
// Entries modified only as a result of building the transaction metadata
Mods newMod;
for (auto& it : items_)
{
auto type = &sfGeneric;
switch (it.second.first)
{
case taaMODIFY:
#ifdef META_DEBUG
WriteLog (lsTRACE, View) << "Modified Node " << it.first;
#endif
type = &sfModifiedNode;
break;
case taaDELETE:
#ifdef META_DEBUG
WriteLog (lsTRACE, View) << "Deleted Node " << it.first;
#endif
type = &sfDeletedNode;
break;
case taaCREATE:
#ifdef META_DEBUG
WriteLog (lsTRACE, View) << "Created Node " << it.first;
#endif
type = &sfCreatedNode;
break;
default: // ignore these
break;
}
if (type == &sfGeneric)
continue;
auto const origNode =
parent_->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 (origNode, newMod); // thread transaction to owners
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 (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 (curNode, newMod);
if (curNode->isThreadedType ()) // always thread to self
threadTx (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);
meta_.addRaw (s, result, index);
WriteLog (lsTRACE, View) << "Metadata:" << meta_.getJson (0);
}
} // ripple

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/TransactionMeta.h>
#include <ripple/app/ledger/TxMeta.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/STAccount.h>
@@ -29,7 +29,7 @@ namespace ripple {
// VFALCO TODO rename class to TransactionMeta
template<class T>
TransactionMetaSet::TransactionMetaSet (uint256 const& txid,
TxMeta::TxMeta (uint256 const& txid,
std::uint32_t ledger, T const& data, CtorHelper)
: mTransactionID (txid)
, mLedger (ledger)
@@ -46,21 +46,21 @@ TransactionMetaSet::TransactionMetaSet (uint256 const& txid,
setDeliveredAmount (obj.getFieldAmount (sfDeliveredAmount));
}
TransactionMetaSet::TransactionMetaSet (uint256 const& txid,
TxMeta::TxMeta (uint256 const& txid,
std::uint32_t ledger,
Blob const& vec)
: TransactionMetaSet (txid, ledger, vec, CtorHelper ())
: TxMeta (txid, ledger, vec, CtorHelper ())
{
}
TransactionMetaSet::TransactionMetaSet (uint256 const& txid,
TxMeta::TxMeta (uint256 const& txid,
std::uint32_t ledger,
std::string const& data)
: TransactionMetaSet (txid, ledger, data, CtorHelper ())
: TxMeta (txid, ledger, data, CtorHelper ())
{
}
bool TransactionMetaSet::isNodeAffected (uint256 const& node) const
bool TxMeta::isNodeAffected (uint256 const& node) const
{
for (auto const& n : mNodes)
{
@@ -71,7 +71,7 @@ bool TransactionMetaSet::isNodeAffected (uint256 const& node) const
return false;
}
void TransactionMetaSet::setAffectedNode (uint256 const& node, SField const& type,
void TxMeta::setAffectedNode (uint256 const& node, SField const& type,
std::uint16_t nodeType)
{
// make sure the node exists and force its type
@@ -94,7 +94,7 @@ void TransactionMetaSet::setAffectedNode (uint256 const& node, SField const& typ
}
boost::container::flat_set<AccountID>
TransactionMetaSet::getAffectedAccounts() const
TxMeta::getAffectedAccounts() const
{
boost::container::flat_set<AccountID> list;
list.reserve (10);
@@ -137,7 +137,7 @@ TransactionMetaSet::getAffectedAccounts() const
}
else
{
WriteLog (lsFATAL, TransactionMetaSet) << "limit is not amount " << field.getJson (0);
WriteLog (lsFATAL, TxMeta) << "limit is not amount " << field.getJson (0);
}
}
}
@@ -148,7 +148,7 @@ TransactionMetaSet::getAffectedAccounts() const
return list;
}
STObject& TransactionMetaSet::getAffectedNode (SLE::ref node, SField const& type)
STObject& TxMeta::getAffectedNode (SLE::ref node, SField const& type)
{
assert (&type);
uint256 index = node->getIndex ();
@@ -167,7 +167,7 @@ STObject& TransactionMetaSet::getAffectedNode (SLE::ref node, SField const& type
return obj;
}
STObject& TransactionMetaSet::getAffectedNode (uint256 const& node)
STObject& TxMeta::getAffectedNode (uint256 const& node)
{
for (auto& n : mNodes)
{
@@ -178,7 +178,7 @@ STObject& TransactionMetaSet::getAffectedNode (uint256 const& node)
throw std::runtime_error ("Affected node not found");
}
const STObject& TransactionMetaSet::peekAffectedNode (uint256 const& node) const
const STObject& TxMeta::peekAffectedNode (uint256 const& node) const
{
for (auto const& n : mNodes)
{
@@ -189,7 +189,7 @@ const STObject& TransactionMetaSet::peekAffectedNode (uint256 const& node) const
throw std::runtime_error ("Affected node not found");
}
void TransactionMetaSet::init (uint256 const& id, std::uint32_t ledger)
void TxMeta::init (uint256 const& id, std::uint32_t ledger)
{
mTransactionID = id;
mLedger = ledger;
@@ -197,13 +197,13 @@ void TransactionMetaSet::init (uint256 const& id, std::uint32_t ledger)
mDelivered = boost::optional <STAmount> ();
}
void TransactionMetaSet::swap (TransactionMetaSet& s) noexcept
void TxMeta::swap (TxMeta& s) noexcept
{
assert ((mTransactionID == s.mTransactionID) && (mLedger == s.mLedger));
mNodes.swap (s.mNodes);
}
bool TransactionMetaSet::thread (STObject& node, uint256 const& prevTxID, std::uint32_t prevLgrID)
bool TxMeta::thread (STObject& node, uint256 const& prevTxID, std::uint32_t prevLgrID)
{
if (node.getFieldIndex (sfPreviousTxnID) == -1)
{
@@ -223,7 +223,7 @@ static bool compare (const STObject& o1, const STObject& o2)
return o1.getFieldH256 (sfLedgerIndex) < o2.getFieldH256 (sfLedgerIndex);
}
STObject TransactionMetaSet::getAsObject () const
STObject TxMeta::getAsObject () const
{
STObject metaData (sfTransactionMetaData);
assert (mResult != 255);
@@ -235,7 +235,7 @@ STObject TransactionMetaSet::getAsObject () const
return metaData;
}
void TransactionMetaSet::addRaw (Serializer& s, TER result, std::uint32_t index)
void TxMeta::addRaw (Serializer& s, TER result, std::uint32_t index)
{
mResult = static_cast<int> (result);
mIndex = index;

View File

@@ -152,7 +152,7 @@ class MetaView_test
using namespace jtx;
Env env(*this);
wipe(*env.ledger);
MetaView v(env.ledger.get(), tapNONE);
MetaView v(*env.ledger, tapNONE);
succ(v, 0, boost::none);
v.insert(sle(1));
expect(v.exists(k(1)));
@@ -189,7 +189,7 @@ class MetaView_test
v0.unchecked_insert(sle(4));
v0.unchecked_insert(sle(7));
{
MetaView v1(&v0, tapNONE);
MetaView v1(v0, tapNONE);
v1.insert(sle(3));
v1.insert(sle(5));
v1.insert(sle(6));
@@ -252,7 +252,7 @@ class MetaView_test
v0.unchecked_insert(sle(4, 4));
{
MetaView v1(&v0, tapNONE);
MetaView v1(v0, tapNONE);
v1.erase(v1.peek(k(2)));
v1.insert(sle(3, 3));
auto s = v1.peek(k(4));
@@ -263,7 +263,7 @@ class MetaView_test
expect(seq(v1.read(k(3))) == 3);
expect(seq(v1.read(k(4))) == 5);
{
MetaView v2(&v1);
MetaView v2(v1, tapNONE);
auto s = v2.peek(k(3));
seq(s, 6);
v2.update(s);
@@ -280,7 +280,7 @@ class MetaView_test
expect(seq(v1.read(k(4))) == 5);
{
MetaView v2(&v1);
MetaView v2(v1, tapNONE);
auto s = v2.peek(k(3));
seq(s, 6);
v2.update(s);
@@ -311,36 +311,41 @@ class MetaView_test
{
Env env(*this);
wipe(*env.ledger);
MetaView v0(env.ledger.get(), tapNONE);
MetaView v0(*env.ledger, tapNONE);
expect(v0.seq() != 98);
expect(v0.seq() == env.ledger->seq());
expect(v0.time() != 99);
expect(v0.time() == env.ledger->time());
expect(v0.parentCloseTime() != 99);
expect(v0.parentCloseTime() ==
env.ledger->parentCloseTime());
expect(v0.flags() == tapNONE);
{
// Shallow copy
MetaView v1(v0);
MetaView v1(shallow_copy, v0);
expect (v1.seq() == v0.seq());
expect (v1.time() == v1.time());
expect (v1.parentCloseTime() ==
v1.parentCloseTime());
expect (v1.flags() == tapNONE);
MetaView v2(&v1, tapNO_CHECK_SIGN);
expect(v2.time() == v1.time());
MetaView v2(v1, tapNO_CHECK_SIGN);
expect(v2.parentCloseTime() ==
v1.parentCloseTime());
expect(v2.seq() == v1.seq());
expect(v2.flags() == tapNO_CHECK_SIGN);
MetaView v3(&v2);
MetaView v3(v2, tapNONE);
expect(v3.seq() == v2.seq());
expect(v3.time() == v2.time());
expect(v3.flags() == v2.flags());
expect(v3.parentCloseTime() ==
v2.parentCloseTime());
expect(v3.flags() == tapNONE);
}
{
PaymentView v1(&v0, tapNO_CHECK_SIGN);
PaymentView v1(v0, tapNO_CHECK_SIGN);
expect(v1.seq() == v0.seq());
expect(v1.time() == v0.time());
expect(v1.parentCloseTime() ==
v0.parentCloseTime());
expect(v1.flags() == tapNO_CHECK_SIGN);
PaymentView v2(&v1);
expect(v2.seq() == v1.seq());
expect(v2.time() == v1.time());
expect(v2.parentCloseTime() ==
v1.parentCloseTime());
expect(v2.flags() == v1.flags());
}
}
@@ -359,9 +364,9 @@ class MetaView_test
wipe(*env.ledger);
BasicView& v0 = *env.ledger;
v0.unchecked_insert(sle(1));
MetaView v1(&v0, tapNONE);
MetaView v1(v0, tapNONE);
{
MetaView v2(&v1);
MetaView v2(v1, tapNONE);
v2.erase(v2.peek(k(1)));
v2.apply(v1);
}

View File

@@ -20,6 +20,7 @@
#include <ripple/app/ledger/tests/common_ledger.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/paths/FindPaths.h>
#include <ripple/app/tx/apply.h>
#include <ripple/protocol/RippleAddress.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/types.h>
@@ -127,9 +128,9 @@ parseTransaction(TestAccount& account, Json::Value const& tx_json, bool sign)
void
applyTransaction(Ledger::pointer const& ledger, STTx const& tx, bool check)
{
TransactionEngine engine(ledger);
auto r = engine.applyTransaction(tx,
tapOPEN_LEDGER | (check ? tapNONE : tapNO_CHECK_SIGN));
auto const r = apply (*ledger, tx,
check ? tapNONE : tapNO_CHECK_SIGN, getConfig(),
beast::Journal{});
if (r.first != tesSUCCESS)
throw std::runtime_error("r != tesSUCCESS");
if (!r.second)
@@ -441,9 +442,11 @@ close_and_advance(Ledger::pointer& ledger, std::shared_ptr<Ledger const>& LCL)
// that other Ledger constructor can take a const Ledger.
Ledger oldLCL(*LCL, false);
Ledger::pointer newLCL = std::make_shared<Ledger>(false, oldLCL);
MetaView accum(*newLCL, tapNONE);
// Set up to write SHAMap changes to our database,
// perform updates, extract changes
applyTransactions(&set, newLCL, newLCL, retriableTransactions, false);
applyTransactions(&set, accum, newLCL, retriableTransactions);
accum.apply(*newLCL, {});
newLCL->updateSkipList();
newLCL->setClosed();
newLCL->stateMap().flushDirty(

View File

@@ -67,9 +67,9 @@
#include <ripple/websocket/MakeServer.h>
#include <ripple/crypto/RandomNumbers.h>
#include <beast/asio/io_latency_probe.h>
#include <boost/asio/signal_set.hpp>
#include <beast/module/core/text/LexicalCast.h>
#include <beast/module/core/thread/DeadlineTimer.h>
#include <boost/asio/signal_set.hpp>
#include <fstream>
namespace ripple {
@@ -1337,11 +1337,9 @@ bool ApplicationImp::loadOldLedger (
txn->getJson(0);
Serializer s;
txn->getSTransaction()->add(s);
if (! cur->txInsert(item->getTag(),
std::make_shared<Serializer const>(std::move(s)),
nullptr))
if (m_journal.warning) m_journal.warning <<
"Unable to add transaction " << item->getTag();
cur->txInsert(item->getTag(),
std::make_shared<Serializer const>(
std::move(s)), nullptr);
getApp().getHashRouter().setFlag (item->getTag(), SF_SIGGOOD);
}
@@ -1485,7 +1483,7 @@ static void addTxnSeqField ()
}
else
{
TransactionMetaSet m (transID, 0, txnMeta);
TxMeta m (transID, 0, txnMeta);
txIDs.push_back (std::make_pair (transID, m.getIndex ()));
}

View File

@@ -35,7 +35,7 @@ namespace ripple {
// VFALCO TODO rename to SortedTxSet
class CanonicalTXSet
{
public:
private:
class Key
{
public:
@@ -71,6 +71,7 @@ public:
std::uint32_t mSeq;
};
public:
using iterator = std::map <Key, std::shared_ptr<STTx const>>::iterator;
using const_iterator = std::map <Key, std::shared_ptr<STTx const>>::const_iterator;

View File

@@ -24,6 +24,7 @@
#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>
@@ -38,7 +39,7 @@
#include <ripple/app/misc/Validations.h>
#include <ripple/app/misc/impl/AccountTxPaging.h>
#include <ripple/app/misc/UniqueNodeList.h>
#include <ripple/app/tx/TransactionEngine.h>
#include <ripple/app/tx/apply.h>
#include <ripple/app/tx/TransactionMaster.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/Time.h>
@@ -251,19 +252,6 @@ public:
*/
void apply (std::unique_lock<std::mutex>& batchLock);
/**
* Apply each transaction to open ledger.
*
* @param ledger Open ledger.
* @param engine Engine that applies transactions to open ledger.
* @param transactions Batch of transactions to apply.
* @return Whether any transactions in batch succeeded.
*/
bool batchApply (
Ledger::pointer& ledger,
TransactionEngine& engine,
std::vector<TransactionStatus>& transactions);
//
// Owner functions.
//
@@ -987,14 +975,35 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
batchLock.unlock();
{
Ledger::pointer ledger;
TransactionEngine engine;
{
bool applied = false;
boost::optional<MetaView> accum;
auto lock = beast::make_lock(getApp().getMasterMutex());
if (batchApply (ledger, engine, transactions))
{
std::lock_guard <std::recursive_mutex> lock (
m_ledgerMaster.peekMutex());
ledger = m_ledgerMaster.getCurrentLedgerHolder().getMutable();
accum.emplace(*ledger, tapNONE);
for (TransactionStatus& e : transactions)
{
ViewFlags flags = tapNONE;
flags = flags | tapNO_CHECK_SIGN;
if (e.admin)
flags = flags | tapADMIN;
std::tie (e.result, e.applied) =
ripple::apply (*accum,
*e.transaction->getSTransaction(), flags,
getConfig(), deprecatedLogs().journal(
"NetworkOPs"));
applied |= e.applied;
}
}
if (applied)
{
accum->apply(*ledger,
deprecatedLogs().journal("NetworkOPs"));
ledger->setImmutable();
m_ledgerMaster.getCurrentLedgerHolder().set (ledger);
}
@@ -1101,28 +1110,6 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
mDispatchState = DispatchState::none;
}
bool NetworkOPsImp::batchApply (Ledger::pointer& ledger,
TransactionEngine& engine,
std::vector<TransactionStatus>& transactions)
{
bool applied = false;
std::lock_guard <std::recursive_mutex> lock (m_ledgerMaster.peekMutex());
ledger = m_ledgerMaster.getCurrentLedgerHolder().getMutable();
engine.setLedger (ledger);
for (TransactionStatus& e : transactions)
{
std::tie (e.result, e.applied) = engine.applyTransaction (
*e.transaction->getSTransaction(),
e.admin ? (tapOPEN_LEDGER | tapNO_CHECK_SIGN | tapADMIN) : (
tapOPEN_LEDGER | tapNO_CHECK_SIGN));
applied |= e.applied;
}
return applied;
}
//
// Owner functions
//
@@ -1793,7 +1780,7 @@ NetworkOPs::AccountTxs NetworkOPsImp::getAccountTxs (
ledger->pendSaveValidated(false, false);
}
ret.emplace_back (txn, std::make_shared<TransactionMetaSet> (
ret.emplace_back (txn, std::make_shared<TxMeta> (
txn->getID (), txn->getLedger (), txnMeta));
}
}

View File

@@ -233,7 +233,7 @@ public:
virtual std::size_t getLocalTxCount () = 0;
// client information retrieval functions
using AccountTx = std::pair<Transaction::pointer, TransactionMetaSet::pointer>;
using AccountTx = std::pair<Transaction::pointer, TxMeta::pointer>;
using AccountTxs = std::vector<AccountTx>;
virtual AccountTxs getAccountTxs (

View File

@@ -46,7 +46,7 @@ convertBlobsToTxResult (
tr->setStatus (Transaction::sqlTransactionStatus(status));
tr->setLedger (ledger_index);
auto metaset = std::make_shared<TransactionMetaSet> (
auto metaset = std::make_shared<TxMeta> (
tr->getID (), tr->getLedger (), rawMeta);
to.emplace_back(std::move(tr), metaset);

View File

@@ -525,8 +525,8 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
if (valid)
{
boost::optional<PaymentView> sandbox;
sandbox.emplace(cache->getLedger().get(),
tapOPEN_LEDGER);
sandbox.emplace(*cache->getLedger(),
tapNONE);
auto& sourceAccount = !isXRP (currIssuer.account)
? currIssuer.account
@@ -552,8 +552,8 @@ 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().get(),
tapOPEN_LEDGER);
sandbox.emplace(*cache->getLedger(),
tapNONE);
rc = path::RippleCalc::rippleCalculate (
*sandbox,
saMaxAmount,

View File

@@ -378,7 +378,7 @@ TER Pathfinder::getPathLiquidity (
path::RippleCalc::Input rcInput;
rcInput.defaultPathsAllowed = false;
PaymentView sandbox (mLedger.get(), tapOPEN_LEDGER);
PaymentView 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.get(), tapOPEN_LEDGER);
PaymentView sandbox (*mLedger, tapNONE);
path::RippleCalc::Input rcInput;
rcInput.partialPaymentAllowed = true;

View File

@@ -212,7 +212,7 @@ TER PathCursor::advanceNode (bool const bReverse) const
if (node().sleOffer->isFieldPresent (sfExpiration) &&
(node().sleOffer->getFieldU32 (sfExpiration) <=
view().time()))
view().parentCloseTime()))
{
// Offer is expired.
WriteLog (lsTRACE, RippleCalc)

View File

@@ -73,14 +73,14 @@ public:
/** @{ */
explicit
PaymentView (PaymentView const* parent)
: ViewWrapper (parent)
: ViewWrapper (*parent, parent->flags())
, pv_ (parent)
{
}
explicit
PaymentView (PaymentView* parent)
: ViewWrapper (parent)
: ViewWrapper (*parent, parent->flags())
, pv_ (parent)
{
}

56
src/ripple/app/tx/apply.h Normal file
View File

@@ -0,0 +1,56 @@
//------------------------------------------------------------------------------
/*
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_TX_APPLY_H_INCLUDED
#define RIPPLE_TX_APPLY_H_INCLUDED
#include <ripple/core/Config.h>
#include <ripple/ledger/View.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/TER.h>
#include <beast/utility/Journal.h>
#include <memory>
#include <utility>
namespace ripple {
/** Apply a transaction to a BasicView.
Throws:
Exceptions are thrown on broken invariants. Callers
should catch these exceptions to protect the ledger
and the running process.
std::logic_error
(any)
@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,
Config const& config,
beast::Journal journal);
} // ripple
#endif

View File

@@ -0,0 +1,55 @@
//------------------------------------------------------------------------------
/*
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/tx/impl/ApplyContext.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/Indexes.h>
#include <cassert>
namespace ripple {
ApplyContext::ApplyContext(
BasicView& base, STTx const& tx_,
ViewFlags flags, Config const& config_,
beast::Journal journal_)
: tx (tx_)
, config (config_)
, journal(journal_)
, base_ (base)
, flags_(flags)
{
view_.emplace(base_, flags_);
}
void
ApplyContext::discard()
{
view_.emplace(base_, flags_);
}
void
ApplyContext::apply(TER ter)
{
view_->apply(base_, tx, ter, journal);
}
} // ripple

View File

@@ -17,11 +17,13 @@
*/
//==============================================================================
#ifndef RIPPLE_APP_TX_TRANSACTIONENGINE_H_INCLUDED
#define RIPPLE_APP_TX_TRANSACTIONENGINE_H_INCLUDED
#ifndef RIPPLE_TX_APPLYCONTEXT_H_INCLUDED
#define RIPPLE_TX_APPLYCONTEXT_H_INCLUDED
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/ledger/MetaView.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/STTx.h>
#include <beast/utility/Journal.h>
#include <boost/optional.hpp>
#include <utility>
@@ -29,71 +31,54 @@ namespace ripple {
// tx_enable_test
// One instance per ledger.
// Only one transaction applied at a time.
class TransactionEngine
/** State information when applying a tx. */
class ApplyContext
{
boost::optional<MetaView> mNodes;
void txnWrite();
protected:
Ledger::pointer mLedger;
int mTxnSeq = 0;
public:
TransactionEngine() = default;
explicit
TransactionEngine (Ledger::ref ledger)
: mLedger (ledger)
{
assert (mLedger);
}
ApplyContext (BasicView& base,
STTx const& tx, ViewFlags flags,
Config const& config,
beast::Journal = {});
STTx const& tx;
Config const& config;
beast::Journal const journal;
View&
view ()
view()
{
return *mNodes;
return *view_;
}
Ledger::ref
getLedger()
View const&
view() const
{
return mLedger;
}
void
setLedger (Ledger::ref ledger)
{
assert (ledger);
mLedger = ledger;
return *view_;
}
/** Sets the DeliveredAmount field in the metadata */
void
deliverAmount (STAmount const& delivered)
{
mNodes->setDeliveredAmount(delivered);
view_->setDeliveredAmount(delivered);
}
std::pair<TER, bool>
applyTransaction (STTx const&, ViewFlags);
/** Discard changes and start fresh. */
void
discard();
bool
checkInvariants (TER result, STTx const& txn, ViewFlags params);
/** Apply the transaction result to the base. */
void
apply (TER);
private:
BasicView& base_;
ViewFlags flags_;
beast::Journal j_;
boost::optional<MetaView> view_;
};
inline ViewFlags operator| (const ViewFlags& l1, const ViewFlags& l2)
{
return static_cast<ViewFlags> (static_cast<int> (l1) | static_cast<int> (l2));
}
inline ViewFlags operator& (const ViewFlags& l1, const ViewFlags& l2)
{
return static_cast<ViewFlags> (static_cast<int> (l1) & static_cast<int> (l2));
}
} // ripple
#endif

View File

@@ -1,4 +1,4 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
@@ -18,37 +18,21 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/tx/impl/CancelOffer.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
class CancelOffer
: public Transactor
TER
CancelOffer::preCheck ()
{
public:
CancelOffer (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("CancelOffer"))
{
}
TER preCheck () override
{
std::uint32_t const uTxFlags (mTxn.getFlags ());
if (uTxFlags & tfUniversalMask)
{
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Invalid flags set.";
return temINVALID_FLAG;
}
@@ -57,48 +41,39 @@ public:
if (!uOfferSequence)
{
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"No sequence specified.";
return temBAD_SEQUENCE;
}
return Transactor::preCheck ();
}
}
TER doApply () override
{
TER
CancelOffer::doApply ()
{
std::uint32_t const uOfferSequence = mTxn.getFieldU32 (sfOfferSequence);
if (mTxnAccount->getFieldU32 (sfSequence) - 1 <= uOfferSequence)
{
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Sequence " << uOfferSequence << " is invalid.";
return temBAD_SEQUENCE;
}
uint256 const offerIndex (getOfferIndex (mTxnAccountID, uOfferSequence));
auto sleOffer = mEngine->view().peek (
auto sleOffer = view().peek (
keylet::offer(offerIndex));
if (sleOffer)
{
m_journal.debug << "Trying to cancel offer #" << uOfferSequence;
return offerDelete (mEngine->view(), sleOffer);
j_.debug << "Trying to cancel offer #" << uOfferSequence;
return offerDelete (view(), sleOffer);
}
m_journal.debug << "Offer #" << uOfferSequence << " can't be found.";
j_.debug << "Offer #" << uOfferSequence << " can't be found.";
return tesSUCCESS;
}
};
TER
transact_CancelOffer (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
return CancelOffer (txn, params, engine).apply ();
}
}

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
/*
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_TX_CANCELOFFER_H_INCLUDED
#define RIPPLE_TX_CANCELOFFER_H_INCLUDED
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
class CancelOffer
: public Transactor
{
public:
template <class... Args>
CancelOffer (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER preCheck () override;
TER doApply () override;
};
}
#endif

View File

@@ -18,38 +18,32 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/tx/impl/CancelTicket.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
class CancelTicket
: public Transactor
TER
CancelTicket::preCheck()
{
public:
CancelTicket (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("CancelTicket"))
{
#if ! RIPPLE_ENABLE_TICKETS
if (! (view().flags() & tapENABLE_TESTING))
return temDISABLED;
#endif
return Transactor::preCheck ();
}
}
TER doApply () override
{
TER
CancelTicket::doApply ()
{
assert (mTxnAccount);
uint256 const ticketId = mTxn.getFieldH256 (sfTicketID);
// VFALCO This is highly suspicious, we're requiring that the
// transaction provide the return value of getTicketIndex?
SLE::pointer sleTicket = mEngine->view().peek (keylet::ticket(ticketId));
SLE::pointer sleTicket = view().peek (keylet::ticket(ticketId));
if (!sleTicket)
return tecNO_ENTRY;
@@ -69,7 +63,7 @@ public:
{
std::uint32_t const expiration = sleTicket->getFieldU32 (sfExpiration);
if (mEngine->view().time() >= expiration)
if (view().parentCloseTime() >= expiration)
authorized = true;
}
@@ -78,29 +72,14 @@ public:
std::uint64_t const hint (sleTicket->getFieldU64 (sfOwnerNode));
TER const result = dirDelete (mEngine->view (), false, hint,
TER const result = dirDelete (ctx_.view (), false, hint,
getOwnerDirIndex (ticket_owner), ticketId, false, (hint == 0));
adjustOwnerCount(mEngine->view(), mEngine->view().peek(
adjustOwnerCount(view(), view().peek(
keylet::account(ticket_owner)), -1);
mEngine->view ().erase (sleTicket);
ctx_.view ().erase (sleTicket);
return result;
}
};
TER
transact_CancelTicket (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
#if ! RIPPLE_ENABLE_TICKETS
if (! (engine->view().flags() & tapENABLE_TESTING))
return temDISABLED;
#endif
return CancelTicket (txn, params, engine).apply();
}
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 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_TX_CANCELTICKET_H_INCLUDED
#define RIPPLE_TX_CANCELTICKET_H_INCLUDED
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
class CancelTicket
: public Transactor
{
public:
template <class... Args>
CancelTicket (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER preCheck() override;
TER doApply () override;
};
}
#endif

View File

@@ -18,33 +18,18 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Change.h>
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/AmendmentTable.h>
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
class Change
: public Transactor
TER
Change::doApply()
{
public:
Change (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("Change"))
{
}
TER doApply () override
{
if (mTxn.getTxnType () == ttAMENDMENT)
return applyAmendment ();
@@ -52,80 +37,84 @@ public:
return applyFee ();
return temUNKNOWN;
}
}
TER checkSign () override
{
TER
Change::checkSign()
{
if (mTxn.getAccountID (sfAccount).isNonZero ())
{
m_journal.warning << "Bad source account";
j_.warning << "Bad source account";
return temBAD_SRC_ACCOUNT;
}
if (!mTxn.getSigningPubKey ().empty () || !mTxn.getSignature ().empty ())
{
m_journal.warning << "Bad signature";
j_.warning << "Bad signature";
return temBAD_SIGNATURE;
}
return tesSUCCESS;
}
}
TER checkSeq () override
{
TER
Change::checkSeq()
{
if ((mTxn.getSequence () != 0) || mTxn.isFieldPresent (sfPreviousTxnID))
{
m_journal.warning << "Bad sequence";
j_.warning << "Bad sequence";
return temBAD_SEQUENCE;
}
return tesSUCCESS;
}
}
TER payFee () override
{
TER
Change::payFee()
{
if (mTxn.getTransactionFee () != STAmount ())
{
m_journal.warning << "Non-zero fee";
j_.warning << "Non-zero fee";
return temBAD_FEE;
}
return tesSUCCESS;
}
}
TER preCheck () override
{
TER
Change::preCheck()
{
mTxnAccountID = mTxn.getAccountID(sfAccount);
if (mTxnAccountID.isNonZero ())
{
m_journal.warning << "Bad source id";
j_.warning << "Bad source id";
return temBAD_SRC_ACCOUNT;
}
if (mParams & tapOPEN_LEDGER)
if (view().open())
{
m_journal.warning << "Change transaction against open ledger";
j_.warning << "Change transaction against open ledger";
return temINVALID;
}
return tesSUCCESS;
}
}
private:
TER applyAmendment ()
{
TER
Change::applyAmendment()
{
uint256 amendment (mTxn.getFieldH256 (sfAmendment));
auto const k = keylet::amendments();
SLE::pointer amendmentObject =
mEngine->view().peek (k);
view().peek (k);
if (!amendmentObject)
{
amendmentObject = std::make_shared<SLE>(k);
mEngine->view().insert(amendmentObject);
view().insert(amendmentObject);
}
STVector256 amendments =
@@ -137,7 +126,7 @@ private:
amendments.push_back (amendment);
amendmentObject->setFieldV256 (sfAmendments, amendments);
mEngine->view().update (amendmentObject);
view().update (amendmentObject);
getApp().getAmendmentTable ().enable (amendment);
@@ -145,22 +134,23 @@ private:
getApp().getOPs ().setAmendmentBlocked ();
return tesSUCCESS;
}
}
TER applyFee ()
{
TER
Change::applyFee()
{
auto const k = keylet::fees();
SLE::pointer feeObject = mEngine->view().peek (k);
SLE::pointer feeObject = view().peek (k);
if (!feeObject)
{
feeObject = std::make_shared<SLE>(k);
mEngine->view().insert(feeObject);
view().insert(feeObject);
}
// VFALCO-FIXME this generates errors
// m_journal.trace <<
// j_.trace <<
// "Previous fee object: " << feeObject->getJson (0);
feeObject->setFieldU64 (
@@ -172,30 +162,13 @@ private:
feeObject->setFieldU32 (
sfReserveIncrement, mTxn.getFieldU32 (sfReserveIncrement));
mEngine->view().update (feeObject);
view().update (feeObject);
// VFALCO-FIXME this generates errors
// m_journal.trace <<
// j_.trace <<
// "New fee object: " << feeObject->getJson (0);
m_journal.warning << "Fees have been changed";
j_.warning << "Fees have been changed";
return tesSUCCESS;
}
// VFALCO TODO Can this be removed?
bool mustHaveValidAccount () override
{
return false;
}
};
TER
transact_Change (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
return Change (txn, params, engine).apply ();
}
}

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
/*
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_TX_CHANGE_H_INCLUDED
#define RIPPLE_TX_CHANGE_H_INCLUDED
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/AmendmentTable.h>
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
class Change
: public Transactor
{
public:
template <class... Args>
Change (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER doApply () override;
TER checkSign () override;
TER checkSeq () override;
TER payFee () override;
TER preCheck () override;
private:
TER applyAmendment ();
TER applyFee ();
// VFALCO TODO Can this be removed?
bool mustHaveValidAccount () override
{
return false;
}
};
}
#endif

View File

@@ -18,9 +18,10 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/CreateOffer.h>
#include <ripple/app/tx/impl/OfferStream.h>
#include <ripple/app/tx/impl/Taker.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/protocol/Quality.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
@@ -31,42 +32,34 @@
namespace ripple {
class CreateOffer
: public Transactor
TER
CreateOffer::checkAcceptAsset(IssueRef issue) const
{
private:
// What kind of offer we are placing
CrossType cross_type_;
/** Determine if we are authorized to hold the asset we want to get */
TER
checkAcceptAsset(IssueRef issue) const
{
// Only valid for custom currencies
assert (!isXRP (issue.currency));
auto const issuerAccount = mEngine->view().read(
auto const issuerAccount = ctx_.view().read(
keylet::account(issue.account));
if (!issuerAccount)
{
if (m_journal.warning) m_journal.warning <<
if (j_.warning) j_.warning <<
"delay: can't receive IOUs from non-existent issuer: " <<
to_string (issue.account);
return (mParams & tapRETRY)
return (view().flags() & tapRETRY)
? terNO_ACCOUNT
: tecNO_ISSUER;
}
if (issuerAccount->getFieldU32 (sfFlags) & lsfRequireAuth)
{
auto const trustLine = mEngine->view().read(
auto const trustLine = ctx_.view().read(
keylet::line(mTxnAccountID, issue.account, issue.currency));
if (!trustLine)
{
return (mParams & tapRETRY)
return (view().flags() & tapRETRY)
? terNO_LINE
: tecNO_LINE;
}
@@ -81,35 +74,33 @@ private:
if (!is_authorized)
{
if (m_journal.debug) m_journal.debug <<
if (j_.debug) j_.debug <<
"delay: can't receive IOUs from issuer without auth.";
return (mParams & tapRETRY)
return (view().flags() & tapRETRY)
? terNO_AUTH
: tecNO_AUTH;
}
}
return tesSUCCESS;
}
}
static
bool
dry_offer (View& view, Offer const& offer)
{
bool
CreateOffer::dry_offer (View& view, Offer const& offer)
{
if (offer.fully_consumed ())
return true;
auto const amount = accountFunds(view, offer.owner(),
offer.amount().out, fhZERO_IF_FROZEN, getConfig());
offer.amount().out, fhZERO_IF_FROZEN, ctx_.config);
return (amount <= zero);
}
}
static
std::pair<bool, Quality>
select_path (
std::pair<bool, Quality>
CreateOffer::select_path (
bool have_direct, OfferStream const& direct,
bool have_bridge, OfferStream const& leg1, OfferStream const& leg2)
{
{
// If we don't have any viable path, why are we here?!
assert (have_direct || have_bridge);
@@ -133,15 +124,15 @@ private:
// Either there was no direct offer, or it didn't have a better quality
// than the bridge.
return std::make_pair (false, bridged_quality);
}
}
std::pair<TER, Amounts>
bridged_cross (
std::pair<TER, Amounts>
CreateOffer::bridged_cross (
Taker& taker,
View& view,
View& view_cancel,
Clock::time_point const when)
{
{
auto const& taker_amount = taker.original_offer ();
assert (!isXRP (taker_amount.in) && !isXRP (taker_amount.out));
@@ -150,13 +141,13 @@ private:
throw std::logic_error ("Bridging with XRP and an endpoint.");
OfferStream offers_direct (view, view_cancel,
Book (taker.issue_in (), taker.issue_out ()), when, m_journal);
Book (taker.issue_in (), taker.issue_out ()), when, ctx_.config, j_);
OfferStream offers_leg1 (view, view_cancel,
Book (taker.issue_in (), xrpIssue ()), when, m_journal);
Book (taker.issue_in (), xrpIssue ()), when, ctx_.config, j_);
OfferStream offers_leg2 (view, view_cancel,
Book (xrpIssue (), taker.issue_out ()), when, m_journal);
Book (xrpIssue (), taker.issue_out ()), when, ctx_.config, j_);
TER cross_result = tesSUCCESS;
@@ -191,23 +182,23 @@ private:
if (use_direct)
{
if (m_journal.debug)
if (j_.debug)
{
m_journal.debug << count << " Direct:";
m_journal.debug << " offer: " << offers_direct.tip ();
m_journal.debug << " in: " << offers_direct.tip ().amount().in;
m_journal.debug << " out: " << offers_direct.tip ().amount ().out;
m_journal.debug << " owner: " << offers_direct.tip ().owner ();
m_journal.debug << " funds: " << accountFunds(view,
j_.debug << count << " Direct:";
j_.debug << " offer: " << offers_direct.tip ();
j_.debug << " in: " << offers_direct.tip ().amount().in;
j_.debug << " out: " << offers_direct.tip ().amount ().out;
j_.debug << " owner: " << offers_direct.tip ().owner ();
j_.debug << " funds: " << accountFunds(view,
offers_direct.tip ().owner (),
offers_direct.tip ().amount ().out,
fhIGNORE_FREEZE,
getConfig());
ctx_.config);
}
cross_result = taker.cross(offers_direct.tip ());
m_journal.debug << "Direct Result: " << transToken (cross_result);
j_.debug << "Direct Result: " << transToken (cross_result);
if (dry_offer (view, offers_direct.tip ()))
{
@@ -217,36 +208,36 @@ private:
}
else
{
if (m_journal.debug)
if (j_.debug)
{
auto const owner1_funds_before = accountFunds(view,
offers_leg1.tip ().owner (),
offers_leg1.tip ().amount ().out,
fhIGNORE_FREEZE,
getConfig());
ctx_.config);
auto const owner2_funds_before = accountFunds(view,
offers_leg2.tip ().owner (),
offers_leg2.tip ().amount ().out,
fhIGNORE_FREEZE,
getConfig());
ctx_.config);
m_journal.debug << count << " Bridge:";
m_journal.debug << " offer1: " << offers_leg1.tip ();
m_journal.debug << " in: " << offers_leg1.tip ().amount().in;
m_journal.debug << " out: " << offers_leg1.tip ().amount ().out;
m_journal.debug << " owner: " << offers_leg1.tip ().owner ();
m_journal.debug << " funds: " << owner1_funds_before;
m_journal.debug << " offer2: " << offers_leg2.tip ();
m_journal.debug << " in: " << offers_leg2.tip ().amount ().in;
m_journal.debug << " out: " << offers_leg2.tip ().amount ().out;
m_journal.debug << " owner: " << offers_leg2.tip ().owner ();
m_journal.debug << " funds: " << owner2_funds_before;
j_.debug << count << " Bridge:";
j_.debug << " offer1: " << offers_leg1.tip ();
j_.debug << " in: " << offers_leg1.tip ().amount().in;
j_.debug << " out: " << offers_leg1.tip ().amount ().out;
j_.debug << " owner: " << offers_leg1.tip ().owner ();
j_.debug << " funds: " << owner1_funds_before;
j_.debug << " offer2: " << offers_leg2.tip ();
j_.debug << " in: " << offers_leg2.tip ().amount ().in;
j_.debug << " out: " << offers_leg2.tip ().amount ().out;
j_.debug << " owner: " << offers_leg2.tip ().owner ();
j_.debug << " funds: " << owner2_funds_before;
}
cross_result = taker.cross(offers_leg1.tip (), offers_leg2.tip ());
m_journal.debug << "Bridge Result: " << transToken (cross_result);
j_.debug << "Bridge Result: " << transToken (cross_result);
if (dry_offer (view, offers_leg1.tip ()))
{
@@ -268,7 +259,7 @@ private:
if (taker.done())
{
m_journal.debug << "The taker reports he's done during crossing!";
j_.debug << "The taker reports he's done during crossing!";
break;
}
@@ -281,19 +272,19 @@ private:
}
return std::make_pair(cross_result, taker.remaining_offer ());
}
}
std::pair<TER, Amounts>
direct_cross (
std::pair<TER, Amounts>
CreateOffer::direct_cross (
Taker& taker,
View& view,
View& view_cancel,
Clock::time_point const when)
{
{
OfferStream offers (
view, view_cancel,
Book (taker.issue_in (), taker.issue_out ()),
when, m_journal);
when, ctx_.config, j_);
TER cross_result (tesSUCCESS);
int count = 0;
@@ -313,20 +304,20 @@ private:
count++;
if (m_journal.debug)
if (j_.debug)
{
m_journal.debug << count << " Direct:";
m_journal.debug << " offer: " << offer;
m_journal.debug << " in: " << offer.amount ().in;
m_journal.debug << " out: " << offer.amount ().out;
m_journal.debug << " owner: " << offer.owner ();
m_journal.debug << " funds: " << accountFunds(view,
offer.owner (), offer.amount ().out, fhIGNORE_FREEZE, getConfig());
j_.debug << count << " Direct:";
j_.debug << " offer: " << offer;
j_.debug << " in: " << offer.amount ().in;
j_.debug << " out: " << offer.amount ().out;
j_.debug << " owner: " << offer.owner ();
j_.debug << " funds: " << accountFunds(view,
offer.owner (), offer.amount ().out, fhIGNORE_FREEZE, ctx_.config);
}
cross_result = taker.cross (offer);
m_journal.debug << "Direct Result: " << transToken (cross_result);
j_.debug << "Direct Result: " << transToken (cross_result);
if (dry_offer (view, offer))
{
@@ -342,7 +333,7 @@ private:
if (taker.done())
{
m_journal.debug << "The taker reports he's done during crossing!";
j_.debug << "The taker reports he's done during crossing!";
break;
}
@@ -355,15 +346,14 @@ private:
}
return std::make_pair(cross_result, taker.remaining_offer ());
}
}
// Step through the stream for as long as possible, skipping any offers
// that are from the taker or which cross the taker's threshold.
// Return false if the is no offer in the book, true otherwise.
static
bool
step_account (OfferStream& stream, Taker const& taker)
{
// Step through the stream for as long as possible, skipping any offers
// that are from the taker or which cross the taker's threshold.
// Return false if the is no offer in the book, true otherwise.
bool
CreateOffer::step_account (OfferStream& stream, Taker const& taker)
{
while (stream.step ())
{
auto const& offer = stream.tip ();
@@ -379,25 +369,25 @@ private:
// We ran out of offers. Can't advance.
return false;
}
}
// Fill offer as much as possible by consuming offers already on the books,
// and adjusting account balances accordingly.
//
// Charges fees on top to taker.
std::pair<TER, Amounts>
cross (
// Fill offer as much as possible by consuming offers already on the books,
// and adjusting account balances accordingly.
//
// Charges fees on top to taker.
std::pair<TER, Amounts>
CreateOffer::cross (
View& view,
View& cancel_view,
Amounts const& taker_amount)
{
{
Clock::time_point const when =
mEngine->view().time();
ctx_.view().parentCloseTime();
beast::WrappedSink takerSink (m_journal, "Taker ");
beast::WrappedSink takerSink (j_, "Taker ");
Taker taker (cross_type_, view, mTxnAccountID, taker_amount,
mTxn.getFlags(), beast::Journal (takerSink));
mTxn.getFlags(), ctx_.config, beast::Journal (takerSink));
try
{
@@ -408,58 +398,50 @@ private:
}
catch (std::exception const& e)
{
m_journal.error << "Exception during offer crossing: " << e.what ();
j_.error << "Exception during offer crossing: " << e.what ();
return std::make_pair (tecINTERNAL, taker.remaining_offer ());
}
catch (...)
{
m_journal.error << "Exception during offer crossing.";
j_.error << "Exception during offer crossing.";
return std::make_pair (tecINTERNAL, taker.remaining_offer ());
}
}
}
static
std::string
format_amount (STAmount const& amount)
{
std::string
CreateOffer::format_amount (STAmount const& amount)
{
std::string txt = amount.getText ();
txt += "/";
txt += to_string (amount.issue().currency);
return txt;
}
}
public:
CreateOffer (
CrossType cross_type,
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("CreateOffer"))
, cross_type_ (cross_type)
{
}
/** Returns the reserve the account would have if an offer was added. */
STAmount
getAccountReserve (SLE::pointer account)
{
return STAmount (mEngine->view().fees().accountReserve(
STAmount
CreateOffer::getAccountReserve (SLE::pointer account)
{
return STAmount (ctx_.view().fees().accountReserve(
account->getFieldU32 (sfOwnerCount) + 1));
}
}
TER
CreateOffer::preCheck ()
{
cross_type_ = CrossType::IouToIou;
bool const pays_xrp =
mTxn.getFieldAmount (sfTakerPays).native ();
bool const gets_xrp =
mTxn.getFieldAmount (sfTakerGets).native ();
if (pays_xrp && !gets_xrp)
cross_type_ = CrossType::IouToXrp;
else if (gets_xrp && !pays_xrp)
cross_type_ = CrossType::XrpToIou;
TER
preCheck () override
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
if (uTxFlags & tfOfferCreateMask)
{
if (m_journal.debug) m_journal.debug <<
if (j_.debug) j_.debug <<
"Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
@@ -469,7 +451,7 @@ public:
if (bImmediateOrCancel && bFillOrKill)
{
if (m_journal.debug) m_journal.debug <<
if (j_.debug) j_.debug <<
"Malformed transaction: both IoC and FoK set.";
return temINVALID_FLAG;
}
@@ -478,7 +460,7 @@ public:
if (bHaveExpiration && (mTxn.getFieldU32 (sfExpiration) == 0))
{
if (m_journal.debug) m_journal.warning <<
if (j_.debug) j_.warning <<
"Malformed offer: bad expiration";
return temBAD_EXPIRATION;
}
@@ -487,7 +469,7 @@ public:
if (bHaveCancel && (mTxn.getFieldU32 (sfOfferSequence) == 0))
{
if (m_journal.debug) m_journal.debug <<
if (j_.debug) j_.debug <<
"Malformed offer: bad cancel sequence";
return temBAD_SEQUENCE;
}
@@ -500,13 +482,13 @@ public:
if (saTakerPays.native () && saTakerGets.native ())
{
if (m_journal.debug) m_journal.warning <<
if (j_.debug) j_.warning <<
"Malformed offer: XRP for XRP";
return temBAD_OFFER;
}
if (saTakerPays <= zero || saTakerGets <= zero)
{
if (m_journal.debug) m_journal.warning <<
if (j_.debug) j_.warning <<
"Malformed offer: bad amount";
return temBAD_OFFER;
}
@@ -519,14 +501,14 @@ public:
if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID)
{
if (m_journal.debug) m_journal.debug <<
if (j_.debug) j_.debug <<
"Malformed offer: redundant offer";
return temREDUNDANT;
}
// We don't allow a non-native currency to use the currency code XRP.
if (badCurrency() == uPaysCurrency || badCurrency() == uGetsCurrency)
{
if (m_journal.debug) m_journal.warning <<
if (j_.debug) j_.warning <<
"Malformed offer: Bad currency.";
return temBAD_CURRENCY;
}
@@ -534,17 +516,17 @@ public:
if (saTakerPays.native () != !uPaysIssuerID ||
saTakerGets.native () != !uGetsIssuerID)
{
if (m_journal.warning) m_journal.warning <<
if (j_.warning) j_.warning <<
"Malformed offer: bad issuer";
return temBAD_ISSUER;
}
return Transactor::preCheck ();
}
}
std::pair<TER, bool>
applyGuts (View& view, View& view_cancel)
{
std::pair<TER, bool>
CreateOffer::applyGuts (View& view, View& view_cancel)
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
bool const bPassive (uTxFlags & tfPassive);
@@ -591,15 +573,15 @@ public:
if (isGlobalFrozen (view, uPaysIssuerID) || isGlobalFrozen (view, uGetsIssuerID))
{
if (m_journal.warning) m_journal.warning <<
if (j_.warning) j_.warning <<
"Offer involves frozen asset";
result = tecFROZEN;
}
else if (accountFunds(view, mTxnAccountID, saTakerGets,
fhZERO_IF_FROZEN, getConfig()) <= zero)
fhZERO_IF_FROZEN, ctx_.config) <= zero)
{
if (m_journal.debug) m_journal.debug <<
if (j_.debug) j_.debug <<
"delay: Offers must be at least partially funded.";
result = tecUNFUNDED_OFFER;
@@ -608,7 +590,7 @@ public:
// before the transaction sequence number.
else if (bHaveCancel && (uAccountSequenceNext - 1 <= uCancelSequence))
{
if (m_journal.debug) m_journal.debug <<
if (j_.debug) j_.debug <<
"uAccountSequenceNext=" << uAccountSequenceNext <<
" uOfferSequence=" << uCancelSequence;
@@ -617,7 +599,7 @@ public:
if (result != tesSUCCESS)
{
m_journal.debug << "final result: " << transToken (result);
j_.debug << "final result: " << transToken (result);
return { result, true };
}
@@ -632,7 +614,7 @@ public:
// to fail to delete it.
if (sleCancel)
{
m_journal.debug << "Create cancels order " << uCancelSequence;
j_.debug << "Create cancels order " << uCancelSequence;
result = offerDelete (view, sleCancel);
}
}
@@ -641,7 +623,7 @@ public:
// because we definitively know the time that it closed but we do not
// know the closing time of the ledger that is under construction.
if (bHaveExpiration &&
(mEngine->view().time() >= uExpiration))
(ctx_.view().parentCloseTime() >= uExpiration))
{
return { tesSUCCESS, true };
}
@@ -650,7 +632,8 @@ public:
if (result == tesSUCCESS && !saTakerPays.native ())
result = checkAcceptAsset (Issue (uPaysCurrency, uPaysIssuerID));
bool const bOpenLedger (mParams & tapOPEN_LEDGER);
bool const bOpenLedger =
ctx_.view().open();
bool crossed = false;
if (result == tesSUCCESS)
@@ -663,27 +646,27 @@ public:
// empty (fully crossed), or something in-between.
Amounts place_offer;
m_journal.debug << "Attempting cross: " <<
j_.debug << "Attempting cross: " <<
to_string (taker_amount.in.issue ()) << " -> " <<
to_string (taker_amount.out.issue ());
if (m_journal.trace)
if (j_.trace)
{
m_journal.debug << " mode: " <<
j_.debug << " mode: " <<
(bPassive ? "passive " : "") <<
(bSell ? "sell" : "buy");
m_journal.trace <<" in: " << format_amount (taker_amount.in);
m_journal.trace << " out: " << format_amount (taker_amount.out);
j_.trace <<" in: " << format_amount (taker_amount.in);
j_.trace << " out: " << format_amount (taker_amount.out);
}
std::tie(result, place_offer) = cross (view, view_cancel, taker_amount);
assert (result != tefINTERNAL);
if (m_journal.trace)
if (j_.trace)
{
m_journal.trace << "Cross result: " << transToken (result);
m_journal.trace << " in: " << format_amount (place_offer.in);
m_journal.trace << " out: " << format_amount (place_offer.out);
j_.trace << "Cross result: " << transToken (result);
j_.trace << " in: " << format_amount (place_offer.in);
j_.trace << " out: " << format_amount (place_offer.out);
}
if (result == tecFAILED_PROCESSING && bOpenLedger)
@@ -691,7 +674,7 @@ public:
if (result != tesSUCCESS)
{
m_journal.debug << "final result: " << transToken (result);
j_.debug << "final result: " << transToken (result);
return { result, true };
}
@@ -705,7 +688,7 @@ public:
// never be negative. If it is, something went very very wrong.
if (place_offer.in < zero || place_offer.out < zero)
{
m_journal.fatal << "Cross left offer negative!" <<
j_.fatal << "Cross left offer negative!" <<
" in: " << format_amount (place_offer.in) <<
" out: " << format_amount (place_offer.out);
return { tefINTERNAL, true };
@@ -713,7 +696,7 @@ public:
if (place_offer.in == zero || place_offer.out == zero)
{
m_journal.debug << "Offer fully crossed!";
j_.debug << "Offer fully crossed!";
return { result, true };
}
@@ -728,22 +711,22 @@ public:
if (result != tesSUCCESS)
{
m_journal.debug << "final result: " << transToken (result);
j_.debug << "final result: " << transToken (result);
return { result, true };
}
if (m_journal.trace)
if (j_.trace)
{
m_journal.trace << "Place" << (crossed ? " remaining " : " ") << "offer:";
m_journal.trace << " Pays: " << saTakerPays.getFullText ();
m_journal.trace << " Gets: " << saTakerGets.getFullText ();
j_.trace << "Place" << (crossed ? " remaining " : " ") << "offer:";
j_.trace << " Pays: " << saTakerPays.getFullText ();
j_.trace << " Gets: " << saTakerGets.getFullText ();
}
// For 'fill or kill' offers, failure to fully cross means that the
// entire operation should be aborted, with only fees paid.
if (bFillOrKill)
{
m_journal.trace << "Fill or Kill: offer killed";
j_.trace << "Fill or Kill: offer killed";
return { tesSUCCESS, false };
}
@@ -751,7 +734,7 @@ public:
// placed - it gets cancelled and the operation succeeds.
if (bImmediateOrCancel)
{
m_journal.trace << "Immediate or cancel: offer cancelled";
j_.trace << "Immediate or cancel: offer cancelled";
return { tesSUCCESS, true };
}
@@ -764,7 +747,7 @@ public:
result = tecINSUF_RESERVE_OFFER;
if (result != tesSUCCESS)
m_journal.debug << "final result: " << transToken (result);
j_.debug << "final result: " << transToken (result);
return { result, true };
}
@@ -788,7 +771,7 @@ public:
// Update owner count.
adjustOwnerCount(view, sleCreator, 1);
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"adding to book: " << to_string (saTakerPays.issue ()) <<
" : " << to_string (saTakerGets.issue ());
@@ -827,46 +810,26 @@ public:
}
if (result != tesSUCCESS)
m_journal.debug << "final result: " << transToken (result);
j_.debug << "final result: " << transToken (result);
return { result, true };
}
TER
doApply() override
{
// This is the ledger view that we work against. Transactions are applied
// as we go on processing transactions.
MetaView view (&mEngine->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 (&mEngine->view());
auto const result = applyGuts(view, viewCancel);
if (result.second)
view.apply(mEngine->view());
else
viewCancel.apply(mEngine->view());
return result.first;
}
};
}
TER
transact_CreateOffer (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
CreateOffer::doApply()
{
CrossType cross_type = CrossType::IouToIou;
bool const pays_xrp = txn.getFieldAmount (sfTakerPays).native ();
bool const gets_xrp = txn.getFieldAmount (sfTakerGets).native ();
if (pays_xrp && !gets_xrp)
cross_type = CrossType::IouToXrp;
else if (gets_xrp && !pays_xrp)
cross_type = CrossType::XrpToIou;
return CreateOffer (cross_type, txn, params, engine).apply ();
// 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());
// 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());
auto const result = applyGuts(view, viewCancel);
if (result.second)
view.apply(ctx_.view());
else
viewCancel.apply(ctx_.view());
return result.first;
}
}

View File

@@ -0,0 +1,119 @@
//------------------------------------------------------------------------------
/*
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_TX_CREATEOFFER_H_INCLUDED
#define RIPPLE_TX_CREATEOFFER_H_INCLUDED
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/tx/impl/OfferStream.h>
#include <ripple/app/tx/impl/Taker.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/protocol/Quality.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
#include <beast/cxx14/memory.h>
#include <beast/utility/Journal.h>
#include <beast/utility/WrappedSink.h>
#include <stdexcept>
#include <utility>
namespace ripple {
class CreateOffer
: public Transactor
{
public:
template <class... Args>
CreateOffer (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
/** Returns the reserve the account would have if an offer was added. */
// VFALCO This function is not needed just inline the behavior
STAmount
getAccountReserve (SLE::pointer account); // const?
TER
preCheck () override;
std::pair<TER, bool>
applyGuts (View& view, View& view_cancel);
TER
doApply() override;
private:
/** Determine if we are authorized to hold the asset we want to get */
TER
checkAcceptAsset(IssueRef issue) const;
bool
dry_offer (View& view, Offer const& offer);
static
std::pair<bool, Quality>
select_path (
bool have_direct, OfferStream const& direct,
bool have_bridge, OfferStream const& leg1, OfferStream const& leg2);
std::pair<TER, Amounts>
bridged_cross (
Taker& taker,
View& view,
View& view_cancel,
Clock::time_point const when);
std::pair<TER, Amounts>
direct_cross (
Taker& taker,
View& view,
View& view_cancel,
Clock::time_point const when);
// Step through the stream for as long as possible, skipping any offers
// that are from the taker or which cross the taker's threshold.
// Return false if the is no offer in the book, true otherwise.
static
bool
step_account (OfferStream& stream, Taker const& taker);
// Fill offer as much as possible by consuming offers already on the books,
// and adjusting account balances accordingly.
//
// Charges fees on top to taker.
std::pair<TER, Amounts>
cross (
View& view,
View& cancel_view,
Amounts const& taker_amount);
static
std::string
format_amount (STAmount const& amount);
private:
// What kind of offer we are placing
CrossType cross_type_;
};
}
#endif

View File

@@ -18,55 +18,44 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/tx/impl/CreateTicket.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
class CreateTicket
: public Transactor
TER
CreateTicket::preCheck ()
{
public:
CreateTicket (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("CreateTicket"))
{
#if ! RIPPLE_ENABLE_TICKETS
if (! (view().flags() & tapENABLE_TESTING))
return temDISABLED;
#endif
}
TER
preCheck () override
{
if (mTxn.isFieldPresent (sfExpiration))
{
if (mTxn.getFieldU32 (sfExpiration) == 0)
{
m_journal.warning <<
j_.warning <<
"Malformed transaction: bad expiration";
return temBAD_EXPIRATION;
}
}
return Transactor::preCheck ();
}
}
/** Returns the reserve the account would have if an offer was added. */
STAmount
getAccountReserve (SLE::pointer account)
{
return STAmount (mEngine->view().fees().accountReserve(
STAmount
CreateTicket::getAccountReserve (SLE::pointer account)
{
return STAmount (view().fees().accountReserve(
account->getFieldU32 (sfOwnerCount) + 1));
}
}
TER doApply () override
{
TER
CreateTicket::doApply ()
{
assert (mTxnAccount);
// A ticket counts against the reserve of the issuing account, but we
@@ -81,7 +70,7 @@ public:
{
expiration = mTxn.getFieldU32 (sfExpiration);
if (mEngine->view().time() >= expiration)
if (view().parentCloseTime() >= expiration)
return tesSUCCESS;
}
@@ -91,13 +80,13 @@ public:
sleTicket->setFieldU32 (sfSequence, mTxn.getSequence ());
if (expiration != 0)
sleTicket->setFieldU32 (sfExpiration, expiration);
mEngine->view().insert (sleTicket);
view().insert (sleTicket);
if (mTxn.isFieldPresent (sfTarget))
{
AccountID const target_account (mTxn.getAccountID (sfTarget));
SLE::pointer sleTarget = mEngine->view().peek (keylet::account(target_account));
SLE::pointer sleTarget = view().peek (keylet::account(target_account));
// Destination account does not exist.
if (!sleTarget)
@@ -116,13 +105,13 @@ public:
ownerDirDescriber(p, b, mTxnAccountID);
};
TER result = dirAdd(mEngine->view(),
TER result = dirAdd(view(),
hint,
getOwnerDirIndex (mTxnAccountID),
sleTicket->getIndex (),
describer);
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Creating ticket " << to_string (sleTicket->getIndex ()) <<
": " << transHuman (result);
@@ -132,23 +121,9 @@ public:
sleTicket->setFieldU64(sfOwnerNode, hint);
// If we succeeded, the new entry counts agains the creator's reserve.
adjustOwnerCount(mEngine->view(), mTxnAccount, 1);
adjustOwnerCount(view(), mTxnAccount, 1);
return result;
}
};
TER
transact_CreateTicket (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
#if ! RIPPLE_ENABLE_TICKETS
if (! (engine->view().flags() & tapENABLE_TESTING))
return temDISABLED;
#endif
return CreateTicket (txn, params, engine).apply ();
}
}

View File

@@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 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_TX_CREATETICKET_H_INCLUDED
#define RIPPLE_TX_CREATETICKET_H_INCLUDED
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
class CreateTicket
: public Transactor
{
public:
template <class... Args>
CreateTicket (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER
preCheck () override;
/** Returns the reserve the account would have if an offer was added. */
// VFALCO Not needed, just inline the behavior.
STAmount
getAccountReserve (SLE::pointer account);
TER doApply () override;
};
}
#endif

View File

@@ -23,13 +23,15 @@
namespace ripple {
OfferStream::OfferStream (View& view, View& view_cancel,
BookRef book, Clock::time_point when, beast::Journal journal)
: m_journal (journal)
BookRef book, Clock::time_point when,
Config const& config, beast::Journal journal)
: j_ (journal)
, m_view (view)
, m_view_cancel (view_cancel)
, m_book (book)
, m_when (when)
, m_tip (view, book)
, config_ (config)
{
}
@@ -46,7 +48,7 @@ OfferStream::erase (View& view)
if (p == nullptr)
{
if (m_journal.error) m_journal.error <<
if (j_.error) j_.error <<
"Missing directory " << m_tip.dir() <<
" for offer " << m_tip.index();
return;
@@ -57,7 +59,7 @@ OfferStream::erase (View& view)
if (it == v.end())
{
if (m_journal.error) m_journal.error <<
if (j_.error) j_.error <<
"Missing offer " << m_tip.index() <<
" for directory " << m_tip.dir();
return;
@@ -67,7 +69,7 @@ OfferStream::erase (View& view)
p->setFieldV256 (sfIndexes, v);
view.update (p);
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Missing offer " << m_tip.index() <<
" removed from directory " << m_tip.dir();
}
@@ -99,7 +101,7 @@ OfferStream::step ()
if (entry->isFieldPresent (sfExpiration) &&
entry->getFieldU32 (sfExpiration) <= m_when)
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Removing expired offer " << entry->getIndex();
offerDelete (view_cancel(),
view_cancel().peek(
@@ -114,7 +116,7 @@ OfferStream::step ()
// Remove if either amount is zero
if (amount.empty())
{
if (m_journal.warning) m_journal.warning <<
if (j_.warning) j_.warning <<
"Removing bad offer " << entry->getIndex();
offerDelete (view_cancel(),
view_cancel().peek(
@@ -128,7 +130,7 @@ OfferStream::step ()
// looking up the funds twice?
auto const owner_funds = accountFunds(view(),
m_offer.owner(), amount.out, fhZERO_IF_FROZEN,
getConfig());
config_);
// Check for unfunded offer
if (owner_funds <= zero)
@@ -138,18 +140,18 @@ OfferStream::step ()
// offer is "found unfunded" versus "became unfunded"
auto const original_funds = accountFunds(view_cancel(),
m_offer.owner(), amount.out, fhZERO_IF_FROZEN,
getConfig());
config_);
if (original_funds == owner_funds)
{
offerDelete (view_cancel(), view_cancel().peek(
keylet::offer(entry->key())));
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Removing unfunded offer " << entry->getIndex();
}
else
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Removing became unfunded offer " << entry->getIndex();
}
m_offer = Offer{};

View File

@@ -50,20 +50,23 @@ namespace ripple {
class OfferStream
{
private:
beast::Journal m_journal;
beast::Journal j_;
std::reference_wrapper <View> m_view;
std::reference_wrapper <View> m_view_cancel;
Book m_book;
Clock::time_point m_when;
BookTip m_tip;
Offer m_offer;
Config const& config_;
void
erase (View& view);
public:
OfferStream (View& view, View& view_cancel, BookRef book,
Clock::time_point when, beast::Journal journal);
OfferStream (View& view, View& view_cancel,
BookRef book, Clock::time_point when,
Config const& config,
beast::Journal journal);
View&
view () noexcept

View File

@@ -18,8 +18,8 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Payment.h>
#include <ripple/app/paths/RippleCalc.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/TxFlags.h>
@@ -27,36 +27,14 @@ namespace ripple {
// See https://ripple.com/wiki/Transaction_Format#Payment_.280.29
class Payment
: public Transactor
TER
Payment::preCheck ()
{
/* The largest number of paths we allow */
static std::size_t const MaxPathSize = 6;
/* The longest path we allow */
static std::size_t const MaxPathLength = 8;
public:
Payment (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("Payment"))
{
}
TER preCheck () override
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
if (uTxFlags & tfPaymentMask)
{
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Invalid flags set.";
return temINVALID_FLAG;
}
@@ -94,25 +72,25 @@ public:
if (!uDstAccountID)
{
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Payment destination account not specified.";
return temDST_NEEDED;
}
if (bMax && maxSourceAmount <= zero)
{
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"bad max amount: " << maxSourceAmount.getFullText ();
return temBAD_AMOUNT;
}
if (saDstAmount <= zero)
{
m_journal.trace << "Malformed transaction: "<<
j_.trace << "Malformed transaction: "<<
"bad dst amount: " << saDstAmount.getFullText ();
return temBAD_AMOUNT;
}
if (badCurrency() == uSrcCurrency || badCurrency() == uDstCurrency)
{
m_journal.trace <<"Malformed transaction: " <<
j_.trace <<"Malformed transaction: " <<
"Bad currency.";
return temBAD_CURRENCY;
}
@@ -120,7 +98,7 @@ public:
{
// You're signing yourself a payment.
// If bPaths is true, you might be trying some arbitrage.
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Redundant payment from " << to_string (mTxnAccountID) <<
" to self without path for " << to_string (uDstCurrency);
return temREDUNDANT;
@@ -128,44 +106,45 @@ public:
if (bXRPDirect && bMax)
{
// Consistent but redundant transaction.
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"SendMax specified for XRP to XRP.";
return temBAD_SEND_XRP_MAX;
}
if (bXRPDirect && bPaths)
{
// XRP is sent without paths.
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Paths specified for XRP to XRP.";
return temBAD_SEND_XRP_PATHS;
}
if (bXRPDirect && partialPaymentAllowed)
{
// Consistent but redundant transaction.
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Partial payment specified for XRP to XRP.";
return temBAD_SEND_XRP_PARTIAL;
}
if (bXRPDirect && limitQuality)
{
// Consistent but redundant transaction.
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"Limit quality specified for XRP to XRP.";
return temBAD_SEND_XRP_LIMIT;
}
if (bXRPDirect && !defaultPathsAllowed)
{
// Consistent but redundant transaction.
m_journal.trace << "Malformed transaction: " <<
j_.trace << "Malformed transaction: " <<
"No ripple direct specified for XRP to XRP.";
return temBAD_SEND_XRP_NO_DIRECT;
}
return Transactor::preCheck ();
}
}
TER doApply () override
{
TER
Payment::doApply ()
{
// Ripple if source or destination is non-native or if there are paths.
std::uint32_t const uTxFlags = mTxn.getFlags ();
bool const partialPaymentAllowed = uTxFlags & tfPartialPayment;
@@ -186,31 +165,32 @@ public:
saDstAmount.mantissa(), saDstAmount.exponent (),
saDstAmount < zero);
m_journal.trace <<
j_.trace <<
"maxSourceAmount=" << maxSourceAmount.getFullText () <<
" saDstAmount=" << saDstAmount.getFullText ();
// Open a ledger for editing.
auto const k = keylet::account(uDstAccountID);
SLE::pointer sleDst = mEngine->view().peek (k);
SLE::pointer sleDst = view().peek (k);
if (!sleDst)
{
// Destination account does not exist.
if (!saDstAmount.native ())
{
m_journal.trace <<
j_.trace <<
"Delay transaction: Destination account does not exist.";
// Another transaction could create the account and then this
// transaction would succeed.
return tecNO_DST;
}
else if (mParams & tapOPEN_LEDGER && partialPaymentAllowed)
else if (view().open()
&& partialPaymentAllowed)
{
// You cannot fund an account with a partial payment.
// Make retry work smaller, by rejecting this.
m_journal.trace <<
j_.trace <<
"Delay transaction: Partial payment not allowed to create account.";
@@ -218,11 +198,11 @@ public:
// transaction would succeed.
return telNO_DST_PARTIAL;
}
else if (saDstAmount < STAmount (mEngine->view().fees().accountReserve(0)))
else if (saDstAmount < STAmount (view().fees().accountReserve(0)))
{
// getReserve() is the minimum amount that an account can have.
// Reserve is not scaled by load.
m_journal.trace <<
j_.trace <<
"Delay transaction: Destination account does not exist. " <<
"Insufficent payment to create account.";
@@ -236,7 +216,7 @@ public:
sleDst = std::make_shared<SLE>(k);
sleDst->setAccountID (sfAccount, uDstAccountID);
sleDst->setFieldU32 (sfSequence, 1);
mEngine->view().insert(sleDst);
view().insert(sleDst);
}
else if ((sleDst->getFlags () & lsfRequireDestTag) &&
!mTxn.isFieldPresent (sfDestinationTag))
@@ -246,7 +226,7 @@ public:
// We didn't make this test for a newly-formed account because there's
// no way for this field to be set.
m_journal.trace << "Malformed transaction: DestinationTag required.";
j_.trace << "Malformed transaction: DestinationTag required.";
return tecDST_TAG_NEEDED;
}
@@ -255,7 +235,7 @@ public:
// Tell the engine that we are intending to change the the destination
// account. The source account gets always charged a fee so it's always
// marked as modified.
mEngine->view().update (sleDst);
view().update (sleDst);
}
TER terResult;
@@ -278,7 +258,7 @@ public:
rcInput.defaultPathsAllowed = defaultPathsAllowed;
rcInput.limitQuality = limitQuality;
rcInput.deleteUnfundedOffers = true;
rcInput.isLedgerOpen = static_cast<bool>(mParams & tapOPEN_LEDGER);
rcInput.isLedgerOpen = view().open();
bool pathTooBig = spsPaths.size () > MaxPathSize;
@@ -294,9 +274,9 @@ public:
{
path::RippleCalc::Output rc;
{
PaymentView view (&mEngine->view());
PaymentView pv (view(), view().flags());
rc = path::RippleCalc::rippleCalculate (
view,
pv,
maxSourceAmount,
saDstAmount,
uDstAccountID,
@@ -306,13 +286,13 @@ public:
// VFALCO NOTE We might not need to apply, depending
// on the TER. But always applying *should*
// be safe.
view.apply(mEngine->view());
pv.apply(view());
}
// TODO: is this right? If the amount is the correct amount, was
// the delivered amount previously set?
if (rc.result () == tesSUCCESS && rc.actualAmountOut != saDstAmount)
mEngine->deliverAmount (rc.actualAmountOut);
ctx_.deliverAmount (rc.actualAmountOut);
terResult = rc.result ();
}
@@ -324,7 +304,7 @@ public:
}
catch (std::exception const& e)
{
m_journal.trace <<
j_.trace <<
"Caught throw: " << e.what ();
terResult = tefEXCEPTION;
@@ -340,7 +320,7 @@ public:
// This is the total reserve in drops.
auto const uReserve =
mEngine->view().fees().accountReserve(uOwnerCount);
view().fees().accountReserve(uOwnerCount);
// mPriorBalance is the balance on the sending account BEFORE the
// fees were charged. We want to make sure we have enough reserve
@@ -352,7 +332,7 @@ public:
{
// Vote no. However the transaction might succeed, if applied in
// a different order.
m_journal.trace << "Delay transaction: Insufficient funds: " <<
j_.trace << "Delay transaction: Insufficient funds: " <<
" " << mPriorBalance.getText () <<
" / " << (saDstAmount + mmm).getText () <<
" (" << uReserve << ")";
@@ -381,7 +361,7 @@ public:
if (transResultInfo (terResult, strToken, strHuman))
{
m_journal.trace <<
j_.trace <<
strToken << ": " << strHuman;
}
else
@@ -390,16 +370,6 @@ public:
}
return terResult;
}
};
TER
transact_Payment (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
return Payment(txn, params, engine).apply ();
}
} // ripple

View File

@@ -0,0 +1,55 @@
//------------------------------------------------------------------------------
/*
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_TX_PAYMENT_H_INCLUDED
#define RIPPLE_TX_PAYMENT_H_INCLUDED
#include <ripple/app/paths/RippleCalc.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
// See https://ripple.com/wiki/Transaction_Format#Payment_.280.29
class Payment
: public Transactor
{
/* The largest number of paths we allow */
static std::size_t const MaxPathSize = 6;
/* The longest path we allow */
static std::size_t const MaxPathLength = 8;
public:
template <class... Args>
Payment (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER preCheck () override;
TER doApply () override;
};
} // ripple
#endif

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/tx/impl/SetAccount.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/Indexes.h>
@@ -27,33 +27,14 @@
namespace ripple {
class SetAccount
: public Transactor
TER
SetAccount::preCheck ()
{
static std::size_t const DOMAIN_BYTES_MAX = 256;
static std::size_t const PUBLIC_BYTES_MAX = 33;
public:
SetAccount (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("SetAccount"))
{
}
TER preCheck () override
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
if (uTxFlags & tfAccountSetMask)
{
m_journal.trace << "Malformed transaction: Invalid flags set.";
j_.trace << "Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
@@ -62,7 +43,7 @@ public:
if ((uSetFlag != 0) && (uSetFlag == uClearFlag))
{
m_journal.trace << "Malformed transaction: Set and clear same flag.";
j_.trace << "Malformed transaction: Set and clear same flag.";
return temINVALID_FLAG;
}
@@ -74,7 +55,7 @@ public:
if (bSetRequireAuth && bClearRequireAuth)
{
m_journal.trace << "Malformed transaction: Contradictory flags set.";
j_.trace << "Malformed transaction: Contradictory flags set.";
return temINVALID_FLAG;
}
@@ -86,7 +67,7 @@ public:
if (bSetRequireDest && bClearRequireDest)
{
m_journal.trace << "Malformed transaction: Contradictory flags set.";
j_.trace << "Malformed transaction: Contradictory flags set.";
return temINVALID_FLAG;
}
@@ -98,7 +79,7 @@ public:
if (bSetDisallowXRP && bClearDisallowXRP)
{
m_journal.trace << "Malformed transaction: Contradictory flags set.";
j_.trace << "Malformed transaction: Contradictory flags set.";
return temINVALID_FLAG;
}
@@ -109,16 +90,17 @@ public:
if (uRate && (uRate < QUALITY_ONE))
{
m_journal.trace << "Malformed transaction: Bad transfer rate.";
j_.trace << "Malformed transaction: Bad transfer rate.";
return temBAD_TRANSFER_RATE;
}
}
return Transactor::preCheck ();
}
}
TER doApply () override
{
TER
SetAccount::doApply ()
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
std::uint32_t const uFlagsIn = mTxnAccount->getFieldU32 (sfFlags);
@@ -140,20 +122,20 @@ public:
//
if (bSetRequireAuth && !(uFlagsIn & lsfRequireAuth))
{
if (! dirIsEmpty (mEngine->view(),
if (! dirIsEmpty (view(),
keylet::ownerDir(mTxnAccountID)))
{
m_journal.trace << "Retry: Owner directory not empty.";
return (mParams & tapRETRY) ? terOWNERS : tecOWNERS;
j_.trace << "Retry: Owner directory not empty.";
return (view().flags() & tapRETRY) ? terOWNERS : tecOWNERS;
}
m_journal.trace << "Set RequireAuth.";
j_.trace << "Set RequireAuth.";
uFlagsOut |= lsfRequireAuth;
}
if (bClearRequireAuth && (uFlagsIn & lsfRequireAuth))
{
m_journal.trace << "Clear RequireAuth.";
j_.trace << "Clear RequireAuth.";
uFlagsOut &= ~lsfRequireAuth;
}
@@ -162,13 +144,13 @@ public:
//
if (bSetRequireDest && !(uFlagsIn & lsfRequireDestTag))
{
m_journal.trace << "Set lsfRequireDestTag.";
j_.trace << "Set lsfRequireDestTag.";
uFlagsOut |= lsfRequireDestTag;
}
if (bClearRequireDest && (uFlagsIn & lsfRequireDestTag))
{
m_journal.trace << "Clear lsfRequireDestTag.";
j_.trace << "Clear lsfRequireDestTag.";
uFlagsOut &= ~lsfRequireDestTag;
}
@@ -177,13 +159,13 @@ public:
//
if (bSetDisallowXRP && !(uFlagsIn & lsfDisallowXRP))
{
m_journal.trace << "Set lsfDisallowXRP.";
j_.trace << "Set lsfDisallowXRP.";
uFlagsOut |= lsfDisallowXRP;
}
if (bClearDisallowXRP && (uFlagsIn & lsfDisallowXRP))
{
m_journal.trace << "Clear lsfDisallowXRP.";
j_.trace << "Clear lsfDisallowXRP.";
uFlagsOut &= ~lsfDisallowXRP;
}
@@ -194,20 +176,20 @@ public:
{
if (!mSigMaster)
{
m_journal.trace << "Must use master key to disable master key.";
j_.trace << "Must use master key to disable master key.";
return tecNEED_MASTER_KEY;
}
if (!mTxnAccount->isFieldPresent (sfRegularKey))
return tecNO_REGULAR_KEY;
m_journal.trace << "Set lsfDisableMaster.";
j_.trace << "Set lsfDisableMaster.";
uFlagsOut |= lsfDisableMaster;
}
if ((uClearFlag == asfDisableMaster) && (uFlagsIn & lsfDisableMaster))
{
m_journal.trace << "Clear lsfDisableMaster.";
j_.trace << "Clear lsfDisableMaster.";
uFlagsOut &= ~lsfDisableMaster;
}
@@ -230,18 +212,18 @@ public:
{
if (!mSigMaster && !(uFlagsIn & lsfDisableMaster))
{
m_journal.trace << "Can't use regular key to set NoFreeze.";
j_.trace << "Can't use regular key to set NoFreeze.";
return tecNEED_MASTER_KEY;
}
m_journal.trace << "Set NoFreeze flag";
j_.trace << "Set NoFreeze flag";
uFlagsOut |= lsfNoFreeze;
}
// Anyone may set global freeze
if (uSetFlag == asfGlobalFreeze)
{
m_journal.trace << "Set GlobalFreeze flag";
j_.trace << "Set GlobalFreeze flag";
uFlagsOut |= lsfGlobalFreeze;
}
@@ -251,7 +233,7 @@ public:
if ((uSetFlag != asfGlobalFreeze) && (uClearFlag == asfGlobalFreeze) &&
((uFlagsOut & lsfNoFreeze) == 0))
{
m_journal.trace << "Clear GlobalFreeze flag";
j_.trace << "Clear GlobalFreeze flag";
uFlagsOut &= ~lsfGlobalFreeze;
}
@@ -260,13 +242,13 @@ public:
//
if ((uSetFlag == asfAccountTxnID) && !mTxnAccount->isFieldPresent (sfAccountTxnID))
{
m_journal.trace << "Set AccountTxnID";
j_.trace << "Set AccountTxnID";
mTxnAccount->makeFieldPresent (sfAccountTxnID);
}
if ((uClearFlag == asfAccountTxnID) && mTxnAccount->isFieldPresent (sfAccountTxnID))
{
m_journal.trace << "Clear AccountTxnID";
j_.trace << "Clear AccountTxnID";
mTxnAccount->makeFieldAbsent (sfAccountTxnID);
}
@@ -279,12 +261,12 @@ public:
if (!uHash)
{
m_journal.trace << "unset email hash";
j_.trace << "unset email hash";
mTxnAccount->makeFieldAbsent (sfEmailHash);
}
else
{
m_journal.trace << "set email hash";
j_.trace << "set email hash";
mTxnAccount->setFieldH128 (sfEmailHash, uHash);
}
}
@@ -298,12 +280,12 @@ public:
if (!uHash)
{
m_journal.trace << "unset wallet locator";
j_.trace << "unset wallet locator";
mTxnAccount->makeFieldAbsent (sfWalletLocator);
}
else
{
m_journal.trace << "set wallet locator";
j_.trace << "set wallet locator";
mTxnAccount->setFieldH256 (sfWalletLocator, uHash);
}
}
@@ -317,18 +299,18 @@ public:
if (messageKey.size () > PUBLIC_BYTES_MAX)
{
m_journal.trace << "message key too long";
j_.trace << "message key too long";
return telBAD_PUBLIC_KEY;
}
if (messageKey.empty ())
{
m_journal.debug << "set message key";
j_.debug << "set message key";
mTxnAccount->makeFieldAbsent (sfMessageKey);
}
else
{
m_journal.debug << "set message key";
j_.debug << "set message key";
mTxnAccount->setFieldVL (sfMessageKey, messageKey);
}
}
@@ -342,18 +324,18 @@ public:
if (domain.size () > DOMAIN_BYTES_MAX)
{
m_journal.trace << "domain too long";
j_.trace << "domain too long";
return telBAD_DOMAIN;
}
if (domain.empty ())
{
m_journal.trace << "unset domain";
j_.trace << "unset domain";
mTxnAccount->makeFieldAbsent (sfDomain);
}
else
{
m_journal.trace << "set domain";
j_.trace << "set domain";
mTxnAccount->setFieldVL (sfDomain, domain);
}
}
@@ -367,12 +349,12 @@ public:
if (uRate == 0 || uRate == QUALITY_ONE)
{
m_journal.trace << "unset transfer rate";
j_.trace << "unset transfer rate";
mTxnAccount->makeFieldAbsent (sfTransferRate);
}
else if (uRate > QUALITY_ONE)
{
m_journal.trace << "set transfer rate";
j_.trace << "set transfer rate";
mTxnAccount->setFieldU32 (sfTransferRate, uRate);
}
}
@@ -381,16 +363,6 @@ public:
mTxnAccount->setFieldU32 (sfFlags, uFlagsOut);
return tesSUCCESS;
}
};
TER
transact_SetAccount (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
return SetAccount(txn, params, engine).apply ();
}
}

View File

@@ -0,0 +1,52 @@
//------------------------------------------------------------------------------
/*
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_TX_SETACCOUNT_H_INCLUDED
#define RIPPLE_TX_SETACCOUNT_H_INCLUDED
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/Quality.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
class SetAccount
: public Transactor
{
static std::size_t const DOMAIN_BYTES_MAX = 256;
static std::size_t const PUBLIC_BYTES_MAX = 33;
public:
template <class... Args>
SetAccount (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER preCheck () override;
TER doApply () override;
};
} // ripple
#endif

View File

@@ -18,18 +18,16 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/tx/impl/SetRegularKey.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/protocol/types.h>
namespace ripple {
class SetRegularKey
: public Transactor
std::uint64_t
SetRegularKey::calculateBaseFee ()
{
std::uint64_t calculateBaseFee () override
{
if ( mTxnAccount
&& (! (mTxnAccount->getFlags () & lsfPasswordSpent))
&& (calcAccountID(mSigningPubKey) == mTxnAccountID))
@@ -39,39 +37,27 @@ class SetRegularKey
}
return Transactor::calculateBaseFee ();
}
}
public:
SetRegularKey (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("SetRegularKey"))
{
}
TER preCheck () override
{
TER
SetRegularKey::preCheck ()
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
if (uTxFlags & tfUniversalMask)
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
return Transactor::preCheck ();
}
}
TER doApply () override
{
TER
SetRegularKey::doApply ()
{
if (mFeeDue == zero)
mTxnAccount->setFlag (lsfPasswordSpent);
@@ -88,16 +74,6 @@ public:
}
return tesSUCCESS;
}
};
TER
transact_SetRegularKey (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
return SetRegularKey(txn, params, engine).apply ();
}
}

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
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_TX_SETREGULARKEY_H_INCLUDED
#define RIPPLE_TX_SETREGULARKEY_H_INCLUDED
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/protocol/types.h>
namespace ripple {
class SetRegularKey
: public Transactor
{
std::uint64_t calculateBaseFee () override;
public:
template <class... Args>
SetRegularKey (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER preCheck () override;
TER doApply () override;
};
} // ripple
#endif

View File

@@ -18,7 +18,8 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/tx/impl/SetSignerList.h>
#include <ripple/app/tx/impl/SignerEntries.h>
#include <ripple/protocol/STObject.h>
#include <ripple/protocol/STArray.h>
@@ -31,62 +32,6 @@
namespace ripple {
/**
See the README.md for an overview of the SetSignerList transaction that
this class implements.
*/
class SetSignerList final
: public Transactor
{
private:
// Values determined during preCheck for use later.
enum Operation {unknown, set, destroy};
Operation do_ {unknown};
std::uint32_t quorum_ {0};
std::vector<SignerEntries::SignerEntry> signers_;
public:
SetSignerList (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("SetSignerList"))
{
}
/**
Applies the transaction if it is well formed and the ledger state permits.
*/
TER doApply () override;
protected:
/**
Check anything that can be checked without the ledger.
*/
TER preCheck () override;
private:
// signers are not const because method (intentionally) sorts vector.
TER validateQuorumAndSignerEntries (
std::uint32_t quorum,
std::vector<SignerEntries::SignerEntry>& signers) const;
// Methods called by doApply()
TER replaceSignerList (uint256 const& index);
TER destroySignerList (uint256 const& index);
void writeSignersToLedger (SLE::pointer ledgerEntry);
static std::size_t ownerCountDelta (std::size_t entryCount);
};
//------------------------------------------------------------------------------
TER
SetSignerList::doApply ()
{
@@ -116,6 +61,11 @@ SetSignerList::doApply ()
TER
SetSignerList::preCheck()
{
#if ! RIPPLE_ENABLE_MULTI_SIGN
if (! (view().flags() & tapENABLE_TESTING))
return temDISABLED;
#endif
// We need the account ID later, so do this check first.
preCheckAccount ();
@@ -127,7 +77,7 @@ SetSignerList::preCheck()
if (quorum_ && hasSignerEntries)
{
SignerEntries::Decoded signers (
SignerEntries::deserialize (mTxn, m_journal, "transaction"));
SignerEntries::deserialize (mTxn, j_, "transaction"));
if (signers.ter != tesSUCCESS)
return signers.ter;
@@ -150,7 +100,7 @@ SetSignerList::preCheck()
else
{
// Neither a set nor a destroy. Malformed.
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Malformed transaction: Invalid signer set list format.";
return temMALFORMED;
}
@@ -169,7 +119,7 @@ SetSignerList::validateQuorumAndSignerEntries (
if ((signerCount < SignerEntries::minEntries)
|| (signerCount > SignerEntries::maxEntries))
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Too many or too few signers in signer list.";
return temMALFORMED;
}
@@ -180,7 +130,7 @@ SetSignerList::validateQuorumAndSignerEntries (
if (std::adjacent_find (
signers.begin (), signers.end ()) != signers.end ())
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Duplicate signers in signer list";
return temBAD_SIGNER;
}
@@ -194,7 +144,7 @@ SetSignerList::validateQuorumAndSignerEntries (
if (signer.account == mTxnAccountID)
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"A signer may not self reference account.";
return temBAD_SIGNER;
}
@@ -204,7 +154,7 @@ SetSignerList::validateQuorumAndSignerEntries (
}
if ((quorum <= 0) || (allSignersWeight < quorum))
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Quorum is unreachable";
return temBAD_QUORUM;
}
@@ -225,7 +175,7 @@ SetSignerList::replaceSignerList (uint256 const& index)
std::uint32_t const addedOwnerCount = ownerCountDelta (signers_.size ());
auto const newReserve =
mEngine->view().fees().accountReserve(
view().fees().accountReserve(
oldOwnerCount + addedOwnerCount);
// We check the reserve against the starting balance because we want to
@@ -236,7 +186,7 @@ SetSignerList::replaceSignerList (uint256 const& index)
// Everything's ducky. Add the ltSIGNER_LIST to the ledger.
auto signerList = std::make_shared<SLE>(ltSIGNER_LIST, index);
mEngine->view().insert (signerList);
view().insert (signerList);
writeSignersToLedger (signerList);
// Lambda for call to dirAdd.
@@ -247,10 +197,10 @@ SetSignerList::replaceSignerList (uint256 const& index)
// Add the signer list to the account's directory.
std::uint64_t hint;
TER result = dirAdd(mEngine->view (),
TER result = dirAdd(ctx_.view (),
hint, getOwnerDirIndex (mTxnAccountID), index, describer);
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Create signer list for account " <<
mTxnAccountID << ": " << transHuman (result);
@@ -260,7 +210,7 @@ SetSignerList::replaceSignerList (uint256 const& index)
signerList->setFieldU64 (sfOwnerNode, hint);
// If we succeeded, the new entry counts against the creator's reserve.
adjustOwnerCount(mEngine->view(),
adjustOwnerCount(view(),
mTxnAccount, addedOwnerCount);
return result;
@@ -271,7 +221,7 @@ SetSignerList::destroySignerList (uint256 const& index)
{
// See if there's an ltSIGNER_LIST for this account.
SLE::pointer signerList =
mEngine->view().peek (keylet::signers(index));
view().peek (keylet::signers(index));
// If the signer list doesn't exist we've already succeeded in deleting it.
if (!signerList)
@@ -282,7 +232,7 @@ SetSignerList::destroySignerList (uint256 const& index)
std::uint32_t removeFromOwnerCount = 0;
auto const k = keylet::signers(mTxnAccountID);
SLE::pointer accountSignersList =
mEngine->view().peek (k);
view().peek (k);
if (accountSignersList)
{
STArray const& actualList =
@@ -293,14 +243,14 @@ SetSignerList::destroySignerList (uint256 const& index)
// Remove the node from the account directory.
std::uint64_t const hint (signerList->getFieldU64 (sfOwnerNode));
TER const result = dirDelete(mEngine->view (), false, hint,
TER const result = dirDelete(ctx_.view (), false, hint,
getOwnerDirIndex (mTxnAccountID), index, false, (hint == 0));
if (result == tesSUCCESS)
adjustOwnerCount(mEngine->view(),
adjustOwnerCount(view(),
mTxnAccount, removeFromOwnerCount);
mEngine->view ().erase (signerList);
ctx_.view ().erase (signerList);
return result;
}
@@ -357,17 +307,4 @@ SetSignerList::ownerCountDelta (std::size_t entryCount)
return 2 + entryCount;
}
TER
transact_SetSignerList (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
#if ! RIPPLE_ENABLE_MULTI_SIGN
if (! (engine->view().flags() & tapENABLE_TESTING))
return temDISABLED;
#endif
return SetSignerList (txn, params, engine).apply ();
}
} // namespace ripple

View File

@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 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_TX_SETSIGNERLIST_H_INCLUDED
#define RIPPLE_TX_SETSIGNERLIST_H_INCLUDED
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/tx/impl/SignerEntries.h>
#include <ripple/protocol/STObject.h>
#include <ripple/protocol/STArray.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/STAccount.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/basics/Log.h>
#include <algorithm>
#include <cstdint>
#include <vector>
namespace ripple {
/**
See the README.md for an overview of the SetSignerList transaction that
this class implements.
*/
class SetSignerList : public Transactor
{
private:
// Values determined during preCheck for use later.
enum Operation {unknown, set, destroy};
Operation do_ {unknown};
std::uint32_t quorum_ {0};
std::vector<SignerEntries::SignerEntry> signers_;
public:
template <class... Args>
SetSignerList (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER doApply () override;
TER preCheck () override;
private:
// `signers` is sorted on return
TER validateQuorumAndSignerEntries (
std::uint32_t quorum,
std::vector<SignerEntries::SignerEntry>& signers) const;
TER replaceSignerList (uint256 const& index);
TER destroySignerList (uint256 const& index);
void writeSignersToLedger (SLE::pointer ledgerEntry);
static std::size_t ownerCountDelta (std::size_t entryCount);
};
} // ripple
#endif

View File

@@ -19,36 +19,21 @@
#include <BeastConfig.h>
#include <ripple/protocol/Quality.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/tx/impl/SetTrust.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
class SetTrust
: public Transactor
TER
SetTrust::preCheck ()
{
public:
SetTrust (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
: Transactor (
txn,
params,
engine,
deprecatedLogs().journal("SetTrust"))
{
}
TER preCheck () override
{
std::uint32_t const uTxFlags = mTxn.getFlags ();
if (uTxFlags & tfTrustSetMask)
{
m_journal.trace <<
j_.trace <<
"Malformed transaction: Invalid flags set.";
return temINVALID_FLAG;
}
@@ -60,7 +45,7 @@ public:
if (saLimitAmount.native ())
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Malformed transaction: specifies native limit " <<
saLimitAmount.getFullText ();
return temBAD_LIMIT;
@@ -68,14 +53,14 @@ public:
if (badCurrency() == saLimitAmount.getCurrency ())
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Malformed transaction: specifies XRP as IOU";
return temBAD_CURRENCY;
}
if (saLimitAmount < zero)
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Malformed transaction: Negative credit limit.";
return temBAD_LIMIT;
}
@@ -85,16 +70,17 @@ public:
if (!issuer || issuer == noAccount())
{
if (m_journal.trace) m_journal.trace <<
if (j_.trace) j_.trace <<
"Malformed transaction: no destination account.";
return temDST_NEEDED;
}
return Transactor::preCheck ();
}
}
TER doApply () override
{
TER
SetTrust::doApply ()
{
TER terResult = tesSUCCESS;
STAmount const saLimitAmount (mTxn.getFieldAmount (sfLimitAmount));
@@ -123,7 +109,7 @@ public:
STAmount const reserveCreate ((uOwnerCount < 2)
? 0
: mEngine->view().fees().accountReserve(uOwnerCount + 1));
: view().fees().accountReserve(uOwnerCount + 1));
std::uint32_t uQualityIn (bQualityIn ? mTxn.getFieldU32 (sfQualityIn) : 0);
std::uint32_t uQualityOut (bQualityOut ? mTxn.getFieldU32 (sfQualityOut) : 0);
@@ -141,7 +127,7 @@ public:
if (bSetAuth && !(mTxnAccount->getFieldU32 (sfFlags) & lsfRequireAuth))
{
m_journal.trace <<
j_.trace <<
"Retry: Auth not required.";
return tefNO_AUTH_REQUIRED;
}
@@ -152,31 +138,31 @@ public:
// trust line to oneself to be deleted. If no such trust
// lines exist now, why not remove this code and simply
// return an error?
SLE::pointer sleDelete = mEngine->view().peek (
SLE::pointer sleDelete = view().peek (
keylet::line(mTxnAccountID, uDstAccountID, currency));
if (sleDelete)
{
m_journal.warning <<
j_.warning <<
"Clearing redundant line.";
return trustDelete (mEngine->view(),
return trustDelete (view(),
sleDelete, mTxnAccountID, uDstAccountID);
}
else
{
m_journal.trace <<
j_.trace <<
"Malformed transaction: Can not extend credit to self.";
return temDST_IS_SRC;
}
}
SLE::pointer sleDst =
mEngine->view().peek (keylet::account(uDstAccountID));
view().peek (keylet::account(uDstAccountID));
if (!sleDst)
{
m_journal.trace <<
j_.trace <<
"Delay transaction: Destination account does not exist.";
return tecNO_DST;
}
@@ -184,7 +170,7 @@ public:
STAmount saLimitAllow = saLimitAmount;
saLimitAllow.setIssuer (mTxnAccountID);
SLE::pointer sleRippleState = mEngine->view().peek (
SLE::pointer sleRippleState = view().peek (
keylet::line(mTxnAccountID, uDstAccountID, currency));
if (sleRippleState)
@@ -337,7 +323,7 @@ public:
if (bLowReserveSet && !bLowReserved)
{
// Set reserve for low account.
adjustOwnerCount(mEngine->view(),
adjustOwnerCount(view(),
sleLowAccount, 1);
uFlagsOut |= lsfLowReserve;
@@ -348,7 +334,7 @@ public:
if (bLowReserveClear && bLowReserved)
{
// Clear reserve for low account.
adjustOwnerCount(mEngine->view(),
adjustOwnerCount(view(),
sleLowAccount, -1);
uFlagsOut &= ~lsfLowReserve;
}
@@ -356,7 +342,7 @@ public:
if (bHighReserveSet && !bHighReserved)
{
// Set reserve for high account.
adjustOwnerCount(mEngine->view(),
adjustOwnerCount(view(),
sleHighAccount, 1);
uFlagsOut |= lsfHighReserve;
@@ -367,7 +353,7 @@ public:
if (bHighReserveClear && bHighReserved)
{
// Clear reserve for high account.
adjustOwnerCount(mEngine->view(),
adjustOwnerCount(view(),
sleHighAccount, -1);
uFlagsOut &= ~lsfHighReserve;
}
@@ -379,13 +365,13 @@ public:
{
// Delete.
terResult = trustDelete (mEngine->view(),
terResult = trustDelete (view(),
sleRippleState, uLowAccountID, uHighAccountID);
}
// Reserve is not scaled by load.
else if (bReserveIncrease && mPriorBalance < reserveCreate)
{
m_journal.trace <<
j_.trace <<
"Delay transaction: Insufficent reserve to add trust line.";
// Another transaction could provide XRP to the account and then
@@ -394,9 +380,9 @@ public:
}
else
{
mEngine->view().update (sleRippleState);
view().update (sleRippleState);
m_journal.trace << "Modify ripple line";
j_.trace << "Modify ripple line";
}
}
// Line does not exist.
@@ -404,13 +390,13 @@ public:
&& (!bQualityIn || !uQualityIn) // Not setting quality in or setting default quality in.
&& (!bQualityOut || !uQualityOut)) // Not setting quality out or setting default quality out.
{
m_journal.trace <<
j_.trace <<
"Redundant: Setting non-existent ripple line to defaults.";
return tecNO_LINE_REDUNDANT;
}
else if (mPriorBalance < reserveCreate) // Reserve is not scaled by load.
{
m_journal.trace <<
j_.trace <<
"Delay transaction: Line does not exist. Insufficent reserve to create line.";
// Another transaction could create the account and then this transaction would succeed.
@@ -424,12 +410,12 @@ public:
uint256 index (getRippleStateIndex (
mTxnAccountID, uDstAccountID, currency));
m_journal.trace <<
j_.trace <<
"doTrustSet: Creating ripple line: " <<
to_string (index);
// Create a new ripple line.
terResult = trustCreate (mEngine->view(),
terResult = trustCreate (view(),
bHigh,
mTxnAccountID,
uDstAccountID,
@@ -445,16 +431,6 @@ public:
}
return terResult;
}
};
TER
transact_SetTrust (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
return SetTrust (txn, params, engine).apply ();
}
}

View File

@@ -0,0 +1,49 @@
//------------------------------------------------------------------------------
/*
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_TX_SETTRUST_H_INCLUDED
#define RIPPLE_TX_SETTRUST_H_INCLUDED
#include <ripple/protocol/Quality.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
class SetTrust
: public Transactor
{
public:
template <class... Args>
SetTrust (Args&&... args)
: Transactor(std::forward<
Args>(args)...)
{
}
TER preCheck () override;
TER doApply () override;
};
} // ripple
#endif

View File

@@ -515,23 +515,15 @@ BasicTaker::do_cross (
//==============================================================================
std::uint32_t
Taker::calculateRate (
View const& view,
AccountID const& issuer,
AccountID const& account)
{
return isXRP (issuer) || (account == issuer)
? QUALITY_ONE
: rippleTransferRate (view, issuer);
}
Taker::Taker (CrossType cross_type, View& view, AccountID const& account,
Amounts const& offer, std::uint32_t flags, beast::Journal journal)
Taker::Taker (CrossType cross_type, View& view,
AccountID const& account, Amounts const& offer,
std::uint32_t flags, Config const& config,
beast::Journal journal)
: BasicTaker (cross_type, account, offer, Quality(offer), flags,
calculateRate(view, offer.in.getIssuer(), account),
calculateRate(view, offer.out.getIssuer(), account), journal)
, view_ (view)
, config_ (config)
, xrp_flow_ (0)
, direct_crossings_ (0)
, bridge_crossings_ (0)
@@ -587,7 +579,7 @@ STAmount
Taker::get_funds (AccountID const& account, STAmount const& amount) const
{
return accountFunds(view_, account, amount, fhZERO_IF_FROZEN,
getConfig());
config_);
}
TER Taker::transferXRP (
@@ -779,4 +771,16 @@ Taker::cross (Offer const& leg1, Offer const& leg2)
return fill (ret.first, leg1, ret.second, leg2);
}
std::uint32_t
Taker::calculateRate (
View const& view,
AccountID const& issuer,
AccountID const& account)
{
return isXRP (issuer) || (account == issuer)
? QUALITY_ONE
: rippleTransferRate (view, issuer);
}
} // ripple

View File

@@ -21,6 +21,7 @@
#define RIPPLE_APP_BOOK_TAKER_H_INCLUDED
#include <ripple/app/tx/impl/Offer.h>
#include <ripple/core/Config.h>
#include <ripple/ledger/View.h>
#include <ripple/protocol/Quality.h>
#include <ripple/protocol/TER.h>
@@ -239,48 +240,14 @@ public:
class Taker
: public BasicTaker
{
private:
static
std::uint32_t
calculateRate (View const& view,
AccountID const& issuer,
AccountID const& account);
// The underlying ledger entry we are dealing with
View& view_;
// The amount of XRP that flowed if we were autobridging
STAmount xrp_flow_;
// The number direct crossings that we performed
std::uint32_t direct_crossings_;
// The number autobridged crossings that we performed
std::uint32_t bridge_crossings_;
TER
fill (BasicTaker::Flow const& flow, Offer const& offer);
TER
fill (
BasicTaker::Flow const& flow1, Offer const& leg1,
BasicTaker::Flow const& flow2, Offer const& leg2);
TER
transferXRP (AccountID const& from, AccountID const& to, STAmount const& amount);
TER
redeemIOU (AccountID const& account, STAmount const& amount, Issue const& issue);
TER
issueIOU (AccountID const& account, STAmount const& amount, Issue const& issue);
public:
Taker () = delete;
Taker (Taker const&) = delete;
Taker (CrossType cross_type, View& view, AccountID const& account,
Amounts const& offer, std::uint32_t flags, beast::Journal journal);
Taker (CrossType cross_type, View& view,
AccountID const& account, Amounts const& offer,
std::uint32_t flags, Config const& config,
beast::Journal journal);
~Taker () = default;
void
@@ -318,6 +285,45 @@ public:
TER
cross (Offer const& leg1, Offer const& leg2);
/** @} */
private:
static
std::uint32_t
calculateRate (View const& view,
AccountID const& issuer,
AccountID const& account);
TER
fill (BasicTaker::Flow const& flow, Offer const& offer);
TER
fill (
BasicTaker::Flow const& flow1, Offer const& leg1,
BasicTaker::Flow const& flow2, Offer const& leg2);
TER
transferXRP (AccountID const& from, AccountID const& to, STAmount const& amount);
TER
redeemIOU (AccountID const& account, STAmount const& amount, Issue const& issue);
TER
issueIOU (AccountID const& account, STAmount const& amount, Issue const& issue);
private:
// The underlying ledger entry we are dealing with
View& view_;
Config const& config_;
// The amount of XRP that flowed if we were autobridging
STAmount xrp_flow_;
// The number direct crossings that we performed
std::uint32_t direct_crossings_;
// The number autobridged crossings that we performed
std::uint32_t bridge_crossings_;
};
}

View File

@@ -1,254 +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/tx/TransactionEngine.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/Indexes.h>
#include <cassert>
namespace ripple {
//
// XXX Make sure all fields are recognized in transactions.
//
std::pair<TER, bool>
TransactionEngine::applyTransaction (
STTx const& txn,
ViewFlags flags)
{
TER terResult = tefINTERNAL;
bool didApply = false;
try
{
assert (mLedger);
WriteLog (lsTRACE, TransactionEngine) << "applyTransaction>";
uint256 const& txID = txn.getTransactionID ();
if (!txID)
{
WriteLog (lsWARNING, TransactionEngine) <<
"applyTransaction: invalid transaction id";
return std::make_pair(temINVALID_FLAG, false);
}
mNodes.emplace(mLedger.get(), flags, txID);
#ifdef BEAST_DEBUG
if (1)
{
Serializer ser;
txn.add (ser);
SerialIter sit(ser.slice());
STTx s2 (sit);
if (!s2.isEquivalent (txn))
{
WriteLog (lsFATAL, TransactionEngine) <<
"Transaction serdes mismatch";
WriteLog (lsINFO, TransactionEngine) << txn.getJson (0);
WriteLog (lsFATAL, TransactionEngine) << s2.getJson (0);
assert (false);
}
}
#endif
terResult = Transactor::transact (txn, flags, this);
if (terResult == temUNKNOWN)
{
WriteLog (lsWARNING, TransactionEngine) <<
"applyTransaction: Invalid transaction: unknown transaction type";
return std::make_pair(temUNKNOWN, false);
}
if (ShouldLog (lsDEBUG, TransactionEngine))
{
std::string strToken;
std::string strHuman;
transResultInfo (terResult, strToken, strHuman);
WriteLog (lsDEBUG, TransactionEngine) <<
"applyTransaction: terResult=" << strToken <<
" : " << terResult <<
" : " << strHuman;
}
didApply = isTesSuccess (terResult);
if (isTecClaim (terResult) && !(flags & tapRETRY))
{
// only claim the transaction fee
WriteLog (lsDEBUG, TransactionEngine) <<
"Reprocessing tx " << txID << " to only claim fee";
mNodes.emplace(mLedger.get(), flags, txID);
SLE::pointer txnAcct = view().peek(
keylet::account(txn.getAccountID(sfAccount)));
if (!txnAcct)
terResult = terNO_ACCOUNT;
else
{
std::uint32_t t_seq = txn.getSequence ();
std::uint32_t a_seq = txnAcct->getFieldU32 (sfSequence);
if (a_seq < t_seq)
terResult = terPRE_SEQ;
else if (a_seq > t_seq)
terResult = tefPAST_SEQ;
else
{
STAmount fee = txn.getTransactionFee ();
STAmount balance = txnAcct->getFieldAmount (sfBalance);
// We retry/reject the transaction if the account
// balance is zero or we're applying against an open
// ledger and the balance is less than the fee
if ((balance == zero) ||
((flags & tapOPEN_LEDGER) && (balance < fee)))
{
// Account has no funds or ledger is open
terResult = terINSUF_FEE_B;
}
else
{
if (fee > balance)
fee = balance;
txnAcct->setFieldAmount (sfBalance, balance - fee);
txnAcct->setFieldU32 (sfSequence, t_seq + 1);
view().update (txnAcct);
didApply = true;
}
}
}
}
else if (!didApply)
{
WriteLog (lsDEBUG, TransactionEngine) << "Not applying transaction " << txID;
}
if (didApply && !checkInvariants (terResult, txn, flags))
{
WriteLog (lsFATAL, TransactionEngine) <<
"Transaction violates invariants";
WriteLog (lsFATAL, TransactionEngine) <<
txn.getJson (0);
WriteLog (lsFATAL, TransactionEngine) <<
transToken (terResult) << ": " << transHuman (terResult);
WriteLog (lsFATAL, TransactionEngine) <<
mNodes->getJson (0);
didApply = false;
terResult = tefINTERNAL;
}
if (didApply)
{
// Transaction succeeded fully or (retries are not allowed and the
// transaction could claim a fee)
Serializer m;
mNodes->calcRawMeta (m, terResult, mTxnSeq++);
mNodes->apply(*mLedger);
Serializer s;
txn.add (s);
if (flags & tapOPEN_LEDGER)
{
if (! mLedger->txInsert(txID,
std::make_shared<
Serializer const>(std::move(s)),
nullptr))
{
WriteLog (lsFATAL, TransactionEngine) <<
"Duplicate transaction applied";
assert (false);
throw std::runtime_error ("Duplicate transaction applied");
}
}
else
{
if (! mLedger->txInsert(txID,
std::make_shared<Serializer const>(std::move(s)),
std::make_shared<Serializer const>(std::move(m))))
{
WriteLog (lsFATAL, TransactionEngine) <<
"Duplicate transaction applied to closed ledger";
assert (false);
throw std::runtime_error ("Duplicate transaction applied to closed ledger");
}
// Charge whatever fee they specified. We break the encapsulation of
// STAmount here and use "special knowledge" - namely that a native
// amount is stored fully in the mantissa:
auto const fee = txn.getTransactionFee ();
// The transactor guarantees these will never trigger
if (!fee.native () || fee.negative ())
throw std::runtime_error ("amount is negative!");
if (fee != zero)
mLedger->destroyCoins (fee.mantissa ());
}
}
mNodes = boost::none;
if (!(flags & tapOPEN_LEDGER) && isTemMalformed (terResult))
{
// XXX Malformed or failed transaction in closed ledger must bow out.
}
}
catch(std::exception const& e)
{
WriteLog (lsFATAL, TransactionEngine) <<
"Caught exception: " << e.what();
return { tefEXCEPTION, false };
}
catch(...)
{
WriteLog (lsFATAL, TransactionEngine) <<
"Caught unknown exception";
return { tefEXCEPTION, false };
}
return { terResult, didApply };
}
bool
TransactionEngine::checkInvariants (
TER result,
STTx const& txn,
ViewFlags flags)
{
// VFALCO I deleted a bunch of code that was wrapped in #if 0.
// If you need it, check the commit log.
return true;
}
} // ripple

View File

@@ -21,94 +21,36 @@
#include <ripple/app/main/Application.h>
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/app/tx/impl/SignerEntries.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/core/LoadFeeTrack.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/types.h>
namespace ripple {
TER transact_Payment (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_SetAccount (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_SetRegularKey (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_SetTrust (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_CreateOffer (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_CancelOffer (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_Change (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_CreateTicket (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_CancelTicket (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER transact_SetSignerList (STTx const& txn, ViewFlags params, TransactionEngine* engine);
TER
Transactor::transact (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine)
{
switch (txn.getTxnType ())
{
case ttPAYMENT:
return transact_Payment (txn, params, engine);
case ttACCOUNT_SET:
return transact_SetAccount (txn, params, engine);
case ttREGULAR_KEY_SET:
return transact_SetRegularKey (txn, params, engine);
case ttTRUST_SET:
return transact_SetTrust (txn, params, engine);
case ttOFFER_CREATE:
return transact_CreateOffer (txn, params, engine);
case ttOFFER_CANCEL:
return transact_CancelOffer (txn, params, engine);
case ttAMENDMENT:
case ttFEE:
return transact_Change (txn, params, engine);
case ttTICKET_CREATE:
return transact_CreateTicket (txn, params, engine);
case ttTICKET_CANCEL:
return transact_CancelTicket (txn, params, engine);
case ttSIGNER_LIST_SET:
return transact_SetSignerList (txn, params, engine);
default:
return temUNKNOWN;
}
}
Transactor::Transactor (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine,
beast::Journal journal)
: mTxn (txn)
, mEngine (engine)
, mParams (mEngine->view().flags())
Transactor::Transactor(
ApplyContext& ctx)
: mTxn (ctx.tx)
, ctx_ (ctx)
, j_ (ctx.journal)
, mHasAuthKey (false)
, mSigMaster (false)
, m_journal (journal)
{
assert(mEngine->view().flags() == params);
}
void Transactor::calculateFee ()
{
mFeeDue = STAmount (getApp().getFeeTrack().scaleFeeLoad(
calculateBaseFee(), mEngine->view().fees().base,
mEngine->view().fees().units, mParams & tapADMIN));
calculateBaseFee(), view().fees().base,
view().fees().units, view().flags() & tapADMIN));
}
std::uint64_t Transactor::calculateBaseFee ()
{
// Returns the fee in fee units
return getConfig ().TRANSACTION_FEE_BASE;
return ctx_.config.TRANSACTION_FEE_BASE;
}
TER Transactor::payFee ()
@@ -119,9 +61,9 @@ TER Transactor::payFee ()
return temBAD_AMOUNT;
// Only check fee is sufficient when the ledger is open.
if ((mParams & tapOPEN_LEDGER) && saPaid < mFeeDue)
if (view().open() && saPaid < mFeeDue)
{
m_journal.trace << "Insufficient fee paid: " <<
j_.trace << "Insufficient fee paid: " <<
saPaid.getText () << "/" << mFeeDue.getText ();
return telINSUF_FEE_P;
@@ -135,11 +77,11 @@ TER Transactor::payFee ()
if (mSourceBalance < saPaid)
{
m_journal.trace << "Insufficient balance:" <<
j_.trace << "Insufficient balance:" <<
" balance=" << mSourceBalance.getText () <<
" paid=" << saPaid.getText ();
if ((mSourceBalance > zero) && (!(mParams & tapOPEN_LEDGER)))
if ((mSourceBalance > zero) && ! view().open())
{
// Closed ledger, non-zero balance, less than fee
mSourceBalance.clear ();
@@ -156,6 +98,8 @@ TER Transactor::payFee ()
mSourceBalance -= saPaid;
mTxnAccount->setFieldAmount (sfBalance, mSourceBalance);
// VFALCO Should we call view().destroyCoins() here as well?
return tesSUCCESS;
}
@@ -168,16 +112,16 @@ TER Transactor::checkSeq ()
{
if (a_seq < t_seq)
{
m_journal.trace <<
j_.trace <<
"applyTransaction: has future sequence number " <<
"a_seq=" << a_seq << " t_seq=" << t_seq;
return terPRE_SEQ;
}
if (mEngine->view().txExists(mTxn.getTransactionID ()))
if (view().txExists(mTxn.getTransactionID ()))
return tefALREADY;
m_journal.trace << "applyTransaction: has past sequence number " <<
j_.trace << "applyTransaction: has past sequence number " <<
"a_seq=" << a_seq << " t_seq=" << t_seq;
return tefPAST_SEQ;
}
@@ -187,7 +131,7 @@ TER Transactor::checkSeq ()
return tefWRONG_PRIOR;
if (mTxn.isFieldPresent (sfLastLedgerSequence) &&
(mEngine->getLedger()->getLedgerSeq() > mTxn.getFieldU32 (sfLastLedgerSequence)))
(view().seq() > mTxn.getFieldU32 (sfLastLedgerSequence)))
return tefMAX_LEDGER;
mTxnAccount->setFieldU32 (sfSequence, t_seq + 1);
@@ -214,7 +158,7 @@ TER Transactor::preCheckAccount ()
if (!mTxnAccountID)
{
m_journal.warning << "applyTransaction: bad transaction source id";
j_.warning << "applyTransaction: bad transaction source id";
return temBAD_SRC_ACCOUNT;
}
return tesSUCCESS;
@@ -235,17 +179,17 @@ TER Transactor::preCheckSigningKey ()
if (!mTxn.isKnownGood ())
{
if (mTxn.isKnownBad () ||
(!(mParams & tapNO_CHECK_SIGN) && !mTxn.checkSign(
(!(view().flags() & tapNO_CHECK_SIGN) && !mTxn.checkSign(
(
#if RIPPLE_ENABLE_MULTI_SIGN
true
#else
mEngine->view().flags() & tapENABLE_TESTING
view().flags() & tapENABLE_TESTING
#endif
))))
{
mTxn.setBad ();
m_journal.debug << "apply: Invalid transaction (bad signature)";
j_.debug << "apply: Invalid transaction (bad signature)";
return temINVALID;
}
@@ -269,7 +213,7 @@ TER Transactor::apply ()
return terResult;
// Find source account
mTxnAccount = mEngine->view().peek (keylet::account(mTxnAccountID));
mTxnAccount = view().peek (keylet::account(mTxnAccountID));
calculateFee ();
@@ -279,7 +223,7 @@ TER Transactor::apply ()
{
if (mustHaveValidAccount ())
{
m_journal.trace <<
j_.trace <<
"applyTransaction: delay: source account does not exist " <<
toBase58(mTxn.getAccountID(sfAccount));
return terNO_ACCOUNT;
@@ -305,7 +249,7 @@ TER Transactor::apply ()
if (terResult != tesSUCCESS) return (terResult);
if (mTxnAccount)
mEngine->view().update (mTxnAccount);
view().update (mTxnAccount);
return doApply ();
}
@@ -314,7 +258,7 @@ TER Transactor::checkSign ()
{
#if RIPPLE_ENABLE_MULTI_SIGN
#else
if(mEngine->view().flags() & tapENABLE_TESTING)
if(view().flags() & tapENABLE_TESTING)
#endif
{
// If the mSigningPubKey is empty, then we must be multi-signing.
@@ -347,13 +291,13 @@ TER Transactor::checkSingleSign ()
}
else if (mHasAuthKey)
{
m_journal.trace <<
j_.trace <<
"applyTransaction: Delay: Not authorized to use account.";
return tefBAD_AUTH;
}
else
{
m_journal.trace <<
j_.trace <<
"applyTransaction: Invalid: Not authorized to use account.";
return tefBAD_AUTH_MASTER;
}
@@ -372,15 +316,16 @@ struct GetSignerListResult
};
// We need the SignerList for every SigningFor while multi-signing.
static
GetSignerListResult
getSignerList (
AccountID signingForAcctID, TransactionEngine* engine, beast::Journal journal)
getSignerList (AccountID signingForAcctID,
BasicView const& view, beast::Journal journal)
{
GetSignerListResult ret;
auto const k = keylet::signers(signingForAcctID);
SLE::pointer accountSignersList =
engine->view().peek (k);
auto const accountSignersList =
view.read (k);
// If the signer list doesn't exist the account is not multi-signing.
if (!accountSignersList)
@@ -414,7 +359,7 @@ CheckSigningAccountsResult
checkSigningAccounts (
std::vector<SignerEntries::SignerEntry> signerEntries,
STArray const& signingAccounts,
TransactionEngine* engine,
ApplyContext& ctx,
beast::Journal journal)
{
CheckSigningAccountsResult ret;
@@ -489,8 +434,8 @@ checkSigningAccounts (
// In any of these cases we need to know whether the account is in
// the ledger. Determine that now.
SLE::pointer signersAccountRoot =
engine->view().peek (keylet::account(signingAcctID));
auto signersAccountRoot =
ctx.view().read (keylet::account(signingAcctID));
if (signingAcctIDFromPubKey == signingAcctID)
{
@@ -553,7 +498,7 @@ TER Transactor::checkMultiSign ()
// Get mTxnAccountID's SignerList and Quorum.
using namespace TransactorDetail;
GetSignerListResult const outer =
getSignerList (mTxnAccountID, mEngine, m_journal);
getSignerList (mTxnAccountID, view(), j_);
if (outer.ter != tesSUCCESS)
return outer.ter;
@@ -587,7 +532,7 @@ TER Transactor::checkMultiSign ()
// from these signers directly effect the quorum.
CheckSigningAccountsResult const outerSigningAccountsResult =
checkSigningAccounts (
outer.signerEntries, signingAccounts, mEngine, m_journal);
outer.signerEntries, signingAccounts, ctx_, j_);
if (outerSigningAccountsResult.ter != tesSUCCESS)
return outerSigningAccountsResult.ter;
@@ -602,7 +547,7 @@ TER Transactor::checkMultiSign ()
{
if (++signerEntriesItr == outer.signerEntries.end ())
{
m_journal.trace <<
j_.trace <<
"applyTransaction: Invalid SigningFor.Account.";
return tefBAD_SIGNATURE;
}
@@ -610,21 +555,21 @@ TER Transactor::checkMultiSign ()
if (signerEntriesItr->account != signingForID)
{
// The signingForID is not in the SignerEntries.
m_journal.trace <<
j_.trace <<
"applyTransaction: Invalid SigningFor.Account.";
return tefBAD_SIGNATURE;
}
if (signerEntriesItr->weight <= 0)
{
// The SigningFor entry needs a weight greater than zero.
m_journal.trace <<
j_.trace <<
"applyTransaction: SigningFor.Account needs weight > 0.";
return tefBAD_SIGNATURE;
}
// See if the signingForID has a SignerList.
GetSignerListResult const inner =
getSignerList (signingForID, mEngine, m_journal);
getSignerList (signingForID, view(), j_);
if (inner.ter != tesSUCCESS)
return inner.ter;
@@ -632,7 +577,7 @@ TER Transactor::checkMultiSign ()
// Results from these signers indirectly effect the quorum.
CheckSigningAccountsResult const innerSigningAccountsResult =
checkSigningAccounts (
inner.signerEntries, signingAccounts, mEngine, m_journal);
inner.signerEntries, signingAccounts, ctx_, j_);
if (innerSigningAccountsResult.ter != tesSUCCESS)
return innerSigningAccountsResult.ter;
@@ -652,7 +597,7 @@ TER Transactor::checkMultiSign ()
// -- January 2015
if (innerSigningAccountsResult.weightSum < inner.quorum)
{
m_journal.trace <<
j_.trace <<
"applyTransaction: Level-2 SigningFor did not make quorum.";
return tefBAD_QUORUM;
}
@@ -664,7 +609,7 @@ TER Transactor::checkMultiSign ()
// Cannot perform transaction if quorum is not met.
if (weightSum < outer.quorum)
{
m_journal.trace <<
j_.trace <<
"applyTransaction: MultiSignature failed to meet quorum.";
return tefBAD_QUORUM;
}
@@ -673,4 +618,173 @@ TER Transactor::checkMultiSign ()
return tesSUCCESS;
}
//------------------------------------------------------------------------------
static
void
log (std::pair<
TER, bool> const& result,
beast::Journal j)
{
if(j.trace) j.trace <<
"apply: { " << transToken(result.first) <<
", " << (result.second ? "true" : "false") << " }";
}
std::pair<TER, bool>
Transactor::operator()()
{
JLOG(j_.trace) <<
"applyTransaction>";
uint256 const& txID = mTxn.getTransactionID ();
if (!txID)
{
JLOG(j_.warning) <<
"applyTransaction: transaction id may not be zero";
auto const result =
std::make_pair(temINVALID_FLAG, false);
log(result, j_);
return result;
}
#ifdef BEAST_DEBUG
{
Serializer ser;
mTxn.add (ser);
SerialIter sit(ser.slice());
STTx s2 (sit);
if (! s2.isEquivalent(mTxn))
{
JLOG(j_.fatal) <<
"Transaction serdes mismatch";
JLOG(j_.info) << to_string(mTxn.getJson (0));
JLOG(j_.fatal) << s2.getJson (0);
assert (false);
}
}
#endif
TER terResult = apply();
if (terResult == temUNKNOWN)
{
JLOG(j_.warning) <<
"applyTransaction: Invalid transaction: unknown transaction type";
auto const result =
std::make_pair(temUNKNOWN, false);
log(result, j_);
return result;
}
if (j_.debug)
{
std::string strToken;
std::string strHuman;
transResultInfo (terResult, strToken, strHuman);
j_.debug <<
"applyTransaction: terResult=" << strToken <<
" : " << terResult <<
" : " << strHuman;
}
bool didApply = isTesSuccess (terResult);
if (isTecClaim (terResult) && !(view().flags() & tapRETRY))
{
// only claim the transaction fee
JLOG(j_.debug) <<
"Reprocessing tx " << txID << " to only claim fee";
ctx_.discard();
auto const txnAcct = view().peek(
keylet::account(mTxn.getAccountID(sfAccount)));
if (txnAcct)
{
std::uint32_t t_seq = mTxn.getSequence ();
std::uint32_t a_seq = txnAcct->getFieldU32 (sfSequence);
if (a_seq < t_seq)
terResult = terPRE_SEQ;
else if (a_seq > t_seq)
terResult = tefPAST_SEQ;
else
{
STAmount fee = mTxn.getTransactionFee ();
STAmount balance = txnAcct->getFieldAmount (sfBalance);
// We retry/reject the transaction if the account
// balance is zero or we're applying against an open
// ledger and the balance is less than the fee
if ((balance == zero) ||
(view().open() && (balance < fee)))
{
// Account has no funds or ledger is open
terResult = terINSUF_FEE_B;
}
else
{
if (fee > balance)
fee = balance;
txnAcct->setFieldAmount (sfBalance, balance - fee);
txnAcct->setFieldU32 (sfSequence, t_seq + 1);
view().update (txnAcct);
didApply = true;
}
}
}
else
{
terResult = terNO_ACCOUNT;
}
}
else if (!didApply)
{
JLOG(j_.debug) << "Not applying transaction " << txID;
}
if (didApply)
{
// Transaction succeeded fully or (retries are
// not allowed and the transaction could claim a fee)
if(view().closed())
{
// VFALCO Fix this nonsense with Amount
// Charge whatever fee they specified. We break the
// encapsulation of STAmount here and use "special
// knowledge" - namely that a native amount is
// stored fully in the mantissa:
auto const fee = mTxn.getTransactionFee ();
// The transactor guarantees these will never trigger
if (!fee.native () || fee.negative ())
{
// VFALCO Log to journal here
// JLOG(journal.fatal) << "invalid fee";
throw std::logic_error(
"amount is negative!");
}
if (fee != zero)
view().destroyCoins (fee.mantissa ());
}
ctx_.apply(terResult);
// VFALCO NOTE since we called apply(), it is not
// okay to look at view() past this point.
}
auto const result =
std::make_pair(terResult, didApply);
log(result, j_);
return result;
}
}

View File

@@ -20,27 +20,17 @@
#ifndef RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED
#define RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED
#include <ripple/app/tx/TransactionEngine.h>
#include <ripple/app/tx/impl/ApplyContext.h>
#include <beast/utility/Journal.h>
namespace ripple {
class Transactor
{
public:
static
TER
transact (
STTx const& txn,
ViewFlags params,
TransactionEngine* engine);
TER
apply ();
protected:
STTx const& mTxn;
TransactionEngine* mEngine;
ViewFlags const mParams;
ApplyContext& ctx_;
beast::Journal j_;
AccountID mTxnAccountID;
STAmount mFeeDue;
@@ -51,36 +41,53 @@ protected:
bool mSigMaster;
RippleAddress mSigningPubKey;
beast::Journal m_journal;
public:
/** Process the transaction. */
std::pair<TER, bool>
operator()();
virtual TER preCheck ();
View&
view()
{
return ctx_.view();
}
View const&
view() const
{
return ctx_.view();
}
protected:
TER
apply();
explicit
Transactor (ApplyContext& ctx);
// Non-virtual components of preCheck()
TER preCheckAccount ();
TER preCheckSigningKey ();
virtual TER checkSeq ();
virtual TER payFee ();
void calculateFee ();
// VFALCO This is the equivalent of dynamic_cast
// to discover the type of the derived class,
// and therefore bad.
virtual
bool
mustHaveValidAccount()
{
return true;
}
// Returns the fee, not scaled for load (Should be in fee units. FIXME)
virtual std::uint64_t calculateBaseFee ();
virtual TER preCheck ();
virtual TER checkSeq ();
virtual TER payFee ();
virtual TER checkSign ();
virtual TER doApply () = 0;
Transactor (
const STTx& txn,
ViewFlags params,
TransactionEngine* engine,
beast::Journal journal = beast::Journal ());
virtual bool mustHaveValidAccount ()
{
return true;
}
private:
TER checkSingleSign ();
TER checkMultiSign ();

View File

@@ -0,0 +1,86 @@
//------------------------------------------------------------------------------
/*
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/tx/apply.h>
#include <ripple/app/tx/impl/ApplyContext.h>
#include <ripple/app/tx/impl/CancelOffer.h>
#include <ripple/app/tx/impl/CancelTicket.h>
#include <ripple/app/tx/impl/Change.h>
#include <ripple/app/tx/impl/CreateOffer.h>
#include <ripple/app/tx/impl/CreateTicket.h>
#include <ripple/app/tx/impl/Payment.h>
#include <ripple/app/tx/impl/SetAccount.h>
#include <ripple/app/tx/impl/SetRegularKey.h>
#include <ripple/app/tx/impl/SetSignerList.h>
#include <ripple/app/tx/impl/SetTrust.h>
namespace ripple {
template <class Processor,
class... Args>
static
std::pair<TER, bool>
do_apply (Args&&... args)
{
ApplyContext ctx (
std::forward<Args>(args)...);
Processor p(ctx);
return p();
}
template <class... Args>
static
std::pair<TER, bool>
invoke (TxType type,
Args&&... args)
{
switch(type)
{
case ttACCOUNT_SET: return do_apply< SetAccount >(std::forward<Args>(args)...);
case ttOFFER_CANCEL: return do_apply< CancelOffer >(std::forward<Args>(args)...);
case ttOFFER_CREATE: return do_apply< CreateOffer >(std::forward<Args>(args)...);
case ttPAYMENT: return do_apply< Payment >(std::forward<Args>(args)...);
case ttREGULAR_KEY_SET: return do_apply< SetRegularKey >(std::forward<Args>(args)...);
case ttSIGNER_LIST_SET: return do_apply< SetSignerList >(std::forward<Args>(args)...);
case ttTICKET_CANCEL: return do_apply< CancelTicket >(std::forward<Args>(args)...);
case ttTICKET_CREATE: return do_apply< CreateTicket >(std::forward<Args>(args)...);
case ttTRUST_SET: return do_apply< SetTrust >(std::forward<Args>(args)...);
// VFALCO These are both the same?
case ttAMENDMENT:
case ttFEE: return do_apply< Change >(std::forward<Args>(args)...);
default:
break;
}
return { temUNKNOWN, false };
}
std::pair<TER, bool>
apply (BasicView& view,
STTx const& tx, ViewFlags flags,
Config const& config,
beast::Journal journal)
{
return invoke (tx.getTxnType(),
view, tx, flags, config, journal);
}
} // ripple

View File

@@ -55,7 +55,7 @@ public:
void testCanceledOffer ()
{
using namespace jtx;
Env env = *this;
Env env (*this);
auto const gw = Account ("gateway");
auto const USD = gw["USD"];

View File

@@ -20,6 +20,7 @@
#include <ripple/app/ledger/LedgerConsensus.h>
#include <ripple/app/ledger/LedgerTiming.h>
#include <ripple/app/ledger/tests/common_ledger.h>
#include <ripple/app/tx/apply.h>
#include <ripple/basics/seconds_clock.h>
#include <ripple/protocol/TxFormats.h>
#include <ripple/protocol/TxFlags.h>
@@ -90,12 +91,13 @@ TestLedger::TestLedger (
createGenesisLedger(startAmountDrops, masterAcct);
}
std::pair<TER, bool> TestLedger::applyTransaction (STTx const& tx, bool check)
std::pair<TER, bool>
TestLedger::applyTransaction (STTx const& tx, bool check)
{
// Apply the transaction to the open ledger.
TransactionEngine engine(openLedger_);
auto r = engine.applyTransaction (
tx, tapOPEN_LEDGER | (check ? tapNONE : tapNO_CHECK_SIGN));
auto const r = apply(
*openLedger_, tx, check ? tapNONE : tapNO_CHECK_SIGN,
getConfig(), beast::Journal{});
// Close the open ledger to see if the transaction was real committed.
//

View File

@@ -26,6 +26,7 @@
#include <ripple/protocol/TER.h>
#include <ripple/core/Config.h>
#include <ripple/ledger/View.h>
#include <beast/utility/Journal.h>
#include <boost/optional.hpp>
#include <functional>
#include <memory>
@@ -65,11 +66,40 @@ struct Fees
//------------------------------------------------------------------------------
/** A view into a ledger's state items.
/** Information about the notional ledger backing the view. */
struct ViewInfo
{
// Fields for all ledgers
bool open = true;
LedgerIndex seq = 0;
std::uint32_t parentCloseTime = 0;
The interface provides raw access for state item
modification operations. There is no checkpointing
// Fields for closed ledgers
// Closed means "tx set already determined"
//uint256 hash;
//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.
A raw interace is provided for mutable ledgers.
*/
class BasicView
{
@@ -80,24 +110,44 @@ public:
virtual ~BasicView() = default;
/** Returns information about the ledger. */
virtual
ViewInfo 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;
/** Returns the sequence number of the base ledger. */
virtual
LedgerIndex
seq() const = 0;
/** Return the last known close time.
The epoch is based on the Ripple network clock.
*/
virtual
std::uint32_t
time() const = 0;
/** Determine if a state item exists.
@note This can be more efficient than calling read.
@@ -204,6 +254,18 @@ public:
void
destroyCoins (std::uint64_t feeDrops) = 0;
/** Returns the number of newly inserted transactions.
This will always be zero for closed ledgers, there
is no efficient way to count the number of tx in
the map. For views representing open ledgers this
starts out as one and gets incremented for each
transaction that is applied.
*/
virtual
std::size_t
txCount() const = 0;
/** Returns `true` if a tx exists in the tx map. */
virtual
bool
@@ -214,10 +276,11 @@ public:
@param metaData Optional metadata (may be nullptr)
*/
virtual
bool
void
txInsert (uint256 const& key,
std::shared_ptr<Serializer const> const& txn,
std::shared_ptr<Serializer const> const& metaData) = 0;
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData) = 0;
// DEBUG ROUTINE
// Return a list of transaction keys in the tx map.
@@ -255,11 +318,6 @@ enum ViewFlags
//
tapENABLE_TESTING = 0x02,
// Transaction is running against an open ledger
// true = failures are not forwarded, check transaction fee
// false = debit ledger for consumed funds
tapOPEN_LEDGER = 0x10,
// This is not the transaction's last pass
// Transaction can be retried, soft failures allowed
tapRETRY = 0x20,
@@ -268,6 +326,27 @@ enum ViewFlags
tapADMIN = 0x400,
};
inline
ViewFlags operator|(
ViewFlags const& lhs,
ViewFlags const& rhs)
{
return static_cast<ViewFlags>(
static_cast<int>(lhs) |
static_cast<int>(rhs));
}
inline
ViewFlags
operator&(
ViewFlags const& lhs,
ViewFlags const& rhs)
{
return static_cast<ViewFlags>(
static_cast<int>(lhs) &
static_cast<int>(rhs));
}
/** A contextual view into a ledger's state items.
This refinement of BasicView provides an interface where
@@ -422,24 +501,18 @@ public:
{
}
ViewInfo const&
info() const
{
return view_.info();
}
Fees const&
fees() const override
{
return view_.fees();
}
LedgerIndex
seq() const override
{
return view_.seq();
}
std::uint32_t
time() const override
{
return view_.time();
}
bool
exists (Keylet const& k) const override
{
@@ -488,20 +561,25 @@ public:
return view_.destroyCoins(feeDrops);
}
std::size_t
txCount() const override
{
return view_.txCount();
}
bool
txExists (uint256 const& key) const override
{
return view_.txExists(key);
}
bool
void
txInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData) override
{
return view_.txInsert(
key, txn, metaData);
view_.txInsert(key, txn, metaData);
}
std::vector<uint256>
@@ -528,24 +606,18 @@ public:
{
}
ViewInfo const&
info() const
{
return view_.info();
}
Fees const&
fees() const override
{
return view_.fees();
}
LedgerIndex
seq() const override
{
return view_.seq();
}
std::uint32_t
time() const override
{
return view_.time();
}
bool
exists (Keylet const& k) const override
{
@@ -594,20 +666,25 @@ public:
return view_.destroyCoins(feeDrops);
}
std::size_t
txCount() const override
{
return view_.txCount();
}
bool
txExists (uint256 const& key) const override
{
return view_.txExists(key);
}
bool
void
txInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData) override
{
return view_.txInsert(
key, txn, metaData);
view_.txInsert(key, txn, metaData);
}
std::vector<uint256>

View File

@@ -1240,7 +1240,7 @@ accountSend (View& view,
{
// VFALCO Its laborious to have to mutate the
// TER based on params everywhere
terResult = (view.flags() & tapOPEN_LEDGER)
terResult = view.open()
? telFAILED_PROCESSING
: tecFAILED_PROCESSING;
}
@@ -1497,7 +1497,7 @@ transferXRP (View& view,
// VFALCO Its unfortunate we have to keep
// mutating these TER everywhere
// FIXME: this logic should be moved to callers maybe?
return (view.flags() & tapOPEN_LEDGER)
return view.open()
? telFAILED_PROCESSING
: tecFAILED_PROCESSING;
}

View File

@@ -25,10 +25,11 @@
namespace ripple {
// See https://ripple.com/wiki/Transaction_errors
// VFALCO TODO consider renaming TER to TxErr or TxResult for clarity.
//
enum TER // aka TransactionEngineResult
// "Transaction Engine Result"
// or Transaction ERror.
//
enum TER
{
// Note: Range is stable. Exact numbers are currently unstable. Use tokens.

View File

@@ -304,7 +304,8 @@ ripplePathFind (RippleLineCache::pointer const& cache,
saMaxAmount.negate();
boost::optional<PaymentView> sandbox;
sandbox.emplace(lpLedger.get(), tapOPEN_LEDGER);
sandbox.emplace(*lpLedger, tapNONE);
assert(sandbox->open());
auto rc = path::RippleCalc::rippleCalculate(
*sandbox,
@@ -329,7 +330,8 @@ ripplePathFind (RippleLineCache::pointer const& cache,
<< "Trying with an extra path element";
spsComputed.push_back(fullLiquidityPath);
sandbox.emplace(lpLedger.get(), tapOPEN_LEDGER);
sandbox.emplace(*lpLedger, tapNONE);
assert(sandbox->open());
rc = path::RippleCalc::rippleCalculate(
*sandbox,
saMaxAmount, // --> Amount to send is unlimited

View File

@@ -65,7 +65,7 @@ Json::Value doTransactionEntry (RPC::Context& context)
else
{
Transaction::pointer tpTrans;
TransactionMetaSet::pointer tmTrans;
TxMeta::pointer tmTrans;
if (!getTransaction (*lpLedger, uTransID, tpTrans, tmTrans,
getApp().getMasterTransaction()))

View File

@@ -83,7 +83,7 @@ Json::Value doTx (RPC::Context& context)
}
else
{
TransactionMetaSet::pointer txMeta;
TxMeta::pointer txMeta;
if (getTransactionMeta (*lgr, txn->getID (), txMeta))
{

View File

@@ -27,7 +27,7 @@ addPaymentDeliveredAmount (
Json::Value& meta,
RPC::Context& context,
Transaction::pointer transaction,
TransactionMetaSet::pointer transactionMeta)
TxMeta::pointer transactionMeta)
{
// We only want to add a "delivered_amount" field if the transaction
// succeeded - otherwise nothing could have been delivered.

View File

@@ -28,7 +28,7 @@ addPaymentDeliveredAmount (
Json::Value&,
RPC::Context&,
Transaction::pointer,
TransactionMetaSet::pointer);
TxMeta::pointer);
} // RPC
} // ripple

View File

@@ -27,6 +27,7 @@
#include <ripple/test/jtx/tags.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/core/Config.h>
#include <ripple/json/json_value.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/Indexes.h>
@@ -117,6 +118,10 @@ class Env
public:
beast::unit_test::suite& test;
/** Configuration used. */
// VFALCO NOTE Some code still calls getConfig()
Config const config;
/** The master account. */
Account const master;

View File

@@ -28,8 +28,8 @@
#include <ripple/test/jtx/seq.h>
#include <ripple/test/jtx/sig.h>
#include <ripple/test/jtx/utility.h>
#include <ripple/app/tx/apply.h>
#include <ripple/app/paths/FindPaths.h>
#include <ripple/app/tx/TransactionEngine.h>
#include <ripple/basics/Slice.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/ErrorCodes.h>
@@ -198,11 +198,12 @@ Env::submit (JTx const& jt)
if (stx)
{
ViewFlags flags = tapNONE;
flags = flags | tapOPEN_LEDGER;
flags = flags | tapENABLE_TESTING;
TransactionEngine txe (ledger);
// VFALCO Could wrap the log in a Journal here
std::tie(ter, didApply) =
txe.applyTransaction(*stx, flags);
ripple::apply(
*ledger, *stx, flags, config,
beast::Journal{});
}
else
{

View File

@@ -39,6 +39,7 @@
#include <ripple/app/ledger/impl/LedgerMaster.cpp>
#include <ripple/app/ledger/impl/LedgerTiming.cpp>
#include <ripple/app/ledger/impl/MetaView.cpp>
#include <ripple/app/ledger/impl/TxMeta.cpp>
#include <ripple/app/ledger/tests/common_ledger.cpp>
#include <ripple/app/ledger/tests/DeferredCredits.test.cpp>

View File

@@ -19,6 +19,7 @@
#include <BeastConfig.h>
#include <ripple/app/tx/impl/apply.cpp>
#include <ripple/app/tx/impl/BookTip.cpp>
#include <ripple/app/tx/impl/CancelOffer.cpp>
#include <ripple/app/tx/impl/CancelTicket.cpp>
@@ -37,8 +38,7 @@
#include <ripple/app/tx/impl/Taker.cpp>
#include <ripple/app/tx/impl/TransactionMaster.cpp>
#include <ripple/app/tx/impl/Transaction.cpp>
#include <ripple/app/tx/impl/TransactionEngine.cpp>
#include <ripple/app/tx/impl/TransactionMeta.cpp>
#include <ripple/app/tx/impl/ApplyContext.cpp>
#include <ripple/app/tx/impl/TransactionAcquire.cpp>
#include <ripple/app/tx/impl/Transactor.cpp>