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