Ejemplo n.º 1
0
static void
createTestAccounts(Application& app, int nbAccounts,
                   std::function<int64(int)> getBalance,
                   std::function<int(int)> getVote)
{
    // set up world
    SecretKey root = getRoot();

    SequenceNumber rootSeq = getAccountSeqNum(root, app) + 1;

    auto& lm = app.getLedgerManager();
    auto& db = app.getDatabase();

    int64 setupBalance = lm.getMinBalance(0);

    LedgerDelta delta(lm.getCurrentLedgerHeader());
    for (int i = 0; i < nbAccounts; i++)
    {
        int64 bal = getBalance(i);
        if (bal >= 0)
        {
            SecretKey to = getTestAccount(i);
            applyPaymentTx(app, root, to, rootSeq++, setupBalance);

            AccountFrame act;
            REQUIRE(AccountFrame::loadAccount(to.getPublicKey(), act, db));
            act.getAccount().balance = bal;
            act.getAccount().inflationDest.activate() =
                getTestAccount(getVote(i)).getPublicKey();
            act.storeChange(delta, db);
        }
    }
}
Ejemplo n.º 2
0
SequenceNumber
getAccountSeqNum(SecretKey const& k, Application& app)
{
    AccountFrame account;
    REQUIRE(AccountFrame::loadAccount(k.getPublicKey(), account,
                                      app.getDatabase()));
    return account.getSeqNum();
}
Ejemplo n.º 3
0
uint64_t
getAccountBalance(SecretKey const& k, Application& app)
{
    AccountFrame account;
    REQUIRE(AccountFrame::loadAccount(k.getPublicKey(), account,
                                      app.getDatabase()));
    return account.getBalance();
}
bool
CreateAccountOpFrame::doApply(LedgerDelta& delta, LedgerManager& ledgerManager)
{
    AccountFrame destAccount;

    Database& db = ledgerManager.getDatabase();

    if (!AccountFrame::loadAccount(mCreateAccount.destination, destAccount, db))
    {
        if (mCreateAccount.startingBalance < ledgerManager.getMinBalance(0))
        { // not over the minBalance to make an account
            innerResult().code(CREATE_ACCOUNT_LOW_RESERVE);
            return false;
        }
        else
        {
            int64_t minBalance =
                mSourceAccount->getMinimumBalance(ledgerManager);

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

            mSourceAccount->getAccount().balance -=
                mCreateAccount.startingBalance;
            mSourceAccount->storeChange(delta, db);

            destAccount.getAccount().accountID = mCreateAccount.destination;
            destAccount.getAccount().seqNum =
                delta.getHeaderFrame().getStartingSequenceNumber();
            destAccount.getAccount().balance = mCreateAccount.startingBalance;

            destAccount.storeAdd(delta, db);

            innerResult().code(CREATE_ACCOUNT_SUCCESS);
            return true;
        }
    }
    else
    {
        innerResult().code(CREATE_ACCOUNT_ALREADY_EXIST);
        return false;
    }
}
Ejemplo n.º 5
0
bool
Simulation::loadAccount(AccountInfo& account)
{
    // assumes all nodes are in sync
    auto app = mNodes.begin()->second;

    AccountFrame ret;
    if (!AccountFrame::loadAccount(account.mKey.getPublicKey(), ret,
                                   app->getDatabase()))
    {
        return false;
    }

    account.mBalance = ret.getBalance();
    account.mSeq = ret.getSeqNum();
    return true;
}
Ejemplo n.º 6
0
void
applyPaymentTx(Application& app, SecretKey& from, SecretKey& to,
               SequenceNumber seq, int64_t amount, PaymentResultCode result)
{
    TransactionFramePtr txFrame;

    AccountFrame fromAccount;
    AccountFrame toAccount;
    bool beforeToExists = AccountFrame::loadAccount(
        to.getPublicKey(), toAccount, app.getDatabase());

    REQUIRE(AccountFrame::loadAccount(from.getPublicKey(), fromAccount,
                                      app.getDatabase()));

    txFrame = createPaymentTx(from, to, seq, amount);

    LedgerDelta delta(app.getLedgerManager().getCurrentLedgerHeader());
    txFrame->apply(delta, app);

    checkTransaction(*txFrame);
    auto txResult = txFrame->getResult();
    auto innerCode = PaymentOpFrame::getInnerCode(txResult.result.results()[0]);
    REQUIRE(innerCode == result);

    REQUIRE(txResult.feeCharged == app.getLedgerManager().getTxFee());

    AccountFrame toAccountAfter;
    bool afterToExists = AccountFrame::loadAccount(
        to.getPublicKey(), toAccountAfter, app.getDatabase());

    if (!(innerCode == PAYMENT_SUCCESS || innerCode == PAYMENT_SUCCESS_MULTI))
    {
        // check that the target account didn't change
        REQUIRE(beforeToExists == afterToExists);
        if (beforeToExists && afterToExists)
        {
            REQUIRE(memcmp(&toAccount.getAccount(),
                           &toAccountAfter.getAccount(),
                           sizeof(AccountEntry)) == 0);
        }
    }
    else
    {
        REQUIRE(afterToExists);
    }
}
Ejemplo n.º 7
0
vector<Simulation::AccountInfoPtr>
Simulation::accountsOutOfSyncWithDb()
{
    vector<AccountInfoPtr> result;
    int iApp = 0;
    int64_t totalOffsets = 0;
    for (auto pair : mNodes)
    {
        iApp++;
        auto app = pair.second;
        for (auto accountIt = mAccounts.begin() + 1;
             accountIt != mAccounts.end(); accountIt++)
        {
            auto account = *accountIt;
            AccountFrame accountFrame;
            bool res = AccountFrame::loadAccount(
                account->mKey.getPublicKey(), accountFrame, app->getDatabase());
            int64_t offset;
            if (res)
            {
                offset = accountFrame.getBalance() -
                         static_cast<int64_t>(account->mBalance);
                account->mSeq = accountFrame.getSeqNum();
            }
            else
            {
                offset = -1;
            }
            if (offset != 0)
            {
                LOG(DEBUG) << "On node " << iApp << ", account " << account->mId
                           << " is off by " << (offset) << "\t(has "
                           << accountFrame.getBalance() << " should have "
                           << account->mBalance << ")";
                totalOffsets += abs(offset);
                result.push_back(account);
            }
        }
    }
    LOG(INFO)
        << "Ledger has not yet caught up to the simulation. totalOffsets: "
        << totalOffsets;
    return result;
}
Ejemplo n.º 8
0
bool
PaymentOpFrame::doApply(LedgerDelta& delta, LedgerManager& ledgerManager)
{
    AccountFrame destAccount;

    // if sending to self directly, just mark as success
    if (mPayment.destination == getSourceID() && mPayment.path.empty())
    {
        innerResult().code(PAYMENT_SUCCESS);
        return true;
    }

    Database& db = ledgerManager.getDatabase();

    if (!AccountFrame::loadAccount(mPayment.destination, destAccount, db))
    { // this tx is creating an account
        if (mPayment.currency.type() == CURRENCY_TYPE_NATIVE)
        {
            if (mPayment.amount < ledgerManager.getMinBalance(0))
            { // not over the minBalance to make an account
                innerResult().code(PAYMENT_LOW_RESERVE);
                return false;
            }
            else
            {
                destAccount.getAccount().accountID = mPayment.destination;
                destAccount.getAccount().seqNum =
                    delta.getHeaderFrame().getStartingSequenceNumber();
                destAccount.getAccount().balance = 0;

                destAccount.storeAdd(delta, db);
            }
        }
        else
        { // trying to send credit to an unmade account
            innerResult().code(PAYMENT_NO_DESTINATION);
            return false;
        }
    }

    return sendNoCreate(destAccount, delta, ledgerManager);
}
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;
}
Ejemplo n.º 10
0
static void
doInflation(Application& app, int nbAccounts,
            std::function<int64(int)> getBalance,
            std::function<int(int)> getVote, int expectedWinnerCount)
{
    // simulate the expected inflation based off the current ledger state
    std::map<int, int64> balances;

    // load account balances
    for (int i = 0; i < nbAccounts; i++)
    {
        AccountFrame act;
        if (getBalance(i) < 0)
        {
            balances[i] = -1;
            REQUIRE(!AccountFrame::loadAccount(getTestAccount(i).getPublicKey(),
                                               act, app.getDatabase()));
        }
        else
        {
            REQUIRE(AccountFrame::loadAccount(getTestAccount(i).getPublicKey(),
                                              act, app.getDatabase()));
            balances[i] = act.getBalance();
            // double check that inflationDest is setup properly
            if (act.getAccount().inflationDest)
            {
                REQUIRE(getTestAccount(getVote(i)).getPublicKey() ==
                        *act.getAccount().inflationDest);
            }
            else
            {
                REQUIRE(getVote(i) < 0);
            }
        }
    }
    LedgerManager& lm = app.getLedgerManager();
    LedgerHeader& cur = lm.getCurrentLedgerHeader();
    cur.feePool = 10000;

    int64 expectedTotcoins = cur.totalCoins;
    int64 expectedFees = cur.feePool;

    std::vector<int64> expectedBalances;

    auto root = getRoot();
    TransactionFramePtr txFrame =
        createInflation(root, getAccountSeqNum(root, app) + 1);

    expectedFees += txFrame->getFee(app);

    expectedBalances =
        simulateInflation(nbAccounts, expectedTotcoins, expectedFees,
                          [&](int i)
                          {
                              return balances[i];
                          },
                          getVote);

    // perform actual inflation
    {
        LedgerDelta delta(lm.getCurrentLedgerHeader());
        REQUIRE(txFrame->apply(delta, app));
        delta.commit();
    }

    // verify ledger state
    LedgerHeader& cur2 = lm.getCurrentLedgerHeader();

    REQUIRE(cur2.totalCoins == expectedTotcoins);
    REQUIRE(cur2.feePool == expectedFees);

    // verify balances
    InflationResult const& infResult =
        getFirstResult(*txFrame).tr().inflationResult();
    auto const& payouts = infResult.payouts();
    int actualChanges = 0;

    for (int i = 0; i < nbAccounts; i++)
    {
        AccountFrame act;
        auto const& pk = getTestAccount(i).getPublicKey();
        if (expectedBalances[i] < 0)
        {
            REQUIRE(!AccountFrame::loadAccount(pk, act, app.getDatabase()));
            REQUIRE(balances[i] < 0); // account didn't get deleted
        }
        else
        {
            REQUIRE(AccountFrame::loadAccount(pk, act, app.getDatabase()));
            REQUIRE(expectedBalances[i] == act.getBalance());

            if (expectedBalances[i] != balances[i])
            {
                REQUIRE(balances[i] >= 0);
                actualChanges++;
                bool found = false;
                for (auto const& p : payouts)
                {
                    if (p.destination == pk)
                    {
                        int64 computedFromResult = balances[i] + p.amount;
                        REQUIRE(computedFromResult == expectedBalances[i]);
                        found = true;
                        break;
                    }
                }
                REQUIRE(found);
            }
        }
    }
    REQUIRE(actualChanges == expectedWinnerCount);
    REQUIRE(expectedWinnerCount == payouts.size());
}
Ejemplo n.º 11
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;
}