Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/test/peermanager_tests.cpp
// Copyright (c) 2020 The Bitcoin developers | // Copyright (c) 2020 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <avalanche/delegationbuilder.h> | #include <avalanche/delegationbuilder.h> | ||||
#include <avalanche/peermanager.h> | #include <avalanche/peermanager.h> | ||||
#include <avalanche/proofbuilder.h> | #include <avalanche/proofbuilder.h> | ||||
#include <avalanche/proofcomparator.h> | #include <avalanche/proofcomparator.h> | ||||
#include <avalanche/test/util.h> | #include <avalanche/test/util.h> | ||||
#include <script/standard.h> | #include <script/standard.h> | ||||
#include <util/time.h> | |||||
#include <util/translation.h> | #include <util/translation.h> | ||||
#include <validation.h> | #include <validation.h> | ||||
#include <test/util/setup_common.h> | #include <test/util/setup_common.h> | ||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
using namespace avalanche; | using namespace avalanche; | ||||
Show All 20 Lines | struct TestPeerManager { | ||||
auto &pview = pm.peers.get<by_proofid>(); | auto &pview = pm.peers.get<by_proofid>(); | ||||
auto it = pview.find(proof->getId()); | auto it = pview.find(proof->getId()); | ||||
return it == pview.end() ? NO_PEER : it->peerid; | return it == pview.end() ? NO_PEER : it->peerid; | ||||
} | } | ||||
}; | }; | ||||
} // namespace | } // namespace | ||||
} // namespace avalanche | } // namespace avalanche | ||||
namespace { | |||||
struct NoCoolDownFixture : public TestingSetup { | |||||
NoCoolDownFixture() { | |||||
gArgs.ForceSetArg("-avalancheconflictingproofcooldown", "0"); | |||||
} | |||||
~NoCoolDownFixture() { | |||||
gArgs.ClearForcedArg("-avalancheconflictingproofcooldown"); | |||||
} | |||||
}; | |||||
} // namespace | |||||
BOOST_FIXTURE_TEST_SUITE(peermanager_tests, TestingSetup) | BOOST_FIXTURE_TEST_SUITE(peermanager_tests, TestingSetup) | ||||
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 | ||||
▲ Show 20 Lines • Show All 750 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(proof_accessors) { | ||||
BOOST_CHECK(Proof::FromHex(badProof, badProofHex, error)); | BOOST_CHECK(Proof::FromHex(badProof, badProofHex, error)); | ||||
ProofRegistrationState state; | ProofRegistrationState state; | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
!pm.registerProof(std::make_shared<Proof>(std::move(badProof)), state)); | !pm.registerProof(std::make_shared<Proof>(std::move(badProof)), state)); | ||||
BOOST_CHECK(state.GetResult() == ProofRegistrationResult::INVALID); | BOOST_CHECK(state.GetResult() == ProofRegistrationResult::INVALID); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(conflicting_proof_rescan) { | BOOST_FIXTURE_TEST_CASE(conflicting_proof_rescan, NoCoolDownFixture) { | ||||
avalanche::PeerManager pm; | avalanche::PeerManager pm; | ||||
const CKey key = CKey::MakeCompressedKey(); | const CKey key = CKey::MakeCompressedKey(); | ||||
const Amount amount = 10 * COIN; | const Amount amount = 10 * COIN; | ||||
const uint32_t height = 100; | const uint32_t height = 100; | ||||
const bool is_coinbase = false; | const bool is_coinbase = false; | ||||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(conflicting_orphans) { | ||||
// proof30 will replace orphan20. | // proof30 will replace orphan20. | ||||
pm.updatedBlockTip(); | pm.updatedBlockTip(); | ||||
BOOST_CHECK(!pm.isBoundToPeer(proof30->getId())); | BOOST_CHECK(!pm.isBoundToPeer(proof30->getId())); | ||||
BOOST_CHECK(pm.isOrphan(proof30->getId())); | BOOST_CHECK(pm.isOrphan(proof30->getId())); | ||||
BOOST_CHECK(!pm.exists(orphan20->getId())); | BOOST_CHECK(!pm.exists(orphan20->getId())); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(preferred_conflicting_proof) { | BOOST_FIXTURE_TEST_CASE(preferred_conflicting_proof, NoCoolDownFixture) { | ||||
avalanche::PeerManager pm; | avalanche::PeerManager pm; | ||||
const CKey key = CKey::MakeCompressedKey(); | const CKey key = CKey::MakeCompressedKey(); | ||||
const Amount amount(10 * COIN); | const Amount amount(10 * COIN); | ||||
const uint32_t height = 100; | const uint32_t height = 100; | ||||
const bool is_coinbase = false; | const bool is_coinbase = false; | ||||
CScript script = GetScriptForDestination(PKHash(key.GetPubKey())); | CScript script = GetScriptForDestination(PKHash(key.GetPubKey())); | ||||
Show All 34 Lines | BOOST_FIXTURE_TEST_CASE(preferred_conflicting_proof, NoCoolDownFixture) { | ||||
// evicted. | // evicted. | ||||
BOOST_CHECK(!pm.registerProof(proofSeq20)); | BOOST_CHECK(!pm.registerProof(proofSeq20)); | ||||
BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId())); | BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId())); | ||||
BOOST_CHECK(!pm.isBoundToPeer(proofSeq20->getId())); | BOOST_CHECK(!pm.isBoundToPeer(proofSeq20->getId())); | ||||
BOOST_CHECK(pm.isInConflictingPool(proofSeq20->getId())); | BOOST_CHECK(pm.isInConflictingPool(proofSeq20->getId())); | ||||
BOOST_CHECK(!pm.exists(proofSeq10->getId())); | BOOST_CHECK(!pm.exists(proofSeq10->getId())); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(update_next_conflict_time) { | BOOST_FIXTURE_TEST_CASE(update_next_conflict_time, NoCoolDownFixture) { | ||||
avalanche::PeerManager pm; | avalanche::PeerManager pm; | ||||
auto now = GetTime<std::chrono::seconds>(); | auto now = GetTime<std::chrono::seconds>(); | ||||
SetMockTime(now.count()); | SetMockTime(now.count()); | ||||
// Updating the time of an unknown peer should fail | // Updating the time of an unknown peer should fail | ||||
for (size_t i = 0; i < 10; i++) { | for (size_t i = 0; i < 10; i++) { | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
Show All 16 Lines | BOOST_CHECK(!pm.updateNextPossibleConflictTime( | ||||
peerid, now - std::chrono::seconds{1})); | peerid, now - std::chrono::seconds{1})); | ||||
checkNextPossibleConflictTime(now); | checkNextPossibleConflictTime(now); | ||||
BOOST_CHECK(pm.updateNextPossibleConflictTime( | BOOST_CHECK(pm.updateNextPossibleConflictTime( | ||||
peerid, now + std::chrono::seconds{1})); | peerid, now + std::chrono::seconds{1})); | ||||
checkNextPossibleConflictTime(now + std::chrono::seconds{1}); | checkNextPossibleConflictTime(now + std::chrono::seconds{1}); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(register_force_accept) { | BOOST_FIXTURE_TEST_CASE(register_force_accept, NoCoolDownFixture) { | ||||
avalanche::PeerManager pm; | avalanche::PeerManager pm; | ||||
const CKey key = CKey::MakeCompressedKey(); | const CKey key = CKey::MakeCompressedKey(); | ||||
const Amount amount(10 * COIN); | const Amount amount(10 * COIN); | ||||
const uint32_t height = 100; | const uint32_t height = 100; | ||||
const bool is_coinbase = false; | const bool is_coinbase = false; | ||||
CScript script = GetScriptForDestination(PKHash(key.GetPubKey())); | CScript script = GetScriptForDestination(PKHash(key.GetPubKey())); | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < 10; i++) { | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pm.registerProof(proofSeq10, RegistrationMode::FORCE_ACCEPT)); | pm.registerProof(proofSeq10, RegistrationMode::FORCE_ACCEPT)); | ||||
BOOST_CHECK(pm.isBoundToPeer(proofSeq10->getId())); | BOOST_CHECK(pm.isBoundToPeer(proofSeq10->getId())); | ||||
BOOST_CHECK(pm.isInConflictingPool(proofSeq30->getId())); | BOOST_CHECK(pm.isInConflictingPool(proofSeq30->getId())); | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(evicted_proof) { | BOOST_FIXTURE_TEST_CASE(evicted_proof, NoCoolDownFixture) { | ||||
avalanche::PeerManager pm; | avalanche::PeerManager pm; | ||||
const CKey key = CKey::MakeCompressedKey(); | const CKey key = CKey::MakeCompressedKey(); | ||||
const Amount amount(10 * COIN); | const Amount amount(10 * COIN); | ||||
const uint32_t height = 100; | const uint32_t height = 100; | ||||
const bool is_coinbase = false; | const bool is_coinbase = false; | ||||
CScript script = GetScriptForDestination(PKHash(key.GetPubKey())); | CScript script = GetScriptForDestination(PKHash(key.GetPubKey())); | ||||
Show All 31 Lines | BOOST_FIXTURE_TEST_CASE(evicted_proof, NoCoolDownFixture) { | ||||
{ | { | ||||
ProofRegistrationState state; | ProofRegistrationState state; | ||||
BOOST_CHECK(!pm.registerProof(proofSeq10, state)); | BOOST_CHECK(!pm.registerProof(proofSeq10, state)); | ||||
BOOST_CHECK(state.GetResult() == ProofRegistrationResult::REJECTED); | BOOST_CHECK(state.GetResult() == ProofRegistrationResult::REJECTED); | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(conflicting_proof_cooldown) { | |||||
avalanche::PeerManager pm; | |||||
const CKey key = CKey::MakeCompressedKey(); | |||||
const Amount amount(10 * COIN); | |||||
const uint32_t height = 100; | |||||
const bool is_coinbase = false; | |||||
CScript script = GetScriptForDestination(PKHash(key.GetPubKey())); | |||||
const COutPoint conflictingOutpoint(TxId(GetRandHash()), 0); | |||||
{ | |||||
LOCK(cs_main); | |||||
CCoinsViewCache &coins = ::ChainstateActive().CoinsTip(); | |||||
coins.AddCoin(conflictingOutpoint, | |||||
Coin(CTxOut(amount, script), height, is_coinbase), false); | |||||
} | |||||
auto buildProofWithSequence = [&](uint64_t sequence) { | |||||
ProofBuilder pb(sequence, 0, key); | |||||
BOOST_CHECK( | |||||
pb.addUTXO(conflictingOutpoint, amount, height, is_coinbase, key)); | |||||
return pb.build(); | |||||
}; | |||||
auto proofSeq20 = buildProofWithSequence(20); | |||||
auto proofSeq30 = buildProofWithSequence(30); | |||||
auto proofSeq40 = buildProofWithSequence(40); | |||||
int64_t conflictingProofCooldown = 100; | |||||
gArgs.ForceSetArg("-avalancheconflictingproofcooldown", | |||||
strprintf("%d", conflictingProofCooldown)); | |||||
int64_t now = GetTime(); | |||||
auto increaseMockTime = [&](int64_t s) { | |||||
now += s; | |||||
SetMockTime(now); | |||||
}; | |||||
increaseMockTime(0); | |||||
BOOST_CHECK(pm.registerProof(proofSeq30)); | |||||
BOOST_CHECK(pm.isBoundToPeer(proofSeq30->getId())); | |||||
auto checkRegistrationFailure = [&](const ProofRef &proof, | |||||
ProofRegistrationResult reason) { | |||||
ProofRegistrationState state; | |||||
BOOST_CHECK(!pm.registerProof(proof, state)); | |||||
BOOST_CHECK(state.GetResult() == reason); | |||||
}; | |||||
// Registering a conflicting proof will fail due to the conflicting proof | |||||
// cooldown | |||||
checkRegistrationFailure(proofSeq20, | |||||
ProofRegistrationResult::COOLDOWN_NOT_ELAPSED); | |||||
BOOST_CHECK(!pm.exists(proofSeq20->getId())); | |||||
// The cooldown applies as well if the proof is the favorite | |||||
checkRegistrationFailure(proofSeq40, | |||||
ProofRegistrationResult::COOLDOWN_NOT_ELAPSED); | |||||
BOOST_CHECK(!pm.exists(proofSeq40->getId())); | |||||
// Elapse the cooldown | |||||
increaseMockTime(conflictingProofCooldown); | |||||
// The proof will now be added to conflicting pool | |||||
checkRegistrationFailure(proofSeq20, ProofRegistrationResult::CONFLICTING); | |||||
BOOST_CHECK(pm.isInConflictingPool(proofSeq20->getId())); | |||||
// But no other | |||||
checkRegistrationFailure(proofSeq40, | |||||
ProofRegistrationResult::COOLDOWN_NOT_ELAPSED); | |||||
BOOST_CHECK(!pm.exists(proofSeq40->getId())); | |||||
BOOST_CHECK(pm.isInConflictingPool(proofSeq20->getId())); | |||||
// Elapse the cooldown | |||||
increaseMockTime(conflictingProofCooldown); | |||||
// The proof will now be added to conflicting pool | |||||
checkRegistrationFailure(proofSeq40, ProofRegistrationResult::CONFLICTING); | |||||
BOOST_CHECK(pm.isInConflictingPool(proofSeq40->getId())); | |||||
BOOST_CHECK(!pm.exists(proofSeq20->getId())); | |||||
gArgs.ClearForcedArg("-avalancheconflictingproofcooldown"); | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |