#include #include #include #include #include #include #include #include #include namespace xrpl { bool operator<(CanonicalTXSet::Key const& lhs, CanonicalTXSet::Key const& rhs) { if (lhs.account_ < rhs.account_) return true; if (lhs.account_ > rhs.account_) return false; if (lhs.seqProxy_ < rhs.seqProxy_) return true; if (lhs.seqProxy_ > rhs.seqProxy_) return false; return lhs.txId_ < rhs.txId_; } uint256 CanonicalTXSet::accountKey(AccountID const& account) { uint256 ret = beast::zero; memcpy(ret.begin(), account.begin(), account.size()); ret ^= salt_; return ret; } void CanonicalTXSet::insert(std::shared_ptr const& txn) { map_.insert( std::make_pair( Key(accountKey(txn->getAccountID(sfAccount)), txn->getSeqProxy(), txn->getTransactionID()), txn)); } std::shared_ptr CanonicalTXSet::popAcctTransaction(std::shared_ptr const& tx) { // Determining the next viable transaction for an account with Tickets: // // 1. Prioritize transactions with Sequences over transactions with // Tickets. // // 2. For transactions not using Tickets, look for consecutive Sequence // numbers. For transactions using Tickets, don't worry about // consecutive Sequence numbers. Tickets can process out of order. // // 3. After handling all transactions with Sequences, return Tickets // with the lowest Ticket ID first. std::shared_ptr result; uint256 const effectiveAccount{accountKey(tx->getAccountID(sfAccount))}; auto const seqProxy = tx->getSeqProxy(); Key const after(effectiveAccount, seqProxy, beast::zero); auto const itrNext{map_.lower_bound(after)}; if (itrNext != map_.end() && itrNext->first.getAccount() == effectiveAccount && (!itrNext->second->getSeqProxy().isSeq() || itrNext->second->getSeqProxy().value() == seqProxy.value() + 1)) { result = std::move(itrNext->second); map_.erase(itrNext); } return result; } } // namespace xrpl