Exemplo n.º 1
0
void OrderBookDB::addOrderBook(const uint160& ci, const uint160& co,
    const uint160& ii, const uint160& io)
{
    bool toXRP = co.isZero();
    ScopedLockType sl (mLock, __FILE__, __LINE__);

    if (toXRP)
    { // We don't want to search through all the to-XRP or from-XRP order books!
        BOOST_FOREACH(OrderBook::ref ob, mSourceMap[currencyIssuer_ct(ci, ii)])
        {
            if ((ob->getCurrencyOut() == co) && (ob->getIssuerOut() == io))
                return;
        }
    }
    else
    {
Exemplo n.º 2
0
TER PaymentTransactor::doApply ()
{
    // Ripple if source or destination is non-native or if there are paths.
    std::uint32_t const uTxFlags = mTxn.getFlags ();
	//bool const bPartialPayment = is_bit_set(uTxFlags, tfPartialPayment);
    bool const bLimitQuality = is_bit_set (uTxFlags, tfLimitQuality);
    bool const bNoRippleDirect = is_bit_set (uTxFlags, tfNoRippleDirect);
    bool const bPaths = mTxn.isFieldPresent (sfPaths);
    bool const bMax = mTxn.isFieldPresent (sfSendMax);
    uint160 const uDstAccountID = mTxn.getFieldAccount160 (sfDestination);
    STAmount const saDstAmount = mTxn.getFieldAmount (sfAmount);
    STAmount const saMaxAmount = bMax
                                   ? mTxn.getFieldAmount (sfSendMax)
                                   : saDstAmount.isNative ()
                                   ? saDstAmount
                                   : STAmount (saDstAmount.getCurrency (),
                                        mTxnAccountID,
                                        saDstAmount.getMantissa (),
                                        saDstAmount.getExponent (),
                                        saDstAmount < zero);
    uint160 const uSrcCurrency = saMaxAmount.getCurrency ();
    uint160 const uDstCurrency = saDstAmount.getCurrency ();
    bool const bSTRDirect = uSrcCurrency.isZero () && uDstCurrency.isZero ();

	
    m_journal.trace <<
        "saMaxAmount=" << saMaxAmount.getFullText () <<
        " saDstAmount=" << saDstAmount.getFullText ();

    if (!saDstAmount.isLegalNet () || !saMaxAmount.isLegalNet ())
        return temBAD_AMOUNT;

    if (uTxFlags & tfPaymentMask)
    {
        m_journal.trace <<
            "Malformed transaction: Invalid flags set.";

        return temINVALID_FLAG;
    }
    else if (!uDstAccountID)
    {
        m_journal.trace <<
            "Malformed transaction: Payment destination account not specified.";

        return temDST_NEEDED;
    }
    else if (bMax && saMaxAmount <= zero)
    {
        m_journal.trace <<
            "Malformed transaction: bad max amount: " << saMaxAmount.getFullText ();

        return temBAD_AMOUNT;
    }
    else if (saDstAmount <= zero)
    {
        m_journal.trace <<
            "Malformed transaction: bad dst amount: " << saDstAmount.getFullText ();

        return temBAD_AMOUNT;
    }
    else if (CURRENCY_BAD == uSrcCurrency || CURRENCY_BAD == uDstCurrency)
    {
        m_journal.trace <<
            "Malformed transaction: Bad currency.";

        return temBAD_CURRENCY;
    }
    else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
    {
        m_journal.trace <<
            "Malformed transaction: Redundant transaction:" <<
            " src=" << to_string (mTxnAccountID) <<
            " dst=" << to_string (uDstAccountID) <<
            " src_cur=" << to_string (uSrcCurrency) <<
            " dst_cur=" << to_string (uDstCurrency);

        return temREDUNDANT;
    }
    else if (bMax && saMaxAmount == saDstAmount && saMaxAmount.getCurrency () == saDstAmount.getCurrency ())
    {
        m_journal.trace <<
            "Malformed transaction: Redundant SendMax.";

        return temREDUNDANT_SEND_MAX;
    }
    else if (bSTRDirect && bMax)
    {
        m_journal.trace <<
            "Malformed transaction: SendMax specified for STR to STR.";

        return temBAD_SEND_STR_MAX;
    }
    else if (bSTRDirect && bPaths)
    {
        m_journal.trace <<
            "Malformed transaction: Paths specified for STR to STR.";

        return temBAD_SEND_STR_PATHS;
    }
    else if (bSTRDirect && bLimitQuality)
    {
        m_journal.trace <<
            "Malformed transaction: Limit quality specified for STR to STR.";

        return temBAD_SEND_STR_LIMIT;
    }
    else if (bSTRDirect && bNoRippleDirect)
    {
        m_journal.trace <<
            "Malformed transaction: No ripple direct specified for STR to STR.";

        return temBAD_SEND_STR_NO_DIRECT;
    }

    SLE::pointer sleDst (mEngine->entryCache (
        ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uDstAccountID)));

    if (!sleDst)
    {
        // Destination account does not exist.

        if (!saDstAmount.isNative ())
        {
            m_journal.trace <<
                "Delay transaction: Destination account does not exist.";

            // Another transaction could create the account and then this transaction would succeed.
            return tecNO_DST;
        }
        
        // Note: Reserve is not scaled by load.
        else if (saDstAmount.getNValue () < mEngine->getLedger ()->getReserve (0))
        {
            m_journal.trace <<
                "Delay transaction: Destination account does not exist. " <<
                "Insufficient payment to create account.";

            // Another transaction could create the account and then this
            // transaction would succeed.
            return tecNO_DST_INSUF_STR;
        }

        // Create the account.
        sleDst = mEngine->entryCreate (
            ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uDstAccountID));

        sleDst->setFieldAccount (sfAccount, uDstAccountID);
        sleDst->setFieldU32 (sfSequence, 1);
    }
    else if ((sleDst->getFlags () & lsfRequireDestTag) && !mTxn.isFieldPresent (sfDestinationTag))
    {
        m_journal.trace <<
            "Malformed transaction: DestinationTag required.";

        return tefDST_TAG_NEEDED;
    }
    else
    {
        mEngine->entryModify (sleDst);
    }

    TER terResult;
    // XXX Should bMax be sufficient to imply ripple?
    bool const bRipple = bPaths || bMax || !saDstAmount.isNative ();

    if (bRipple)
    {
        // Ripple payment

        STPathSet spsPaths = mTxn.getFieldPathSet (sfPaths);
        std::vector<PathState::pointer> vpsExpanded;
        STAmount saMaxAmountAct;
        STAmount saDstAmountAct;

        try
        {
            bool const openLedger = is_bit_set (mParams, tapOPEN_LEDGER);
			bool tooManyPaths = false;
			if (spsPaths.size() > MAX_NUM_PATHS) tooManyPaths = true;
			else
			{
				for (auto const& path : spsPaths)
				{
					if (path.size() > MAX_PATH_SIZE)
					{
						tooManyPaths = true;
						break;
					}
				}
			}

			
			terResult = openLedger && tooManyPaths
				? telBAD_PATH_COUNT // Too many paths for proposed ledger.
				: RippleCalc::rippleCalc(
				mEngine->view(),
				saMaxAmountAct,
				saDstAmountAct,
				vpsExpanded,
				saMaxAmount,
				saDstAmount,
				uDstAccountID,
				mTxnAccountID,
				spsPaths,
				false,
				bLimitQuality,
				bNoRippleDirect, // Always compute for finalizing ledger.
				false, // Not standalone, delete unfundeds.
				is_bit_set(mParams, tapOPEN_LEDGER));

			if (isTerRetry(terResult))
				terResult = tecPATH_DRY;

			if ((tesSUCCESS == terResult) && (saDstAmountAct != saDstAmount))
				mEngine->view().setDeliveredAmount(saDstAmountAct);
			
        }
        catch (std::exception const& e)
        {
            m_journal.trace <<
                "Caught throw: " << e.what ();

            terResult   = tefEXCEPTION;
        }
    }
    else
    {
        // Direct STR payment.

        std::uint32_t const uOwnerCount (mTxnAccount->getFieldU32 (sfOwnerCount));
        std::uint64_t const uReserve (mEngine->getLedger ()->getReserve (uOwnerCount));

        // Make sure have enough reserve to send. Allow final spend to use reserve for fee.
        if (mPriorBalance < saDstAmount + std::max(uReserve, mTxn.getTransactionFee ().getNValue ()))
        {
            // Vote no. However, transaction might succeed, if applied in a different order.
            m_journal.trace << "Delay transaction: Insufficient funds: " <<
                " " << mPriorBalance.getText () <<
                " / " << (saDstAmount + uReserve).getText () <<
                " (" << uReserve << ")";

            terResult   = tecUNFUNDED_PAYMENT;
        }
        else
        {
            mTxnAccount->setFieldAmount (sfBalance, mSourceBalance - saDstAmount);
            sleDst->setFieldAmount (sfBalance, sleDst->getFieldAmount (sfBalance) + saDstAmount);


            terResult = tesSUCCESS;
        }
    }

    std::string strToken;
    std::string strHuman;

    if (transResultInfo (terResult, strToken, strHuman))
    {
        m_journal.trace <<
            strToken << ": " << strHuman;
    }
    else
    {
        assert (false);
    }

    return terResult;
}