示例#1
0
LedgerDelta::LedgerDelta(LedgerDelta& outerDelta)
    : mOuterDelta(&outerDelta)
    , mHeader(&outerDelta.getHeader())
    , mCurrentHeader(outerDelta.getHeader())
    , mPreviousHeaderValue(outerDelta.getHeader())
{
}
void
LedgerManagerImpl::closeLedgerHelper(LedgerDelta const& delta)
{
    delta.markMeters(mApp);
    mApp.getBucketManager().addBatch(mApp, mCurrentLedger->mHeader.ledgerSeq,
                                     delta.getLiveEntries(),
                                     delta.getDeadEntries());

    mApp.getBucketManager().snapshotLedger(mCurrentLedger->mHeader);

    mCurrentLedger->storeInsert(*this);

    mApp.getPersistentState().setState(PersistentState::kLastClosedLedger,
                                       binToHex(mCurrentLedger->getHash()));

    // Store the current HAS in the database; this is really just to checkpoint
    // the bucketlist so we can survive a restart and re-attach to the buckets.
    HistoryArchiveState has(mCurrentLedger->mHeader.ledgerSeq,
                            mApp.getBucketManager().getBucketList());

    // We almost always want to try to resolve completed merges to single
    // buckets, as it makes restarts less fragile: fewer saved/restored shadows,
    // fewer buckets for the user to accidentally delete from their buckets
    // dir. But we support the option of not-doing so, only for the sake of
    // testing. Note: this is nonblocking in any case.
    if (!mApp.getConfig().ARTIFICIALLY_PESSIMIZE_MERGES_FOR_TESTING)
    {
        has.resolveAnyReadyFutures();
    }

    mApp.getPersistentState().setState(PersistentState::kHistoryArchiveState,
                                       has.toString());

    advanceLedgerPointers();
}
示例#3
0
void
AccountFrame::storeDelete(LedgerDelta& delta, Database& db,
                          LedgerKey const& key)
{
    flushCachedEntry(key, db);

    std::string actIDStrKey = PubKeyUtils::toStrKey(key.account().accountID);
    {
        auto timer = db.getDeleteTimer("account");
        auto prep = db.getPreparedStatement(
            "DELETE from accounts where accountid= :v1");
        auto& st = prep.statement();
        st.exchange(soci::use(actIDStrKey));
        st.define_and_bind();
        st.execute(true);
    }
    {
        auto timer = db.getDeleteTimer("signer");
        auto prep =
            db.getPreparedStatement("DELETE from signers where accountid= :v1");
        auto& st = prep.statement();
        st.exchange(soci::use(actIDStrKey));
        st.define_and_bind();
        st.execute(true);
    }
    delta.deleteEntry(key);
}
bool
CreateAccountOpFrame::doApply(medida::MetricsRegistry& metrics,
                              LedgerDelta& delta, LedgerManager& ledgerManager)
{
    AccountFrame::pointer destAccount;

    Database& db = ledgerManager.getDatabase();

    destAccount = AccountFrame::loadAccount(mCreateAccount.destination, db);
    if (!destAccount)
    {
        if (mCreateAccount.startingBalance < ledgerManager.getMinBalance(0))
        { // not over the minBalance to make an account
            metrics.NewMeter({"op-create-account", "failure", "low-reserve"},
                             "operation").Mark();
            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
                metrics.NewMeter({"op-create-account", "failure", "underfunded"},
                                 "operation").Mark();
                innerResult().code(CREATE_ACCOUNT_UNDERFUNDED);
                return false;
            }

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

            destAccount = make_shared<AccountFrame>(mCreateAccount.destination);
            destAccount->getAccount().seqNum =
                delta.getHeaderFrame().getStartingSequenceNumber();
            destAccount->getAccount().balance = mCreateAccount.startingBalance;

            destAccount->storeAdd(delta, db);

            metrics.NewMeter({"op-create-account", "success", "apply"},
                             "operation").Mark();
            innerResult().code(CREATE_ACCOUNT_SUCCESS);
            return true;
        }
    }
    else
    {
        metrics.NewMeter({"op-create-account", "failure", "already-exist"},
                         "operation").Mark();
        innerResult().code(CREATE_ACCOUNT_ALREADY_EXIST);
        return false;
    }
}
示例#5
0
void
OfferFrame::storeDelete(LedgerDelta& delta, Database& db, LedgerKey const& key)
{
    auto timer = db.getDeleteTimer("offer");

    db.getSession() << "DELETE FROM offers WHERE offerid=:s",
        use(key.offer().offerID);

    delta.deleteEntry(key);
}
示例#6
0
void
OfferFrame::storeDelete(LedgerDelta& delta, Database& db, LedgerKey const& key)
{
    auto timer = db.getDeleteTimer("offer");
    auto prep = db.getPreparedStatement("DELETE FROM offers WHERE offerid=:s");
    auto& st = prep.statement();
    st.exchange(use(key.offer().offerID));
    st.define_and_bind();
    st.execute(true);
    delta.deleteEntry(key);
}
示例#7
0
void
TrustFrame::storeDelete(LedgerDelta& delta, Database& db, LedgerKey const& key)
{
    flushCachedEntry(key, db);

    std::string actIDStrKey, issuerStrKey, assetCode;
    getKeyFields(key, actIDStrKey, issuerStrKey, assetCode);

    auto timer = db.getDeleteTimer("trust");
    db.getSession() << "DELETE FROM trustlines "
                       "WHERE accountid=:v1 AND issuer=:v2 AND assetcode=:v3",
        use(actIDStrKey), use(issuerStrKey), use(assetCode);

    delta.deleteEntry(key);
}
示例#8
0
void
TrustFrame::storeAdd(LedgerDelta& delta, Database& db)
{
    if (!isValid())
    {
        throw std::runtime_error("Invalid TrustEntry");
    }

    auto key = getKey();
    flushCachedEntry(key, db);

    if (mIsIssuer)
        return;

    touch(delta);

    std::string actIDStrKey, issuerStrKey, assetCode;
    unsigned int assetType = getKey().trustLine().asset.type();
    getKeyFields(getKey(), actIDStrKey, issuerStrKey, assetCode);

    auto prep = db.getPreparedStatement(
        "INSERT INTO trustlines "
        "(accountid, assettype, issuer, assetcode, balance, tlimit, flags, "
        "lastmodified) "
        "VALUES (:v1, :v2, :v3, :v4, :v5, :v6, :v7, :v8)");
    auto& st = prep.statement();
    st.exchange(use(actIDStrKey));
    st.exchange(use(assetType));
    st.exchange(use(issuerStrKey));
    st.exchange(use(assetCode));
    st.exchange(use(mTrustLine.balance));
    st.exchange(use(mTrustLine.limit));
    st.exchange(use(mTrustLine.flags));
    st.exchange(use(getLastModified()));
    st.define_and_bind();
    {
        auto timer = db.getInsertTimer("trust");
        st.execute(true);
    }

    if (st.get_affected_rows() != 1)
    {
        throw std::runtime_error("Could not update data in SQL");
    }

    delta.addEntry(*this);
}
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;
    }
}
示例#10
0
void
TrustFrame::storeChange(LedgerDelta& delta, Database& db)
{
    if (!isValid())
    {
        throw std::runtime_error("Invalid TrustEntry");
    }

    auto key = getKey();
    flushCachedEntry(key, db);

    if (mIsIssuer)
        return;

    touch(delta);

    std::string actIDStrKey, issuerStrKey, assetCode;
    getKeyFields(key, actIDStrKey, issuerStrKey, assetCode);

    auto prep = db.getPreparedStatement(
        "UPDATE trustlines "
        "SET balance=:b, tlimit=:tl, flags=:a, lastmodified=:lm "
        "WHERE accountid=:v1 AND issuer=:v2 AND assetcode=:v3");
    auto& st = prep.statement();
    st.exchange(use(mTrustLine.balance));
    st.exchange(use(mTrustLine.limit));
    st.exchange(use(mTrustLine.flags));
    st.exchange(use(getLastModified()));
    st.exchange(use(actIDStrKey));
    st.exchange(use(issuerStrKey));
    st.exchange(use(assetCode));
    st.define_and_bind();
    {
        auto timer = db.getUpdateTimer("trust");
        st.execute(true);
    }
    if (st.get_affected_rows() != 1)
    {
        throw std::runtime_error("Could not update data in SQL");
    }

    delta.modEntry(*this);
}
void
TransactionFrame::storeTransaction(LedgerManager& ledgerManager,
                                   LedgerDelta const& delta, int txindex,
                                   SHA256& resultHasher) const
{
    auto txBytes(xdr::xdr_to_opaque(mEnvelope));
    auto txResultBytes(xdr::xdr_to_opaque(getResultPair()));

    resultHasher.add(txResultBytes);

    std::string txBody = base64::encode(
        reinterpret_cast<const unsigned char*>(txBytes.data()), txBytes.size());

    std::string txResult = base64::encode(
        reinterpret_cast<const unsigned char*>(txResultBytes.data()),
        txResultBytes.size());

    xdr::opaque_vec<> txMeta(delta.getTransactionMeta());

    std::string meta = base64::encode(
        reinterpret_cast<const unsigned char*>(txMeta.data()), txMeta.size());

    string txIDString(binToHex(getContentsHash()));

    auto timer = ledgerManager.getDatabase().getInsertTimer("txhistory");
    soci::statement st =
        (ledgerManager.getDatabase().getSession().prepare
             << "INSERT INTO txhistory (txid, ledgerseq, txindex, txbody, "
                "txresult, txmeta) VALUES "
                "(:id,:seq,:txindex,:txb,:txres,:meta)",
         soci::use(txIDString),
         soci::use(ledgerManager.getCurrentLedgerHeader().ledgerSeq),
         soci::use(txindex), soci::use(txBody), soci::use(txResult),
         soci::use(meta));

    st.execute(true);

    if (st.get_affected_rows() != 1)
    {
        throw std::runtime_error("Could not update data in SQL");
    }
}
示例#12
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);
}
示例#13
0
void
AccountFrame::storeDelete(LedgerDelta& delta, Database& db,
                          LedgerKey const& key)
{
    flushCachedEntry(key, db);

    std::string actIDStrKey = PubKeyUtils::toStrKey(key.account().accountID);
    soci::session& session = db.getSession();
    {
        auto timer = db.getDeleteTimer("account");
        session << "DELETE from accounts where accountid= :v1",
            soci::use(actIDStrKey);
    }
    {
        auto timer = db.getDeleteTimer("signer");
        session << "DELETE from signers where accountid= :v1",
            soci::use(actIDStrKey);
    }
    delta.deleteEntry(key);
}
示例#14
0
void
OfferFrame::storeChange(LedgerDelta& delta, Database& db) const
{

    auto timer = db.getUpdateTimer("offer");

    soci::statement st =
        (db.getSession().prepare << "UPDATE offers SET amount=:a, pricen=:n, "
                                    "priced=:D, price=:p WHERE offerid=:s",
         use(mOffer.amount), use(mOffer.price.n), use(mOffer.price.d),
         use(computePrice()), use(mOffer.offerID));

    st.execute(true);

    if (st.get_affected_rows() != 1)
    {
        throw std::runtime_error("could not update SQL");
    }

    delta.modEntry(*this);
}
void
TransactionFrame::prepareResult(LedgerDelta& delta,
                                LedgerManager& ledgerManager)
{
    Database& db = ledgerManager.getDatabase();
    int64_t fee = getResult().feeCharged;

    if (fee > 0)
    {
        int64_t avail = mSigningAccount->getAccount().balance;
        if (avail < fee)
        {
            // take all their balance to be safe
            fee = avail;
        }
        mSigningAccount->setSeqNum(mEnvelope.tx.seqNum);
        mSigningAccount->getAccount().balance -= fee;
        delta.getHeader().feePool += fee;

        mSigningAccount->storeChange(delta, db);
    }
}
示例#16
0
void
AccountFrame::storeUpdate(LedgerDelta& delta, Database& db, bool insert)
{
    assert(isValid());

    touch(delta);

    flushCachedEntry(db);

    std::string actIDStrKey = PubKeyUtils::toStrKey(mAccountEntry.accountID);
    std::string sql;

    if (insert)
    {
        sql = std::string(
            "INSERT INTO accounts ( accountid, balance, seqnum, "
            "numsubentries, inflationdest, homedomain, thresholds, flags, "
            "lastmodified ) "
            "VALUES ( :id, :v1, :v2, :v3, :v4, :v5, :v6, :v7, :v8 )");
    }
    else
    {
        sql = std::string(
            "UPDATE accounts SET balance = :v1, seqnum = :v2, "
            "numsubentries = :v3, "
            "inflationdest = :v4, homedomain = :v5, thresholds = :v6, "
            "flags = :v7, lastmodified = :v8 WHERE accountid = :id");
    }

    auto prep = db.getPreparedStatement(sql);

    soci::indicator inflation_ind = soci::i_null;
    string inflationDestStrKey;

    if (mAccountEntry.inflationDest)
    {
        inflationDestStrKey =
            PubKeyUtils::toStrKey(*mAccountEntry.inflationDest);
        inflation_ind = soci::i_ok;
    }

    string thresholds(bn::encode_b64(mAccountEntry.thresholds));

    {
        soci::statement& st = prep.statement();
        st.exchange(use(actIDStrKey, "id"));
        st.exchange(use(mAccountEntry.balance, "v1"));
        st.exchange(use(mAccountEntry.seqNum, "v2"));
        st.exchange(use(mAccountEntry.numSubEntries, "v3"));
        st.exchange(use(inflationDestStrKey, inflation_ind, "v4"));
        string homeDomain(mAccountEntry.homeDomain);
        st.exchange(use(homeDomain, "v5"));
        st.exchange(use(thresholds, "v6"));
        st.exchange(use(mAccountEntry.flags, "v7"));
        st.exchange(use(getLastModified(), "v8"));
        st.define_and_bind();
        {
            auto timer = insert ? db.getInsertTimer("account")
                                : db.getUpdateTimer("account");
            st.execute(true);
        }

        if (st.get_affected_rows() != 1)
        {
            throw std::runtime_error("Could not update data in SQL");
        }
        if (insert)
        {
            delta.addEntry(*this);
        }
        else
        {
            delta.modEntry(*this);
        }
    }

    if (mUpdateSigners)
    {
        applySigners(db);
    }
}
示例#17
0
static CreateOfferResult
applyCreateOfferHelper(Application& app, LedgerDelta& delta, uint64 offerId,
                       SecretKey& source, Currency& takerGets,
                       Currency& takerPays, Price const& price, int64_t amount,
                       SequenceNumber seq)
{
    uint64_t expectedOfferID = delta.getHeaderFrame().getLastGeneratedID() + 1;
    if (offerId != 0)
    {
        expectedOfferID = offerId;
    }

    TransactionFramePtr txFrame;

    txFrame = createOfferOp(offerId, source, takerGets, takerPays, price,
                            amount, seq);

    txFrame->apply(delta, app);

    checkTransaction(*txFrame);

    auto& results = txFrame->getResult().result.results();

    REQUIRE(results.size() == 1);

    auto& createOfferResult = results[0].tr().createOfferResult();

    if (createOfferResult.code() == CREATE_OFFER_SUCCESS)
    {
        OfferFrame offer;

        auto& offerResult = createOfferResult.success().offer;
        auto& offerEntry = offer.getOffer();

        switch (offerResult.effect())
        {
        case CREATE_OFFER_CREATED:
        case CREATE_OFFER_UPDATED:
            REQUIRE(OfferFrame::loadOffer(source.getPublicKey(),
                                          expectedOfferID, offer,
                                          app.getDatabase()));
            REQUIRE(memcmp(&offerEntry, &offerResult.offer(),
                           sizeof(OfferEntry)) == 0);
            REQUIRE(offerEntry.price == price);
            REQUIRE(memcmp(&offerEntry.takerGets, &takerGets,
                           sizeof(Currency)) == 0);
            REQUIRE(memcmp(&offerEntry.takerPays, &takerPays,
                           sizeof(Currency)) == 0);
            break;
        case CREATE_OFFER_DELETED:
            REQUIRE(!OfferFrame::loadOffer(source.getPublicKey(),
                                           expectedOfferID, offer,
                                           app.getDatabase()));
            break;
        default:
            abort();
        }
    }

    return createOfferResult;
}
示例#18
0
void
OfferFrame::storeAdd(LedgerDelta& delta, Database& db) const
{
    std::string actIDStrKey = PubKeyUtils::toStrKey(mOffer.sellerID);

    soci::statement st(db.getSession().prepare << "select 1");

    auto timer = db.getInsertTimer("offer");

    unsigned int sellingType = mOffer.selling.type();
    unsigned int buyingType = mOffer.buying.type();
    std::string sellingIssuerStrKey, buyingIssuerStrKey;
    std::string sellingAssetCode, buyingAssetCode;

    if(sellingType == ASSET_TYPE_CREDIT_ALPHANUM4)
    {
        sellingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.selling.alphaNum4().issuer); 
        assetCodeToStr(mOffer.selling.alphaNum4().assetCode,
            sellingAssetCode);
       
    } else if(sellingType == ASSET_TYPE_CREDIT_ALPHANUM12)
    {
        sellingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.selling.alphaNum12().issuer);
        assetCodeToStr(mOffer.selling.alphaNum12().assetCode,
            sellingAssetCode);
    }

    if(buyingType == ASSET_TYPE_CREDIT_ALPHANUM4)
    {
        buyingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.buying.alphaNum4().issuer);
        assetCodeToStr(mOffer.buying.alphaNum4().assetCode,
            buyingAssetCode);

    } else if(buyingType == ASSET_TYPE_CREDIT_ALPHANUM12)
    {
        buyingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.buying.alphaNum12().issuer);
        assetCodeToStr(mOffer.buying.alphaNum12().assetCode,
            buyingAssetCode);
    }
    
   
    
    st = (db.getSession().prepare
        << "INSERT INTO offers (sellerid,offerid,"
        "sellingassettype,sellingassetcode,sellingissuer,"
        "buyingassettype,buyingassetcode,buyingissuer,"
        "amount,pricen,priced,price,flags) VALUES "
        "(:v1,:v2,:v3,:v4,:v5,:v6,:v7,:v8,:v9,:v10,:v11,:v12,:v13)",
        use(actIDStrKey), use(mOffer.offerID), use(sellingType), 
        use(sellingAssetCode),
        use(sellingIssuerStrKey), use(buyingType), use(buyingAssetCode),
        use(buyingIssuerStrKey), use(mOffer.amount), use(mOffer.price.n),
        use(mOffer.price.d), use(computePrice()), use(mOffer.flags));
    st.execute(true);
    

    if (st.get_affected_rows() != 1)
    {
        throw std::runtime_error("could not update SQL");
    }

    delta.addEntry(*this);
}
示例#19
0
void
OfferFrame::storeUpdateHelper(LedgerDelta& delta, Database& db, bool insert)
{
    touch(delta);

    if (!isValid())
    {
        throw std::runtime_error("Invalid asset");
    }

    std::string actIDStrKey = PubKeyUtils::toStrKey(mOffer.sellerID);

    unsigned int sellingType = mOffer.selling.type();
    unsigned int buyingType = mOffer.buying.type();
    std::string sellingIssuerStrKey, buyingIssuerStrKey;
    std::string sellingAssetCode, buyingAssetCode;
    soci::indicator selling_ind = soci::i_null, buying_ind = soci::i_null;

    if (sellingType == ASSET_TYPE_CREDIT_ALPHANUM4)
    {
        sellingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.selling.alphaNum4().issuer);
        assetCodeToStr(mOffer.selling.alphaNum4().assetCode, sellingAssetCode);
        selling_ind = soci::i_ok;
    }
    else if (sellingType == ASSET_TYPE_CREDIT_ALPHANUM12)
    {
        sellingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.selling.alphaNum12().issuer);
        assetCodeToStr(mOffer.selling.alphaNum12().assetCode, sellingAssetCode);
        selling_ind = soci::i_ok;
    }

    if (buyingType == ASSET_TYPE_CREDIT_ALPHANUM4)
    {
        buyingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.buying.alphaNum4().issuer);
        assetCodeToStr(mOffer.buying.alphaNum4().assetCode, buyingAssetCode);
        buying_ind = soci::i_ok;
    }
    else if (buyingType == ASSET_TYPE_CREDIT_ALPHANUM12)
    {
        buyingIssuerStrKey =
            PubKeyUtils::toStrKey(mOffer.buying.alphaNum12().issuer);
        assetCodeToStr(mOffer.buying.alphaNum12().assetCode, buyingAssetCode);
        buying_ind = soci::i_ok;
    }

    string sql;

    if (insert)
    {
        sql = "INSERT INTO offers (sellerid,offerid,"
              "sellingassettype,sellingassetcode,sellingissuer,"
              "buyingassettype,buyingassetcode,buyingissuer,"
              "amount,pricen,priced,price,flags,lastmodified) VALUES "
              "(:sid,:oid,:sat,:sac,:si,:bat,:bac,:bi,:a,:pn,:pd,:p,:f,:l)";
    }
    else
    {
        sql = "UPDATE offers SET sellingassettype=:sat "
              ",sellingassetcode=:sac,sellingissuer=:si,"
              "buyingassettype=:bat,buyingassetcode=:bac,buyingissuer=:bi,"
              "amount=:a,pricen=:pn,priced=:pd,price=:p,flags=:f,"
              "lastmodified=:l WHERE offerid=:oid";
    }

    auto prep = db.getPreparedStatement(sql);
    auto& st = prep.statement();

    if (insert)
    {
        st.exchange(use(actIDStrKey, "sid"));
    }
    st.exchange(use(mOffer.offerID, "oid"));
    st.exchange(use(sellingType, "sat"));
    st.exchange(use(sellingAssetCode, selling_ind, "sac"));
    st.exchange(use(sellingIssuerStrKey, selling_ind, "si"));
    st.exchange(use(buyingType, "bat"));
    st.exchange(use(buyingAssetCode, buying_ind, "bac"));
    st.exchange(use(buyingIssuerStrKey, buying_ind, "bi"));
    st.exchange(use(mOffer.amount, "a"));
    st.exchange(use(mOffer.price.n, "pn"));
    st.exchange(use(mOffer.price.d, "pd"));
    auto price = computePrice();
    st.exchange(use(price, "p"));
    st.exchange(use(mOffer.flags, "f"));
    st.exchange(use(getLastModified(), "l"));
    st.define_and_bind();

    auto timer =
        insert ? db.getInsertTimer("offer") : db.getUpdateTimer("offer");
    st.execute(true);

    if (st.get_affected_rows() != 1)
    {
        throw std::runtime_error("could not update SQL");
    }

    if (insert)
    {
        delta.addEntry(*this);
    }
    else
    {
        delta.modEntry(*this);
    }
}
bool
ManageDataOpFrame::doApply(Application& app, LedgerDelta& delta,
                           LedgerManager& ledgerManager)
{
    if (app.getLedgerManager().getCurrentLedgerVersion() == 3)
    {
        throw std::runtime_error(
            "MANAGE_DATA not supported on ledger version 3");
    }

    Database& db = ledgerManager.getDatabase();

    auto dataFrame =
        DataFrame::loadData(mSourceAccount->getID(), mManageData.dataName, db);

    if (mManageData.dataValue)
    {
        if (!dataFrame)
        { // create a new data entry

            if (!mSourceAccount->addNumEntries(1, ledgerManager))
            {
                app.getMetrics()
                    .NewMeter({"op-manage-data", "invalid", "low reserve"},
                              "operation")
                    .Mark();
                innerResult().code(MANAGE_DATA_LOW_RESERVE);
                return false;
            }

            dataFrame = std::make_shared<DataFrame>();
            dataFrame->getData().accountID = mSourceAccount->getID();
            dataFrame->getData().dataName = mManageData.dataName;
            dataFrame->getData().dataValue = *mManageData.dataValue;

            dataFrame->storeAdd(delta, db);
            mSourceAccount->storeChange(delta, db);
        }
        else
        { // modify an existing entry
            delta.recordEntry(*dataFrame);
            dataFrame->getData().dataValue = *mManageData.dataValue;
            dataFrame->storeChange(delta, db);
        }
    }
    else
    { // delete an existing piece of data

        if (!dataFrame)
        {
            app.getMetrics()
                .NewMeter({"op-manage-data", "invalid", "not-found"},
                          "operation")
                .Mark();
            innerResult().code(MANAGE_DATA_NAME_NOT_FOUND);
            return false;
        }
        delta.recordEntry(*dataFrame);
        mSourceAccount->addNumEntries(-1, ledgerManager);
        mSourceAccount->storeChange(delta, db);
        dataFrame->storeDelete(delta, db);
    }

    innerResult().code(MANAGE_DATA_SUCCESS);

    app.getMetrics()
        .NewMeter({"op-manage-data", "success", "apply"}, "operation")
        .Mark();
    return true;
}
示例#21
0
void
AccountFrame::storeUpdate(LedgerDelta& delta, Database& db, bool insert) const
{
    flushCachedEntry(db);

    std::string actIDStrKey = PubKeyUtils::toStrKey(mAccountEntry.accountID);
    std::string sql;

    if (insert)
    {
        sql = std::string(
            "INSERT INTO accounts ( accountid, balance, seqnum, "
            "numsubentries, inflationdest, homedomain, thresholds, flags) "
            "VALUES ( :id, :v1, :v2, :v3, :v4, :v5, :v6, :v7 )");
    }
    else
    {
        sql = std::string(
            "UPDATE accounts SET balance = :v1, seqnum = :v2, "
            "numsubentries = :v3, "
            "inflationdest = :v4, homedomain = :v5, thresholds = :v6, "
            "flags = :v7 WHERE accountid = :id");
    }

    auto prep = db.getPreparedStatement(sql);

    soci::indicator inflation_ind = soci::i_null;
    string inflationDestStrKey;

    if (mAccountEntry.inflationDest)
    {
        inflationDestStrKey =
            PubKeyUtils::toStrKey(*mAccountEntry.inflationDest);
        inflation_ind = soci::i_ok;
    }

    string thresholds(bn::encode_b64(mAccountEntry.thresholds));

    {
        soci::statement& st = prep.statement();
        st.exchange(use(actIDStrKey, "id"));
        st.exchange(use(mAccountEntry.balance, "v1"));
        st.exchange(use(mAccountEntry.seqNum, "v2"));
        st.exchange(use(mAccountEntry.numSubEntries, "v3"));
        st.exchange(use(inflationDestStrKey, inflation_ind, "v4"));
        st.exchange(use(string(mAccountEntry.homeDomain), "v5"));
        st.exchange(use(thresholds, "v6"));
        st.exchange(use(mAccountEntry.flags, "v7"));
        st.define_and_bind();
        {
            auto timer = insert ? db.getInsertTimer("account")
                                : db.getUpdateTimer("account");
            st.execute(true);
        }

        if (st.get_affected_rows() != 1)
        {
            throw std::runtime_error("Could not update data in SQL");
        }
        if (insert)
        {
            delta.addEntry(*this);
        }
        else
        {
            delta.modEntry(*this);
        }
    }

    if (mUpdateSigners)
    {
        // instead separate signatures from account, just like offers are
        // separate entities
        AccountFrame::pointer startAccountFrame;
        startAccountFrame = loadAccount(getID(), db);
        if (!startAccountFrame)
        {
            throw runtime_error("could not load account!");
        }
        AccountEntry& startAccount = startAccountFrame->mAccountEntry;

        // deal with changes to Signers
        if (mAccountEntry.signers.size() < startAccount.signers.size())
        { // some signers were removed
            for (auto const& startSigner : startAccount.signers)
            {
                bool found = false;
                for (auto const& finalSigner : mAccountEntry.signers)
                {
                    if (finalSigner.pubKey == startSigner.pubKey)
                    {
                        if (finalSigner.weight != startSigner.weight)
                        {
                            std::string signerStrKey =
                                PubKeyUtils::toStrKey(finalSigner.pubKey);
                            {
                                auto timer = db.getUpdateTimer("signer");
                                db.getSession()
                                    << "UPDATE signers set weight=:v1 where "
                                       "accountid=:v2 and publickey=:v3",
                                    use(finalSigner.weight), use(actIDStrKey),
                                    use(signerStrKey);
                            }
                        }
                        found = true;
                        break;
                    }
                }
                if (!found)
                { // delete signer
                    std::string signerStrKey =
                        PubKeyUtils::toStrKey(startSigner.pubKey);

                    soci::statement st =
                        (db.getSession().prepare << "DELETE from signers where "
                                                    "accountid=:v2 and "
                                                    "publickey=:v3",
                         use(actIDStrKey), use(signerStrKey));

                    {
                        auto timer = db.getDeleteTimer("signer");
                        st.execute(true);
                    }

                    if (st.get_affected_rows() != 1)
                    {
                        throw std::runtime_error(
                            "Could not update data in SQL");
                    }
                }
            }
        }
        else
        { // signers added or the same
            for (auto const& finalSigner : mAccountEntry.signers)
            {
                bool found = false;
                for (auto const& startSigner : startAccount.signers)
                {
                    if (finalSigner.pubKey == startSigner.pubKey)
                    {
                        if (finalSigner.weight != startSigner.weight)
                        {
                            std::string signerStrKey =
                                PubKeyUtils::toStrKey(finalSigner.pubKey);

                            soci::statement st =
                                (db.getSession().prepare
                                     << "UPDATE signers set weight=:v1 where "
                                        "accountid=:v2 and publickey=:v3",
                                 use(finalSigner.weight), use(actIDStrKey),
                                 use(signerStrKey));

                            st.execute(true);

                            if (st.get_affected_rows() != 1)
                            {
                                throw std::runtime_error(
                                    "Could not update data in SQL");
                            }
                        }
                        found = true;
                        break;
                    }
                }
                if (!found)
                { // new signer
                    std::string signerStrKey =
                        PubKeyUtils::toStrKey(finalSigner.pubKey);

                    soci::statement st = (db.getSession().prepare
                                              << "INSERT INTO signers "
                                                 "(accountid,publickey,weight) "
                                                 "VALUES (:v1,:v2,:v3)",
                                          use(actIDStrKey), use(signerStrKey),
                                          use(finalSigner.weight));

                    st.execute(true);

                    if (st.get_affected_rows() != 1)
                    {
                        throw std::runtime_error(
                            "Could not update data in SQL");
                    }
                }
            }
        }

        // Flush again to ensure changed signers are reloaded.
        flushCachedEntry(db);
    }
}