Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/test/peermanager_tests.cpp
Show First 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | buildProofWithSequence(const CKey &key, | ||||
int64_t sequence) { | int64_t sequence) { | ||||
return buildProofWithOutpoints(key, outpoints, 10 * COIN, key, | return buildProofWithOutpoints(key, outpoints, 10 * COIN, key, | ||||
sequence); | sequence); | ||||
} | } | ||||
} // namespace | } // namespace | ||||
} // namespace avalanche | } // namespace avalanche | ||||
namespace { | namespace { | ||||
struct NoCoolDownFixture : public TestingSetup { | struct PeerManagerFixture : public TestChain100Setup { | ||||
PeerManagerFixture() { | |||||
gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "0"); | |||||
} | |||||
~PeerManagerFixture() { | |||||
gArgs.ClearForcedArg("-avaproofstakeutxoconfirmations"); | |||||
} | |||||
}; | |||||
} // namespace | |||||
namespace { | |||||
struct NoCoolDownFixture : public PeerManagerFixture { | |||||
NoCoolDownFixture() { | NoCoolDownFixture() { | ||||
gArgs.ForceSetArg("-avalancheconflictingproofcooldown", "0"); | gArgs.ForceSetArg("-avalancheconflictingproofcooldown", "0"); | ||||
} | } | ||||
~NoCoolDownFixture() { | ~NoCoolDownFixture() { | ||||
gArgs.ClearForcedArg("-avalancheconflictingproofcooldown"); | gArgs.ClearForcedArg("-avalancheconflictingproofcooldown"); | ||||
} | } | ||||
}; | }; | ||||
} // namespace | } // namespace | ||||
BOOST_FIXTURE_TEST_SUITE(peermanager_tests, TestingSetup) | BOOST_FIXTURE_TEST_SUITE(peermanager_tests, PeerManagerFixture) | ||||
BOOST_AUTO_TEST_CASE(select_peer_linear) { | BOOST_AUTO_TEST_CASE(select_peer_linear) { | ||||
// No peers. | // No peers. | ||||
BOOST_CHECK_EQUAL(selectPeerImpl({}, 0, 0), NO_PEER); | BOOST_CHECK_EQUAL(selectPeerImpl({}, 0, 0), NO_PEER); | ||||
BOOST_CHECK_EQUAL(selectPeerImpl({}, 1, 3), NO_PEER); | BOOST_CHECK_EQUAL(selectPeerImpl({}, 1, 3), NO_PEER); | ||||
// One peer | // One peer | ||||
const std::vector<Slot> oneslot = {{100, 100, 23}}; | const std::vector<Slot> oneslot = {{100, 100, 23}}; | ||||
▲ Show 20 Lines • Show All 550 Lines • ▼ Show 20 Lines | BOOST_CHECK_EQUAL(getPeerId({COutPoint(txid1, 4), COutPoint(txid2, 0)}), | ||||
NO_PEER); | NO_PEER); | ||||
// Mutliple inputs, collision on both inputs. | // Mutliple inputs, collision on both inputs. | ||||
BOOST_CHECK_EQUAL(getPeerId({COutPoint(txid1, 0), COutPoint(txid2, 2)}), | BOOST_CHECK_EQUAL(getPeerId({COutPoint(txid1, 0), COutPoint(txid2, 2)}), | ||||
NO_PEER); | NO_PEER); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(orphan_proofs) { | BOOST_AUTO_TEST_CASE(orphan_proofs) { | ||||
gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "1"); | |||||
avalanche::PeerManager pm; | avalanche::PeerManager pm; | ||||
auto key = CKey::MakeCompressedKey(); | auto key = CKey::MakeCompressedKey(); | ||||
COutPoint outpoint1 = COutPoint(TxId(GetRandHash()), 0); | COutPoint outpoint1 = COutPoint(TxId(GetRandHash()), 0); | ||||
COutPoint outpoint2 = COutPoint(TxId(GetRandHash()), 0); | COutPoint outpoint2 = COutPoint(TxId(GetRandHash()), 0); | ||||
COutPoint outpoint3 = COutPoint(TxId(GetRandHash()), 0); | COutPoint outpoint3 = COutPoint(TxId(GetRandHash()), 0); | ||||
COutPoint outpoint4 = COutPoint(TxId(GetRandHash()), 0); | |||||
const Amount v = 5 * COIN; | const Amount v = 5 * COIN; | ||||
const int height = 1234; | const int height = 98; | ||||
const int wrongHeight = 12345; | const int wrongHeight = 99; | ||||
const int immatureHeight = 100; | |||||
const auto makeProof = [&](const COutPoint &outpoint, const int h) { | const auto makeProof = [&](const COutPoint &outpoint, const int h) { | ||||
return buildProofWithOutpoints(key, {outpoint}, v, key, 0, h); | return buildProofWithOutpoints(key, {outpoint}, v, key, 0, h); | ||||
}; | }; | ||||
auto proof1 = makeProof(outpoint1, height); | auto proof1 = makeProof(outpoint1, height); | ||||
auto proof2 = makeProof(outpoint2, height); | auto proof2 = makeProof(outpoint2, height); | ||||
auto proof3 = makeProof(outpoint3, wrongHeight); | auto proof3 = makeProof(outpoint3, wrongHeight); | ||||
auto proof4 = makeProof(outpoint4, immatureHeight); | |||||
// Add outpoints 1 and 3, not 2 | // Add outpoints, except for proof 2 | ||||
addCoin(outpoint1, key, v, height); | addCoin(outpoint1, key, v, height); | ||||
addCoin(outpoint3, key, v, height); | addCoin(outpoint3, key, v, height); | ||||
addCoin(outpoint4, key, v, immatureHeight); | |||||
// Add the proofs | // Add the proofs | ||||
BOOST_CHECK(pm.registerProof(proof1)); | BOOST_CHECK(pm.registerProof(proof1)); | ||||
auto registerOrphan = [&](const ProofRef &proof) { | auto registerOrphan = [&](const ProofRef &proof) { | ||||
ProofRegistrationState state; | ProofRegistrationState state; | ||||
BOOST_CHECK(!pm.registerProof(proof, state)); | BOOST_CHECK(!pm.registerProof(proof, state)); | ||||
BOOST_CHECK(state.GetResult() == ProofRegistrationResult::ORPHAN); | BOOST_CHECK(state.GetResult() == ProofRegistrationResult::ORPHAN); | ||||
}; | }; | ||||
registerOrphan(proof2); | registerOrphan(proof2); | ||||
registerOrphan(proof3); | registerOrphan(proof3); | ||||
registerOrphan(proof4); | |||||
auto checkOrphan = [&](const ProofRef &proof, bool expectedOrphan) { | auto checkOrphan = [&](const ProofRef &proof, bool expectedOrphan) { | ||||
const ProofId &proofid = proof->getId(); | const ProofId &proofid = proof->getId(); | ||||
BOOST_CHECK(pm.exists(proofid)); | BOOST_CHECK(pm.exists(proofid)); | ||||
BOOST_CHECK_EQUAL(pm.isOrphan(proofid), expectedOrphan); | BOOST_CHECK_EQUAL(pm.isOrphan(proofid), expectedOrphan); | ||||
BOOST_CHECK_EQUAL(pm.isBoundToPeer(proofid), !expectedOrphan); | BOOST_CHECK_EQUAL(pm.isBoundToPeer(proofid), !expectedOrphan); | ||||
bool ret = false; | bool ret = false; | ||||
pm.forEachPeer([&](const Peer &peer) { | pm.forEachPeer([&](const Peer &peer) { | ||||
if (proof->getId() == peer.proof->getId()) { | if (proof->getId() == peer.proof->getId()) { | ||||
ret = true; | ret = true; | ||||
} | } | ||||
}); | }); | ||||
BOOST_CHECK_EQUAL(ret, !expectedOrphan); | BOOST_CHECK_EQUAL(ret, !expectedOrphan); | ||||
}; | }; | ||||
// Good | // Good | ||||
checkOrphan(proof1, false); | checkOrphan(proof1, false); | ||||
// MISSING_UTXO | // MISSING_UTXO | ||||
checkOrphan(proof2, true); | checkOrphan(proof2, true); | ||||
// HEIGHT_MISMATCH | // HEIGHT_MISMATCH | ||||
checkOrphan(proof3, true); | checkOrphan(proof3, true); | ||||
// IMMATURE_UTXO | |||||
checkOrphan(proof4, true); | |||||
// Add outpoint2, proof2 is no longer considered orphan | // Add outpoint2, proof2 is no longer considered orphan | ||||
addCoin(outpoint2, key, v, height); | addCoin(outpoint2, key, v, height); | ||||
pm.updatedBlockTip(); | pm.updatedBlockTip(); | ||||
checkOrphan(proof2, false); | checkOrphan(proof2, false); | ||||
// The status of proof1 and proof3 are unchanged | // The status of proof1 and proof3 are unchanged | ||||
checkOrphan(proof1, false); | checkOrphan(proof1, false); | ||||
checkOrphan(proof3, true); | checkOrphan(proof3, true); | ||||
// Mine a block to increase the chain height for proof4 verification | |||||
mineBlocks(1); | |||||
pm.updatedBlockTip(); | |||||
checkOrphan(proof4, false); | |||||
// Spend outpoint1, proof1 becomes orphan | // Spend outpoint1, proof1 becomes orphan | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | ||||
coins.SpendCoin(outpoint1); | coins.SpendCoin(outpoint1); | ||||
} | } | ||||
pm.updatedBlockTip(); | pm.updatedBlockTip(); | ||||
Show All 16 Lines | BOOST_AUTO_TEST_CASE(orphan_proofs) { | ||||
// The status of proof 1 and proof2 are unchanged | // The status of proof 1 and proof2 are unchanged | ||||
checkOrphan(proof1, true); | checkOrphan(proof1, true); | ||||
checkOrphan(proof2, false); | checkOrphan(proof2, false); | ||||
// Track expected orphans so we can test them later | // Track expected orphans so we can test them later | ||||
std::vector<ProofRef> orphans; | std::vector<ProofRef> orphans; | ||||
orphans.push_back(proof1); | orphans.push_back(proof1); | ||||
orphans.push_back(proof2); | |||||
orphans.push_back(proof3); | |||||
// Fill up orphan pool to test the size limit | // Fill up orphan pool to test the size limit | ||||
for (uint32_t i = 1; i < AVALANCHE_MAX_ORPHAN_PROOFS; i++) { | for (uint32_t i = 1; i < AVALANCHE_MAX_ORPHAN_PROOFS; i++) { | ||||
COutPoint outpoint = COutPoint(TxId(GetRandHash()), 0); | COutPoint outpoint = COutPoint(TxId(GetRandHash()), 0); | ||||
auto proof = | auto proof = | ||||
buildProofWithOutpoints(key, {outpoint}, 10 * COIN, key, 0, height); | buildProofWithOutpoints(key, {outpoint}, 10 * COIN, key, 0, height); | ||||
registerOrphan(proof); | registerOrphan(proof); | ||||
orphans.push_back(proof); | orphans.push_back(proof); | ||||
Show All 21 Lines | BOOST_AUTO_TEST_CASE(orphan_proofs) { | ||||
} | } | ||||
// Reorg so that some more proofs become orphans | // Reorg so that some more proofs become orphans | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | ||||
coins.SpendCoin(outpoint2); | coins.SpendCoin(outpoint2); | ||||
coins.SpendCoin(outpoint3); | coins.SpendCoin(outpoint3); | ||||
coins.SpendCoin(outpoint4); | |||||
orphans.push_back(proof2); | |||||
orphans.push_back(proof3); | |||||
orphans.push_back(proof4); | |||||
} | } | ||||
pm.updatedBlockTip(); | pm.updatedBlockTip(); | ||||
// New orphans are rejected when the pool is full, even if they have higher | // New orphans are rejected when the pool is full, even if they have higher | ||||
// proof scores. | // proof scores. | ||||
{ | { | ||||
COutPoint outpoint = COutPoint(TxId(GetRandHash()), 0); | COutPoint outpoint = COutPoint(TxId(GetRandHash()), 0); | ||||
▲ Show 20 Lines • Show All 995 Lines • Show Last 20 Lines |