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(); }
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; } }
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); }
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); }
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); }
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; } }
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"); } }
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); }
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); }
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); } }
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); } }
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; }
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); }
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; }
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); } }