Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13114983
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
26 KB
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Mar 2, 09:02 (21 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187154
Default Alt Text
(26 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment