std::pair<TER, core::Amounts>
CreateOffer::crossOffersDirect (
    core::LedgerView& view,
    core::Amounts const& taker_amount)
{
    core::Taker::Options const options (mTxn.getFlags());

    core::Clock::time_point const when (
        mEngine->getLedger ()->getParentCloseTimeNC ());

    core::LedgerView view_cancel (view.duplicate());
    core::OfferStream offers (
        view, view_cancel,
        Book (taker_amount.in.issue(), taker_amount.out.issue()),
        when, m_journal);
    core::Taker taker (offers.view(), mTxnAccountID, taker_amount, options);

    TER cross_result (tesSUCCESS);

    while (true)
    {
        // Modifying the order or logic of these
        // operations causes a protocol breaking change.

        // Checks which remove offers are performed early so we
        // can reduce the size of the order book as much as possible
        // before terminating the loop.

        if (taker.done())
        {
            m_journal.debug << "The taker reports he's done during crossing!";
            break;
        }

        if (! offers.step ())
        {
            // Place the order since there are no
            // more offers and the order has a balance.
            m_journal.debug << "No more offers to consider during crossing!";
            break;
        }

        auto const& offer (offers.tip());

        if (taker.reject (offer.quality()))
        {
            // Place the order since there are no more offers
            // at the desired quality, and the order has a balance.
            break;
        }

        if (offer.account() == taker.account())
        {
            // Skip offer from self. The offer will be considered expired and
            // will get deleted.
            continue;
        }

        if (m_journal.debug) m_journal.debug <<
                "  Offer: " << offer.entry()->getIndex() << std::endl <<
                "         " << offer.amount().in << " : " << offer.amount().out;

        cross_result = taker.cross (offer);

        if (cross_result != tesSUCCESS)
        {
            cross_result = tecFAILED_PROCESSING;
            break;
        }
    }

    return std::make_pair(cross_result, taker.remaining_offer ());
}
Exemple #2
0
bool
OfferStream::step ()
{
    // Modifying the order or logic of these
    // operations causes a protocol breaking change.

    for(;;)
    {
        // BookTip::step deletes the current offer from the view before
        // advancing to the next (unless the ledger entry is missing).
        if (! m_tip.step())
            return false;

        SLE::pointer const& entry (m_tip.entry());

        // Remove if missing
        if (! entry)
        {
            erase (view());
            erase (view_cancel());
            continue;
        }

        // Remove if expired
        if (entry->isFieldPresent (sfExpiration) &&
                entry->getFieldU32 (sfExpiration) <= m_when)
        {
            view_cancel().offerDelete (entry->getIndex());
            if (m_journal.trace) m_journal.trace <<
                                                     "Removing expired offer " << entry->getIndex();
            continue;
        }

        m_offer = Offer (entry, m_tip.quality());

        Amounts const amount (m_offer.amount());

        // Remove if either amount is zero
        if (amount.empty())
        {
            view_cancel().offerDelete (entry->getIndex());
            if (m_journal.warning) m_journal.warning <<
                        "Removing bad offer " << entry->getIndex();
            m_offer = Offer{};
            continue;
        }

        // Calculate owner funds
        // NIKB NOTE The calling code also checks the funds, how expensive is
        //           looking up the funds twice?
        Amount const owner_funds (view().accountFunds (
                                      m_offer.account(), m_offer.amount().out, fhZERO_IF_FROZEN));

        // Check for unfunded offer
        if (owner_funds <= zero)
        {
            // If the owner's balance in the pristine view is the same,
            // we haven't modified the balance and therefore the
            // offer is "found unfunded" versus "became unfunded"
            if (view_cancel().accountFunds (m_offer.account(),
                                            m_offer.amount().out, fhZERO_IF_FROZEN) == owner_funds)
            {
                view_cancel().offerDelete (entry->getIndex());
                if (m_journal.trace) m_journal.trace <<
                                                         "Removing unfunded offer " << entry->getIndex();
            }
            else
            {
                if (m_journal.trace) m_journal.trace <<
                                                         "Removing became unfunded offer " << entry->getIndex();
            }
            m_offer = Offer{};
            continue;
        }

        break;
    }

    return true;
}