std::shared_ptr<LedgerEntry const> LedgerStateRoot::Impl::loadOffer(LedgerKey const& key) const { uint64_t offerID = key.offer().offerID; std::string actIDStrKey = KeyUtils::toStrKey(key.offer().sellerID); std::string sql = "SELECT sellerid, offerid, " "sellingassettype, sellingassetcode, sellingissuer, " "buyingassettype, buyingassetcode, buyingissuer, " "amount, pricen, priced, flags, lastmodified " "FROM offers " "WHERE sellerid= :id AND offerid= :offerid"; auto prep = mDatabase.getPreparedStatement(sql); auto& st = prep.statement(); st.exchange(soci::use(actIDStrKey)); st.exchange(soci::use(offerID)); std::vector<LedgerEntry> offers; { auto timer = mDatabase.getSelectTimer("offer"); offers = loadOffers(prep); } return offers.size() == 0 ? nullptr : std::make_shared<LedgerEntry const>(offers.front()); }
OfferFrame::pointer OfferFrame::loadOffer(AccountID const& sellerID, uint64_t offerID, Database& db, LedgerDelta* delta) { OfferFrame::pointer retOffer; std::string actIDStrKey = KeyUtils::toStrKey(sellerID); std::string sql = offerColumnSelector; sql += " WHERE sellerid = :id AND offerid = :offerid"; auto prep = db.getPreparedStatement(sql); auto& st = prep.statement(); st.exchange(use(actIDStrKey)); st.exchange(use(offerID)); auto timer = db.getSelectTimer("offer"); loadOffers(prep, [&retOffer](LedgerEntry const& offer) { retOffer = make_shared<OfferFrame>(offer); }); if (delta && retOffer) { delta->recordEntry(*retOffer); } return retOffer; }
std::unordered_map<AccountID, std::vector<OfferFrame::pointer>> OfferFrame::loadAllOffers(Database& db) { std::unordered_map<AccountID, std::vector<OfferFrame::pointer>> retOffers; std::string sql = offerColumnSelector; sql += " ORDER BY sellerid"; auto prep = db.getPreparedStatement(sql); auto timer = db.getSelectTimer("offer"); loadOffers(prep, [&retOffers](LedgerEntry const& of) { auto& thisUserOffers = retOffers[of.data.offer().sellerID]; thisUserOffers.emplace_back(make_shared<OfferFrame>(of)); }); return retOffers; }
std::vector<LedgerEntry> LedgerStateRoot::Impl::loadAllOffers() const { std::string sql = "SELECT sellerid, offerid, " "sellingassettype, sellingassetcode, sellingissuer, " "buyingassettype, buyingassetcode, buyingissuer, " "amount, pricen, priced, flags, lastmodified " "FROM offers"; auto prep = mDatabase.getPreparedStatement(sql); std::vector<LedgerEntry> offers; { auto timer = mDatabase.getSelectTimer("offer"); offers = loadOffers(prep); } return offers; }
// Note: This function is currently only used in AllowTrustOpFrame, which means // the asset parameter will never satisfy asset.type() == ASSET_TYPE_NATIVE. As // a consequence, I have not implemented that possibility so this function // throws in that case. std::vector<LedgerEntry> LedgerStateRoot::Impl::loadOffersByAccountAndAsset(AccountID const& accountID, Asset const& asset) const { std::string sql = "SELECT sellerid, offerid, " "sellingassettype, sellingassetcode, sellingissuer, " "buyingassettype, buyingassetcode, buyingissuer, " "amount, pricen, priced, flags, lastmodified " "FROM offers "; sql += " WHERE sellerid = :acc" " AND ((sellingassetcode = :code AND sellingissuer = :iss)" " OR (buyingassetcode = :code AND buyingissuer = :iss))"; std::string accountStr = KeyUtils::toStrKey(accountID); std::string assetCode; std::string assetIssuer; if (asset.type() == ASSET_TYPE_CREDIT_ALPHANUM4) { assetCodeToStr(asset.alphaNum4().assetCode, assetCode); assetIssuer = KeyUtils::toStrKey(asset.alphaNum4().issuer); } else if (asset.type() == ASSET_TYPE_CREDIT_ALPHANUM12) { assetCodeToStr(asset.alphaNum12().assetCode, assetCode); assetIssuer = KeyUtils::toStrKey(asset.alphaNum12().issuer); } else { throw std::runtime_error("Invalid asset type"); } auto prep = mDatabase.getPreparedStatement(sql); auto& st = prep.statement(); st.exchange(soci::use(accountStr, "acc")); st.exchange(soci::use(assetCode, "code")); st.exchange(soci::use(assetIssuer, "iss")); std::vector<LedgerEntry> offers; { auto timer = mDatabase.getSelectTimer("offer"); offers = loadOffers(prep); } return offers; }
void OfferFrame::loadOffers(AccountID const& accountID, std::vector<OfferFrame::pointer>& retOffers, Database& db) { std::string actIDStrKey; actIDStrKey = KeyUtils::toStrKey(accountID); std::string sql = offerColumnSelector; sql += " WHERE sellerid = :id"; auto prep = db.getPreparedStatement(sql); auto& st = prep.statement(); st.exchange(use(actIDStrKey)); auto timer = db.getSelectTimer("offer"); loadOffers(prep, [&retOffers](LedgerEntry const& of) { retOffers.emplace_back(make_shared<OfferFrame>(of)); }); }
void OfferFrame::loadOffers(AccountID const& accountID, std::vector<OfferFrame::pointer>& retOffers, Database& db) { soci::session& session = db.getSession(); std::string actIDStrKey; actIDStrKey = PubKeyUtils::toStrKey(accountID); soci::details::prepare_temp_type sql = (session.prepare << offerColumnSelector << " WHERE sellerid=:id", use(actIDStrKey)); auto timer = db.getSelectTimer("offer"); loadOffers(sql, [&retOffers](LedgerEntry const& of) { retOffers.emplace_back(make_shared<OfferFrame>(of)); }); }
OfferFrame::pointer OfferFrame::loadOffer(AccountID const& sellerID, uint64_t offerID, Database& db) { OfferFrame::pointer retOffer; std::string actIDStrKey; actIDStrKey = PubKeyUtils::toStrKey(sellerID); soci::session& session = db.getSession(); soci::details::prepare_temp_type sql = (session.prepare << offerColumnSelector << " where sellerid=:id and offerid=:offerid", use(actIDStrKey), use(offerID)); auto timer = db.getSelectTimer("offer"); loadOffers(sql, [&retOffer](LedgerEntry const& offer) { retOffer = make_shared<OfferFrame>(offer); }); return retOffer; }
void OfferFrame::loadBestOffers(size_t numOffers, size_t offset, Asset const& selling, Asset const& buying, vector<OfferFrame::pointer>& retOffers, Database& db) { std::string sql = offerColumnSelector; std::string sellingAssetCode, sellingIssuerStrKey; std::string buyingAssetCode, buyingIssuerStrKey; bool useSellingAsset = false; bool useBuyingAsset = false; if (selling.type() == ASSET_TYPE_NATIVE) { sql += " WHERE sellingassettype = 0"; } else { if (selling.type() == ASSET_TYPE_CREDIT_ALPHANUM4) { assetCodeToStr(selling.alphaNum4().assetCode, sellingAssetCode); sellingIssuerStrKey = PubKeyUtils::toStrKey(selling.alphaNum4().issuer); } else if (selling.type() == ASSET_TYPE_CREDIT_ALPHANUM12) { assetCodeToStr(selling.alphaNum12().assetCode, sellingAssetCode); sellingIssuerStrKey = PubKeyUtils::toStrKey(selling.alphaNum12().issuer); } else { throw std::runtime_error("unknown asset type"); } useSellingAsset = true; sql += " WHERE sellingassetcode = :pcur AND sellingissuer = :pi"; } if (buying.type() == ASSET_TYPE_NATIVE) { sql += " AND buyingassettype = 0"; } else { if (buying.type() == ASSET_TYPE_CREDIT_ALPHANUM4) { assetCodeToStr(buying.alphaNum4().assetCode, buyingAssetCode); buyingIssuerStrKey = PubKeyUtils::toStrKey(buying.alphaNum4().issuer); } else if (buying.type() == ASSET_TYPE_CREDIT_ALPHANUM12) { assetCodeToStr(buying.alphaNum12().assetCode, buyingAssetCode); buyingIssuerStrKey = PubKeyUtils::toStrKey(buying.alphaNum12().issuer); } else { throw std::runtime_error("unknown asset type"); } useBuyingAsset = true; sql += " AND buyingassetcode = :gcur AND buyingissuer = :gi"; } // price is an approximation of the actual n/d (truncated math, 15 digits) // ordering by offerid gives precendence to older offers for fairness sql += " ORDER BY price, offerid LIMIT :n OFFSET :o"; auto prep = db.getPreparedStatement(sql); auto& st = prep.statement(); if (useSellingAsset) { st.exchange(use(sellingAssetCode)); st.exchange(use(sellingIssuerStrKey)); } if (useBuyingAsset) { st.exchange(use(buyingAssetCode)); st.exchange(use(buyingIssuerStrKey)); } st.exchange(use(numOffers)); st.exchange(use(offset)); auto timer = db.getSelectTimer("offer"); loadOffers(prep, [&retOffers](LedgerEntry const& of) { retOffers.emplace_back(make_shared<OfferFrame>(of)); }); }
std::list<LedgerEntry>::const_iterator LedgerStateRoot::Impl::loadBestOffers(std::list<LedgerEntry>& offers, Asset const& buying, Asset const& selling, size_t numOffers, size_t offset) const { std::string sql = "SELECT sellerid, offerid, " "sellingassettype, sellingassetcode, sellingissuer, " "buyingassettype, buyingassetcode, buyingissuer, " "amount, pricen, priced, flags, lastmodified " "FROM offers "; std::string sellingAssetCode, sellingIssuerStrKey; if (selling.type() == ASSET_TYPE_NATIVE) { sql += " WHERE sellingassettype = 0 AND sellingissuer IS NULL"; } else { if (selling.type() == ASSET_TYPE_CREDIT_ALPHANUM4) { assetCodeToStr(selling.alphaNum4().assetCode, sellingAssetCode); sellingIssuerStrKey = KeyUtils::toStrKey(selling.alphaNum4().issuer); } else if (selling.type() == ASSET_TYPE_CREDIT_ALPHANUM12) { assetCodeToStr(selling.alphaNum12().assetCode, sellingAssetCode); sellingIssuerStrKey = KeyUtils::toStrKey(selling.alphaNum12().issuer); } else { throw std::runtime_error("unknown asset type"); } sql += " WHERE sellingassetcode = :sac AND sellingissuer = :si"; } std::string buyingAssetCode, buyingIssuerStrKey; if (buying.type() == ASSET_TYPE_NATIVE) { sql += " AND buyingassettype = 0 AND buyingissuer IS NULL"; } else { if (buying.type() == ASSET_TYPE_CREDIT_ALPHANUM4) { assetCodeToStr(buying.alphaNum4().assetCode, buyingAssetCode); buyingIssuerStrKey = KeyUtils::toStrKey(buying.alphaNum4().issuer); } else if (buying.type() == ASSET_TYPE_CREDIT_ALPHANUM12) { assetCodeToStr(buying.alphaNum12().assetCode, buyingAssetCode); buyingIssuerStrKey = KeyUtils::toStrKey(buying.alphaNum12().issuer); } else { throw std::runtime_error("unknown asset type"); } sql += " AND buyingassetcode = :bac AND buyingissuer = :bi"; } // price is an approximation of the actual n/d (truncated math, 15 digits) // ordering by offerid gives precendence to older offers for fairness sql += " ORDER BY price, offerid LIMIT :n OFFSET :o"; auto prep = mDatabase.getPreparedStatement(sql); auto& st = prep.statement(); if (selling.type() != ASSET_TYPE_NATIVE) { st.exchange(soci::use(sellingAssetCode, "sac")); st.exchange(soci::use(sellingIssuerStrKey, "si")); } if (buying.type() != ASSET_TYPE_NATIVE) { st.exchange(soci::use(buyingAssetCode, "bac")); st.exchange(soci::use(buyingIssuerStrKey, "bi")); } st.exchange(soci::use(numOffers, "n")); st.exchange(soci::use(offset, "o")); { auto timer = mDatabase.getSelectTimer("offer"); return loadOffers(prep, offers); } }
void OfferFrame::loadBestOffers(size_t numOffers, size_t offset, Asset const& selling, Asset const& buying, vector<OfferFrame::pointer>& retOffers, Database& db) { soci::session& session = db.getSession(); soci::details::prepare_temp_type sql = (session.prepare << offerColumnSelector); std::string sellingAssetCode, sellingIssuerStrKey; std::string buyingAssetCode, buyingIssuerStrKey; if (selling.type() == ASSET_TYPE_NATIVE) { sql << " WHERE sellingassettype=0"; } else { if(selling.type() == ASSET_TYPE_CREDIT_ALPHANUM4) { assetCodeToStr(selling.alphaNum4().assetCode, sellingAssetCode); sellingIssuerStrKey = PubKeyUtils::toStrKey(selling.alphaNum4().issuer); } else if(selling.type() == ASSET_TYPE_CREDIT_ALPHANUM12) { assetCodeToStr(selling.alphaNum12().assetCode, sellingAssetCode); sellingIssuerStrKey = PubKeyUtils::toStrKey(selling.alphaNum12().issuer); }else throw std::runtime_error("unknown asset type"); sql << " WHERE sellingassetcode=:pcur AND sellingissuer = :pi", use(sellingAssetCode), use(sellingIssuerStrKey); } if (buying.type() == ASSET_TYPE_NATIVE) { sql << " AND buyingassettype=0"; } else { if(buying.type() == ASSET_TYPE_CREDIT_ALPHANUM4) { assetCodeToStr(buying.alphaNum4().assetCode, buyingAssetCode); buyingIssuerStrKey = PubKeyUtils::toStrKey(buying.alphaNum4().issuer); } else if(buying.type() == ASSET_TYPE_CREDIT_ALPHANUM12) { assetCodeToStr(buying.alphaNum12().assetCode, buyingAssetCode); buyingIssuerStrKey = PubKeyUtils::toStrKey(buying.alphaNum12().issuer); }else throw std::runtime_error("unknown asset type"); sql << " AND buyingassetcode=:gcur AND buyingissuer = :gi", use(buyingAssetCode), use(buyingIssuerStrKey); } sql << " ORDER BY price,offerid LIMIT :n OFFSET :o", use(numOffers), use(offset); auto timer = db.getSelectTimer("offer"); loadOffers(sql, [&retOffers](LedgerEntry const& of) { retOffers.emplace_back(make_shared<OfferFrame>(of)); }); }