Bitcoin ABC 0.30.3
P2P Digital Currency
stakecontendercache.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6
8
9namespace avalanche {
10
11void StakeContenderCache::cleanup(const int minHeight) {
12 std::set<BlockHash> hashesToErase;
13 auto &mwHeightView = manualWinners.get<by_blockheight>();
14 for (auto it = mwHeightView.begin();
15 it != mwHeightView.lower_bound(minHeight); it++) {
16 hashesToErase.insert(it->prevblockhash);
17 }
18
19 auto &cHeightView = contenders.get<by_blockheight>();
20 for (auto it = cHeightView.begin();
21 it != cHeightView.lower_bound(minHeight); it++) {
22 hashesToErase.insert(it->prevblockhash);
23 }
24
25 for (const auto &blockhash : hashesToErase) {
26 auto &mwHashView = manualWinners.get<by_prevblockhash>();
27 auto [mwHashBegin, mwHashEnd] = mwHashView.equal_range(blockhash);
28 mwHashView.erase(mwHashBegin, mwHashEnd);
29
30 auto &cHashView = contenders.get<by_prevblockhash>();
31 auto [cHashBegin, cHashEnd] = cHashView.equal_range(blockhash);
32 cHashView.erase(cHashBegin, cHashEnd);
33 }
34}
35
36bool StakeContenderCache::add(const CBlockIndex *pindex, const ProofRef &proof,
37 uint8_t status) {
38 return contenders
39 .emplace(pindex->GetBlockHash(), pindex->nHeight, proof->getId(),
40 status, proof->getPayoutScript(), proof->getScore())
41 .second;
42}
43
45 PeerManager &pm) {
46 // "Promote" past contenders to activeTip and check that those contenders
47 // are still valid proofs to be stake winners. This is done because new
48 // stake contenders are only added when a new proof is seen for the first
49 // time. We need to persist the cached payout scripts and proof scores since
50 // they are not guaranteed to be stored by peerManager.
51 const BlockHash &blockhash = activeTip->GetBlockHash();
52 const int height = activeTip->nHeight;
53 for (auto &contender : contenders) {
54 const ProofId &proofid = contender.proofid;
55 if (pm.isRemoteProof(proofid) &&
56 (pm.isBoundToPeer(proofid) || pm.isDangling(proofid))) {
57 contenders.emplace(blockhash, height, proofid,
59 contender.payoutScriptPubkey, contender.score);
60 }
61 }
62}
63
65 const CBlockIndex *pindex, const std::vector<CScript> &payoutScripts) {
66 const BlockHash &prevblockhash = pindex->GetBlockHash();
67 auto &view = manualWinners.get<by_prevblockhash>();
68 auto it = view.find(prevblockhash);
69 if (it == view.end()) {
70 return manualWinners
71 .emplace(prevblockhash, pindex->nHeight, payoutScripts)
72 .second;
73 }
74 return manualWinners.replace(
75 it, ManualWinners(prevblockhash, pindex->nHeight, payoutScripts));
76}
77
79 auto &view = contenders.get<by_stakecontenderid>();
80 auto it = view.find(contenderId);
81 if (it == view.end()) {
82 return false;
83 }
84
85 return contenders.modify(it, [&](StakeContenderCacheEntry &entry) {
87 });
88}
89
91 auto &view = contenders.get<by_stakecontenderid>();
92 auto it = view.find(contenderId);
93 if (it == view.end()) {
94 return false;
95 }
96
97 return contenders.modify(it, [&](StakeContenderCacheEntry &entry) {
100 });
101}
102
104 auto &view = contenders.get<by_stakecontenderid>();
105 auto it = view.find(contenderId);
106 if (it == view.end()) {
107 return false;
108 }
109
110 return contenders.modify(it, [&](StakeContenderCacheEntry &entry) {
112 });
113}
114
116 auto &view = contenders.get<by_stakecontenderid>();
117 auto it = view.find(contenderId);
118 if (it == view.end()) {
119 return false;
120 }
121
122 return contenders.modify(it, [&](StakeContenderCacheEntry &entry) {
125 });
126}
127
129 const StakeContenderId &contenderId) const {
130 auto &view = contenders.get<by_stakecontenderid>();
131 auto it = view.find(contenderId);
132 if (it == view.end()) {
133 return -1;
134 }
135
136 // Contender is accepted
137 if (it->isAccepted()) {
138 return 0;
139 }
140
141 // If the contender matches a manual winner, it is accepted.
142 auto &manualWinnersView = manualWinners.get<by_prevblockhash>();
143 auto manualWinnerIt = manualWinnersView.find(it->prevblockhash);
144 if (manualWinnerIt != manualWinners.end()) {
145 for (auto &payoutScript : manualWinnerIt->payoutScripts) {
146 if (payoutScript == it->payoutScriptPubkey) {
147 return 0;
148 }
149 }
150 }
151
152 // Contender is rejected
153 return 1;
154}
155
157 std::vector<CScript> &payouts) const {
158 // Winners determined by avalanche are sorted by reward rank
159 std::vector<const StakeContenderCacheEntry *> rankedWinners;
160 auto &view = contenders.get<by_prevblockhash>();
161 auto [begin, end] = view.equal_range(prevblockhash);
162 for (auto it = begin; it != end; it++) {
163 if (it->isInWinnerSet()) {
164 rankedWinners.push_back(&(*it));
165 }
166 }
167
168 std::sort(rankedWinners.begin(), rankedWinners.end(),
169 [](const StakeContenderCacheEntry *left,
170 const StakeContenderCacheEntry *right) {
171 return left->computeRewardRank() < right->computeRewardRank();
172 });
173
174 payouts.clear();
175
176 // Add manual winners first, preserving order
177 auto &manualWinnersView = manualWinners.get<by_prevblockhash>();
178 auto manualWinnerIt = manualWinnersView.find(prevblockhash);
179 if (manualWinnerIt != manualWinners.end()) {
180 payouts.reserve(manualWinnerIt->payoutScripts.size() +
181 rankedWinners.size());
182
183 payouts.insert(payouts.begin(), manualWinnerIt->payoutScripts.begin(),
184 manualWinnerIt->payoutScripts.end());
185 } else {
186 payouts.reserve(rankedWinners.size());
187 }
188
189 // Add ranked winners, preserving reward rank order
190 for (const auto &rankedWinner : rankedWinners) {
191 payouts.push_back(rankedWinner->payoutScriptPubkey);
192 }
193
194 return payouts.size() > 0;
195}
196
197} // namespace avalanche
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
BlockHash GetBlockHash() const
Definition: blockindex.h:146
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
bool isDangling(const ProofId &proofid) const
bool isRemoteProof(const ProofId &proofid) const
bool isBoundToPeer(const ProofId &proofid) const
bool invalidate(const StakeContenderId &contenderId)
bool accept(const StakeContenderId &contenderId)
Helpers to set avalanche state of a contender.
bool reject(const StakeContenderId &contenderId)
int getVoteStatus(const StakeContenderId &contenderId) const
Get contender acceptance state for avalanche voting.
bool setWinners(const CBlockIndex *pindex, const std::vector< CScript > &payoutScripts)
Set proof(s) that should be treated as winners (already finalized).
void cleanup(const int minHeight)
bool add(const CBlockIndex *pindex, const ProofRef &proof, uint8_t status=StakeContenderStatus::UNKNOWN)
Add a proof to consider in staking rewards pre-consensus.
bool finalize(const StakeContenderId &contenderId)
bool getWinners(const BlockHash &prevblockhash, std::vector< CScript > &payouts) const
Get payout scripts of the winning proofs.
void promoteToBlock(const CBlockIndex *activeTip, PeerManager &pm)
Promote cache entries to a the active chain tip.
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
uint8_t status
StakeContenderIds are unique for each block to ensure that the peer polling for their acceptance has ...