Page MenuHomePhabricator

No OneTemporary

diff --git a/src/avalanche/proofpool.cpp b/src/avalanche/proofpool.cpp
index 0379e2f9b..2f2453c98 100644
--- a/src/avalanche/proofpool.cpp
+++ b/src/avalanche/proofpool.cpp
@@ -1,141 +1,153 @@
// Copyright (c) 2021 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <avalanche/proofpool.h>
#include <avalanche/peermanager.h>
#include <avalanche/proofcomparator.h>
#include <unordered_set>
namespace avalanche {
ProofPool::AddProofStatus
ProofPool::addProofIfNoConflict(const ProofRef &proof,
ConflictingProofSet &conflictingProofs) {
const ProofId &proofid = proof->getId();
// Make sure the set is empty before we add items
conflictingProofs.clear();
auto &poolView = pool.get<by_proofid>();
if (poolView.find(proofid) != poolView.end()) {
return AddProofStatus::DUPLICATED;
}
// Attach UTXOs to this proof.
for (size_t i = 0; i < proof->getStakes().size(); i++) {
auto p = pool.emplace(i, proof);
if (!p.second) {
// We have a collision with an existing proof.
conflictingProofs.insert(p.first->proof);
}
}
// If there is a conflict, just cleanup the mess.
if (conflictingProofs.size() > 0) {
for (const auto &s : proof->getStakes()) {
auto it = pool.find(s.getStake().getUTXO());
assert(it != pool.end());
// We need to delete that one.
if (it->proof->getId() == proofid) {
pool.erase(it);
}
}
return AddProofStatus::REJECTED;
}
cacheClean = false;
return AddProofStatus::SUCCEED;
}
ProofPool::AddProofStatus
ProofPool::addProofIfPreferred(const ProofRef &proof,
ConflictingProofSet &conflictingProofs) {
auto status = addProofIfNoConflict(proof, conflictingProofs);
// In case the proof was rejected due to conflict and it is the best
// candidate, override the conflicting ones and add it again
if (status != AddProofStatus::REJECTED ||
ConflictingProofComparator()(*conflictingProofs.begin(), proof)) {
return status;
}
for (auto &conflictingProof : conflictingProofs) {
removeProof(conflictingProof->getId());
}
status = addProofIfNoConflict(proof);
assert(status == AddProofStatus::SUCCEED);
cacheClean = false;
return AddProofStatus::SUCCEED;
}
// Having the ProofId passed by reference is risky because it is usually a
// reference to a proof member. This proof will be deleted during the erasure
// loop so we pass it by value.
bool ProofPool::removeProof(ProofId proofid) {
cacheClean = false;
auto &poolView = pool.get<by_proofid>();
return poolView.erase(proofid);
}
std::unordered_set<ProofRef, SaltedProofHasher>
ProofPool::rescan(PeerManager &peerManager) {
auto previousPool = std::move(pool);
pool.clear();
cacheClean = false;
std::unordered_set<ProofRef, SaltedProofHasher> registeredProofs;
for (auto &entry : previousPool) {
if (registeredProofs.insert(entry.proof).second) {
peerManager.registerProof(entry.proof);
}
}
return registeredProofs;
}
+std::unordered_set<ProofId, SaltedProofIdHasher>
+ProofPool::getProofIds() const {
+ std::unordered_set<ProofId, SaltedProofIdHasher> proofIds;
+
+ auto &poolView = pool.get<by_proofid>();
+ for (auto it = poolView.begin(); it != poolView.end(); it++) {
+ proofIds.insert(it->proof->getId());
+ }
+
+ return proofIds;
+}
+
ProofRef ProofPool::getProof(const ProofId &proofid) const {
auto &poolView = pool.get<by_proofid>();
auto it = poolView.find(proofid);
return it == poolView.end() ? ProofRef() : it->proof;
}
ProofRef ProofPool::getProof(const COutPoint &outpoint) const {
auto it = pool.find(outpoint);
return it == pool.end() ? ProofRef() : it->proof;
}
ProofRef ProofPool::getLowestScoreProof() const {
auto &poolView = pool.get<by_proof_score>();
return poolView.rbegin() == poolView.rend() ? ProofRef()
: poolView.rbegin()->proof;
}
size_t ProofPool::countProofs() {
if (cacheClean) {
return cacheProofCount;
}
size_t count = 0;
ProofId lastProofId;
auto &poolView = pool.get<by_proofid>();
for (auto it = poolView.begin(); it != poolView.end(); it++) {
const ProofId &proofId = it->proof->getId();
if (lastProofId != proofId) {
lastProofId = proofId;
count++;
}
}
cacheProofCount = count;
cacheClean = true;
return cacheProofCount;
}
} // namespace avalanche
diff --git a/src/avalanche/proofpool.h b/src/avalanche/proofpool.h
index 5ddf7bf55..d840dbaef 100644
--- a/src/avalanche/proofpool.h
+++ b/src/avalanche/proofpool.h
@@ -1,125 +1,126 @@
// Copyright (c) 2021 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_AVALANCHE_PROOFPOOL_H
#define BITCOIN_AVALANCHE_PROOFPOOL_H
#include <avalanche/proof.h>
#include <avalanche/proofcomparator.h>
#include <avalanche/proofid.h>
#include <coins.h>
#include <primitives/transaction.h>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index_container.hpp>
#include <cstdint>
namespace avalanche {
class PeerManager;
struct ProofPoolEntry {
size_t utxoIndex;
ProofRef proof;
const COutPoint &getUTXO() const {
return proof->getStakes().at(utxoIndex).getStake().getUTXO();
}
ProofPoolEntry(size_t _utxoIndex, ProofRef _proof)
: utxoIndex(_utxoIndex), proof(std::move(_proof)) {}
};
struct by_utxo;
struct by_proofid;
struct by_proof_score;
struct ProofPoolEntryProofIdKeyExtractor {
using result_type = ProofId;
result_type operator()(const ProofPoolEntry &entry) const {
return entry.proof->getId();
}
};
namespace bmi = boost::multi_index;
/**
* Map a proof to each utxo. A proof can be mapped with several utxos.
*/
class ProofPool {
boost::multi_index_container<
ProofPoolEntry,
bmi::indexed_by<
// index by utxo
bmi::hashed_unique<
bmi::tag<by_utxo>,
bmi::const_mem_fun<ProofPoolEntry, const COutPoint &,
&ProofPoolEntry::getUTXO>,
SaltedOutpointHasher>,
// index by proofid
bmi::hashed_non_unique<bmi::tag<by_proofid>,
ProofPoolEntryProofIdKeyExtractor,
SaltedProofIdHasher>,
// index by proof score
bmi::ordered_non_unique<
bmi::tag<by_proof_score>,
bmi::member<ProofPoolEntry, ProofRef, &ProofPoolEntry::proof>,
ProofComparatorByScore>>>
pool;
bool cacheClean = true;
size_t cacheProofCount = 0;
public:
enum AddProofStatus {
REJECTED = 0, //!< Rejected due to conflicts
SUCCEED = 1, //!< Added successfully
DUPLICATED = 2, //!< Already in pool
};
using ConflictingProofSet = std::set<ProofRef, ConflictingProofComparator>;
/**
* Attempt to add a proof to the pool, and fail if there is a conflict on
* any UTXO.
*/
AddProofStatus addProofIfNoConflict(const ProofRef &proof,
ConflictingProofSet &conflictingProofs);
AddProofStatus addProofIfNoConflict(const ProofRef &proof) {
ConflictingProofSet dummy;
return addProofIfNoConflict(proof, dummy);
}
/**
* Attempt to add a proof to the pool. In case there is a conflict with one
* or more UTXO, the proof is only added if it is the best candidate over
* all the conflicting proofs according to ConflictingProofComparator.
*/
AddProofStatus addProofIfPreferred(const ProofRef &proof,
ConflictingProofSet &conflictingProofs);
AddProofStatus addProofIfPreferred(const ProofRef &proof) {
ConflictingProofSet dummy;
return addProofIfPreferred(proof, dummy);
}
bool removeProof(ProofId proofid);
std::unordered_set<ProofRef, SaltedProofHasher>
rescan(PeerManager &peerManager);
+ std::unordered_set<ProofId, SaltedProofIdHasher> getProofIds() const;
ProofRef getProof(const ProofId &proofid) const;
ProofRef getProof(const COutPoint &outpoint) const;
ProofRef getLowestScoreProof() const;
size_t size() const { return pool.size(); }
size_t countProofs();
};
} // namespace avalanche
#endif // BITCOIN_AVALANCHE_PROOFPOOL_H
diff --git a/src/avalanche/test/proofpool_tests.cpp b/src/avalanche/test/proofpool_tests.cpp
index 04cfd51a2..c480a5aea 100644
--- a/src/avalanche/test/proofpool_tests.cpp
+++ b/src/avalanche/test/proofpool_tests.cpp
@@ -1,374 +1,414 @@
// Copyright (c) 2021 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <avalanche/proofpool.h>
#include <avalanche/peermanager.h>
#include <avalanche/proofcomparator.h>
#include <key.h>
#include <primitives/transaction.h>
#include <primitives/txid.h>
#include <random.h>
#include <avalanche/test/util.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
using namespace avalanche;
BOOST_FIXTURE_TEST_SUITE(proofpool_tests, TestChain100Setup)
+BOOST_AUTO_TEST_CASE(get_proof_ids) {
+ ProofPool testPool;
+ CChainState &active_chainstate =
+ Assert(m_node.chainman)->ActiveChainstate();
+
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 0);
+
+ std::unordered_set<ProofId, SaltedProofIdHasher> proofIds;
+ for (size_t i = 0; i < 10; i++) {
+ auto proof = buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
+ BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
+ ProofPool::AddProofStatus::SUCCEED);
+ proofIds.insert(proof->getId());
+ }
+
+ auto fetchedProofIds = testPool.getProofIds();
+ BOOST_CHECK_EQUAL(testPool.countProofs(), 10);
+ BOOST_CHECK_EQUAL(fetchedProofIds.size(), 10);
+ for (auto proofid : proofIds) {
+ BOOST_CHECK_EQUAL(fetchedProofIds.count(proofid), 1);
+ }
+}
+
BOOST_AUTO_TEST_CASE(add_remove_proof_no_conflict) {
ProofPool testPool;
CChainState &active_chainstate =
Assert(m_node.chainman)->ActiveChainstate();
std::vector<ProofRef> proofs;
for (size_t i = 0; i < 10; i++) {
// Add a bunch of random proofs
auto proof = buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
ProofPool::AddProofStatus::SUCCEED);
BOOST_CHECK_EQUAL(testPool.countProofs(), i + 1);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), i + 1);
// Trying to add them again will return a duplicated status
for (size_t j = 0; j < 10; j++) {
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
ProofPool::AddProofStatus::DUPLICATED);
BOOST_CHECK_EQUAL(testPool.countProofs(), i + 1);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), i + 1);
}
proofs.push_back(std::move(proof));
}
const CKey key = CKey::MakeCompressedKey();
const COutPoint conflictingOutpoint{TxId(GetRandHash()), 0};
auto buildProofWithSequence = [&](uint64_t sequence) {
ProofBuilder pb(sequence, 0, key, UNSPENDABLE_ECREG_PAYOUT_SCRIPT);
BOOST_CHECK(
pb.addUTXO(conflictingOutpoint, 10 * COIN, 123456, false, key));
return pb.build();
};
auto proof_seq10 = buildProofWithSequence(10);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof_seq10),
ProofPool::AddProofStatus::SUCCEED);
BOOST_CHECK_EQUAL(testPool.countProofs(), 11);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 11);
proofs.push_back(std::move(proof_seq10));
auto proof_seq20 = buildProofWithSequence(20);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof_seq20),
ProofPool::AddProofStatus::REJECTED);
BOOST_CHECK_EQUAL(testPool.countProofs(), 11);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 11);
// Removing proofs which are not in the pool will fail
for (size_t i = 0; i < 10; i++) {
BOOST_CHECK(!testPool.removeProof(ProofId(GetRandHash())));
}
BOOST_CHECK_EQUAL(testPool.countProofs(), 11);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 11);
for (auto proof : proofs) {
BOOST_CHECK(testPool.removeProof(proof->getId()));
}
BOOST_CHECK_EQUAL(testPool.size(), 0);
BOOST_CHECK_EQUAL(testPool.countProofs(), 0);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 0);
}
BOOST_AUTO_TEST_CASE(rescan) {
gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "1");
ProofPool testPool;
avalanche::PeerManager pm(PROOF_DUST_THRESHOLD, *Assert(m_node.chainman));
testPool.rescan(pm);
BOOST_CHECK_EQUAL(testPool.size(), 0);
BOOST_CHECK_EQUAL(testPool.countProofs(), 0);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 0);
// No peer should be created
bool hasPeer = false;
pm.forEachPeer([&](const Peer &p) { hasPeer = true; });
BOOST_CHECK(!hasPeer);
CChainState &active_chainstate =
Assert(m_node.chainman)->ActiveChainstate();
std::set<ProofRef, ProofRefComparatorByAddress> poolProofs;
for (size_t i = 0; i < 10; i++) {
auto proof = buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
ProofPool::AddProofStatus::SUCCEED);
poolProofs.insert(std::move(proof));
BOOST_CHECK_EQUAL(testPool.countProofs(), i + 1);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), i + 1);
}
testPool.rescan(pm);
// All the proofs should be registered as peer
std::set<ProofRef, ProofRefComparatorByAddress> pmProofs;
pm.forEachPeer([&](const Peer &p) { pmProofs.insert(p.proof); });
BOOST_CHECK_EQUAL_COLLECTIONS(poolProofs.begin(), poolProofs.end(),
pmProofs.begin(), pmProofs.end());
BOOST_CHECK_EQUAL(testPool.size(), 0);
BOOST_CHECK_EQUAL(testPool.countProofs(), 0);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 0);
gArgs.ClearForcedArg("-avaproofstakeutxoconfirmations");
}
BOOST_AUTO_TEST_CASE(proof_override) {
ProofPool testPool;
const CKey key = CKey::MakeCompressedKey();
auto buildProofWithSequenceAndOutpoints =
[&](uint64_t sequence, const std::vector<COutPoint> &outpoints) {
ProofBuilder pb(sequence, 0, key, UNSPENDABLE_ECREG_PAYOUT_SCRIPT);
for (const COutPoint &outpoint : outpoints) {
BOOST_CHECK(
pb.addUTXO(outpoint, 10 * COIN, 123456, false, key));
}
return pb.build();
};
const COutPoint outpoint1{TxId(GetRandHash()), 0};
const COutPoint outpoint2{TxId(GetRandHash()), 0};
const COutPoint outpoint3{TxId(GetRandHash()), 0};
// Build and register 3 proofs with a single utxo
auto proof_seq10 = buildProofWithSequenceAndOutpoints(10, {outpoint1});
auto proof_seq20 = buildProofWithSequenceAndOutpoints(20, {outpoint2});
auto proof_seq30 = buildProofWithSequenceAndOutpoints(30, {outpoint3});
BOOST_CHECK_EQUAL(testPool.addProofIfPreferred(proof_seq10),
ProofPool::AddProofStatus::SUCCEED);
BOOST_CHECK(testPool.getProof(proof_seq10->getId()));
BOOST_CHECK_EQUAL(testPool.countProofs(), 1);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 1);
BOOST_CHECK_EQUAL(testPool.addProofIfPreferred(proof_seq20),
ProofPool::AddProofStatus::SUCCEED);
BOOST_CHECK(testPool.getProof(proof_seq20->getId()));
BOOST_CHECK_EQUAL(testPool.countProofs(), 2);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 2);
BOOST_CHECK_EQUAL(testPool.addProofIfPreferred(proof_seq30),
ProofPool::AddProofStatus::SUCCEED);
BOOST_CHECK(testPool.getProof(proof_seq30->getId()));
BOOST_CHECK_EQUAL(testPool.countProofs(), 3);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 3);
// Build a proof that conflicts with the above 3, but has a higher sequence
auto proof_seq123 = buildProofWithSequenceAndOutpoints(
123, {outpoint1, outpoint2, outpoint3});
ProofPool::ConflictingProofSet expectedConflictingProofs = {
proof_seq10, proof_seq20, proof_seq30};
// The no conflict call should reject our candidate and not alter the 3
// conflicting proofs
ProofPool::ConflictingProofSet conflictingProofs;
BOOST_CHECK_EQUAL(
testPool.addProofIfNoConflict(proof_seq123, conflictingProofs),
ProofPool::AddProofStatus::REJECTED);
BOOST_CHECK_EQUAL_COLLECTIONS(
conflictingProofs.begin(), conflictingProofs.end(),
expectedConflictingProofs.begin(), expectedConflictingProofs.end());
BOOST_CHECK_EQUAL(testPool.countProofs(), 3);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 3);
BOOST_CHECK(!testPool.getProof(proof_seq123->getId()));
BOOST_CHECK(testPool.getProof(proof_seq10->getId()));
BOOST_CHECK(testPool.getProof(proof_seq20->getId()));
BOOST_CHECK(testPool.getProof(proof_seq30->getId()));
// The conflict handling call will override the 3 conflicting proofs
conflictingProofs.clear();
BOOST_CHECK_EQUAL(
testPool.addProofIfPreferred(proof_seq123, conflictingProofs),
ProofPool::AddProofStatus::SUCCEED);
BOOST_CHECK_EQUAL_COLLECTIONS(
conflictingProofs.begin(), conflictingProofs.end(),
expectedConflictingProofs.begin(), expectedConflictingProofs.end());
BOOST_CHECK_EQUAL(testPool.countProofs(), 1);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 1);
BOOST_CHECK(testPool.getProof(proof_seq123->getId()));
BOOST_CHECK(!testPool.getProof(proof_seq10->getId()));
BOOST_CHECK(!testPool.getProof(proof_seq20->getId()));
BOOST_CHECK(!testPool.getProof(proof_seq30->getId()));
}
BOOST_AUTO_TEST_CASE(conflicting_proofs_set) {
ProofPool testPool;
const CKey key = CKey::MakeCompressedKey();
const COutPoint conflictingOutpoint{TxId(GetRandHash()), 0};
auto buildProofWithSequence = [&](uint64_t sequence) {
ProofBuilder pb(sequence, 0, key, UNSPENDABLE_ECREG_PAYOUT_SCRIPT);
BOOST_CHECK(
pb.addUTXO(conflictingOutpoint, 10 * COIN, 123456, false, key));
return pb.build();
};
auto proofSeq10 = buildProofWithSequence(10);
auto proofSeq20 = buildProofWithSequence(20);
auto proofSeq30 = buildProofWithSequence(30);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proofSeq20),
ProofPool::AddProofStatus::SUCCEED);
CChainState &active_chainstate =
Assert(m_node.chainman)->ActiveChainstate();
auto getRandomConflictingProofSet = [&active_chainstate]() {
return ProofPool::ConflictingProofSet{
buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE),
buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE),
buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE),
};
};
auto checkConflictingProofs =
[&](const ProofPool::ConflictingProofSet &conflictingProofs,
const ProofPool::ConflictingProofSet &expectedConflictingProofs) {
BOOST_CHECK_EQUAL_COLLECTIONS(conflictingProofs.begin(),
conflictingProofs.end(),
expectedConflictingProofs.begin(),
expectedConflictingProofs.end());
};
{
// Without override, duplicated proof
auto conflictingProofs = getRandomConflictingProofSet();
BOOST_CHECK_EQUAL(
testPool.addProofIfNoConflict(proofSeq20, conflictingProofs),
ProofPool::AddProofStatus::DUPLICATED);
checkConflictingProofs(conflictingProofs, {});
}
{
// With override, duplicated proof
auto conflictingProofs = getRandomConflictingProofSet();
BOOST_CHECK_EQUAL(
testPool.addProofIfPreferred(proofSeq20, conflictingProofs),
ProofPool::AddProofStatus::DUPLICATED);
checkConflictingProofs(conflictingProofs, {});
}
{
// Without override, worst proof
auto conflictingProofs = getRandomConflictingProofSet();
BOOST_CHECK_EQUAL(
testPool.addProofIfNoConflict(proofSeq10, conflictingProofs),
ProofPool::AddProofStatus::REJECTED);
checkConflictingProofs(conflictingProofs, {proofSeq20});
}
{
// Without override, better proof
auto conflictingProofs = getRandomConflictingProofSet();
BOOST_CHECK_EQUAL(
testPool.addProofIfNoConflict(proofSeq30, conflictingProofs),
ProofPool::AddProofStatus::REJECTED);
checkConflictingProofs(conflictingProofs, {proofSeq20});
}
{
// With override, worst proof
auto conflictingProofs = getRandomConflictingProofSet();
BOOST_CHECK_EQUAL(
testPool.addProofIfPreferred(proofSeq10, conflictingProofs),
ProofPool::AddProofStatus::REJECTED);
checkConflictingProofs(conflictingProofs, {proofSeq20});
}
{
// With override, better proof
auto conflictingProofs = getRandomConflictingProofSet();
BOOST_CHECK_EQUAL(
testPool.addProofIfPreferred(proofSeq30, conflictingProofs),
ProofPool::AddProofStatus::SUCCEED);
checkConflictingProofs(conflictingProofs, {proofSeq20});
}
}
BOOST_AUTO_TEST_CASE(get_proof) {
ProofPool testPool;
for (size_t i = 0; i < 10; i++) {
BOOST_CHECK(!testPool.getProof(ProofId(GetRandHash())));
}
CChainState &active_chainstate =
Assert(m_node.chainman)->ActiveChainstate();
for (size_t i = 0; i < 10; i++) {
auto proof = buildRandomProof(active_chainstate, MIN_VALID_PROOF_SCORE);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
ProofPool::AddProofStatus::SUCCEED);
auto retrievedProof = testPool.getProof(proof->getId());
BOOST_CHECK_NE(retrievedProof, nullptr);
BOOST_CHECK_EQUAL(retrievedProof->getId(), proof->getId());
}
}
BOOST_AUTO_TEST_CASE(get_lowest_score_proof) {
ProofPool testPool;
BOOST_CHECK_EQUAL(testPool.getLowestScoreProof(), nullptr);
const CKey key = CKey::MakeCompressedKey();
auto buildProofWithRandomOutpoints = [&](uint32_t score) {
int numOutpoints = InsecureRand32() % 10 + 1;
ProofBuilder pb(0, 0, key, UNSPENDABLE_ECREG_PAYOUT_SCRIPT);
for (int i = 0; i < numOutpoints; i++) {
Amount amount = 1 * COIN;
if (i == numOutpoints - 1) {
// Last UTXO is the remainder
amount =
(int64_t(score) * COIN) / 100 - (numOutpoints - 1) * COIN;
}
const COutPoint outpoint{TxId(GetRandHash()), 0};
BOOST_CHECK(pb.addUTXO(outpoint, amount, 123456, false, key));
}
return pb.build();
};
// Add some proofs with different scores and check the lowest scoring proof
for (int i = 9; i >= 0; i--) {
auto proof = buildProofWithRandomOutpoints(MIN_VALID_PROOF_SCORE + i);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
ProofPool::AddProofStatus::SUCCEED);
auto checkLowestScoreProof = testPool.getLowestScoreProof();
BOOST_CHECK_EQUAL(checkLowestScoreProof->getScore(),
MIN_VALID_PROOF_SCORE + i);
BOOST_CHECK_EQUAL(checkLowestScoreProof->getId(), proof->getId());
}
BOOST_CHECK_EQUAL(testPool.countProofs(), 10);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 10);
auto lowestScoreProof = testPool.getLowestScoreProof();
// Adding more proofs doesn't change the lowest scoring proof
for (size_t i = 1; i < 10; i++) {
auto proof = buildProofWithRandomOutpoints(MIN_VALID_PROOF_SCORE + i);
BOOST_CHECK_EQUAL(testPool.addProofIfNoConflict(proof),
ProofPool::AddProofStatus::SUCCEED);
auto checkLowestScoreProof = testPool.getLowestScoreProof();
BOOST_CHECK_EQUAL(checkLowestScoreProof->getScore(),
MIN_VALID_PROOF_SCORE);
BOOST_CHECK_EQUAL(checkLowestScoreProof->getId(),
lowestScoreProof->getId());
}
BOOST_CHECK_EQUAL(testPool.countProofs(), 19);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 19);
// Remove proofs by lowest score, checking the lowest score as we go
for (int scoreCount = 1; scoreCount < 10; scoreCount++) {
for (size_t i = 0; i < 2; i++) {
BOOST_CHECK(
testPool.removeProof(testPool.getLowestScoreProof()->getId()));
BOOST_CHECK_EQUAL(testPool.getLowestScoreProof()->getScore(),
MIN_VALID_PROOF_SCORE + scoreCount);
}
}
// Remove the last proof
BOOST_CHECK(testPool.removeProof(testPool.getLowestScoreProof()->getId()));
BOOST_CHECK_EQUAL(testPool.getLowestScoreProof(), nullptr);
BOOST_CHECK_EQUAL(testPool.countProofs(), 0);
+ BOOST_CHECK_EQUAL(testPool.getProofIds().size(), 0);
}
BOOST_AUTO_TEST_SUITE_END()

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 2, 09:02 (1 d, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187154
Default Alt Text
(26 KB)

Event Timeline