mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-03 20:20:59 +00:00
127 lines
3.5 KiB
C++
127 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include <xrpl/basics/algorithm.h>
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace xrpl {
|
|
|
|
template <class TxID, class Sequence>
|
|
class CensorshipDetector
|
|
{
|
|
public:
|
|
struct TxIDSeq
|
|
{
|
|
TxID txid;
|
|
Sequence seq;
|
|
|
|
TxIDSeq(TxID const& txid, Sequence const& seq) : txid(txid), seq(seq)
|
|
{
|
|
}
|
|
};
|
|
|
|
friend bool
|
|
operator<(TxIDSeq const& lhs, TxIDSeq const& rhs)
|
|
{
|
|
if (lhs.txid != rhs.txid)
|
|
return lhs.txid < rhs.txid;
|
|
return lhs.seq < rhs.seq;
|
|
}
|
|
|
|
friend bool
|
|
operator<(TxIDSeq const& lhs, TxID const& rhs)
|
|
{
|
|
return lhs.txid < rhs;
|
|
}
|
|
|
|
friend bool
|
|
operator<(TxID const& lhs, TxIDSeq const& rhs)
|
|
{
|
|
return lhs < rhs.txid;
|
|
}
|
|
|
|
using TxIDSeqVec = std::vector<TxIDSeq>;
|
|
|
|
private:
|
|
TxIDSeqVec tracker_;
|
|
|
|
public:
|
|
CensorshipDetector() = default;
|
|
|
|
/**
|
|
* Add transactions being proposed for the current consensus round.
|
|
*
|
|
* @param proposed The set of transactions that we are initially proposing
|
|
* for this round.
|
|
*/
|
|
void
|
|
propose(TxIDSeqVec proposed)
|
|
{
|
|
// We want to remove any entries that we proposed in a previous round
|
|
// that did not make it in yet if we are no longer proposing them.
|
|
// And we also want to preserve the Sequence of entries that we proposed
|
|
// in the last round and want to propose again.
|
|
std::sort(proposed.begin(), proposed.end());
|
|
generalizedSetIntersection(
|
|
proposed.begin(),
|
|
proposed.end(),
|
|
tracker_.cbegin(),
|
|
tracker_.cend(),
|
|
[](auto& x, auto const& y) { x.seq = y.seq; },
|
|
[](auto const& x, auto const& y) { return x.txid < y.txid; });
|
|
tracker_ = std::move(proposed);
|
|
}
|
|
|
|
/**
|
|
* Determine which transactions made it and perform censorship detection.
|
|
*
|
|
* This function is called when the server is proposing and a consensus
|
|
* round it participated in completed.
|
|
*
|
|
* @param accepted The set of transactions that the network agreed
|
|
* should be included in the ledger being built.
|
|
* @param pred A predicate invoked for every transaction we've proposed
|
|
* but which hasn't yet made it. The predicate must be
|
|
* callable as:
|
|
* bool pred(TxID const&, Sequence)
|
|
* It must return true for entries that should be removed.
|
|
*/
|
|
template <class Predicate>
|
|
void
|
|
check(std::vector<TxID> accepted, Predicate&& pred)
|
|
{
|
|
auto acceptTxid = accepted.begin();
|
|
auto const ae = accepted.end();
|
|
std::sort(acceptTxid, ae);
|
|
|
|
// We want to remove all tracking entries for transactions that were
|
|
// accepted as well as those which match the predicate.
|
|
|
|
auto i = removeIfIntersectOrMatch(
|
|
tracker_.begin(),
|
|
tracker_.end(),
|
|
accepted.begin(),
|
|
accepted.end(),
|
|
[&pred](auto const& x) { return pred(x.txid, x.seq); },
|
|
std::less<void>{});
|
|
tracker_.erase(i, tracker_.end());
|
|
}
|
|
|
|
/**
|
|
* Removes all elements from the tracker
|
|
*
|
|
* Typically, this function might be called after we reconnect to the
|
|
* network following an outage, or after we start tracking the network.
|
|
*/
|
|
void
|
|
reset()
|
|
{
|
|
tracker_.clear();
|
|
}
|
|
};
|
|
|
|
} // namespace xrpl
|