21#include <validation.h>
23#include <test/util/blockindex.h>
24#include <test/util/random.h>
25#include <test/util/setup_common.h>
27#include <boost/test/unit_test.hpp>
31#include <unordered_map>
37 struct TestPeerManager {
40 return pm.forNode(nodeid, [&](
const Node &
node) {
41 return node.peerid == peerid;
53 auto it =
pview.find(proofid);
59 pm.registerProof(proof);
64 std::vector<uint32_t>
scores;
68 scores.push_back(peer.getScore());
74 static void cleanupDanglingProofs(
81 std::unordered_set<ProofRef, SaltedProofHasher> dummy;
82 pm.cleanupDanglingProofs(dummy);
88 auto it =
pm.remoteProofs.find(boost::make_tuple(proofid, nodeid));
89 if (it ==
pm.remoteProofs.end()) {
92 return std::make_optional(*it);
96 return pm.peers.size();
99 static std::optional<bool>
101 return pm.getRemotePresenceStatus(proofid);
106 for (
auto &peer :
pm.peers) {
107 peerIds.push_back(peer.peerid);
110 pm.removePeer(peerid);
116 pm.localProof = proof;
120 return pm.isFlaky(proofid);
127 uint32_t height = 100,
bool is_coinbase =
false) {
133 Coin(
CTxOut(amount, script), height, is_coinbase),
false);
139 bool is_coinbase =
false) {
147 const std::vector<std::tuple<COutPoint, Amount>> &
outpoints,
150 bool is_coinbase =
false,
int64_t expirationTime = 0,
153 for (
const auto &[outpoint, amount] :
outpoints) {
154 BOOST_CHECK(
pb.addUTXO(outpoint, amount, height, is_coinbase, key));
159 template <
typename... Args>
163 Amount amount, Args &&...args) {
168 [amount](
const auto &
o) { return std::make_tuple(o, amount); });
170 std::forward<Args>(args)...);
184struct PeerManagerFixture :
public TestChain100Setup {
185 PeerManagerFixture() {
195struct NoCoolDownFixture :
public PeerManagerFixture {
196 NoCoolDownFixture() {
213 const std::vector<Slot>
oneslot = {{100, 100, 23}};
231 const std::vector<Slot>
twoslots = {{100, 100, 69}, {300, 100, 42}};
260 std::vector<Slot> slots;
264 for (
int i = 0; i < 100; i++) {
265 slots.emplace_back(max, 1, i);
272 for (
int i = 0; i < 100; i++) {
280 slots[99] = slots[99].withScore(101);
281 max = slots[99].getStop();
284 for (
int i = 0; i < 100; i++) {
295 for (
int i = 0; i < 100; i++) {
296 slots[i] = slots[i].withStart(slots[i].getStart() + 100);
299 slots[0] =
Slot(1, slots[0].getStop() - 1, slots[0].getPeerId());
300 slots[99] = slots[99].withScore(1);
301 max = slots[99].getStop();
308 for (
int i = 0; i < 100; i++) {
315 for (
int c = 0;
c < 1000;
c++) {
317 std::vector<Slot> slots;
327 for (
size_t i = 0; i < size; i++) {
331 slots.emplace_back(start, score, i);
334 for (
int k = 0; k < 100; k++) {
368 std::unordered_map<PeerId, int>
results = {};
369 for (
int i = 0; i < 10000; i++) {
370 size_t n =
pm.selectNode();
381 for (
int i = 0; i < 10000; i++) {
382 size_t n =
pm.selectNode();
399 for (
int i = 0; i < 4; i++) {
401 peerids[i] = TestPeerManager::registerAndGetPeerId(
pm,
p);
408 for (
int i = 0; i < 100; i++) {
425 for (
int i = 0; i < 100; i++) {
431 for (
int i = 0; i < 4; i++) {
433 peerids[i + 4] = TestPeerManager::registerAndGetPeerId(
pm,
p);
455 for (
int i = 0; i < 100; i++) {
474 for (
int i = 0; i < 4; i++) {
477 peerids[i] = TestPeerManager::registerAndGetPeerId(
pm,
p);
489 for (
int i = 0; i < 100; i++) {
513 for (
int i = 0; i < 4; i++) {
517 for (
int i = 0; i < 100; i++) {
526 for (
int i = 0; i < 100; i++) {
534 std::chrono::hours(24)));
536 for (
int i = 0; i < 100; i++) {
547 for (
int i = 0; i < 100; i++) {
572 for (
int i = 0; i < 10; i++) {
580 const PeerId peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
582 for (
int i = 0; i < 10; i++) {
584 BOOST_CHECK(TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
591 for (
int i = 0; i < 5; i++) {
594 BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
600 for (
int i = 0; i < 5; i++) {
603 BOOST_CHECK(TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
612 for (
int i = 0; i < 5; i++) {
615 BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
625 for (
int i = 0; i < 5; i++) {
633 for (
int i = 0; i < 5; i++) {
636 BOOST_CHECK(TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
644 for (
int i = 0; i < 10; i++) {
646 BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
653 for (
int i = 0; i < 10; i++) {
656 BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
672 PeerId peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
677 for (
int i = 0; i < 10; i++) {
680 BOOST_CHECK(TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
692 pm.updatedBlockTip();
695 for (
int i = 0; i < 10; i++) {
697 BOOST_CHECK(!TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
713 pm.updatedBlockTip();
717 peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
719 for (
int i = 0; i < 10; i++) {
721 BOOST_CHECK(TestPeerManager::nodeBelongToPeer(
pm, i, peerid));
734 const int height = 100;
744 const auto getPeerId = [&](
const std::vector<COutPoint> &
outpoints) {
745 return TestPeerManager::registerAndGetPeerId(
817 pm.forEachPeer([&](
const Peer &peer) {
841 for (
auto i = 0; i < 100; i++) {
872 pm.updatedBlockTip();
885 PeerId peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
889 std::chrono::hours(24));
892 for (
int i = 0; i < 10; i++) {
901 for (
int i = 0; i < 10; i++) {
907 peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
911 for (
int i = 0; i < 10; i++) {
914 i, [&](
const Node &n) { return n.nextRequestTime == theFuture; }));
921 for (
int i = 0; i < 10; i++) {
932 std::vector<ProofRef>
proofs;
947 ProofRegistrationResult::ALREADY_REGISTERED);
961 "96527eae083f1f24625f049d9e54bb9a21023beefdde700a6bc02036335b4df141c8b"
962 "c67bb05a971f5ac2745fd683797dde3002321023beefdde700a6bc02036335b4df141"
963 "c8bc67bb05a971f5ac2745fd683797dde3ac135da984db510334abe41134e3d4ef09a"
964 "d006b1152be8bc413182bf6f947eac1f8580fe265a382195aa2d73935cabf86d90a8f"
965 "666d0a62385ae24732eca51575");
994 BOOST_CHECK(state.GetResult() == ProofRegistrationResult::CONFLICTING);
1004 pm.updatedBlockTip();
1017 const bool is_coinbase =
false;
1041 ProofRegistrationResult::CONFLICTING,
1062 std::vector<Amount> &&
amounts) {
1068 return std::make_tuple(
1069 createUtxo(active_chainstate, key, amount),
1147 pm.updatedBlockTip();
1195 for (
size_t i = 0; i < 10; i++) {
1202 PeerId peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
1206 return p.nextPossibleConflictTime == expected;
1214 peerid, now - std::chrono::seconds{1}));
1218 peerid, now + std::chrono::seconds{1}));
1262 for (
size_t i = 0; i < 10; i++) {
1265 !
pm.registerProof(
proofSeq10, RegistrationMode::FORCE_ACCEPT));
1273 for (
size_t i = 0; i < 10; i++) {
1275 pm.registerProof(
proofSeq30, RegistrationMode::FORCE_ACCEPT));
1281 pm.registerProof(
proofSeq10, RegistrationMode::FORCE_ACCEPT));
1358 ProofRegistrationResult::COOLDOWN_NOT_ELAPSED);
1363 ProofRegistrationResult::COOLDOWN_NOT_ELAPSED);
1375 ProofRegistrationResult::COOLDOWN_NOT_ELAPSED);
1422 for (
size_t i = 0; i < 10; i++) {
1433 const bool isImmature =
pm.isImmature(proofid);
1495 for (
size_t i = 0; i < 10; i++) {
1502 for (
size_t i = 0; i < 10; i++) {
1511 for (
size_t i = 0; i < 10; i++) {
1523 for (
size_t i = 0; i < 10; i++) {
1538 TestPeerManager::cleanupDanglingProofs(
pm);
1545 TestPeerManager::cleanupDanglingProofs(
pm);
1549 for (
size_t i = 0; i < 10; i++) {
1563 for (
size_t i = 0; i < 10; i++) {
1573 TestPeerManager::cleanupDanglingProofs(
pm);
1579 TestPeerManager::cleanupDanglingProofs(
pm);
1600 [n = 1]()
mutable { return n++ * MIN_VALID_PROOF_SCORE; });
1602 std::vector<ProofRef>
proofs;
1610 for (
auto &proof :
proofs) {
1671 const bool isImmature =
pm.isImmature(proofid);
1731 TestPeerManager::getPeerIdForProofId(
pm,
peer1Proof2->getId());
1833 return lhs->getId() <
rhs->getId();
1836 using ProofSetById = std::set<ProofRef, ProofComparatorById>;
1842 return tree.forEachLeaf([&](
auto pLeaf) {
1844 pLeaf->getId() == (*it++)->getId();
1854 for (
size_t i = 0; i < 10; i++) {
1861 const auto &
treeRef =
pm.getShareableProofsSnapshot();
1865 auto tree =
pm.getShareableProofsSnapshot();
1870 for (
size_t i = 0; i < 10; i++) {
1881 tree =
pm.getShareableProofsSnapshot();
1894 pm.updatedBlockTip();
1900 tree =
pm.getShareableProofsSnapshot();
1909 for (
size_t i = 0; i < 10; i++) {
1917 tree =
pm.getShareableProofsSnapshot();
1922 for (
size_t i = 0; i < 10; i += 2) {
1935 tree =
pm.getShareableProofsSnapshot();
1946 auto addNode = [&](
NodeId nodeid) {
1953 for (
NodeId nodeid = 0; nodeid < 10; nodeid++) {
1986 for (
size_t i = 0; i <
numProofs; i++) {
2003 return peer.node_count;
2011 TestPeerManager::cleanupDanglingProofs(
pm);
2012 for (
size_t i = 0; i <
numProofs; i++) {
2019 TestPeerManager::cleanupDanglingProofs(
pm);
2020 for (
size_t i = 0; i <
numProofs; i++) {
2043 TestPeerManager::cleanupDanglingProofs(
pm);
2044 for (
size_t i = 0; i <
numProofs; i++) {
2063 for (
size_t i = 1; i <
numProofs; i += 2) {
2067 return peer.node_count == 0;
2075 TestPeerManager::cleanupDanglingProofs(
pm);
2076 for (
size_t i = 0; i <
numProofs; i++) {
2094 TestPeerManager::cleanupDanglingProofs(
pm);
2096 for (
size_t i = 0; i <
numProofs; i++) {
2113 BOOST_CHECK(state.GetResult() == ProofRegistrationResult::MISSING_UTXO);
2142 for (
int64_t i = 0; i < 6; i++) {
2148 ->GetMedianTimePast(),
2151 pm.updatedBlockTip();
2165 const std::vector<std::tuple<uint32_t, uint32_t, double>>
testCases = {
2167 {10, 100, 1. - std::exp(-1. * 10 / 100)},
2178 auto proofid = proof->
getId();
2187 NodeId nodeid) ->
double {
2193 auto getAvailabilityScore = [&]() {
2195 pm.forPeer(proofid, [&](
auto &peer) {
2196 score = peer.availabilityScore;
2206 for (
size_t i = 1; i <= 10; i++) {
2238 pm.forPeer(proofid, [&](
auto &peer) {
2250 for (
size_t i = 1; i <= 10; i++) {
2260 for (
size_t i = 1; i <= 3; i++) {
2285 for (
size_t i = 1; i <= 100; i++) {
2309 return buildProof(key, {{std::move(utxo), amount}},
2315 std::vector<std::pair<ProofId, CScript>> winners;
2317 BOOST_CHECK(!
pm.selectStakingRewardWinner(
nullptr, winners));
2333 std::vector<ProofRef>
proofs;
2335 for (
size_t i = 0; i <
numProofs; i++) {
2341 PeerId peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
2347 proofs.emplace_back(std::move(proof));
2363 for (
size_t i = 0; i <
numProofs; i++) {
2384 size_t(-1.0 * std::log(100000.0) /
2400 for (
size_t i = 0; i <
numProofs; i++) {
2410 for (
size_t i = 0; i <
numProofs; i++) {
2423 for (
const auto &proof :
proofs) {
2429 for (
const auto &proof :
proofs) {
2445 for (
const auto &proof :
proofs) {
2469 for (
const auto &proof :
proofs) {
2486 for (
auto &proof :
proofs) {
2501 PeerId peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
2543 for (
size_t i = 0; i < 4; i++) {
2552 PeerId peerid = TestPeerManager::registerAndGetPeerId(
pm, proof);
2555 return peer.registration_time == now + i * 30min;
2579 [&](
const std::pair<ProofId, CScript> &
winner) {
2580 pm.forEachPeer([&](
const Peer &peer) {
2583 (now - 60min).count());
2660 TestPeerManager::getRemoteProof(
pm, proofid, nodeid);
2748 std::vector<ProofRef>
proofs;
2805 for (
NodeId nodeid = 0; nodeid < 12; nodeid++) {
2818 for (
NodeId nodeid = 0; nodeid < 5; nodeid++) {
2821 for (
NodeId nodeid = 5; nodeid < 12; nodeid++) {
2831 TestPeerManager::setLocalProof(
pm, localProof);
2838 pm.rejectProof(localProof->getId());
2839 TestPeerManager::setLocalProof(
pm,
ProofRef());
2845 for (
NodeId nodeid = 0; nodeid < 5; nodeid++) {
2848 for (
NodeId nodeid = 5; nodeid < 12; nodeid++) {
2863 for (
NodeId nodeid = 0; nodeid < 5; nodeid++) {
2866 for (
NodeId nodeid = 5; nodeid < 12; nodeid++) {
2874 for (
NodeId nodeid = 0; nodeid < 5; nodeid++) {
2877 for (
NodeId nodeid = 5; nodeid < 12; nodeid++) {
2884 TestPeerManager::clearPeers(
pm);
2894 for (
NodeId nodeid = 1; nodeid < 6; nodeid++) {
2900 for (
NodeId nodeid = 1; nodeid < 6; nodeid++) {
2921 std::vector<ProofRef>
proofs;
2922 for (
size_t i = 0; i < 10; i++) {
2929 TestPeerManager::cleanupDanglingProofs(
pm);
2930 for (
const auto &proof :
proofs) {
2940 TestPeerManager::cleanupDanglingProofs(
pm);
2941 for (
const auto &proof :
proofs) {
2947 for (
NodeId nodeid = 0; nodeid < 10; nodeid++) {
2953 for (
const auto &proof :
proofs) {
2959 for (
const auto &proof :
proofs) {
2967 for (
const auto &proof :
proofs) {
2975 for (
NodeId nodeid = 0; nodeid < 10; nodeid++) {
2976 for (
const auto &proof :
proofs) {
2982 for (
const auto &proof :
proofs) {
2984 !TestPeerManager::getRemotePresenceStatus(
pm, proof->
getId())
2991 for (
const auto &proof :
proofs) {
3002 for (
const auto &proof :
proofs) {
3008 for (
NodeId nodeid = 0; nodeid < 10; nodeid++) {
3009 for (
const auto &proof :
proofs) {
3015 for (
const auto &proof :
proofs) {
3031 std::vector<ProofRef>
proofs;
3032 for (
size_t i = 0; i < 10; i++) {
3039 auto peerid = TestPeerManager::getPeerIdForProofId(
pm, proof->getId());
3043 peerid,
mockTime + std::chrono::seconds{100 + i}));
3058 TestPeerManager::clearPeers(
pm);
3065 for (
size_t i = 0; i <
proofs.size(); i++) {
3066 if (
proofs[i]->getId() == proofid) {
3080 BOOST_CHECK_EQUAL(peer.hasFinalized, i < 5);
3081 BOOST_CHECK_EQUAL(peer.registration_time.count(),
3082 (mockTime + std::chrono::seconds{i}).count());
3084 peer.nextPossibleConflictTime.count(),
3085 (
mockTime + std::chrono::seconds{100 + i}).count());
3091 TestPeerManager::clearPeers(
pm);
3122 BOOST_CHECK(!
pm.loadPeersFromFile(
"test_bad_version_avapeers.dat",
3147 BOOST_CHECK(!
pm.loadPeersFromFile(
"test_ill_formed_avapeers.dat",
3177 TestPeerManager::cleanupDanglingProofs(
pm);
3190 pm.updatedBlockTip();
3215 TestPeerManager::cleanupDanglingProofs(
pm);
3221 for (
int64_t i = 0; i < 6; i++) {
3227 ->GetMedianTimePast(),
3230 pm.updatedBlockTip();
static constexpr PeerId NO_PEER
#define Assert(val)
Identity function.
void ForceSetArg(const std::string &strArg, const std::string &strValue)
void ClearForcedArg(const std::string &strArg)
Remove a forced arg setting, used only in testing.
The block chain is a tree shaped structure starting with the genesis block at the root,...
CCoinsView that adds a memory cache for transactions to another CCoinsView.
void AddCoin(const COutPoint &outpoint, Coin coin, bool possible_overwrite)
Add a coin.
bool SpendCoin(const COutPoint &outpoint, Coin *moveto=nullptr)
Spend a coin.
An encapsulated secp256k1 private key.
static CKey MakeCompressedKey()
Produce a valid compressed key.
CPubKey GetPubKey() const
Compute the public key from a private key.
An outpoint - a combination of a transaction hash and an index n into its vout.
Serialized script, used inside transaction inputs and outputs.
An output of a transaction.
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
SnapshotCompletionResult MaybeCompleteSnapshotValidation(std::function< void(bilingual_str)> shutdown_fnc=[](bilingual_str msg) { AbortNode(msg.original, msg);}) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & ActiveChainstate() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
static RCUPtr make(Args &&...args)
Construct a new object that is owned by the pointer.
RegistrationMode
Registration mode.
static constexpr size_t MAX_REMOTE_PROOFS
int64_t getExpirationTime() const
static bool FromHex(Proof &proof, const std::string &hexProof, bilingual_str &errorOut)
const CScript & getPayoutScript() const
const ProofId & getId() const
static uint32_t amountToScore(Amount amount)
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
static const uint256 ZERO
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
static void addCoin(const Amount nValue, const CWallet &wallet, std::vector< std::unique_ptr< CWalletTx > > &wtxs)
std::string FormatScript(const CScript &script)
static const uint8_t tau[]
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
bool FileCommit(FILE *file)
Ensure file contents are fully committed to disk, using a platform-specific feature analogous to fsyn...
bool error(const char *fmt, const Args &...args)
static constexpr Amount PROOF_DUST_THRESHOLD
Minimum amount per utxo.
static constexpr uint32_t AVALANCHE_MAX_IMMATURE_PROOFS
Maximum number of immature proofs the peer manager will accept from the network.
const CScript UNSPENDABLE_ECREG_PAYOUT_SCRIPT
ProofRef buildRandomProof(Chainstate &active_chainstate, uint32_t score, int height, const CKey &masterKey)
constexpr uint32_t MIN_VALID_PROOF_SCORE
PeerId selectPeerImpl(const std::vector< Slot > &slots, const uint64_t slot, const uint64_t max)
Internal methods that are exposed for testing purposes.
RCUPtr< const Proof > ProofRef
FILE * fopen(const fs::path &p, const char *mode)
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
static void addNodeWithScore(Chainstate &active_chainstate, avalanche::PeerManager &pm, NodeId node, uint32_t score)
BOOST_AUTO_TEST_CASE(select_peer_linear)
BOOST_FIXTURE_TEST_CASE(conflicting_proof_rescan, NoCoolDownFixture)
uint256 GetRandHash() noexcept
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
static const double AVALANCHE_STATISTICS_DECAY_FACTOR
Pre-computed decay factor for the avalanche statistics computation.
static constexpr std::chrono::minutes AVALANCHE_STATISTICS_TIME_CONSTANT
Time constant for the avalanche statistics computation.
static constexpr std::chrono::minutes AVALANCHE_STATISTICS_REFRESH_PERIOD
Refresh period for the avalanche statistics computation.
A BlockHash is a unqiue identifier for a block.
A TxId is the identifier of a transaction.
Compare conflicting proofs.
std::chrono::seconds registration_time
static constexpr auto DANGLING_TIMEOUT
Consider dropping the peer if no node is attached after this timeout expired.
static ProofRef buildDuplicatedStakes(ProofBuilder &pb)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
std::chrono::time_point< std::chrono::steady_clock, std::chrono::milliseconds > SteadyMilliseconds