21 std::set<BlockHash> hashesToErase;
23 for (
auto it = mwHeightView.begin();
24 it != mwHeightView.lower_bound(minHeight); it++) {
25 hashesToErase.insert(it->prevblockhash);
28 auto &cHeightView =
contenders.get<by_blockheight>();
29 for (
auto it = cHeightView.begin();
30 it != cHeightView.lower_bound(minHeight); it++) {
31 hashesToErase.insert(it->prevblockhash);
34 for (
const auto &blockhash : hashesToErase) {
36 auto [mwHashBegin, mwHashEnd] = mwHashView.equal_range(blockhash);
37 mwHashView.erase(mwHashBegin, mwHashEnd);
39 auto &cHashView =
contenders.get<by_prevblockhash>();
40 auto [cHashBegin, cHashEnd] = cHashView.equal_range(blockhash);
41 cHashView.erase(cHashBegin, cHashEnd);
50 proof->getPayoutScript(), proof->getScore())
56 std::function<
bool(
const ProofId &proofid)>
const &shouldPromote) {
63 const int height = activeTip->
nHeight;
69 std::vector<StakeContenderCacheEntry> promotedEntries;
72 const ProofId &proofid = contender.proofid;
73 bool promoted =
false;
74 if (shouldPromote(proofid)) {
76 blockhash, height, blocktime, proofid,
82 "Contender with proofid %s, payout %s was%s promoted to "
83 "block %s (height %d) (old id %s, next id %s)\n",
85 promoted ?
"" :
" NOT", blockhash.
ToString(), height,
86 contender.getStakeContenderId().ToString(),
89 contenders.insert(promotedEntries.begin(), promotedEntries.end());
93 const CBlockIndex *pindex,
const std::vector<CScript> &payoutScripts) {
96 auto it = view.find(prevblockhash);
97 if (it == view.end()) {
99 .emplace(prevblockhash, pindex->
nHeight, payoutScripts)
107 auto &view =
contenders.get<by_stakecontenderid>();
108 auto it = view.find(contenderId);
109 if (it == view.end()) {
119 auto &view =
contenders.get<by_stakecontenderid>();
120 auto it = view.find(contenderId);
121 if (it == view.end()) {
132 auto &view =
contenders.get<by_stakecontenderid>();
133 auto it = view.find(contenderId);
134 if (it == view.end()) {
145 auto &view =
contenders.get<by_stakecontenderid>();
146 auto it = view.find(contenderId);
147 if (it == view.end()) {
158 if (it->isAccepted()) {
159 contenderInfo.voteStatus = 0;
160 return contenderInfo;
163 auto &manualWinnersView =
manualWinners.get<by_prevblockhash>();
164 auto manualWinnerIt = manualWinnersView.find(it->prevblockhash);
166 for (
auto &payoutScript : manualWinnerIt->payoutScripts) {
167 if (payoutScript == it->payoutScriptPubkey) {
168 contenderInfo.voteStatus = 0;
169 return contenderInfo;
174 return contenderInfo;
180 if (!contenderInfo) {
184 prevblockhashout = contenderInfo->prevblockhash;
185 return contenderInfo->voteStatus;
189 const BlockHash &prevblockhash,
size_t maxPollable,
190 std::vector<StakeContenderId> &pollableContenders)
const {
191 std::vector<const StakeContenderCacheEntry *> rankedContenders;
192 auto &view =
contenders.get<by_prevblockhash>();
193 auto [begin, end] = view.equal_range(prevblockhash);
194 for (
auto it = begin; it != end; it++) {
195 rankedContenders.push_back(&(*it));
199 std::sort(rankedContenders.begin(), rankedContenders.end(),
202 if (left->isAccepted() != right->isAccepted()) {
204 return left->isAccepted();
214 left->
proofid, rightContenderId,
220 size_t numPollable = std::min(rankedContenders.size(), maxPollable);
221 std::sort(rankedContenders.begin(), rankedContenders.begin() + numPollable,
224 double leftRank = left->computeRewardRank();
225 double rightRank = right->computeRewardRank();
226 const StakeContenderId &leftContenderId =
227 left->getStakeContenderId();
228 const StakeContenderId &rightContenderId =
229 right->getStakeContenderId();
230 return RewardRankComparator()(leftContenderId, leftRank,
231 left->proofid, rightContenderId,
232 rightRank, right->proofid);
236 pollableContenders.clear();
237 pollableContenders.reserve(numPollable);
238 for (
size_t i = 0; i < numPollable; i++) {
239 pollableContenders.push_back(
240 rankedContenders[i]->getStakeContenderId());
243 return pollableContenders.size();
246bool StakeContenderCache::getWinners(
248 std::vector<std::pair<ProofId, CScript>> &winners)
const {
250 std::vector<const StakeContenderCacheEntry *> rankedWinners;
251 auto &view = contenders.get<by_prevblockhash>();
252 auto [begin, end] = view.equal_range(prevblockhash);
253 for (
auto it = begin; it != end; it++) {
254 if (it->isInWinnerSet()) {
255 rankedWinners.push_back(&(*it));
259 std::sort(rankedWinners.begin(), rankedWinners.end(),
262 if (left->isAccepted() != right->isAccepted()) {
264 return left->isAccepted();
274 left->
proofid, rightContenderId,
281 auto &manualWinnersView = manualWinners.get<by_prevblockhash>();
282 auto manualWinnerIt = manualWinnersView.find(prevblockhash);
283 if (manualWinnerIt != manualWinners.end()) {
284 winners.reserve(manualWinnerIt->payoutScripts.size() +
285 rankedWinners.size());
287 for (
auto &payoutScript : manualWinnerIt->payoutScripts) {
288 winners.push_back({
ProofId(), payoutScript});
291 winners.reserve(rankedWinners.size());
295 for (
const auto &rankedWinner : rankedWinners) {
297 {rankedWinner->proofid, rankedWinner->payoutScriptPubkey});
300 return winners.size() > 0;
The block chain is a tree shaped structure starting with the genesis block at the root,...
int64_t GetBlockTime() const
BlockHash GetBlockHash() const
int nHeight
height of the entry in the chain. The genesis block has height 0
ManualWinnersSet manualWinners
bool accept(const StakeContenderId &contenderId)
Helpers to set avalanche state of a contender.
void cleanup(const int requestedMinHeight)
size_t getPollableContenders(const BlockHash &prevblockhash, size_t maxPollable, std::vector< StakeContenderId > &pollableContenders) const
Get the best ranking contenders, accepted contenders ranking first.
bool reject(const StakeContenderId &contenderId)
bool setWinners(const CBlockIndex *pindex, const std::vector< CScript > &payoutScripts)
Set proof(s) that should be treated as winners (already finalized).
bool add(const CBlockIndex *pindex, const ProofRef &proof, uint8_t status=StakeContenderStatus::UNKNOWN)
Add a proof to consider in staking rewards pre-consensus.
std::optional< StakeContenderCacheInfo > getContenderInfo(const StakeContenderId &contenderId) const
void promoteToBlock(const CBlockIndex *activeTip, std::function< bool(const ProofId &proofid)> const &shouldPromote)
Promote cache entries to a the active chain tip.
int getVoteStatus(const StakeContenderId &contenderId, BlockHash &prevblockhashout) const
Get contender acceptance state for avalanche voting.
bool finalize(const StakeContenderId &contenderId)
std::string ToString() const
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
#define LogTrace(category,...)
static std::string ToString(const CService &ip)
A BlockHash is a unqiue identifier for a block.
double computeRewardRank() const
StakeContenderId getStakeContenderId() const
Cache to track stake contenders for recent blocks.
StakeContenderIds are unique for each block to ensure that the peer polling for their acceptance has ...