Beispiel #1
0
Currency
makeCurrency(SecretKey& issuer, std::string const& code)
{
    Currency currency;
    currency.type(CURRENCY_TYPE_ALPHANUM);
    currency.alphaNum().issuer = issuer.getPublicKey();
    strToCurrencyCode(currency.alphaNum().currencyCode, code);
    return currency;
}
bool
AllowTrustOpFrame::doCheckValid()
{
    if (mAllowTrust.currency.type() != CURRENCY_TYPE_ALPHANUM)
    {
        innerResult().code(ALLOW_TRUST_MALFORMED);
        return false;
    }
    Currency ci;
    ci.type(CURRENCY_TYPE_ALPHANUM);
    ci.alphaNum().currencyCode = mAllowTrust.currency.currencyCode();
    ci.alphaNum().issuer = getSourceID();

    if (!isCurrencyValid(ci))
    {
        innerResult().code(ALLOW_TRUST_MALFORMED);
        return false;
    }

    return true;
}
bool
AllowTrustOpFrame::doApply(LedgerDelta& delta, LedgerManager& ledgerManager)
{
    if (!(mSourceAccount->getAccount().flags & AUTH_REQUIRED_FLAG))
    { // this account doesn't require authorization to hold credit
        innerResult().code(ALLOW_TRUST_TRUST_NOT_REQUIRED);
        return false;
    }

    if (!(mSourceAccount->getAccount().flags & AUTH_REVOCABLE_FLAG) &&
        !mAllowTrust.authorize)
    {
        innerResult().code(ALLOW_TRUST_CANT_REVOKE);
        return false;
    }

    Currency ci;
    ci.type(CURRENCY_TYPE_ALPHANUM);
    ci.alphaNum().currencyCode = mAllowTrust.currency.currencyCode();
    ci.alphaNum().issuer = getSourceID();

    Database& db = ledgerManager.getDatabase();
    TrustFrame::pointer trustLine;
    trustLine = TrustFrame::loadTrustLine(mAllowTrust.trustor, ci, db);

    if (!trustLine)
    {
        innerResult().code(ALLOW_TRUST_NO_TRUST_LINE);
        return false;
    }

    innerResult().code(ALLOW_TRUST_SUCCESS);

    trustLine->setAuthorized(mAllowTrust.authorize);

    trustLine->storeChange(delta, db);

    return true;
}
// work backward to determine how much they need to send to get the
// specified amount of currency to the recipient
bool
PaymentOpFrame::sendNoCreate(AccountFrame& destination, LedgerDelta& delta,
                             LedgerManager& ledgerManager)
{
    Database& db = ledgerManager.getDatabase();

    bool multi_mode = mPayment.path.size() != 0;
    if (multi_mode)
    {
        innerResult().code(PAYMENT_SUCCESS_MULTI);
    }
    else
    {
        innerResult().code(PAYMENT_SUCCESS);
    }

    // tracks the last amount that was traded
    int64_t curBReceived = mPayment.amount;
    Currency curB = mPayment.currency;

    // update balances, walks backwards

    // update last balance in the chain
    {

        if (curB.type() == CURRENCY_TYPE_NATIVE)
        {
            destination.getAccount().balance += curBReceived;
            destination.storeChange(delta, db);
        }
        else
        {
            TrustFrame destLine;

            if (!TrustFrame::loadTrustLine(destination.getID(), curB, destLine,
                                           db))
            {
                innerResult().code(PAYMENT_NO_TRUST);
                return false;
            }

            if (!destLine.isAuthorized())
            {
                innerResult().code(PAYMENT_NOT_AUTHORIZED);
                return false;
            }

            if (!destLine.addBalance(curBReceived))
            {
                innerResult().code(PAYMENT_LINE_FULL);
                return false;
            }

            destLine.storeChange(delta, db);
        }

        if (multi_mode)
        {
            innerResult().multi().last =
                SimplePaymentResult(destination.getID(), curB, curBReceived);
        }
    }

    if (multi_mode)
    {
        // now, walk the path backwards
        for (int i = (int)mPayment.path.size() - 1; i >= 0; i--)
        {
            int64_t curASent, actualCurBReceived;
            Currency const& curA = mPayment.path[i];

            OfferExchange oe(delta, ledgerManager);

            // curA -> curB
            OfferExchange::ConvertResult r =
                oe.convertWithOffers(curA, INT64_MAX, curASent, curB,
                                     curBReceived, actualCurBReceived, nullptr);
            switch (r)
            {
            case OfferExchange::eFilterStop:
                assert(false); // no filter -> should not happen
                break;
            case OfferExchange::eOK:
                if (curBReceived == actualCurBReceived)
                {
                    break;
                }
            // fall through
            case OfferExchange::ePartial:
                innerResult().code(PAYMENT_TOO_FEW_OFFERS);
                return false;
            }
            assert(curBReceived == actualCurBReceived);
            curBReceived = curASent; // next round, we need to send enough
            curB = curA;

            // add offers that got taken on the way
            // insert in front to match the path's order
            auto& offers = innerResult().multi().offers;
            offers.insert(offers.begin(), oe.getOfferTrail().begin(),
                          oe.getOfferTrail().end());
        }
    }

    // last step: we've reached the first account in the chain, update its
    // balance

    int64_t curBSent;

    curBSent = curBReceived;

    if (curBSent > mPayment.sendMax)
    { // make sure not over the max
        innerResult().code(PAYMENT_OVER_SENDMAX);
        return false;
    }

    if (curB.type() == CURRENCY_TYPE_NATIVE)
    {
        int64_t minBalance = mSourceAccount->getMinimumBalance(ledgerManager);

        if (mSourceAccount->getAccount().balance < (minBalance + curBSent))
        { // they don't have enough to send
            innerResult().code(PAYMENT_UNDERFUNDED);
            return false;
        }

        mSourceAccount->getAccount().balance -= curBSent;
        mSourceAccount->storeChange(delta, db);
    }
    else
    {
        AccountFrame issuer;
        if (!AccountFrame::loadAccount(curB.alphaNum().issuer, issuer, db))
        {
            throw std::runtime_error("sendCredit Issuer not found");
        }

        TrustFrame sourceLineFrame;
        if (!TrustFrame::loadTrustLine(getSourceID(), curB, sourceLineFrame,
                                       db))
        {
            innerResult().code(PAYMENT_UNDERFUNDED);
            return false;
        }

        if (!sourceLineFrame.addBalance(-curBSent))
        {
            innerResult().code(PAYMENT_UNDERFUNDED);
            return false;
        }

        sourceLineFrame.storeChange(delta, db);
    }

    return true;
}
bool
PathPaymentOpFrame::doApply(medida::MetricsRegistry& metrics,
                            LedgerDelta& delta, LedgerManager& ledgerManager)
{
    AccountFrame::pointer destination;

    Database& db = ledgerManager.getDatabase();

    destination = AccountFrame::loadAccount(mPathPayment.destination, db);

    if (!destination)
    {
        metrics.NewMeter({"op-path-payment", "failure", "no-destination"},
                         "operation").Mark();
        innerResult().code(PATH_PAYMENT_NO_DESTINATION);
        return false;
    }

    innerResult().code(PATH_PAYMENT_SUCCESS);

    // tracks the last amount that was traded
    int64_t curBReceived = mPathPayment.destAmount;
    Currency curB = mPathPayment.destCurrency;

    // update balances, walks backwards

    // build the full path to the destination, starting with sendCurrency
    std::vector<Currency> fullPath;
    fullPath.emplace_back(mPathPayment.sendCurrency);
    fullPath.insert(fullPath.end(), mPathPayment.path.begin(),
                    mPathPayment.path.end());

    // update last balance in the chain
    {
        if (curB.type() == CURRENCY_TYPE_NATIVE)
        {
            destination->getAccount().balance += curBReceived;
            destination->storeChange(delta, db);
        }
        else
        {
            TrustFrame::pointer destLine;

            destLine =
                TrustFrame::loadTrustLine(destination->getID(), curB, db);
            if (!destLine)
            {
                metrics.NewMeter({"op-path-payment", "failure", "no-trust"},
                                 "operation").Mark();
                innerResult().code(PATH_PAYMENT_NO_TRUST);
                return false;
            }

            if (!destLine->isAuthorized())
            {
                metrics.NewMeter(
                            {"op-path-payment", "failure", "not-authorized"},
                            "operation").Mark();
                innerResult().code(PATH_PAYMENT_NOT_AUTHORIZED);
                return false;
            }

            if (!destLine->addBalance(curBReceived))
            {
                metrics.NewMeter({"op-path-payment", "failure", "line-full"},
                                 "operation").Mark();
                innerResult().code(PATH_PAYMENT_LINE_FULL);
                return false;
            }

            destLine->storeChange(delta, db);
        }

        innerResult().success().last =
            SimplePaymentResult(destination->getID(), curB, curBReceived);
    }

    // now, walk the path backwards
    for (int i = (int)fullPath.size() - 1; i >= 0; i--)
    {
        int64_t curASent, actualCurBReceived;
        Currency const& curA = fullPath[i];

        if (curA == curB)
        {
            continue;
        }

        OfferExchange oe(delta, ledgerManager);

        // curA -> curB
        OfferExchange::ConvertResult r =
            oe.convertWithOffers(curA, INT64_MAX, curASent, curB, curBReceived,
                                 actualCurBReceived, nullptr);
        switch (r)
        {
        case OfferExchange::eFilterStop:
            assert(false); // no filter -> should not happen
            break;
        case OfferExchange::eOK:
            if (curBReceived == actualCurBReceived)
            {
                break;
            }
        // fall through
        case OfferExchange::ePartial:
            metrics.NewMeter({"op-path-payment", "failure", "too-few-offers"},
                             "operation").Mark();
            innerResult().code(PATH_PAYMENT_TOO_FEW_OFFERS);
            return false;
        }
        assert(curBReceived == actualCurBReceived);
        curBReceived = curASent; // next round, we need to send enough
        curB = curA;

        // add offers that got taken on the way
        // insert in front to match the path's order
        auto& offers = innerResult().success().offers;
        offers.insert(offers.begin(), oe.getOfferTrail().begin(),
                      oe.getOfferTrail().end());
    }

    // last step: we've reached the first account in the chain, update its
    // balance

    int64_t curBSent;

    curBSent = curBReceived;

    if (curBSent > mPathPayment.sendMax)
    { // make sure not over the max
        metrics.NewMeter({"op-path-payment", "failure", "over-send-max"},
                         "operation").Mark();
        innerResult().code(PATH_PAYMENT_OVER_SENDMAX);
        return false;
    }

    if (curB.type() == CURRENCY_TYPE_NATIVE)
    {
        int64_t minBalance = mSourceAccount->getMinimumBalance(ledgerManager);

        if ((mSourceAccount->getAccount().balance - curBSent) < minBalance)
        { // they don't have enough to send
            metrics.NewMeter({"op-path-payment", "failure", "underfunded"},
                             "operation").Mark();
            innerResult().code(PATH_PAYMENT_UNDERFUNDED);
            return false;
        }

        mSourceAccount->getAccount().balance -= curBSent;
        mSourceAccount->storeChange(delta, db);
    }
    else
    {
        AccountFrame::pointer issuer;
        issuer = AccountFrame::loadAccount(curB.alphaNum().issuer, db);

        if (!issuer)
        {
            metrics.NewMeter({"op-path-payment", "failure", "no-issuer"},
                             "operation").Mark();
            throw std::runtime_error("sendCredit Issuer not found");
        }

        TrustFrame::pointer sourceLineFrame;
        sourceLineFrame = TrustFrame::loadTrustLine(getSourceID(), curB, db);
        if (!sourceLineFrame)
        {
            metrics.NewMeter({"op-path-payment", "failure", "src-no-trust"},
                             "operation").Mark();
            innerResult().code(PATH_PAYMENT_SRC_NO_TRUST);
            return false;
        }

        if (!sourceLineFrame->isAuthorized())
        {
            metrics.NewMeter(
                        {"op-path-payment", "failure", "src-not-authorized"},
                        "operation").Mark();
            innerResult().code(PATH_PAYMENT_SRC_NOT_AUTHORIZED);
            return false;
        }

        if (!sourceLineFrame->addBalance(-curBSent))
        {
            metrics.NewMeter({"op-path-payment", "failure", "underfunded"},
                             "operation").Mark();
            innerResult().code(PATH_PAYMENT_UNDERFUNDED);
            return false;
        }

        sourceLineFrame->storeChange(delta, db);
    }

    metrics.NewMeter({"op-path-payment", "success", "apply"}, "operation")
        .Mark();

    return true;
}