// 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::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); } }
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 LedgerStateRoot::Impl::insertOrUpdateOffer(LedgerEntry const& entry, bool isInsert) { auto const& offer = entry.data.offer(); std::string actIDStrKey = KeyUtils::toStrKey(offer.sellerID); unsigned int sellingType = offer.selling.type(); unsigned int buyingType = offer.buying.type(); std::string sellingIssuerStrKey, buyingIssuerStrKey; std::string sellingAssetCode, buyingAssetCode; soci::indicator selling_ind = soci::i_null, buying_ind = soci::i_null; double price = double(offer.price.n) / double(offer.price.d); if (sellingType == ASSET_TYPE_CREDIT_ALPHANUM4) { sellingIssuerStrKey = KeyUtils::toStrKey(offer.selling.alphaNum4().issuer); assetCodeToStr(offer.selling.alphaNum4().assetCode, sellingAssetCode); selling_ind = soci::i_ok; } else if (sellingType == ASSET_TYPE_CREDIT_ALPHANUM12) { sellingIssuerStrKey = KeyUtils::toStrKey(offer.selling.alphaNum12().issuer); assetCodeToStr(offer.selling.alphaNum12().assetCode, sellingAssetCode); selling_ind = soci::i_ok; } if (buyingType == ASSET_TYPE_CREDIT_ALPHANUM4) { buyingIssuerStrKey = KeyUtils::toStrKey(offer.buying.alphaNum4().issuer); assetCodeToStr(offer.buying.alphaNum4().assetCode, buyingAssetCode); buying_ind = soci::i_ok; } else if (buyingType == ASSET_TYPE_CREDIT_ALPHANUM12) { buyingIssuerStrKey = KeyUtils::toStrKey(offer.buying.alphaNum12().issuer); assetCodeToStr(offer.buying.alphaNum12().assetCode, buyingAssetCode); buying_ind = soci::i_ok; } std::string sql; if (isInsert) { 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 = mDatabase.getPreparedStatement(sql); auto& st = prep.statement(); if (isInsert) { st.exchange(soci::use(actIDStrKey, "sid")); } st.exchange(soci::use(offer.offerID, "oid")); st.exchange(soci::use(sellingType, "sat")); st.exchange(soci::use(sellingAssetCode, selling_ind, "sac")); st.exchange(soci::use(sellingIssuerStrKey, selling_ind, "si")); st.exchange(soci::use(buyingType, "bat")); st.exchange(soci::use(buyingAssetCode, buying_ind, "bac")); st.exchange(soci::use(buyingIssuerStrKey, buying_ind, "bi")); st.exchange(soci::use(offer.amount, "a")); st.exchange(soci::use(offer.price.n, "pn")); st.exchange(soci::use(offer.price.d, "pd")); st.exchange(soci::use(price, "p")); st.exchange(soci::use(offer.flags, "f")); st.exchange(soci::use(entry.lastModifiedLedgerSeq, "l")); st.define_and_bind(); { auto timer = isInsert ? mDatabase.getInsertTimer("offer") : mDatabase.getUpdateTimer("offer"); st.execute(true); } if (st.get_affected_rows() != 1) { throw std::runtime_error("could not update SQL"); } }
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::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)); }); }