diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj
index c280dee3e7..61c508a27c 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj
+++ b/Builds/VisualStudio2013/RippleD.vcxproj
@@ -2402,11 +2402,6 @@
-
- True
-
-
-
True
diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters
index a5245d5f84..dcaad50074 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters
@@ -3468,12 +3468,6 @@
ripple\module\app\transactors
-
- ripple\module\app\transactors
-
-
- ripple\module\app\transactors
-
ripple\module\app\transactors
diff --git a/src/BeastConfig.h b/src/BeastConfig.h
index 5ccadf2f4a..62d781bb8c 100644
--- a/src/BeastConfig.h
+++ b/src/BeastConfig.h
@@ -205,11 +205,11 @@ This determines whether to add any features to the proposed transaction set.
#define RIPPLE_PROPOSE_AMENDMENTS 0
#endif
-/** Config: RIPPLE_USE_OLD_CREATE_TRANSACTOR
-This determines whether ripple uses the legacy OfferCreate transactor.
+/** Config: RIPPLE_ENABLE_AUTOBRIDGING
+This determines whether ripple implements offer autobridging via XRP.
*/
-#ifndef RIPPLE_USE_OLD_CREATE_TRANSACTOR
-#define RIPPLE_USE_OLD_CREATE_TRANSACTOR 1
+#ifndef RIPPLE_ENABLE_AUTOBRIDGING
+#define RIPPLE_ENABLE_AUTOBRIDGING 0
#endif
#endif
diff --git a/src/ripple/module/app/book/Offer.h b/src/ripple/module/app/book/Offer.h
index 1e20b70d75..1a70fde592 100644
--- a/src/ripple/module/app/book/Offer.h
+++ b/src/ripple/module/app/book/Offer.h
@@ -80,7 +80,8 @@ public:
Amounts const
amount() const
{
- return Amounts (m_entry->getFieldAmount (sfTakerPays),
+ return Amounts (
+ m_entry->getFieldAmount (sfTakerPays),
m_entry->getFieldAmount (sfTakerGets));
}
diff --git a/src/ripple/module/app/book/Taker.h b/src/ripple/module/app/book/Taker.h
index 3d504431f1..3eb01ec9c4 100644
--- a/src/ripple/module/app/book/Taker.h
+++ b/src/ripple/module/app/book/Taker.h
@@ -29,7 +29,6 @@
#include
#include
-//#include
namespace ripple {
namespace core {
@@ -80,6 +79,9 @@ private:
fill (Offer const& leg1, Amounts const& amount1,
Offer const& leg2, Amounts const& amount2);
+ void
+ consume (Offer const& offer, Amounts const& consumed) const;
+
public:
Taker (LedgerView& view, Account const& account,
Amounts const& amount, Options const& options);
diff --git a/src/ripple/module/app/book/impl/Quality.cpp b/src/ripple/module/app/book/impl/Quality.cpp
index 6eda891613..a008af6cd6 100644
--- a/src/ripple/module/app/book/impl/Quality.cpp
+++ b/src/ripple/module/app/book/impl/Quality.cpp
@@ -47,7 +47,7 @@ Quality
Quality::operator++ (int)
{
Quality prev (*this);
- --*this;
+ ++*this;
return prev;
}
@@ -63,7 +63,7 @@ Quality
Quality::operator-- (int)
{
Quality prev (*this);
- ++*this;
+ --*this;
return prev;
}
@@ -77,8 +77,10 @@ Quality::ceil_in (Amounts const& amount, Amount const& limit) const
// Clamp out
if (result.out > amount.out)
result.out = amount.out;
+ assert (result.in == limit);
return result;
}
+ assert (amount.in <= limit);
return amount;
}
@@ -92,8 +94,10 @@ Quality::ceil_out (Amounts const& amount, Amount const& limit) const
// Clamp in
if (result.in > amount.in)
result.in = amount.in;
+ assert (result.out == limit);
return result;
}
+ assert (amount.out <= limit);
return amount;
}
diff --git a/src/ripple/module/app/book/impl/Taker.cpp b/src/ripple/module/app/book/impl/Taker.cpp
index 59919a8b80..227238f9ec 100644
--- a/src/ripple/module/app/book/impl/Taker.cpp
+++ b/src/ripple/module/app/book/impl/Taker.cpp
@@ -19,8 +19,6 @@
#include
-//#include
-
namespace ripple {
namespace core {
@@ -34,6 +32,9 @@ Taker::Taker (LedgerView& view, Account const& account,
, m_amount (amount)
, m_remain (amount)
{
+ assert (m_remain.in > zero);
+ assert (m_remain.out > zero);
+
// If this is a passive order (tfPassive), this prevents
// offers at the same quality level from being consumed.
if (m_options.passive)
@@ -71,11 +72,12 @@ Taker::remaining_offer () const
m_remain.out, m_quality.rate (), m_remain.in, true), m_remain.out);
}
-// Calculate the amount particular user could get through an offer.
-// @param amount the maximum flow that is available to the taker.
-// @param offer the offer to flow through.
-// @param taker the person taking the offer.
-// @return the maximum amount that can flow through this offer.
+/** Calculate the amount particular user could get through an offer.
+ @param amount the maximum flow that is available to the taker.
+ @param offer the offer to flow through.
+ @param taker the person taking the offer.
+ @return the maximum amount that can flow through this offer.
+*/
Amounts
Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
{
@@ -129,6 +131,24 @@ Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
: amount;
}
+// Adjust an offer to indicate that we are consuming some (or all) of it.
+void
+Taker::consume (Offer const& offer, Amounts const& consumed) const
+{
+ Amounts const& remaining (offer.amount ());
+
+ assert (remaining.in > zero && remaining.out > zero);
+ assert (remaining.in >= consumed.in && remaining.out >= consumed.out);
+
+ offer.entry ()->setFieldAmount (sfTakerPays, remaining.in - consumed.in);
+ offer.entry ()->setFieldAmount (sfTakerGets, remaining.out - consumed.out);
+
+ view ().entryModify (offer.entry());
+
+ assert (offer.entry ()->getFieldAmount (sfTakerPays) >= zero);
+ assert (offer.entry ()->getFieldAmount (sfTakerGets) >= zero);
+}
+
// Fill a direct offer.
// @param offer the offer we are going to use.
// @param amount the amount to flow through the offer.
@@ -136,18 +156,10 @@ Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
TER
Taker::fill (Offer const& offer, Amounts const& amount)
{
- TER result (tesSUCCESS);
-
- Amounts const remain (
- offer.entry ()->getFieldAmount (sfTakerPays) - amount.in,
- offer.entry ()->getFieldAmount (sfTakerGets) - amount.out);
-
- offer.entry ()->setFieldAmount (sfTakerPays, remain.in);
- offer.entry ()->setFieldAmount (sfTakerGets, remain.out);
- view ().entryModify (offer.entry());
+ consume (offer, amount);
// Pay the taker, then the owner
- result = view ().accountSend (offer.account(), account(), amount.out);
+ TER result = view ().accountSend (offer.account(), account(), amount.out);
if (result == tesSUCCESS)
result = view ().accountSend (account(), offer.account(), amount.in);
@@ -168,27 +180,14 @@ Taker::fill (
{
assert (amount1.out == amount2.in);
- TER result (tesSUCCESS);
+ consume (leg1, amount1);
+ consume (leg2, amount2);
- Amounts const remain1 (
- leg1.entry ()->getFieldAmount (sfTakerPays) - amount1.in,
- leg1.entry ()->getFieldAmount (sfTakerGets) - amount1.out);
-
- leg1.entry ()->setFieldAmount (sfTakerPays, remain1.in);
- leg1.entry ()->setFieldAmount (sfTakerGets, remain1.out);
- view ().entryModify (leg1.entry());
-
- Amounts const remain2 (
- leg2.entry ()->getFieldAmount (sfTakerPays) - amount2.in,
- leg2.entry ()->getFieldAmount (sfTakerGets) - amount2.out);
- view ().entryModify (leg2.entry ());
-
- // Execute the payments in order:
- // Taker pays Leg1 (amount1.in - A currency)
- // Leg1 pays Leg2 (amount1.out == amount2.in, XRP)
- // Leg2 pays Taker (amount2.out - B currency)
-
- result = view ().accountSend (m_account, leg1.account (), amount1.in);
+ /* It is possible that m_account is the same as leg1.account, leg2.account
+ * or both. This could happen when bridging over one's own offer. In that
+ * case, accountSend won't actually do a send, which is what we want.
+ */
+ TER result = view ().accountSend (m_account, leg1.account (), amount1.in);
if (result == tesSUCCESS)
result = view ().accountSend (leg1.account (), leg2.account (), amount1.out);
@@ -202,17 +201,15 @@ Taker::fill (
bool
Taker::done () const
{
- if (m_options.sell)
+ if (m_options.sell && (m_remain.in <= zero))
{
- // With the sell option, we are finished when
- // we have consumed all the input currency.
- if (m_remain.in <= zero)
- return true;
+ // Sell semantics: we consumed all the input currency
+ return true;
}
- else if (m_remain.out <= zero)
+
+ if (!m_options.sell && (m_remain.out <= zero))
{
- // With the buy option (!sell) we are finished when we
- // have received the desired amount of output currency.
+ // Buy semantics: we received the desired amount of output currency
return true;
}
@@ -224,18 +221,25 @@ TER
Taker::cross (Offer const& offer)
{
assert (!done ());
- Amounts limit (offer.amount());
- if (m_options.sell)
- limit = offer.quality().ceil_in (limit, m_remain.in);
- else
- limit = offer.quality ().ceil_out (limit, m_remain.out);
- assert (limit.out <= offer.amount().out);
+ /* Before we call flow we must set the limit right; for buy semantics we
+ need to clamp the output. And we always want to clamp the input.
+ */
+ Amounts limit (offer.amount());
+
+ if (! m_options.sell)
+ limit = offer.quality ().ceil_out (limit, m_remain.out);
+ limit = offer.quality().ceil_in (limit, m_remain.in);
+
assert (limit.in <= offer.amount().in);
+ assert (limit.out <= offer.amount().out);
+ assert (limit.in <= m_remain.in);
Amounts const amount (flow (limit, offer, account ()));
+
m_remain.out -= amount.out;
m_remain.in -= amount.in;
+
assert (m_remain.in >= zero);
return fill (offer, amount);
}
diff --git a/src/ripple/module/app/book/tests/Quality.test.cpp b/src/ripple/module/app/book/tests/Quality.test.cpp
index 6e5eac3772..7970537de0 100644
--- a/src/ripple/module/app/book/tests/Quality.test.cpp
+++ b/src/ripple/module/app/book/tests/Quality.test.cpp
@@ -222,6 +222,8 @@ public:
void
test_raw()
{
+ testcase ("raw");
+
{
Quality q (0x5d048191fb9130daull); // 126836389.7680090
Amounts const value (
@@ -234,12 +236,85 @@ public:
}
}
+ void
+ test_comparisons()
+ {
+ testcase ("comparisons");
+
+ Amount const amount1 (noCurrency (), noAccount (), 231);
+ Amount const amount2 (noCurrency (), noAccount (), 462);
+ Amount const amount3 (noCurrency (), noAccount (), 924);
+
+ Quality const q11 (core::Amounts (amount1, amount1));
+ Quality const q12 (core::Amounts (amount1, amount2));
+ Quality const q13 (core::Amounts (amount1, amount3));
+ Quality const q21 (core::Amounts (amount2, amount1));
+ Quality const q31 (core::Amounts (amount3, amount1));
+
+ expect (q11 == q11);
+ expect (q11 < q12);
+ expect (q12 < q13);
+ expect (q31 < q21);
+ expect (q21 < q11);
+ expect (q31 != q21);
+ }
+
+ void
+ test_composition ()
+ {
+ testcase ("composition");
+
+ Amount const amount1 (noCurrency (), noAccount (), 231);
+ Amount const amount2 (noCurrency (), noAccount (), 462);
+ Amount const amount3 (noCurrency (), noAccount (), 924);
+
+ Quality const q11 (core::Amounts (amount1, amount1));
+ Quality const q12 (core::Amounts (amount1, amount2));
+ Quality const q13 (core::Amounts (amount1, amount3));
+ Quality const q21 (core::Amounts (amount2, amount1));
+ Quality const q31 (core::Amounts (amount3, amount1));
+
+ expect (composed_quality (q12, q21) == q11);
+
+ Quality const q13_31 (composed_quality (q13, q31));
+ Quality const q31_13 (composed_quality (q31, q13));
+
+ expect (q13_31 == q31_13);
+ expect (q13_31 == q11);
+ }
+
+ void
+ test_operations ()
+ {
+ testcase ("operations");
+
+ Quality const q11 (core::Amounts (
+ Amount (noCurrency (), noAccount (), 731),
+ Amount (noCurrency (), noAccount (), 731)));
+
+ Quality qa (q11);
+ Quality qb (q11);
+
+ expect (qa == qb);
+ expect (++qa != q11);
+ expect (qa != qb);
+ expect (--qb != q11);
+ expect (qa != qb);
+ expect (qb < qa);
+ expect (qb++ < qa);
+ expect (qb++ < qa);
+ expect (qb++ == qa);
+ expect (qa < qb);
+ }
void
run()
{
+ test_comparisons ();
+ test_composition ();
+ test_operations ();
test_ceil_in ();
test_ceil_out ();
- test_raw();
+ test_raw ();
}
};
diff --git a/src/ripple/module/app/ledger/LedgerEntrySet.cpp b/src/ripple/module/app/ledger/LedgerEntrySet.cpp
index f566514f77..5630c0610d 100644
--- a/src/ripple/module/app/ledger/LedgerEntrySet.cpp
+++ b/src/ripple/module/app/ledger/LedgerEntrySet.cpp
@@ -1683,85 +1683,97 @@ TER LedgerEntrySet::accountSend (
Account const& uSenderID, Account const& uReceiverID,
const STAmount& saAmount)
{
- TER terResult = tesSUCCESS;
-
assert (saAmount >= zero);
+ /* If we aren't sending anything or if the sender is the same as the
+ * receiver then we don't need to do anything.
+ */
if (!saAmount || (uSenderID == uReceiverID))
return tesSUCCESS;
- if (saAmount.isNative ())
- {
- // XRP send which does not check reserve and can do pure adjustment.
- SLE::pointer sleSender = !!uSenderID
- ? entryCache (ltACCOUNT_ROOT,
- Ledger::getAccountRootIndex (uSenderID))
- : SLE::pointer ();
- SLE::pointer sleReceiver = !!uReceiverID
- ? entryCache (ltACCOUNT_ROOT,
- Ledger::getAccountRootIndex (uReceiverID))
- : SLE::pointer ();
-
- auto get_balance = [](SLE::pointer acct)
- {
- std::string ret ("-");
-
- if (acct)
- ret = acct->getFieldAmount (sfBalance).getFullText ();
-
- return ret;
- };
-
- WriteLog (lsTRACE, LedgerEntrySet) << "accountSend> " <<
- to_string (uSenderID) <<
- " (" << get_balance(sleSender) <<
- ") -> " << to_string (uReceiverID) <<
- " (" << get_balance(sleReceiver) <<
- ") : " << saAmount.getFullText ();
-
- if (sleSender)
- {
- if (sleSender->getFieldAmount (sfBalance) < saAmount)
- {
- terResult = (mParams & tapOPEN_LEDGER)
- ? telFAILED_PROCESSING
- : tecFAILED_PROCESSING;
- }
- else
- {
- // Decrement XRP balance.
- sleSender->setFieldAmount (sfBalance,
- sleSender->getFieldAmount (sfBalance) - saAmount);
- entryModify (sleSender);
- }
- }
-
- if (tesSUCCESS == terResult && sleReceiver)
- {
- // Increment XRP balance.
- sleReceiver->setFieldAmount (sfBalance,
- sleReceiver->getFieldAmount (sfBalance) + saAmount);
- entryModify (sleReceiver);
- }
-
- WriteLog (lsTRACE, LedgerEntrySet) << "accountSend< " <<
- to_string (uSenderID) <<
- " (" << get_balance(sleSender) <<
- ") -> " << to_string (uReceiverID) <<
- " (" << get_balance(sleReceiver) <<
- ") : " << saAmount.getFullText ();
- }
- else
+ if (!saAmount.isNative ())
{
STAmount saActual;
WriteLog (lsTRACE, LedgerEntrySet) << "accountSend: " <<
- to_string (uSenderID) <<
- " -> " << to_string (uReceiverID) <<
+ to_string (uSenderID) << " -> " << to_string (uReceiverID) <<
" : " << saAmount.getFullText ();
+ return rippleSend (uSenderID, uReceiverID, saAmount, saActual);
+ }
- terResult = rippleSend (uSenderID, uReceiverID, saAmount, saActual);
+ /* XRP send which does not check reserve and can do pure adjustment.
+ * Note that sender or receiver may be null and this not a mistake; this
+ * setup is used during pathfinding and it is carefully controlled to
+ * ensure that transfers are balanced.
+ */
+
+ TER terResult (tesSUCCESS);
+
+ SLE::pointer sender = uSenderID != beast::zero
+ ? entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uSenderID))
+ : SLE::pointer ();
+ SLE::pointer receiver = uReceiverID != beast::zero
+ ? entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uReceiverID))
+ : SLE::pointer ();
+
+ if (ShouldLog (lsTRACE, LedgerEntrySet))
+ {
+ std::string sender_bal ("-");
+ std::string receiver_bal ("-");
+
+ if (sender)
+ sender_bal = sender->getFieldAmount (sfBalance).getFullText ();
+
+ if (receiver)
+ receiver_bal = receiver->getFieldAmount (sfBalance).getFullText ();
+
+ WriteLog (lsTRACE, LedgerEntrySet) << "accountSend> " <<
+ to_string (uSenderID) << " (" << sender_bal <<
+ ") -> " << to_string (uReceiverID) << " (" << receiver_bal <<
+ ") : " << saAmount.getFullText ();
+ }
+
+ if (sender)
+ {
+ if (sender->getFieldAmount (sfBalance) < saAmount)
+ {
+ terResult = (mParams & tapOPEN_LEDGER)
+ ? telFAILED_PROCESSING
+ : tecFAILED_PROCESSING;
+ }
+ else
+ {
+ // Decrement XRP balance.
+ sender->setFieldAmount (sfBalance,
+ sender->getFieldAmount (sfBalance) - saAmount);
+ entryModify (sender);
+ }
+ }
+
+ if (tesSUCCESS == terResult && receiver)
+ {
+ // Increment XRP balance.
+ receiver->setFieldAmount (sfBalance,
+ receiver->getFieldAmount (sfBalance) + saAmount);
+ entryModify (receiver);
+ }
+
+ if (ShouldLog (lsTRACE, LedgerEntrySet))
+ {
+ std::string sender_bal ("-");
+ std::string receiver_bal ("-");
+
+ if (sender)
+ sender_bal = sender->getFieldAmount (sfBalance).getFullText ();
+
+ if (receiver)
+ receiver_bal = receiver->getFieldAmount (sfBalance).getFullText ();
+
+ WriteLog (lsTRACE, LedgerEntrySet) << "accountSend< " <<
+ to_string (uSenderID) << " (" << sender_bal <<
+ ") -> " << to_string (uReceiverID) << " (" << receiver_bal <<
+ ") : " << saAmount.getFullText ();
}
return terResult;
diff --git a/src/ripple/module/app/ledger/LedgerEntrySet.h b/src/ripple/module/app/ledger/LedgerEntrySet.h
index a733503f03..919d6d8f49 100644
--- a/src/ripple/module/app/ledger/LedgerEntrySet.h
+++ b/src/ripple/module/app/ledger/LedgerEntrySet.h
@@ -84,8 +84,8 @@ public:
static char const* getCountedObjectName () { return "LedgerEntrySet"; }
LedgerEntrySet (
- Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false) :
- mLedger (ledger), mParams (tep), mSeq (0), mImmutable (immutable)
+ Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false)
+ : mLedger (ledger), mParams (tep), mSeq (0), mImmutable (immutable)
{
}
@@ -145,11 +145,6 @@ public:
return mLedger;
}
- Ledger::ref getLedgerRef () const
- {
- return mLedger;
- }
-
// basic entry functions
SLE::pointer getEntry (uint256 const & index, LedgerEntryAction&);
LedgerEntryAction hasEntry (uint256 const & index) const;
@@ -165,32 +160,35 @@ public:
// Directory functions.
TER dirAdd (
- std::uint64_t & uNodeDir, // Node of entry.
- uint256 const & uRootIndex,
- uint256 const & uLedgerIndex,
+ std::uint64_t& uNodeDir, // Node of entry.
+ uint256 const& uRootIndex,
+ uint256 const& uLedgerIndex,
std::function fDescriber);
TER dirDelete (
- const bool bKeepRoot,
- const std::uint64_t & uNodeDir, // Node item is mentioned in.
- uint256 const & uRootIndex,
- uint256 const & uLedgerIndex, // Item being deleted
- const bool bStable,
- const bool bSoft);
+ const bool bKeepRoot,
+ const std::uint64_t& uNodeDir, // Node item is mentioned in.
+ uint256 const& uRootIndex,
+ uint256 const& uLedgerIndex, // Item being deleted
+ const bool bStable,
+ const bool bSoft);
- bool dirFirst (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
- bool dirNext (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
- bool dirIsEmpty (uint256 const & uDirIndex);
- TER dirCount (uint256 const & uDirIndex, std::uint32_t & uCount);
+ bool dirFirst (uint256 const& uRootIndex, SLE::pointer& sleNode,
+ unsigned int & uDirEntry, uint256 & uEntryIndex);
+ bool dirNext (uint256 const& uRootIndex, SLE::pointer& sleNode,
+ unsigned int & uDirEntry, uint256 & uEntryIndex);
+ bool dirIsEmpty (uint256 const& uDirIndex);
+ TER dirCount (uint256 const& uDirIndex, std::uint32_t & uCount);
- uint256 getNextLedgerIndex (uint256 const & uHash);
- uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd);
+ uint256 getNextLedgerIndex (uint256 const & uHash);
+ uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd);
- void ownerCountAdjust (Account const& uOwnerID, int iAmount, SLE::ref sleAccountRoot = SLE::pointer ());
+ void ownerCountAdjust (Account const& uOwnerID, int iAmount,
+ SLE::ref sleAccountRoot = SLE::pointer ());
// Offer functions.
- TER offerDelete (uint256 const & offerIndex);
- TER offerDelete (SLE::pointer sleOffer);
+ TER offerDelete (uint256 const & offerIndex);
+ TER offerDelete (SLE::pointer sleOffer);
// Balance functions.
std::uint32_t rippleTransferRate (Account const& issuer);
@@ -220,10 +218,6 @@ public:
sfLowQualityOut, sfHighQualityOut);
}
- STAmount rippleHolds (
- Account const& account, Currency const& currency,
- Account const& issuer);
-
STAmount rippleTransferFee (
Account const& uSenderID, Account const& uReceiverID,
Account const& issuer, const STAmount & saAmount);
@@ -232,10 +226,6 @@ public:
Account const& uSenderID, Account const& uReceiverID,
const STAmount & saAmount, bool bCheckIssuer = true);
- TER rippleSend (
- Account const& uSenderID, Account const& uReceiverID,
- const STAmount & saAmount, STAmount & saActual);
-
STAmount accountHolds (
Account const& account, Currency const& currency,
Account const& issuer);
@@ -249,12 +239,12 @@ public:
const bool bSrcHigh,
Account const& uSrcAccountID,
Account const& uDstAccountID,
- uint256 const & uIndex,
+ uint256 const& uIndex,
SLE::ref sleAccount,
const bool bAuth,
const bool bNoRipple,
- const STAmount & saSrcBalance,
- const STAmount & saSrcLimit,
+ const STAmount& saSrcBalance,
+ const STAmount& saSrcLimit,
const std::uint32_t uSrcQualityIn = 0,
const std::uint32_t uSrcQualityOut = 0);
TER trustDelete (
@@ -266,26 +256,25 @@ public:
// iterator functions
typedef std::map::iterator iterator;
- typedef std::map::const_iterator
- const_iterator;
+ typedef std::map::const_iterator const_iterator;
bool isEmpty () const
{
return mEntries.empty ();
}
- std::map::const_iterator begin () const
+ const_iterator begin () const
{
return mEntries.begin ();
}
- std::map::const_iterator end () const
+ const_iterator end () const
{
return mEntries.end ();
}
- std::map::iterator begin ()
+ iterator begin ()
{
return mEntries.begin ();
}
- std::map::iterator end ()
+ iterator end ()
{
return mEntries.end ();
}
@@ -326,16 +315,15 @@ private:
bool threadOwners (
SLE::ref node, Ledger::ref ledger, NodeToLedgerEntry& newMods);
-};
-inline LedgerEntrySet::iterator range_begin (LedgerEntrySet& x)
-{
- return x.begin ();
-}
-inline LedgerEntrySet::iterator range_end (LedgerEntrySet& x)
-{
- return x.end ();
-}
+ TER rippleSend (
+ Account const& uSenderID, Account const& uReceiverID,
+ const STAmount & saAmount, STAmount & saActual);
+
+ STAmount rippleHolds (
+ Account const& account, Currency const& currency,
+ Account const& issuer);
+};
} // ripple
diff --git a/src/ripple/module/app/transactors/CreateOffer.cpp b/src/ripple/module/app/transactors/CreateOffer.cpp
index 80bd2d2fd3..05d64ab65d 100644
--- a/src/ripple/module/app/transactors/CreateOffer.cpp
+++ b/src/ripple/module/app/transactors/CreateOffer.cpp
@@ -20,10 +20,6 @@
#include
#include
-#if RIPPLE_USE_OLD_CREATE_TRANSACTOR
-#include
-#endif
-
#include
#include
#include
@@ -156,9 +152,6 @@ CreateOffer::doApply ()
std::uint64_t const uRate = STAmount::getRate (saTakerGets, saTakerPays);
TER terResult (tesSUCCESS);
- uint256 uDirectory;
- std::uint64_t uOwnerNode;
- std::uint64_t uBookNode;
// This is the ledger view that we work against. Transactions are applied
// as we go on processing transactions.
@@ -199,14 +192,14 @@ CreateOffer::doApply ()
m_journal.warning <<
"Malformed offer: XRP for XRP";
- terResult = temBAD_OFFER;
+ terResult = temBAD_OFFER;
}
else if (saTakerPays <= zero || saTakerGets <= zero)
{
m_journal.warning <<
"Malformed offer: bad amount";
- terResult = temBAD_OFFER;
+ terResult = temBAD_OFFER;
}
else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID)
{
@@ -360,6 +353,21 @@ CreateOffer::doApply ()
view.accountFunds (mTxnAccountID, saTakerGets).getFullText ();
}
+ if (saTakerPays < zero || saTakerGets < zero)
+ {
+ // Earlier, we verified that the amounts, as specified in the offer,
+ // were not negative. That they are now suggests that something went
+ // very wrong with offer crossing.
+ m_journal.fatal << (crossed ? "Partially consumed" : "Full") <<
+ " offer has negative component:" <<
+ " pays=" << saTakerPays.getFullText () <<
+ " gets=" << saTakerGets.getFullText ();
+
+ assert (saTakerPays >= zero);
+ assert (saTakerGets >= zero);
+ return tefINTERNAL;
+ }
+
if (bFillOrKill && (saTakerPays != zero || saTakerGets != zero))
{
// Fill or kill and have leftovers.
@@ -371,8 +379,8 @@ CreateOffer::doApply ()
auto const accountReserve (mEngine->getLedger ()->getReserve (
sleCreator->getFieldU32 (sfOwnerCount) + 1));
- if (saTakerPays <= zero || // Wants nothing more.
- saTakerGets <= zero || // Offering nothing more.
+ if (saTakerPays == zero || // Wants nothing more.
+ saTakerGets == zero || // Offering nothing more.
bImmediateOrCancel) // Do not persist.
{
// Complete as is.
@@ -408,26 +416,34 @@ CreateOffer::doApply ()
}
else
{
+ assert (saTakerPays > zero);
+ assert (saTakerGets > zero);
+
// We need to place the remainder of the offer into its order book.
if (m_journal.debug) m_journal.debug <<
"offer not fully consumed:" <<
" saTakerPays=" << saTakerPays.getFullText () <<
" saTakerGets=" << saTakerGets.getFullText ();
+ std::uint64_t uOwnerNode;
+ std::uint64_t uBookNode;
+ uint256 uDirectory;
+
// Add offer to owner's directory.
- terResult = view.dirAdd (uOwnerNode,
+ terResult = view.dirAdd (uOwnerNode,
Ledger::getOwnerDirIndex (mTxnAccountID), uLedgerIndex,
- std::bind (&Ledger::ownerDirDescriber, std::placeholders::_1,
- std::placeholders::_2, mTxnAccountID));
+ std::bind (
+ &Ledger::ownerDirDescriber, std::placeholders::_1,
+ std::placeholders::_2, mTxnAccountID));
if (tesSUCCESS == terResult)
{
// Update owner count.
view.ownerCountAdjust (mTxnAccountID, 1, sleCreator);
- uint256 uBookBase = Ledger::getBookBase (
+ uint256 const uBookBase (Ledger::getBookBase (
uPaysCurrency, uPaysIssuerID,
- uGetsCurrency, uGetsIssuerID);
+ uGetsCurrency, uGetsIssuerID));
if (m_journal.debug) m_journal.debug <<
"adding to book: " << to_string (uBookBase) <<
@@ -441,10 +457,11 @@ CreateOffer::doApply ()
// Add offer to order book.
terResult = view.dirAdd (uBookNode, uDirectory, uLedgerIndex,
- std::bind (&Ledger::qualityDirDescriber, std::placeholders::_1,
- std::placeholders::_2, saTakerPays.getCurrency (),
- uPaysIssuerID, saTakerGets.getCurrency (),
- uGetsIssuerID, uRate));
+ std::bind (
+ &Ledger::qualityDirDescriber, std::placeholders::_1,
+ std::placeholders::_2, saTakerPays.getCurrency (),
+ uPaysIssuerID, saTakerGets.getCurrency (),
+ uGetsIssuerID, uRate));
}
if (tesSUCCESS == terResult)
@@ -513,18 +530,16 @@ std::unique_ptr make_CreateOffer (
TransactionEngineParams params,
TransactionEngine* engine)
{
-#if RIPPLE_USE_OLD_CREATE_TRANSACTOR
- return std::make_unique (txn, params, engine);
-#else
+#if RIPPLE_ENABLE_AUTOBRIDGING
STAmount const& amount_in = txn.getFieldAmount (sfTakerPays);
STAmount const& amount_out = txn.getFieldAmount (sfTakerGets);
// Autobridging is only in effect when an offer does not involve XRP
if (!amount_in.isNative() && !amount_out.isNative ())
return std::make_unique (txn, params, engine);
+#endif
return std::make_unique (txn, params, engine);
-#endif
}
}
diff --git a/src/ripple/module/app/transactors/CreateOfferBridged.cpp b/src/ripple/module/app/transactors/CreateOfferBridged.cpp
index 0b227a3249..dc1a5be099 100644
--- a/src/ripple/module/app/transactors/CreateOfferBridged.cpp
+++ b/src/ripple/module/app/transactors/CreateOfferBridged.cpp
@@ -69,10 +69,11 @@ CreateOfferBridged::crossOffers (
TER cross_result (tesSUCCESS);
- bool have_bridged (
- offers_leg1.step_account (taker.account()) &&
- offers_leg2.step_account (taker.account()));
- bool have_direct (offers_direct.step_account (taker.account()));
+ /* Note the subtle distinction here: self-offers encountered in the bridge
+ * are taken, but self-offers encountered in the direct book are not.
+ */
+ bool have_bridged (offers_leg1.step () && offers_leg2.step ());
+ bool have_direct (offers_direct.step_account (taker.account ()));
bool place_order (true);
while (have_direct || have_bridged)
@@ -129,7 +130,7 @@ CreateOfferBridged::crossOffers (
if (use_direct)
{
- if (m_journal.debug) m_journal.debug <<
+ if (m_journal.debug) m_journal.debug << "Direct:" << std::endl <<
" Offer: " << offers_direct.tip () << std::endl <<
" " << offers_direct.tip ().amount().in <<
" : " << offers_direct.tip ().amount ().out;
@@ -144,7 +145,7 @@ CreateOfferBridged::crossOffers (
}
else
{
- if (m_journal.debug) m_journal.debug <<
+ if (m_journal.debug) m_journal.debug << "Bridge:" << std::endl <<
" Offer1: " << offers_leg1.tip () << std::endl <<
" " << offers_leg1.tip ().amount().in <<
" : " << offers_leg1.tip ().amount ().out << std::endl <<
@@ -157,12 +158,12 @@ CreateOfferBridged::crossOffers (
if (offers_leg1.tip ().fully_consumed ())
{
leg1_consumed = true;
- have_bridged = offers_leg1.step_account (taker.account ());
+ have_bridged = offers_leg1.step ();
}
if (have_bridged && offers_leg2.tip ().fully_consumed ())
{
leg2_consumed = true;
- have_bridged = offers_leg2.step_account (taker.account ());
+ have_bridged = offers_leg2.step ();
}
}
@@ -179,9 +180,15 @@ CreateOfferBridged::crossOffers (
break;
}
- // Postcondition: If we aren't done, then we must have consumed at
+ // Postcondition: If we aren't done, then we *must* have consumed at
// least one offer fully.
assert (direct_consumed || leg1_consumed || leg2_consumed);
+
+ if (!direct_consumed && !leg1_consumed && !leg2_consumed)
+ {
+ cross_result = tefINTERNAL;
+ break;
+ }
}
return std::make_pair(cross_result, taker.remaining_offer ());
diff --git a/src/ripple/module/app/transactors/CreateOfferDirect.cpp b/src/ripple/module/app/transactors/CreateOfferDirect.cpp
index b22192cf4c..069486f1d7 100644
--- a/src/ripple/module/app/transactors/CreateOfferDirect.cpp
+++ b/src/ripple/module/app/transactors/CreateOfferDirect.cpp
@@ -73,9 +73,6 @@ CreateOfferDirect::crossOffers (
break;
}
- // NIKB CHECKME Investigate whether we can use offer.step_account() here
- // or whether doing so would cause a protocol-breaking
- // change.
if (! offers.step ())
{
// Place the order since there are no
diff --git a/src/ripple/module/app/transactors/CreateOfferLegacy.cpp b/src/ripple/module/app/transactors/CreateOfferLegacy.cpp
deleted file mode 100644
index 9bd72689a3..0000000000
--- a/src/ripple/module/app/transactors/CreateOfferLegacy.cpp
+++ /dev/null
@@ -1,1186 +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.
-*/
-//==============================================================================
-
-namespace ripple {
-
-/** Determine if an order is still valid
- If the order is not valid it will be marked as unfunded.
-*/
-bool CreateOfferLegacy::isValidOffer (
- SLE::ref sleOffer,
- Account const& uOfferOwnerID,
- STAmount const& saOfferPays,
- STAmount const& saOfferGets,
- Account const& uTakerAccountID,
- HardenedOfferSet& usOfferUnfundedBecame,
- HardenedAccountSet& usAccountTouched,
- STAmount& saOfferFunds)
-{
- if (sleOffer->isFieldPresent (sfExpiration) &&
- sleOffer->getFieldU32 (sfExpiration) <= mEngine->getLedger ()->getParentCloseTimeNC ())
- {
- // Offer is expired. Expired offers are considered unfunded. Delete it.
- m_journal.debug << "isValidOffer: encountered expired offer";
-
- usOfferUnfundedFound.insert (sleOffer->getIndex());
-
- return false;
- }
-
- if (uOfferOwnerID == uTakerAccountID)
- {
- // Would take own offer. Consider old offer expired. Delete it.
- m_journal.debug << "isValidOffer: encountered taker's own old offer";
-
- usOfferUnfundedFound.insert (sleOffer->getIndex());
-
- return false;
- }
-
- if (saOfferGets <= zero || saOfferPays <= zero)
- {
- // Offer has bad amounts. Consider offer expired. Delete it.
- m_journal.warning << "isValidOffer: BAD OFFER:" <<
- " saOfferPays=" << saOfferPays <<
- " saOfferGets=" << saOfferGets;
-
- usOfferUnfundedFound.insert (sleOffer->getIndex());
-
- return false;
- }
-
- m_journal.debug <<
- "isValidOffer: saOfferPays=" << saOfferPays.getFullText ();
-
- saOfferFunds = mEngine->view ().accountFunds (uOfferOwnerID, saOfferPays);
-
- if (saOfferFunds <= zero)
- {
- // Offer is unfunded, possibly due to previous balance action.
- m_journal.debug << "isValidOffer: offer unfunded: delete";
-
- auto account = usAccountTouched.find (uOfferOwnerID);
-
- if (account != usAccountTouched.end ())
- {
- // Previously touched account. Delete unfunded offer on success
- usOfferUnfundedBecame.insert (sleOffer->getIndex());
- }
- else
- {
- // Never touched source account. Delete found unfunded offer
- // when possible.
- usOfferUnfundedFound.insert (sleOffer->getIndex());
- }
-
- return false;
- }
-
- return true;
-}
-
-/**
-*/
-bool CreateOfferLegacy::canCross (
- STAmount const& saTakerFunds,
- STAmount const& saSubTakerPays,
- STAmount const& saSubTakerGets,
- std::uint64_t uTipQuality,
- std::uint64_t uTakeQuality,
- bool isPassive,
- bool& isUnfunded,
- TER& terResult) const
-{
- if (saTakerFunds <= zero)
- {
- // Taker is out of funds. Don't create the offer.
- isUnfunded = true;
- terResult = tesSUCCESS;
- return false;
- }
-
- if (saSubTakerPays <= zero || saSubTakerGets <= zero)
- {
- // Offer is completely consumed
- terResult = tesSUCCESS;
- return false;
- }
-
- // TODO We must also consider the synthesized tip as well
- if ((uTakeQuality < uTipQuality) || (isPassive && (uTakeQuality == uTipQuality)))
- {
- // Offer does not cross this offer
- terResult = tesSUCCESS;
- return false;
- }
-
- return true;
-}
-
-/** Apply a particular offer
-
- An existing offer is on the books. The price is the offer owner's, which
- might be better for taker. The taker pays what they can and gets all taker
- can pay for with `saTakerFunds`/`uTakerPaysRate`, limited by `saOfferPays`
- and `saOfferFunds`/`uOfferPaysRate`.
- If taker is an offer, taker is spending at same or better rate than they
- wanted.
- The taker should consider themselves as wanting to buy X amount and as
- willing to pay at most the rate of Y/X each.
- After having some part of their offer fulfilled at a better rate their offer
- should be reduced accordingly.
- There are no quality costs for offer vs offer taking.
-
- @param bSell `true` if using sell semantics.
- @param uTakerPaysRate >= QUALITY_ONE | TransferRate for third party IOUs paid by taker.
- @param uOfferPaysRate >= QUALITY_ONE | TransferRate for third party IOUs paid by offer owner.
- @param saOfferRate Original saOfferGets/saOfferPays, when offer was made.
- @param saOfferFunds Limit for saOfferPays : How much can pay including fees.
- @param saTakerFunds Limit for saOfferGets : How much can pay including fees.
- @param saOfferPays Request : this should be reduced as the offer is fullfilled.
- @param saOfferGets Request : this should be reduced as the offer is fullfilled.
- @param saTakerPays Limit for taker to pay.
- @param saTakerGets Limit for taker to get.
- @param saTakerPaid Actual amount the taker paid
- @param saTakerGot Actual amount the taker got
- @param saTakerIssuerFee Actual
- @param saOfferIssuerFee Actual
-
- @note Buy vs. Sell semantics:
-
- In Ripple, placed offers are always executed at the rate at which they were
- placed. However, the offer we are processing hasn't been placed yet and it
- can cross with offers that have. Such crossing offers can be consumed by
- existing offers that give a better rate.
-
- The only difference between buy and sell offers is the way in which we
- calculate what remains to be placed on the books after crossing offers
- are consumed.
-
- First, consider the case where a user is trying to place an offer to buy
- 1 BTC for 700 USD:
- If an offer to giving 0.5 BTC for 300 USD is on the books, the offers cross
- and under buy semantics the user buys 0.5 BTC for 300 USD (less than the
- 350 USD he was willing to pay) and the offer is adjusted and placed on the
- books as: "give 0.5 BTC for 350 USD" which is the amount left to buy at the
- original rate.
-
- Now consider the case where a user is trying to place an offer to sell
- 700 USD for 1 BTC instead:
- If an offer to giving 0.5 BTC for 300 USD is on the books, the offers cross
- and under sell semantics the user will sell 350 USD for 0.5 BTC (more than
- he was willing to get) and his offer will be be adjusted and placed on the
- books as: "give 0.57 BTC for 400 USD" which is what is left to sell at the
- original rate.
-*/
-bool CreateOfferLegacy::applyOffer (
- const bool bSell,
- const std::uint32_t uTakerPaysRate, const std::uint32_t uOfferPaysRate,
- const STAmount& saOfferRate,
- const STAmount& saOfferFunds, const STAmount& saTakerFunds,
- const STAmount& saOfferPays, const STAmount& saOfferGets,
- const STAmount& saTakerPays, const STAmount& saTakerGets,
- STAmount& saTakerPaid, STAmount& saTakerGot,
- STAmount& saTakerIssuerFee, STAmount& saOfferIssuerFee)
-{
- saOfferGets.throwComparable (saTakerFunds);
-
- assert (saOfferFunds > zero && saTakerFunds > zero); // Both must have funds.
- assert (saOfferGets > zero && saOfferPays > zero); // Must not be a null offer.
-
- // Available = limited by funds.
- // Limit offerer funds available, by transfer fees.
- STAmount saOfferFundsAvailable = QUALITY_ONE == uOfferPaysRate
- ? saOfferFunds // As is.
- : STAmount::divide (saOfferFunds, STAmount (noCurrency(), noAccount(), uOfferPaysRate, -9)); // Reduce by offer fees.
-
- m_journal.info << "applyOffer: uOfferPaysRate=" << uOfferPaysRate;
- m_journal.info << "applyOffer: saOfferFundsAvailable=" << saOfferFundsAvailable.getFullText ();
-
- // Limit taker funds available, by transfer fees.
- STAmount saTakerFundsAvailable = QUALITY_ONE == uTakerPaysRate
- ? saTakerFunds // As is.
- : STAmount::divide (saTakerFunds, STAmount (noCurrency(), noAccount(), uTakerPaysRate, -9)); // Reduce by taker fees.
-
- m_journal.info << "applyOffer: TAKER_FEES=" << STAmount (noCurrency(), noAccount(), uTakerPaysRate, -9).getFullText ();
- m_journal.info << "applyOffer: uTakerPaysRate=" << uTakerPaysRate;
- m_journal.info << "applyOffer: saTakerFundsAvailable=" << saTakerFundsAvailable.getFullText ();
-
- STAmount saOfferPaysAvailable; // Amount offer can pay out, limited by offer and offerer funds.
- STAmount saOfferGetsAvailable; // Amount offer would get, limited by offer funds.
-
- if (saOfferFundsAvailable >= saOfferPays)
- {
- // Offer was fully funded, avoid math shenanigans.
-
- saOfferPaysAvailable = saOfferPays;
- saOfferGetsAvailable = saOfferGets;
- }
- else
- {
- // Offer has limited funding, limit offer gets and pays by funds available.
-
- saOfferPaysAvailable = saOfferFundsAvailable;
- saOfferGetsAvailable = std::min (saOfferGets, STAmount::mulRound (saOfferPaysAvailable, saOfferRate, saOfferGets, true));
- }
-
- m_journal.info << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText ();
- m_journal.info << "applyOffer: saOfferGetsAvailable=" << saOfferGetsAvailable.getFullText ();
-
- STAmount saTakerPaysAvailable = std::min (saTakerPays, saTakerFundsAvailable);
- m_journal.info << "applyOffer: saTakerPaysAvailable=" << saTakerPaysAvailable.getFullText ();
-
- // Limited = limited by other sides raw numbers.
- // Taker can't pay more to offer than offer can get.
- STAmount saTakerPaysLimited = std::min (saTakerPaysAvailable, saOfferGetsAvailable);
- m_journal.info << "applyOffer: saTakerPaysLimited=" << saTakerPaysLimited.getFullText ();
-
- // Align saTakerGetsLimited with saTakerPaysLimited.
- STAmount saTakerGetsLimited = saTakerPaysLimited >= saOfferGetsAvailable // Cannot actually be greater
- ? saOfferPaysAvailable // Potentially take entire offer. Avoid math shenanigans.
- : std::min (saOfferPaysAvailable, STAmount::divRound (saTakerPaysLimited, saOfferRate, saTakerGets, true)); // Take a portion of offer.
-
- m_journal.info << "applyOffer: saOfferRate=" << saOfferRate.getFullText ();
- m_journal.info << "applyOffer: saTakerGetsLimited=" << saTakerGetsLimited.getFullText ();
-
- // Got & Paid = Calculated by price and transfered without fees.
- // Compute from got as when !bSell, we want got to be exact to finish off offer if possible.
-
- saTakerGot = bSell
- ? saTakerGetsLimited // Get all available that are paid for.
- : std::min (saTakerGets, saTakerGetsLimited); // Limit by wanted.
- saTakerPaid = saTakerGot >= saTakerGetsLimited
- ? saTakerPaysLimited
- : std::min (saTakerPaysLimited, STAmount::mulRound (saTakerGot, saOfferRate, saTakerFunds, true));
-
- m_journal.info << "applyOffer: saTakerGot=" << saTakerGot.getFullText ();
- m_journal.info << "applyOffer: saTakerPaid=" << saTakerPaid.getFullText ();
-
- if (uTakerPaysRate == QUALITY_ONE)
- {
- saTakerIssuerFee = STAmount (saTakerPaid.getCurrency (), saTakerPaid.getIssuer ());
- }
- else
- {
- // Compute fees in a rounding safe way.
-
- STAmount transferRate (noCurrency(), noAccount(), uTakerPaysRate, -9);
- m_journal.info << "applyOffer: transferRate="
- << transferRate.getFullText ();
-
- // TakerCost includes transfer fees.
- STAmount saTakerCost = STAmount::mulRound (
- saTakerPaid, transferRate, true);
-
- m_journal.info << "applyOffer: saTakerCost="
- << saTakerCost.getFullText ();
- m_journal.info << "applyOffer: saTakerFunds="
- << saTakerFunds.getFullText ();
- saTakerIssuerFee = saTakerCost > saTakerFunds
- ? saTakerFunds - saTakerPaid
- // Not enough funds to cover fee, stiff issuer the rounding error.
- : saTakerCost - saTakerPaid;
- m_journal.info << "applyOffer: saTakerIssuerFee="
- << saTakerIssuerFee.getFullText ();
- assert (saTakerIssuerFee >= zero);
- }
-
- if (uOfferPaysRate == QUALITY_ONE)
- {
- saOfferIssuerFee = STAmount (
- saTakerGot.getCurrency (), saTakerGot.getIssuer ());
- }
- else
- {
- // Compute fees in a rounding safe way.
- STAmount saOfferCost = STAmount::mulRound (
- saTakerGot, STAmount (noCurrency(), noAccount(), uOfferPaysRate, -9),
- true);
-
- saOfferIssuerFee = saOfferCost > saOfferFunds
- ? saOfferFunds - saTakerGot
- // Not enough funds to cover fee, stiff issuer the rounding error.
- : saOfferCost - saTakerGot;
- }
-
- m_journal.info << "applyOffer: saTakerGot=" << saTakerGot.getFullText ();
-
- return saTakerGot >= saOfferPaysAvailable;
- // True, if consumed offer.
-}
-
-/** Take as much as possible.
- We adjusts account balances and charges fees on top to taker.
-
- @param uBookBase The order book to take against.
- @param saTakerPays What the taker offers (w/ issuer)
- @param saTakerGets What the taker wanted (w/ issuer)
- @param saTakerPaid What taker could have paid including saved not including
- fees. To reduce an offer.
- @param saTakerGot What taker got not including fees. To reduce an offer.
- @param bUnfunded if tesSUCCESS, consider offer unfunded after taking.
- @return tesSUCCESS, terNO_ACCOUNT, telFAILED_PROCESSING, or
- tecFAILED_PROCESSING
-*/
-TER CreateOfferLegacy::takeOffers (
- const bool bOpenLedger,
- const bool bPassive,
- const bool bSell,
- uint256 const& uBookBase,
- Account const& uTakerAccountID,
- SLE::ref sleTakerAccount,
- const STAmount& saTakerPays,
- const STAmount& saTakerGets,
- STAmount& saTakerPaid,
- STAmount& saTakerGot,
- bool& bUnfunded)
-{
- // The book has the most elements. Take the perspective of the book.
- // Book is ordered for taker: taker pays / taker gets (smaller is better)
- // The order is for the other book's currencies for get and pays are
- // opposites.
- // We want the same ratio for the respective currencies so we swap paid and
- // gets for determing take quality.
-
- assert (saTakerPays && saTakerGets);
-
- m_journal.debug <<
- "takeOffers: bSell: " << bSell <<
- ": against book: " << to_string (uBookBase);
-
- LedgerEntrySet& lesActive = mEngine->view ();
- std::uint64_t const uTakeQuality = STAmount::getRate (saTakerGets, saTakerPays);
- STAmount saTakerRate = STAmount::setRate (uTakeQuality);
- auto const uTakerPaysAccountID = saTakerPays.getIssuer ();
- auto const uTakerGetsAccountID = saTakerGets.getIssuer ();
- TER terResult = temUNCERTAIN;
-
- // Offers that became unfunded.
- HardenedOfferSet usOfferUnfundedBecame;
-
- // Accounts touched.
- HardenedAccountSet usAccountTouched;
-
- saTakerPaid = STAmount (
- saTakerPays.getCurrency (), saTakerPays.getIssuer ());
- saTakerGot = STAmount (
- saTakerGets.getCurrency (), saTakerGets.getIssuer ());
- bUnfunded = false;
-
- // TODO: need to track the synthesized book (source->XRP + XRP->target)
- // here as well.
- OrderBookIterator directBookIter (lesActive,
- saTakerPays.getCurrency(), saTakerPays.getIssuer(),
- saTakerGets.getCurrency(), saTakerGets.getIssuer());
-
- while ((temUNCERTAIN == terResult) && directBookIter.nextOffer())
- {
- STAmount saTakerFunds = lesActive.accountFunds (uTakerAccountID, saTakerPays);
- STAmount saSubTakerPays = saTakerPays - saTakerPaid; // How much more to spend.
- STAmount saSubTakerGets = saTakerGets - saTakerGot; // How much more is wanted.
- std::uint64_t uTipQuality = directBookIter.getCurrentQuality();
-
- if (!canCross(
- saTakerFunds,
- saSubTakerPays,
- saSubTakerGets,
- uTipQuality,
- uTakeQuality,
- bPassive,
- bUnfunded,
- terResult))
- break;
-
- // We have a crossing offer to consider.
-
- // TODO Must consider the synthesized orderbook instead of just the
- // direct one (i.e. look at A->XRP->B)
- SLE::pointer sleOffer = directBookIter.getCurrentOffer ();
-
- if (!sleOffer)
- { // offer is in directory but not in ledger
- // CHECKME is this cleaning up corruption?
- uint256 offerIndex = directBookIter.getCurrentIndex ();
- m_journal.warning <<
- "takeOffers: offer not found : " << offerIndex;
- usMissingOffers.insert (missingOffer_t (
- directBookIter.getCurrentIndex (),
- directBookIter.getCurrentDirectory ()));
-
- continue;
- }
-
- m_journal.debug <<
- "takeOffers: considering offer : " <<
- sleOffer->getJson (0);
-
- auto const& uOfferOwnerID = sleOffer->getFieldAccount160 (sfAccount);
- STAmount saOfferPays = sleOffer->getFieldAmount (sfTakerGets);
- STAmount saOfferGets = sleOffer->getFieldAmount (sfTakerPays);
-
- STAmount saOfferFunds; // Funds of offer owner to payout.
-
- bool const bValid = isValidOffer (
- sleOffer,
- uOfferOwnerID,
- saOfferPays,
- saOfferGets,
- uTakerAccountID,
- usOfferUnfundedBecame,
- usAccountTouched,
- saOfferFunds);
-
- if (bValid)
- {
- STAmount saSubTakerPaid;
- STAmount saSubTakerGot;
- STAmount saTakerIssuerFee;
- STAmount saOfferIssuerFee;
- STAmount saOfferRate = STAmount::setRate (uTipQuality);
-
- if (m_journal.debug)
- {
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerPays: " <<
- saTakerPays.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerPaid: " <<
- saTakerPaid.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerFunds: " <<
- saTakerFunds.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saOfferFunds: " <<
- saOfferFunds.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saOfferPays: " <<
- saOfferPays.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saOfferGets: " <<
- saOfferGets.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saOfferRate: " <<
- saOfferRate.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saSubTakerPays: " <<
- saSubTakerPays.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saSubTakerGets: " <<
- saSubTakerGets.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerPays: " <<
- saTakerPays.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerGets: " <<
- saTakerGets.getFullText ();
- }
-
- bool const bOfferDelete = applyOffer (
- bSell,
- lesActive.rippleTransferRate (
- uTakerAccountID,
- uOfferOwnerID,
- uTakerPaysAccountID),
- lesActive.rippleTransferRate (
- uOfferOwnerID,
- uTakerAccountID,
- uTakerGetsAccountID),
- saOfferRate,
- saOfferFunds,
- saTakerFunds,
- saOfferPays,
- saOfferGets,
- saSubTakerPays,
- saSubTakerGets,
- saSubTakerPaid,
- saSubTakerGot,
- saTakerIssuerFee,
- saOfferIssuerFee);
-
- if (m_journal.debug)
- {
- m_journal.debug <<
- "takeOffers: applyOffer: saSubTakerPaid: " <<
- saSubTakerPaid.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saSubTakerGot: " <<
- saSubTakerGot.getFullText ();
- }
-
- // Adjust offer
- // TODO We need to consider the combined (synthesized)
- // order book.
-
- // Offer owner will pay less. Subtract what taker just got.
- saOfferPays -= saSubTakerGot;
- sleOffer->setFieldAmount (sfTakerGets, saOfferPays);
-
- // Offer owner will get less. Subtract what owner just paid.
- saOfferGets -= saSubTakerPaid;
- sleOffer->setFieldAmount (sfTakerPays, saOfferGets);
-
- mEngine->entryModify (sleOffer);
-
- if (bOfferDelete)
- {
- // TODO need to handle the synthetic case here
-
- // Offer now fully claimed or now unfunded.
- m_journal.debug <<
- "takeOffers: Offer claimed: Delete.";
-
- // Delete unfunded offer on success.
- usOfferUnfundedBecame.insert (sleOffer->getIndex());
-
- // Offer owner's account is no longer pristine.
- usAccountTouched.insert (uOfferOwnerID);
- }
- else if (saSubTakerGot)
- {
- m_journal.debug <<
- "takeOffers: Offer partial claim.";
-
- // TODO check the synthetic case here (to ensure there
- // is no corruption)
-
- if (saOfferPays <= zero || saOfferGets <= zero)
- {
- m_journal.warning <<
- "takeOffers: ILLEGAL OFFER RESULT.";
- bUnfunded = true;
- terResult = bOpenLedger
- ? telFAILED_PROCESSING
- : tecFAILED_PROCESSING;
- }
- }
- else
- {
- // Taker got nothing, probably due to rounding. Consider
- // taker unfunded.
- m_journal.debug << "takeOffers: No claim.";
-
- bUnfunded = true;
- terResult = tesSUCCESS; // Done.
- }
-
- assert (uTakerGetsAccountID == saSubTakerGot.getIssuer ());
- assert (uTakerPaysAccountID == saSubTakerPaid.getIssuer ());
-
- if (!bUnfunded)
- {
- // Distribute funds. The sends charge appropriate fees
- // which are implied by offer.
-
- // TODO Adjust for synthetic transfers - pay into A->XRP
- // and pay out of XRP->B
-
- // Offer owner pays taker.
- terResult = lesActive.accountSend (
- uOfferOwnerID, uTakerAccountID, saSubTakerGot);
-
- if (tesSUCCESS == terResult)
- {
- // TODO: in the synthesized case, pay from B to the original taker
- // Taker -> A -> XRP -> B -> ... -> Taker
-
- // Taker pays offer owner.
- terResult = lesActive.accountSend (
- uTakerAccountID, uOfferOwnerID, saSubTakerPaid);
- }
-
- if (bSell)
- {
- // Sell semantics:
- // Reduce amount considered received to original
- // offer's rate. Not by the crossing rate, which is
- // higher.
- STAmount saEffectiveGot = STAmount::divide(
- saSubTakerPaid, saTakerRate, saTakerGets);
- saSubTakerGot = std::min(saEffectiveGot, saSubTakerGot);
- }
- else
- {
- // Buy semantics: Reduce amount considered paid by
- // taker's rate. Not by actual cost which is lower.
- // That is, take less as to just satify our buy
- // requirement.
-
- // Taker could pay.
- STAmount saTakerCould = saTakerPays - saTakerPaid;
-
- if (saTakerFunds < saTakerCould)
- saTakerCould = saTakerFunds;
-
- STAmount saTakerUsed = STAmount::multiply (
- saSubTakerGot, saTakerRate, saTakerPays);
-
- if (m_journal.debug)
- {
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerCould: " <<
- saTakerCould.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saSubTakerGot: " <<
- saSubTakerGot.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerRate: " <<
- saTakerRate.getFullText ();
- m_journal.debug <<
- "takeOffers: applyOffer: saTakerUsed: " <<
- saTakerUsed.getFullText ();
- }
-
- saSubTakerPaid = std::min (saTakerCould, saTakerUsed);
- }
-
- saTakerPaid += saSubTakerPaid;
- saTakerGot += saSubTakerGot;
-
- if (tesSUCCESS == terResult)
- terResult = temUNCERTAIN;
- }
- }
- }
-
- if (temUNCERTAIN == terResult)
- terResult = tesSUCCESS;
-
- m_journal.debug <<
- "takeOffers: " << transToken (terResult);
-
- if (tesSUCCESS == terResult)
- {
- // On success, delete offers that became unfunded.
- for (auto offerIndex : usOfferUnfundedBecame)
- {
- m_journal.debug <<
-
- "takeOffers: became unfunded: " <<
- to_string (offerIndex);
-
- lesActive.offerDelete (offerIndex);
- }
- }
-
- m_journal.debug <<
- "takeOffers< " << transToken (terResult);
-
- return terResult;
-}
-
-TER CreateOfferLegacy::doApply ()
-{
- if (m_journal.debug) m_journal.debug <<
- "OfferCreate> " << mTxn.getJson (0);
-
- std::uint32_t const uTxFlags = mTxn.getFlags ();
- bool const bPassive (uTxFlags & tfPassive);
- bool const bImmediateOrCancel (uTxFlags & tfImmediateOrCancel);
- bool const bFillOrKill (uTxFlags & tfFillOrKill);
- bool const bSell (uTxFlags & tfSell);
- STAmount saTakerPays = mTxn.getFieldAmount (sfTakerPays);
- STAmount saTakerGets = mTxn.getFieldAmount (sfTakerGets);
-
- if (!saTakerPays.isLegalNet () || !saTakerGets.isLegalNet ())
- return temBAD_AMOUNT;
-
- m_journal.debug <<
- "saTakerPays=" << saTakerPays.getFullText () <<
- " saTakerGets=" << saTakerGets.getFullText ();
-
- auto const uPaysIssuerID = saTakerPays.getIssuer ();
- auto const uGetsIssuerID = saTakerGets.getIssuer ();
-
- bool const bHaveExpiration (mTxn.isFieldPresent (sfExpiration));
- bool const bHaveCancel (mTxn.isFieldPresent (sfOfferSequence));
-
- std::uint32_t const uExpiration = mTxn.getFieldU32 (sfExpiration);
- std::uint32_t const uCancelSequence = mTxn.getFieldU32 (sfOfferSequence);
-
- // FIXME understand why we use SequenceNext instead of current transaction
- // sequence to determine the transaction. Why is the offer seuqnce
- // number insufficient?
-
- std::uint32_t const uAccountSequenceNext = mTxnAccount->getFieldU32 (sfSequence);
- std::uint32_t const uSequence = mTxn.getSequence ();
-
- const uint256 uLedgerIndex = Ledger::getOfferIndex (mTxnAccountID, uSequence);
-
- m_journal.debug <<
- "Creating offer node: " << to_string (uLedgerIndex) <<
- " uSequence=" << uSequence;
-
- auto const uPaysCurrency = saTakerPays.getCurrency ();
- auto const uGetsCurrency = saTakerGets.getCurrency ();
- const std::uint64_t uRate = STAmount::getRate (saTakerGets, saTakerPays);
-
- TER terResult = tesSUCCESS;
- uint256 uDirectory; // Delete hints.
- std::uint64_t uOwnerNode;
- std::uint64_t uBookNode;
-
- LedgerEntrySet& lesActive = mEngine->view ();
- LedgerEntrySet lesCheckpoint = lesActive; // Checkpoint with just fees paid.
- lesActive.bumpSeq (); // Begin ledger variance.
-
- SLE::pointer sleCreator = mEngine->entryCache (
- ltACCOUNT_ROOT, Ledger::getAccountRootIndex (mTxnAccountID));
-
- if (uTxFlags & tfOfferCreateMask)
- {
- m_journal.debug <<
- "Malformed transaction: Invalid flags set.";
-
- return temINVALID_FLAG;
- }
- else if (bImmediateOrCancel && bFillOrKill)
- {
- m_journal.debug <<
- "Malformed transaction: both IoC and FoK set.";
-
- return temINVALID_FLAG;
- }
- else if (bHaveExpiration && !uExpiration)
- {
- m_journal.warning <<
- "Malformed offer: bad expiration";
-
- terResult = temBAD_EXPIRATION;
- }
- else if (saTakerPays.isNative () && saTakerGets.isNative ())
- {
- m_journal.warning <<
- "Malformed offer: XRP for XRP";
-
- terResult = temBAD_OFFER;
- }
- else if (saTakerPays <= zero || saTakerGets <= zero)
- {
- m_journal.warning <<
- "Malformed offer: bad amount";
-
- terResult = temBAD_OFFER;
- }
- else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID)
- {
- m_journal.warning <<
- "Malformed offer: redundant offer";
-
- terResult = temREDUNDANT;
- }
- // FIXME: XRP is not a bad currency, not not allowed as IOU
- else if (badCurrency() == uPaysCurrency || badCurrency() == uGetsCurrency)
- {
- m_journal.warning <<
- "Malformed offer: Bad currency.";
-
- terResult = temBAD_CURRENCY;
- }
- else if (saTakerPays.isNative () != !uPaysIssuerID || saTakerGets.isNative () != !uGetsIssuerID)
- {
- m_journal.warning <<
- "Malformed offer: bad issuer";
-
- terResult = temBAD_ISSUER;
- }
- else if (lesActive.accountFunds (mTxnAccountID, saTakerGets) <= zero)
- {
- m_journal.warning <<
- "delay: Offers must be at least partially funded.";
-
- terResult = tecUNFUNDED_OFFER;
- }
- // This can probably be simplified to make sure that you cancel sequences
- // before the transaction sequence number.
- else if (bHaveCancel && (!uCancelSequence || uAccountSequenceNext - 1 <= uCancelSequence))
- {
- m_journal.debug <<
- "uAccountSequenceNext=" << uAccountSequenceNext <<
- " uOfferSequence=" << uCancelSequence;
-
- terResult = temBAD_SEQUENCE;
- }
-
- // Cancel offer.
- if ((tesSUCCESS == terResult) && bHaveCancel)
- {
- const uint256 uCancelIndex = Ledger::getOfferIndex (mTxnAccountID, uCancelSequence);
- SLE::pointer sleCancel = mEngine->entryCache (ltOFFER, uCancelIndex);
-
- if (sleCancel)
- {
- m_journal.warning <<
- "uCancelSequence=" << uCancelSequence;
-
- terResult = mEngine->view ().offerDelete (sleCancel);
- }
- else
- {
- // It's not an error to not find the offer to cancel: it might have
- // been consumed or removed as we are processing. Additionally, it
- // might not even have been an offer - we don't care.
-
- if (m_journal.warning) m_journal.warning <<
- "offer not found: " <<
- to_string (mTxnAccountID) <<
- " : " << uCancelSequence <<
- " : " << to_string (uCancelIndex);
- }
- }
-
- // We definitely know the time that the parent ledger closed but we do not
- // know the closing time of the ledger under construction.
- // FIXME: Make sure that expiration is documented in terms of the close time
- // of the previous ledger.
- bool bExpired =
- bHaveExpiration &&
- (mEngine->getLedger ()->getParentCloseTimeNC () >= uExpiration);
-
- // If all is well and this isn't an offer to XRP, then we make sure we are
- // authorized to hold what the taker will pay.
- if (tesSUCCESS == terResult && !saTakerPays.isNative () && !bExpired)
- {
- SLE::pointer sleTakerPays = mEngine->entryCache (
- ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uPaysIssuerID));
-
- if (!sleTakerPays)
- {
- m_journal.warning <<
- "delay: can't receive IOUs from non-existent issuer: " <<
- to_string (uPaysIssuerID);
-
- terResult = (mParams & tapRETRY) ? terNO_ACCOUNT : tecNO_ISSUER;
- }
- else if (sleTakerPays->getFieldU32 (sfFlags) & lsfRequireAuth)
- {
- SLE::pointer sleRippleState (mEngine->entryCache (
- ltRIPPLE_STATE,
- Ledger::getRippleStateIndex (
- mTxnAccountID, uPaysIssuerID, uPaysCurrency)));
-
- // Entries have a canonical representation, determined by a
- // lexicographical "greater than" comparison employing strict weak
- // ordering.
- // Determine which entry we need to access.
- bool const canonical_gt (mTxnAccountID > uPaysIssuerID);
-
- if (!sleRippleState)
- {
- terResult = (mParams & tapRETRY)
- ? terNO_LINE
- : tecNO_LINE;
- }
- else if (!(sleRippleState->getFieldU32 (sfFlags) & (canonical_gt ? lsfLowAuth : lsfHighAuth)))
- {
- m_journal.debug <<
- "delay: can't receive IOUs from issuer without auth.";
-
- terResult = (mParams & tapRETRY) ? terNO_AUTH : tecNO_AUTH;
- }
- }
- }
-
- STAmount saPaid;
- STAmount saGot;
- bool bUnfunded = false;
- const bool bOpenLedger = (mParams & tapOPEN_LEDGER);
-
- if ((tesSUCCESS == terResult) && !bExpired)
- {
- const uint256 uTakeBookBase = Ledger::getBookBase (
- uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID);
-
- if (m_journal.trace) m_journal.trace <<
- "take against book:" << to_string (uTakeBookBase) <<
- " for " << saTakerGets.getFullText () <<
- " -> " << saTakerPays.getFullText ();
-
- // Take using the parameters of the offer.
- if (m_journal.debug) m_journal.debug <<
- "takeOffers: BEFORE saTakerGets=" << saTakerGets.getFullText ();
-
- terResult = takeOffers (
- bOpenLedger,
- bPassive,
- bSell,
- uTakeBookBase,
- mTxnAccountID,
- sleCreator,
- saTakerGets, // Reverse as we are the taker for taking.
- saTakerPays,
- saPaid, // Buy semantics: how much would have sold at full price. Sell semantics: how much was sold.
- saGot, // How much was got.
- bUnfunded);
-
- if (m_journal.debug)
- {
- m_journal.debug << "takeOffers=" << terResult;
- m_journal.debug << "takeOffers: saPaid=" << saPaid.getFullText ();
- m_journal.debug << "takeOffers: saGot=" << saGot.getFullText ();
- }
-
- if (tesSUCCESS == terResult && !bUnfunded)
- {
- // Reduce pay in from takers by what offer just got.
- saTakerPays -= saGot;
- // Reduce pay out to takers by what srcAccount just paid.
- saTakerGets -= saPaid;
-
- if (m_journal.debug)
- {
- m_journal.debug <<
- "takeOffers: AFTER saTakerPays=" <<
- saTakerPays.getFullText ();
- m_journal.debug <<
- "takeOffers: AFTER saTakerGets=" <<
- saTakerGets.getFullText ();
- }
- }
- }
-
- if (m_journal.debug)
- {
- m_journal.debug <<
- "takeOffers: saTakerPays=" < " << saTakerGets.getHumanCurrency () <<
- "/" << to_string (saTakerGets.getIssuer ());
-
- uDirectory = Ledger::getQualityIndex (uBookBase, uRate); // Use original rate.
-
- // Add offer to order book.
- terResult = lesActive.dirAdd (uBookNode, uDirectory, uLedgerIndex,
- std::bind (&Ledger::qualityDirDescriber, std::placeholders::_1,
- std::placeholders::_2, saTakerPays.getCurrency (),
- uPaysIssuerID, saTakerGets.getCurrency (), uGetsIssuerID,
- uRate));
- }
-
- if (tesSUCCESS == terResult)
- {
- if (m_journal.debug)
- {
- m_journal.debug <<
- "sfAccount=" <<
- to_string (mTxnAccountID);
- m_journal.debug <<
- "uPaysIssuerID=" <<
- to_string (uPaysIssuerID);
- m_journal.debug <<
- "uGetsIssuerID=" <<
- to_string (uGetsIssuerID);
- m_journal.debug <<
- "saTakerPays.isNative()=" <<
- saTakerPays.isNative ();
- m_journal.debug <<
- "saTakerGets.isNative()=" <<
- saTakerGets.isNative ();
- m_journal.debug <<
- "uPaysCurrency=" <<
- saTakerPays.getHumanCurrency ();
- m_journal.debug <<
- "uGetsCurrency=" <<
- saTakerGets.getHumanCurrency ();
- }
-
- SLE::pointer sleOffer (mEngine->entryCreate (ltOFFER, uLedgerIndex));
-
- sleOffer->setFieldAccount (sfAccount, mTxnAccountID);
- sleOffer->setFieldU32 (sfSequence, uSequence);
- sleOffer->setFieldH256 (sfBookDirectory, uDirectory);
- sleOffer->setFieldAmount (sfTakerPays, saTakerPays);
- sleOffer->setFieldAmount (sfTakerGets, saTakerGets);
- sleOffer->setFieldU64 (sfOwnerNode, uOwnerNode);
- sleOffer->setFieldU64 (sfBookNode, uBookNode);
-
- if (uExpiration)
- sleOffer->setFieldU32 (sfExpiration, uExpiration);
-
- if (bPassive)
- sleOffer->setFlag (lsfPassive);
-
- if (bSell)
- sleOffer->setFlag (lsfSell);
-
- if (m_journal.debug) m_journal.debug <<
- "final terResult=" << transToken (terResult) <<
- " sleOffer=" << sleOffer->getJson (0);
- }
- }
-
- // On storing meta data, delete offers that were found unfunded to prevent
- // encountering them in future.
- if (tesSUCCESS == terResult)
- {
-
- // Go through the list of unfunded offers and remove them
- for (auto const& offerIndex : usOfferUnfundedFound)
- {
- m_journal.trace <<
- "takeOffers: found unfunded: " << to_string (offerIndex);
- lesActive.offerDelete (offerIndex);
- }
-
- // Go through the list of offers not found and remove them from the
- // order book.
- // DAVIDSCHWARTZ - is this a fix to remove corrupted entries?
- for (auto const& indexes : usMissingOffers)
- {
- SLE::pointer sleDirectory (
- lesActive.entryCache (ltDIR_NODE, indexes.second));
-
- if (sleDirectory)
- {
- STVector256 svIndexes = sleDirectory->getFieldV256 (sfIndexes);
- std::vector& vuiIndexes = svIndexes.peekValue();
-
- auto it = std::find (
- vuiIndexes.begin (), vuiIndexes.end (), indexes.first);
-
- if (it != vuiIndexes.end ())
- {
- vuiIndexes.erase (it);
- sleDirectory->setFieldV256 (sfIndexes, svIndexes);
- lesActive.entryModify (sleDirectory);
- m_journal.warning <<
- "takeOffers: offer " << indexes.first <<
- " removed from directory " << indexes.second;
- }
- else
- {
- m_journal.debug <<
- "takeOffers: offer " << indexes.first <<
- " not found in directory " << indexes.second;
- }
- }
- else
- {
- m_journal.warning <<
- "takeOffers: directory " << indexes.second <<
- " not found for offer " << indexes.first;
- }
- }
- }
-
- if (tesSUCCESS != terResult) m_journal.debug <<
- "final terResult=" << transToken (terResult);
-
- return terResult;
-}
-
-}
diff --git a/src/ripple/module/app/transactors/CreateOfferLegacy.h b/src/ripple/module/app/transactors/CreateOfferLegacy.h
deleted file mode 100644
index 498cae7a31..0000000000
--- a/src/ripple/module/app/transactors/CreateOfferLegacy.h
+++ /dev/null
@@ -1,111 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2012, 2013 Ripple Labs Inc.
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-//==============================================================================
-
-#ifndef RIPPLE_TX_CLASSIC_OFFERCREATE_H_INCLUDED
-#define RIPPLE_TX_CLASSIC_OFFERCREATE_H_INCLUDED
-
-#include
-
-namespace ripple {
-
-class CreateOfferLegacy
- : public CreateOffer
-{
-public:
- CreateOfferLegacy (
- SerializedTransaction const& txn,
- TransactionEngineParams params,
- TransactionEngine* engine)
- : CreateOffer (
- txn,
- params,
- engine)
- {
-
- }
-
- TER doApply () override;
-
- virtual std::pair crossOffers (
- core::LedgerView& view,
- core::Amounts const& taker_amount)
- {
- return std::make_pair (tesSUCCESS, core::Amounts ());
- }
-
-private:
- typedef std::unordered_set>
- HardenedAccountSet;
-
- typedef std::unordered_set>
- HardenedOfferSet;
-
- bool isValidOffer (
- SLE::ref sleOfferDir,
- Account const& uOfferOwnerID,
- STAmount const& saOfferPays,
- STAmount const& saOfferGets,
- Account const& uTakerAccountID,
- HardenedOfferSet& usOfferUnfundedBecame,
- HardenedAccountSet& usAccountTouched,
- STAmount& saOfferFunds);
-
- bool applyOffer (
- const bool bSell,
- const std::uint32_t uTakerPaysRate, const std::uint32_t uOfferPaysRate,
- const STAmount& saOfferRate,
- const STAmount& saOfferFunds, const STAmount& saTakerFunds,
- const STAmount& saOfferPays, const STAmount& saOfferGets,
- const STAmount& saTakerPays, const STAmount& saTakerGets,
- STAmount& saTakerPaid, STAmount& saTakerGot,
- STAmount& saTakerIssuerFee, STAmount& saOfferIssuerFee);
-
- bool canCross (
- STAmount const& saTakerFunds,
- STAmount const& saSubTakerPays,
- STAmount const& saSubTakerGets,
- std::uint64_t uTipQuality,
- std::uint64_t uTakeQuality,
- bool isPassive,
- bool& isUnfunded,
- TER& terResult) const;
-
- TER takeOffers (
- bool const bOpenLedger,
- bool const bPassive,
- bool const bSell,
- uint256 const& uBookBase,
- Account const& uTakerAccountID,
- SLE::ref sleTakerAccount,
- STAmount const& saTakerPays,
- STAmount const& saTakerGets,
- STAmount& saTakerPaid,
- STAmount& saTakerGot,
- bool& bUnfunded);
-
- // Offers found unfunded.
- HardenedOfferSet usOfferUnfundedFound;
-
- typedef std::pair missingOffer_t;
- std::set usMissingOffers;
-};
-
-}
-
-#endif
diff --git a/src/ripple/unity/app9.cpp b/src/ripple/unity/app9.cpp
index 46ec6740fd..b844af5af5 100644
--- a/src/ripple/unity/app9.cpp
+++ b/src/ripple/unity/app9.cpp
@@ -38,7 +38,3 @@
#include
#include
#include
-
-#if RIPPLE_USE_OLD_CREATE_TRANSACTOR
-#include
-#endif