Page MenuHomePhabricator

D11667.id34137.diff
No OneTemporary

D11667.id34137.diff

diff --git a/src/avalanche/peermanager.h b/src/avalanche/peermanager.h
--- a/src/avalanche/peermanager.h
+++ b/src/avalanche/peermanager.h
@@ -30,6 +30,8 @@
#include <unordered_set>
#include <vector>
+class CScheduler;
+
namespace avalanche {
/**
@@ -224,6 +226,8 @@
uint32_t connectedPeersScore = 0;
public:
+ PeerManager(CScheduler &scheduler);
+
/**
* Node API.
*/
diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp
--- a/src/avalanche/peermanager.cpp
+++ b/src/avalanche/peermanager.cpp
@@ -8,12 +8,21 @@
#include <avalanche/delegation.h>
#include <avalanche/validation.h>
#include <random.h>
+#include <scheduler.h>
#include <validation.h> // For ChainstateActive()
#include <algorithm>
#include <cassert>
namespace avalanche {
+PeerManager::PeerManager(CScheduler &scheduler) {
+ scheduler.scheduleEvery(
+ [this]() -> bool {
+ this->cleanupDanglingProofs();
+ return true;
+ },
+ 5min);
+}
bool PeerManager::addNode(NodeId nodeid, const ProofId &proofid) {
auto &pview = peers.get<by_proofid>();
diff --git a/src/avalanche/processor.h b/src/avalanche/processor.h
--- a/src/avalanche/processor.h
+++ b/src/avalanche/processor.h
@@ -174,8 +174,9 @@
std::unique_ptr<interfaces::Handler> chainNotificationsHandler;
Processor(const ArgsManager &argsman, interfaces::Chain &chain,
- CConnman *connmanIn, std::unique_ptr<PeerData> peerDataIn,
- CKey sessionKeyIn, uint32_t minQuorumTotalScoreIn,
+ CConnman *connmanIn, CScheduler &scheduler,
+ std::unique_ptr<PeerData> peerDataIn, CKey sessionKeyIn,
+ uint32_t minQuorumTotalScoreIn,
double minQuorumConnectedScoreRatioIn,
int64_t minAvaproofsNodeCountIn, uint32_t staleVoteThresholdIn,
uint32_t staleVoteFactorIn);
@@ -186,6 +187,7 @@
static std::unique_ptr<Processor> MakeProcessor(const ArgsManager &argsman,
interfaces::Chain &chain,
CConnman *connman,
+ CScheduler &scheduler,
bilingual_str &error);
void setQueryTimeoutDuration(std::chrono::milliseconds d) {
diff --git a/src/avalanche/processor.cpp b/src/avalanche/processor.cpp
--- a/src/avalanche/processor.cpp
+++ b/src/avalanche/processor.cpp
@@ -121,15 +121,16 @@
};
Processor::Processor(const ArgsManager &argsman, interfaces::Chain &chain,
- CConnman *connmanIn, std::unique_ptr<PeerData> peerDataIn,
- CKey sessionKeyIn, uint32_t minQuorumTotalScoreIn,
+ CConnman *connmanIn, CScheduler &scheduler,
+ std::unique_ptr<PeerData> peerDataIn, CKey sessionKeyIn,
+ uint32_t minQuorumTotalScoreIn,
double minQuorumConnectedScoreRatioIn,
int64_t minAvaproofsNodeCountIn,
uint32_t staleVoteThresholdIn, uint32_t staleVoteFactorIn)
: connman(connmanIn),
queryTimeoutDuration(argsman.GetArg(
"-avatimeout", AVALANCHE_DEFAULT_QUERY_TIMEOUT.count())),
- round(0), peerManager(std::make_unique<PeerManager>()),
+ round(0), peerManager(std::make_unique<PeerManager>(scheduler)),
peerData(std::move(peerDataIn)), sessionKey(std::move(sessionKeyIn)),
minQuorumScore(minQuorumTotalScoreIn),
minQuorumConnectedScoreRatio(minQuorumConnectedScoreRatioIn),
@@ -149,6 +150,7 @@
std::unique_ptr<Processor> Processor::MakeProcessor(const ArgsManager &argsman,
interfaces::Chain &chain,
CConnman *connman,
+ CScheduler &scheduler,
bilingual_str &error) {
std::unique_ptr<PeerData> peerData;
CKey masterKey;
@@ -308,9 +310,10 @@
// We can't use std::make_unique with a private constructor
return std::unique_ptr<Processor>(new Processor(
- argsman, chain, connman, std::move(peerData), std::move(sessionKey),
- Proof::amountToScore(minQuorumStake), minQuorumConnectedStakeRatio,
- minAvaproofsNodeCount, staleVoteThreshold, staleVoteFactor));
+ argsman, chain, connman, scheduler, std::move(peerData),
+ std::move(sessionKey), Proof::amountToScore(minQuorumStake),
+ minQuorumConnectedStakeRatio, minAvaproofsNodeCount, staleVoteThreshold,
+ staleVoteFactor));
}
bool Processor::addBlockToReconcile(const CBlockIndex *pindex) {
diff --git a/src/avalanche/test/peermanager_tests.cpp b/src/avalanche/test/peermanager_tests.cpp
--- a/src/avalanche/test/peermanager_tests.cpp
+++ b/src/avalanche/test/peermanager_tests.cpp
@@ -290,7 +290,7 @@
BOOST_AUTO_TEST_CASE(peer_probabilities) {
// No peers.
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
BOOST_CHECK_EQUAL(pm.selectNode(), NO_NODE);
const NodeId node0 = 42, node1 = 69, node2 = 37;
@@ -326,7 +326,7 @@
BOOST_AUTO_TEST_CASE(remove_peer) {
// No peers.
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
BOOST_CHECK_EQUAL(pm.selectPeer(), NO_PEER);
// Add 4 peers.
@@ -401,7 +401,7 @@
}
BOOST_AUTO_TEST_CASE(compact_slots) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
// Add 4 peers.
std::array<PeerId, 4> peerids;
@@ -430,7 +430,7 @@
}
BOOST_AUTO_TEST_CASE(node_crud) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
// Create one peer.
auto proof = buildRandomProof(10000000 * MIN_VALID_PROOF_SCORE);
@@ -490,7 +490,7 @@
}
BOOST_AUTO_TEST_CASE(node_binding) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
auto proof = buildRandomProof(MIN_VALID_PROOF_SCORE);
const ProofId &proofid = proof->getId();
@@ -589,7 +589,7 @@
}
BOOST_AUTO_TEST_CASE(node_binding_reorg) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
auto key = CKey::MakeCompressedKey();
@@ -656,7 +656,7 @@
addCoin({txid2, i}, key);
}
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
CKey masterKey = CKey::MakeCompressedKey();
const auto getPeerId = [&](const std::vector<COutPoint> &outpoints) {
return TestPeerManager::registerAndGetPeerId(
@@ -710,7 +710,7 @@
BOOST_AUTO_TEST_CASE(orphan_proofs) {
gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "2");
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
auto key = CKey::MakeCompressedKey();
@@ -899,7 +899,7 @@
}
BOOST_AUTO_TEST_CASE(dangling_node) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
auto proof = buildRandomProof(MIN_VALID_PROOF_SCORE);
PeerId peerid = TestPeerManager::registerAndGetPeerId(pm, proof);
@@ -944,7 +944,7 @@
}
BOOST_AUTO_TEST_CASE(proof_accessors) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
constexpr int numProofs = 10;
@@ -988,7 +988,7 @@
}
BOOST_FIXTURE_TEST_CASE(conflicting_proof_rescan, NoCoolDownFixture) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
@@ -1043,7 +1043,7 @@
BOOST_CHECK_EQUAL(comparator(candidate, reference), expectAccepted);
BOOST_CHECK_EQUAL(comparator(reference, candidate), !expectAccepted);
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
BOOST_CHECK(pm.registerProof(reference));
BOOST_CHECK(pm.isBoundToPeer(reference->getId()));
@@ -1113,7 +1113,7 @@
}
BOOST_AUTO_TEST_CASE(conflicting_orphans) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
@@ -1160,7 +1160,7 @@
}
BOOST_FIXTURE_TEST_CASE(preferred_conflicting_proof, NoCoolDownFixture) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
const COutPoint conflictingOutpoint = createUtxo(key);
@@ -1191,7 +1191,7 @@
}
BOOST_FIXTURE_TEST_CASE(update_next_conflict_time, NoCoolDownFixture) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
auto now = GetTime<std::chrono::seconds>();
SetMockTime(now.count());
@@ -1224,7 +1224,7 @@
}
BOOST_FIXTURE_TEST_CASE(register_force_accept, NoCoolDownFixture) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
@@ -1288,7 +1288,7 @@
}
BOOST_FIXTURE_TEST_CASE(evicted_proof, NoCoolDownFixture) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
@@ -1318,7 +1318,7 @@
}
BOOST_AUTO_TEST_CASE(conflicting_proof_cooldown) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
@@ -1386,7 +1386,7 @@
}
BOOST_FIXTURE_TEST_CASE(reject_proof, NoCoolDownFixture) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
@@ -1461,7 +1461,7 @@
}
BOOST_AUTO_TEST_CASE(should_request_more_nodes) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
auto proof = buildRandomProof(MIN_VALID_PROOF_SCORE);
BOOST_CHECK(pm.registerProof(proof));
@@ -1509,7 +1509,7 @@
}
BOOST_AUTO_TEST_CASE(score_ordering) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
std::vector<uint32_t> expectedScores(10);
// Expect the peers to be ordered by descending score
@@ -1535,7 +1535,7 @@
BOOST_FIXTURE_TEST_CASE(known_score_tracking, NoCoolDownFixture) {
gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "2");
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const CKey key = CKey::MakeCompressedKey();
@@ -1645,7 +1645,7 @@
}
BOOST_AUTO_TEST_CASE(connected_score_tracking) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const auto checkScores = [&pm](uint32_t known, uint32_t connected) {
BOOST_CHECK_EQUAL(pm.getTotalPeersScore(), known);
@@ -1733,7 +1733,7 @@
}
BOOST_FIXTURE_TEST_CASE(proof_radix_tree, NoCoolDownFixture) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
gArgs.ForceSetArg("-enableavalancheproofreplacement", "1");
@@ -1849,7 +1849,7 @@
}
BOOST_AUTO_TEST_CASE(received_avaproofs) {
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
auto addNode = [&](NodeId nodeid) {
auto proof = buildRandomProof(MIN_VALID_PROOF_SCORE);
@@ -1872,7 +1872,7 @@
BOOST_FIXTURE_TEST_CASE(cleanup_dangling_proof, NoCoolDownFixture) {
gArgs.ForceSetArg("-enableavalancheproofreplacement", "1");
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
const auto now = GetTime<std::chrono::seconds>();
auto mocktime = now;
diff --git a/src/avalanche/test/processor_tests.cpp b/src/avalanche/test/processor_tests.cpp
--- a/src/avalanche/test/processor_tests.cpp
+++ b/src/avalanche/test/processor_tests.cpp
@@ -111,7 +111,8 @@
// Get the processor ready.
bilingual_str error;
m_processor = Processor::MakeProcessor(*m_node.args, *m_node.chain,
- m_node.connman.get(), error);
+ m_node.connman.get(),
+ *m_node.scheduler, error);
BOOST_CHECK(m_processor);
gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "1");
@@ -1147,7 +1148,8 @@
bilingual_str error;
std::unique_ptr<Processor> processor = Processor::MakeProcessor(
- *m_node.args, *m_node.chain, m_node.connman.get(), error);
+ *m_node.args, *m_node.chain, m_node.connman.get(), *m_node.scheduler,
+ error);
BOOST_CHECK(processor != nullptr);
BOOST_CHECK(processor->getLocalProof() != nullptr);
@@ -1295,7 +1297,8 @@
bilingual_str error;
std::unique_ptr<Processor> processor = Processor::MakeProcessor(
- *m_node.args, *m_node.chain, m_node.connman.get(), error);
+ *m_node.args, *m_node.chain, m_node.connman.get(),
+ *m_node.scheduler, error);
if (std::get<3>(*it)) {
BOOST_CHECK(processor != nullptr);
@@ -1324,7 +1327,8 @@
bilingual_str error;
auto processor = Processor::MakeProcessor(argsman, *m_node.chain,
- m_node.connman.get(), error);
+ m_node.connman.get(),
+ *m_node.scheduler, error);
BOOST_CHECK_EQUAL(processor->isQuorumEstablished(),
minAvaproofsMessages <= 0);
@@ -1381,7 +1385,8 @@
bilingual_str error;
m_processor = Processor::MakeProcessor(*m_node.args, *m_node.chain,
- m_node.connman.get(), error);
+ m_node.connman.get(),
+ *m_node.scheduler, error);
BOOST_CHECK(m_processor != nullptr);
BOOST_CHECK(error.empty());
diff --git a/src/avalanche/test/proofpool_tests.cpp b/src/avalanche/test/proofpool_tests.cpp
--- a/src/avalanche/test/proofpool_tests.cpp
+++ b/src/avalanche/test/proofpool_tests.cpp
@@ -77,7 +77,7 @@
BOOST_AUTO_TEST_CASE(rescan) {
gArgs.ForceSetArg("-avaproofstakeutxoconfirmations", "1");
ProofPool testPool;
- avalanche::PeerManager pm;
+ avalanche::PeerManager pm(*m_node.scheduler);
testPool.rescan(pm);
BOOST_CHECK_EQUAL(testPool.size(), 0);
diff --git a/src/init.cpp b/src/init.cpp
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -2569,7 +2569,7 @@
// Step 6.5 (I guess ?): Initialize Avalanche.
bilingual_str avalancheError;
g_avalanche = avalanche::Processor::MakeProcessor(
- args, *node.chain, node.connman.get(), avalancheError);
+ args, *node.chain, node.connman.get(), *node.scheduler, avalancheError);
if (!g_avalanche) {
InitError(avalancheError);
return false;
diff --git a/test/functional/abc_feature_proof_cleanup.py b/test/functional/abc_feature_proof_cleanup.py
new file mode 100644
--- /dev/null
+++ b/test/functional/abc_feature_proof_cleanup.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""
+Test the dangling proofs cleanup
+"""
+
+import time
+
+from test_framework.avatools import (
+ gen_proof,
+ get_ava_p2p_interface,
+ get_proof_ids,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+# Interval between 2 proof cleanups
+AVALANCHE_CLEANUP_INTERVAL = 5 * 60
+# Dangling proof timeout
+AVALANCHE_DANGLING_PROOF_TIMEOUT = 15 * 60
+
+
+class ProofsCleanupTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.extra_args = [[
+ '-enableavalanche=1',
+ '-avaproofstakeutxoconfirmations=1',
+ ]] * self.num_nodes
+
+ def run_test(self):
+ node = self.nodes[0]
+
+ mocktime = int(time.time())
+ node.setmocktime(mocktime)
+
+ proofs = []
+ peers = []
+ # The first 5 peers have a node attached
+ for _ in range(5):
+ key, proof = gen_proof(node)
+
+ peer = get_ava_p2p_interface(node)
+ node.addavalanchenode(
+ peer.nodeid,
+ key.get_pubkey().get_bytes().hex(),
+ proof.serialize().hex())
+
+ proofs.append(proof)
+ peers.append(peer)
+
+ # The last 5 peers have no node attached
+ for _ in range(5):
+ _, proof = gen_proof(node)
+ node.sendavalancheproof(proof.serialize().hex())
+ proofs.append(proof)
+
+ peer_info = node.getavalanchepeerinfo()
+ assert_equal(len(peer_info), 10)
+ assert_equal(set(get_proof_ids(node)),
+ set([proof.proofid for proof in proofs]))
+
+ self.log.info("No proof is cleaned before the timeout expires")
+
+ mocktime += AVALANCHE_DANGLING_PROOF_TIMEOUT - 1
+ node.setmocktime(mocktime)
+ # Run the cleanup, the proofs are still there
+ node.mockscheduler(AVALANCHE_CLEANUP_INTERVAL)
+ assert_equal(len(peer_info), 10)
+
+ self.log.info("Check the proofs with attached nodes are not cleaned")
+
+ # Expire the dangling proof timeout
+ mocktime += 1
+ node.setmocktime(mocktime)
+
+ # Run the cleanup, the proofs with no node are cleaned
+ node.mockscheduler(AVALANCHE_CLEANUP_INTERVAL)
+ self.wait_until(lambda: set(get_proof_ids(node)) == set(
+ [proof.proofid for proof in proofs[:5]]), timeout=5)
+
+ self.log.info(
+ "Check the proofs are cleaned on next cleanup after the nodes disconnected")
+
+ for peer in peers:
+ peer.peer_disconnect()
+ peer.wait_for_disconnect()
+
+ node.mockscheduler(AVALANCHE_CLEANUP_INTERVAL)
+ self.wait_until(lambda: get_proof_ids(node) == [])
+
+
+if __name__ == '__main__':
+ ProofsCleanupTest().main()
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -129,6 +129,7 @@
"wallet_watchonly.py": [["--usecli"]],
# Avalanche tests running with and without the legacy proof format
+ "abc_feature_proof_cleanup.py": [["--nolegacyavaproof"]],
"abc_p2p_avalanche_peer_discovery.py": [["--nolegacyavaproof"]],
"abc_p2p_avalanche_proof_voting.py": [["--nolegacyavaproof"]],
"abc_p2p_avalanche_quorum.py": [["--nolegacyavaproof"]],

File Metadata

Mime Type
text/plain
Expires
Tue, May 20, 19:35 (6 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5865794
Default Alt Text
D11667.id34137.diff (18 KB)

Event Timeline