Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13711148
D17479.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Subscribers
None
D17479.diff
View Options
diff --git a/src/avalanche/stakecontendercache.h b/src/avalanche/stakecontendercache.h
--- a/src/avalanche/stakecontendercache.h
+++ b/src/avalanche/stakecontendercache.h
@@ -171,6 +171,15 @@
int getVoteStatus(const StakeContenderId &contenderId,
BlockHash &prevblockhashout) const;
+ /**
+ * Get the best ranking contenders, accepted contenders ranking first. The
+ * output of this function is only reliable to select contenders to
+ * reconcile and should not be called after contender polling begins.
+ */
+ size_t getPollableContenders(
+ const BlockHash &prevblockhash, size_t maxPollable,
+ std::vector<StakeContenderId> &pollableContenders) const;
+
/**
* Get payout scripts of the winning proofs.
*/
diff --git a/src/avalanche/stakecontendercache.cpp b/src/avalanche/stakecontendercache.cpp
--- a/src/avalanche/stakecontendercache.cpp
+++ b/src/avalanche/stakecontendercache.cpp
@@ -162,6 +162,56 @@
return 1;
}
+size_t StakeContenderCache::getPollableContenders(
+ const BlockHash &prevblockhash, size_t maxPollable,
+ std::vector<StakeContenderId> &pollableContenders) const {
+ std::vector<const StakeContenderCacheEntry *> rankedContenders;
+ auto &view = contenders.get<by_prevblockhash>();
+ auto [begin, end] = view.equal_range(prevblockhash);
+ for (auto it = begin; it != end; it++) {
+ rankedContenders.push_back(&(*it));
+ }
+
+ std::sort(rankedContenders.begin(), rankedContenders.end(),
+ [](const StakeContenderCacheEntry *left,
+ const StakeContenderCacheEntry *right) {
+ if (left->isAccepted() != right->isAccepted()) {
+ // Accepted contenders sort first
+ return left->isAccepted();
+ }
+
+ double leftRank = left->computeRewardRank();
+ double rightRank = right->computeRewardRank();
+ if (leftRank != rightRank) {
+ // Lowest rank is best
+ return leftRank < rightRank;
+ }
+
+ // If there's a collision in rank, sort by contender id
+ const StakeContenderId &leftContenderId =
+ left->getStakeContenderId();
+ const StakeContenderId &rightContenderId =
+ right->getStakeContenderId();
+ if (leftContenderId != rightContenderId) {
+ return leftContenderId < rightContenderId;
+ }
+
+ // If there's a collision in contender id, sort by proof id
+ return left->proofid < right->proofid;
+ });
+
+ // Only return up to some maximum number of contenders
+ pollableContenders.clear();
+ size_t numPollable = std::min(rankedContenders.size(), maxPollable);
+ pollableContenders.reserve(numPollable);
+ for (size_t i = 0; i < numPollable; i++) {
+ pollableContenders.push_back(
+ rankedContenders[i]->getStakeContenderId());
+ }
+
+ return pollableContenders.size();
+}
+
bool StakeContenderCache::getWinners(const BlockHash &prevblockhash,
std::vector<CScript> &payouts) const {
// Winners determined by avalanche are sorted by reward rank
diff --git a/src/avalanche/test/stakecontendercache_tests.cpp b/src/avalanche/test/stakecontendercache_tests.cpp
--- a/src/avalanche/test/stakecontendercache_tests.cpp
+++ b/src/avalanche/test/stakecontendercache_tests.cpp
@@ -569,4 +569,51 @@
CheckWinners(cache, blockhashes[0], {}, {});
}
+BOOST_AUTO_TEST_CASE(pollable_contenders_tests) {
+ Chainstate &active_chainstate = Assert(m_node.chainman)->ActiveChainstate();
+ StakeContenderCache cache;
+
+ CBlockIndex *pindex = active_chainstate.m_chain.Tip();
+ const BlockHash &blockhash = pindex->GetBlockHash();
+
+ const size_t maxPollable = 12;
+ std::vector<StakeContenderId> contenders;
+ BOOST_CHECK_EQUAL(
+ cache.getPollableContenders(blockhash, maxPollable, contenders), 0);
+
+ for (size_t c = 0; c < maxPollable * 2; c++) {
+ // Add a new contender with random initial state
+ auto proof = buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
+ BOOST_CHECK(cache.add(pindex, proof, InsecureRandBits(2)));
+
+ // We should never get more contenders than we can poll for in a single
+ // message.
+ BOOST_CHECK(cache.getPollableContenders(blockhash, maxPollable,
+ contenders) <= maxPollable);
+ BOOST_CHECK(contenders.size() <= maxPollable);
+
+ bool acceptanceLatch = true;
+ double lastRank = 0;
+ for (const auto &contender : contenders) {
+ // Check if contender is accepted
+ BlockHash dummy;
+ int voteStatus = cache.getVoteStatus(contender, dummy);
+
+ // Accepted contenders should always rank first, so latch off once
+ // we hit our first rejected contender.
+ if (acceptanceLatch && voteStatus != 0) {
+ acceptanceLatch = false;
+ lastRank = 0;
+ }
+ BOOST_CHECK_EQUAL(voteStatus, acceptanceLatch ? 0 : 1);
+
+ // Check the contender rank is sorted as we expect
+ double rank =
+ contender.ComputeProofRewardRank(MIN_VALID_PROOF_SCORE);
+ BOOST_CHECK(lastRank <= rank);
+ lastRank = rank;
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 26, 10:36 (5 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573295
Default Alt Text
D17479.diff (5 KB)
Attached To
D17479: [avalanche] Add a way to get pollable contenders from contender cache
Event Timeline
Log In to Comment