#pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { template class TOfferStreamBase { public: class StepCounter { private: std::uint32_t const limit_; std::uint32_t count_{0}; beast::Journal j_; public: StepCounter(std::uint32_t limit, beast::Journal j) : limit_(limit), j_(j) { } bool step() { if (count_ >= limit_) { JLOG(j_.debug()) << "Exceeded " << limit_ << " step limit."; return false; } count_++; return true; } [[nodiscard]] std::uint32_t count() const { return count_; } }; protected: beast::Journal const j_; ApplyView& view_; ApplyView& cancelView_; Book book_; bool validBook_; NetClock::time_point const expire_; BookTip tip_; TOffer offer_; std::optional ownerFunds_; StepCounter& counter_; void erase(ApplyView& view); virtual void permRmOffer(uint256 const& offerIndex) = 0; template requires ValidTaker [[nodiscard]] bool shouldRmSmallIncreasedQOffer() const; public: TOfferStreamBase( ApplyView& view, ApplyView& cancelView, Book const& book, NetClock::time_point when, StepCounter& counter, beast::Journal journal); virtual ~TOfferStreamBase() = default; /** * Returns the offer at the tip of the order book. * Offers are always presented in decreasing quality. * Only valid if step() returned `true`. */ [[nodiscard]] TOffer& tip() const { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) return const_cast(this)->offer_; } /** * Advance to the next valid offer. * This automatically removes: * - Offers with missing ledger entries * - Offers found unfunded * - expired offers * @return `true` if there is a valid offer. */ bool step(); [[nodiscard]] TOut ownerFunds() const { return *ownerFunds_; // NOLINT(bugprone-unchecked-optional-access) always set after step() // is called } }; /** * Presents and consumes the offers in an order book. * * The `view_' ` `ApplyView` accumulates changes to the ledger. * The `cancelView_` is used to determine if an offer is found * unfunded or became unfunded. * The `permToRemove` collection identifies offers that should be * removed even if the strand associated with this OfferStream * is not applied. * * Certain invalid offers are added to the `permToRemove` collection: * - Offers with missing ledger entries * - Offers that expired * - Offers found unfunded: * An offer is found unfunded when the corresponding balance is zero * and the caller has not modified the balance. This is accomplished * by also looking up the balance in the cancel view. */ template class FlowOfferStream : public TOfferStreamBase { private: boost::container::flat_set permToRemove_; public: using TOfferStreamBase::TOfferStreamBase; // The following interface allows offer crossing to permanently // remove self crossed offers. The motivation is somewhat // unintuitive. See the discussion in the comments for // BookOfferCrossingStep::limitSelfCrossQuality(). void permRmOffer(uint256 const& offerIndex) override; [[nodiscard]] boost::container::flat_set const& permToRemove() const { return permToRemove_; } }; } // namespace xrpl