bool
TransactionFrame::checkSignature(AccountFrame& account, int32_t neededWeight)
{
    vector<Signer> keyWeights;
    if (account.getAccount().thresholds[0])
        keyWeights.push_back(
            Signer(account.getID(), account.getAccount().thresholds[0]));

    keyWeights.insert(keyWeights.end(), account.getAccount().signers.begin(),
                      account.getAccount().signers.end());

    Hash const& contentsHash = getContentsHash();

    // calculate the weight of the signatures
    int totalWeight = 0;

    for (size_t i = 0; i < getEnvelope().signatures.size(); i++)
    {
        auto const& sig = getEnvelope().signatures[i];

        for (auto it = keyWeights.begin(); it != keyWeights.end(); it++)
        {
            if ((std::memcmp(sig.hint.data(), (*it).pubKey.data(),
                             sizeof(sig.hint)) == 0) &&
                PublicKey::verifySig((*it).pubKey, sig.signature, contentsHash))
            {
                mUsedSignatures[i] = true;
                totalWeight += (*it).weight;
                if (totalWeight >= neededWeight)
                    return true;

                keyWeights.erase(it); // can't sign twice
                break;
            }
        }
    }

    return false;
}
Exemplo n.º 2
0
// 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;
}