23 #include <validation.h>
26 #include <test/util/setup_common.h>
28 #include <boost/mpl/list.hpp>
29 #include <boost/test/unit_test.hpp>
32 #include <type_traits>
39 struct AvalancheTest {
42 static std::vector<CInv> getInvsForNextPoll(
Processor &p) {
48 return p.peerManager->selectNode());
53 static uint32_t getMinQuorumScore(
const Processor &p) {
57 static double getMinQuorumConnectedScoreRatio(
const Processor &p) {
61 static void clearavaproofsNodeCounter(
Processor &p) {
68 std::make_pair(item, voteRecord));
71 static void setFinalizationTip(
Processor &p,
74 p.finalizationTip = pindex;
87 struct CConnmanTest :
public CConnman {
91 m_nodes.push_back(&
node);
108 struct AvalancheTestingSetup :
public TestChain100Setup {
109 const ::Config &config;
110 CConnmanTest *m_connman;
112 std::unique_ptr<Processor> m_processor;
117 std::unordered_set<std::string> m_overridden_args;
119 AvalancheTestingSetup()
120 : TestChain100Setup(), config(
GetConfig()),
121 masterpriv(
CKey::MakeCompressedKey()) {
123 auto connman = std::make_unique<CConnmanTest>(config, 0x1337, 0x1337,
125 m_connman = connman.get();
126 m_node.connman = std::move(connman);
128 config.GetChainParams(), *m_connman, *
m_node.addrman,
133 setArg(
"-avaminquorumstake",
"0");
134 setArg(
"-avaminquorumconnectedstakeratio",
"0");
135 setArg(
"-avaminavaproofsnodecount",
"0");
136 setArg(
"-avaproofstakeutxoconfirmations",
"1");
145 ~AvalancheTestingSetup() {
146 m_connman->ClearNodes();
150 for (
const std::string &key : m_overridden_args) {
153 m_overridden_args.clear();
168 node->nServices = nServices;
171 node->fSuccessfullyConnected =
true;
173 m_connman->AddNode(*
node);
182 const uint32_t height = 100;
191 BOOST_CHECK(pb.addUTXO(outpoint, amount, height,
false, key));
197 return pm.
addNode(nodeid, proofid);
201 bool addNode(
NodeId nodeid) {
202 auto proof = GetProof();
205 pm.
addNode(nodeid, proof->getId());
209 std::array<CNode *, 8> ConnectNodes() {
210 auto proof = GetProof();
213 return pm.registerProof(proof);
215 const ProofId &proofid = proof->getId();
217 std::array<CNode *, 8> nodes;
218 for (
CNode *&n : nodes) {
226 void runEventLoop() { AvalancheTest::runEventLoop(*m_processor); }
228 NodeId getSuitableNodeToQuery() {
229 return AvalancheTest::getSuitableNodeToQuery(*m_processor);
232 std::vector<CInv> getInvsForNextPoll() {
233 return AvalancheTest::getInvsForNextPoll(*m_processor);
236 uint64_t getRound()
const {
return AvalancheTest::getRound(*m_processor); }
239 std::vector<avalanche::VoteItemUpdate> &updates,
240 std::string &
error) {
242 return m_processor->registerVotes(nodeid,
response, updates, banscore,
247 std::vector<avalanche::VoteItemUpdate> &updates) {
250 return m_processor->registerVotes(nodeid,
response, updates, banscore,
254 void setArg(std::string key, std::string value) {
257 m_overridden_args.emplace(std::move(key));
261 return m_processor->addToReconcile(item);
265 struct BlockProvider {
266 AvalancheTestingSetup *fixture;
269 BlockProvider(AvalancheTestingSetup *_fixture)
270 : fixture(_fixture), invType(
MSG_BLOCK) {}
273 CBlock block = fixture->CreateAndProcessBlock({},
CScript());
277 return Assert(fixture->m_node.chainman)
278 ->m_blockman.LookupBlockIndex(blockHash);
285 std::vector<Vote> buildVotesForItems(uint32_t
error,
286 std::vector<CBlockIndex *> &&items) {
287 size_t numItems = items.
size();
289 std::vector<Vote> votes;
290 votes.reserve(numItems);
295 votes.emplace_back(
error, item->GetBlockHash());
303 pindex->nStatus = pindex->nStatus.withFailed();
307 return std::get<const CBlockIndex *>(item);
311 struct ProofProvider {
312 AvalancheTestingSetup *fixture;
315 ProofProvider(AvalancheTestingSetup *_fixture)
319 const ProofRef proof = fixture->GetProof();
327 return proof->
getId();
330 std::vector<Vote> buildVotesForItems(uint32_t
error,
331 std::vector<ProofRef> &&items) {
332 size_t numItems = items.
size();
334 std::vector<Vote> votes;
335 votes.reserve(numItems);
339 for (
auto &item : items) {
340 votes.emplace_back(
error, item->getId());
346 void invalidateItem(
const ProofRef &proof) {
354 return std::get<const ProofRef>(item);
359 AvalancheTestingSetup *fixture;
361 std::vector<avalanche::VoteItemUpdate> updates;
364 TxProvider(AvalancheTestingSetup *_fixture)
365 : fixture(_fixture), invType(
MSG_TX) {}
375 TestMemPoolEntryHelper mempoolEntryHelper;
376 auto entry = mempoolEntryHelper.FromTx(tx);
392 std::vector<Vote> buildVotesForItems(uint32_t
error,
393 std::vector<CTransactionRef> &&items) {
394 size_t numItems = items.
size();
396 std::vector<Vote> votes;
397 votes.reserve(numItems);
400 std::sort(items.begin(), items.end(),
402 return lhs->GetId() < rhs->GetId();
404 for (
auto &item : items) {
405 votes.emplace_back(
error, item->GetId());
421 return std::get<const CTransactionRef>(item);
431 boost::mpl::list<BlockProvider, ProofProvider, TxProvider>;
436 std::set<VoteStatus> status{
441 auto item = provider.buildVoteItem();
443 for (
auto s : status) {
464 auto item = provider.buildVoteItem();
465 auto itemid = provider.getVoteItemId(item);
473 auto avanodes = ConnectNodes();
475 int nextNodeIndex = 0;
476 std::vector<avalanche::VoteItemUpdate> updates;
477 auto registerNewVote = [&](
const Response &resp) {
479 auto nodeid = avanodes[nextNodeIndex++ % avanodes.size()]->GetId();
484 auto finalize = [&](
const auto finalizeItemId) {
485 Response resp = {getRound(), 0, {
Vote(0, finalizeItemId)}};
487 registerNewVote(next(resp));
488 if (updates.size() > 0) {
501 auto finalizeNewItem = [&]() {
502 auto anotherItem = provider.buildVoteItem();
504 auto anotherItemId = provider.getVoteItemId(anotherItem);
507 AvalancheTest::addVoteRecord(*m_processor, anotherVoteItem, voteRecord);
508 finalize(anotherItemId);
528 AvalancheTest::setFinalizationTip(*m_processor, chaintip);
540 auto item = decltype(provider.buildVoteItem())();
547 item = provider.buildVoteItem();
556 const uint32_t invType = provider.invType;
558 auto item = provider.buildVoteItem();
559 auto itemid = provider.getVoteItemId(item);
562 auto avanodes = ConnectNodes();
569 auto invs = getInvsForNextPoll();
576 int nextNodeIndex = 0;
577 std::vector<avalanche::VoteItemUpdate> updates;
578 auto registerNewVote = [&](
const Response &resp) {
580 auto nodeid = avanodes[nextNodeIndex++ % avanodes.size()]->GetId();
586 for (
int i = 0; i < 6; i++) {
587 registerNewVote(next(resp));
594 resp = {getRound(), 0, {
Vote(-1, itemid)}};
595 registerNewVote(next(resp));
600 resp = {getRound(), 0, {
Vote(0, itemid)}};
601 for (
int i = 1; i < 7; i++) {
602 registerNewVote(next(resp));
609 resp = {getRound(), 0, {
Vote(-1, itemid)}};
610 registerNewVote(next(resp));
614 registerNewVote(next(resp));
619 resp = {getRound(), 0, {
Vote(0, itemid)}};
620 for (
int i = 2; i < 8; i++) {
621 registerNewVote(next(resp));
629 registerNewVote(next(resp));
636 invs = getInvsForNextPoll();
642 registerNewVote(next(resp));
644 BOOST_CHECK(provider.fromAnyVoteItem(updates[0].getVoteItem()) == item);
649 invs = getInvsForNextPoll();
653 item = provider.buildVoteItem();
654 itemid = provider.getVoteItemId(item);
658 invs = getInvsForNextPoll();
663 resp = {getRound(), 0, {
Vote(1, itemid)}};
664 for (
int i = 0; i < 6; i++) {
665 registerNewVote(next(resp));
671 registerNewVote(next(resp));
674 BOOST_CHECK(provider.fromAnyVoteItem(updates[0].getVoteItem()) == item);
680 registerNewVote(next(resp));
686 invs = getInvsForNextPoll();
692 registerNewVote(next(resp));
695 BOOST_CHECK(provider.fromAnyVoteItem(updates[0].getVoteItem()) == item);
700 invs = getInvsForNextPoll();
706 const uint32_t invType = provider.invType;
708 auto itemA = provider.buildVoteItem();
709 auto itemidA = provider.getVoteItemId(itemA);
711 auto itemB = provider.buildVoteItem();
712 auto itemidB = provider.getVoteItemId(itemB);
715 auto avanodes = ConnectNodes();
723 auto invs = getInvsForNextPoll();
728 uint64_t round = getRound();
730 std::vector<avalanche::VoteItemUpdate> updates;
732 {round, 0, {
Vote(0, itemidA)}}, updates));
736 std::vector<Vote> votes = provider.buildVotesForItems(0, {itemA, itemB});
739 invs = getInvsForNextPoll();
743 for (
size_t i = 0; i < invs.size(); i++) {
749 for (
int i = 0; i < 4; i++) {
750 NodeId nodeid = getSuitableNodeToQuery();
752 BOOST_CHECK(registerVotes(nodeid, next(resp), updates));
758 NodeId nodeid = getSuitableNodeToQuery();
760 BOOST_CHECK(registerVotes(nodeid, next(resp), updates));
766 NodeId firstNodeid = getSuitableNodeToQuery();
768 NodeId secondNodeid = getSuitableNodeToQuery();
774 BOOST_CHECK(registerVotes(firstNodeid, next(resp), updates));
776 BOOST_CHECK(provider.fromAnyVoteItem(updates[0].getVoteItem()) == itemA);
781 invs = getInvsForNextPoll();
787 BOOST_CHECK(registerVotes(secondNodeid, resp, updates));
789 BOOST_CHECK(provider.fromAnyVoteItem(updates[0].getVoteItem()) == itemB);
794 invs = getInvsForNextPoll();
800 const uint32_t invType = provider.invType;
802 auto item = provider.buildVoteItem();
803 auto itemid = provider.getVoteItemId(item);
810 std::set<NodeId> avanodeIds;
811 auto avanodes = ConnectNodes();
812 for (
auto avanode : avanodes) {
814 avanodeIds.insert(avanode->GetId());
817 auto getSelectedAvanodeId = [&]() {
818 NodeId avanodeid = getSuitableNodeToQuery();
819 BOOST_CHECK(avanodeIds.find(avanodeid) != avanodeIds.end());
824 NodeId avanodeid = getSelectedAvanodeId();
828 auto invs = getInvsForNextPoll();
833 std::set<NodeId> unselectedNodeids = avanodeIds;
834 unselectedNodeids.erase(avanodeid);
835 const size_t remainingNodeIds = unselectedNodeids.size();
837 uint64_t round = getRound();
838 for (
size_t i = 0; i < remainingNodeIds; i++) {
843 NodeId nodeid = getSuitableNodeToQuery();
844 BOOST_CHECK(unselectedNodeids.find(nodeid) != avanodeIds.end());
845 unselectedNodeids.erase(nodeid);
855 std::vector<avalanche::VoteItemUpdate> updates;
856 BOOST_CHECK(registerVotes(avanodeid, resp, updates));
863 auto checkRegisterVotesError = [&](
NodeId nodeid,
865 const std::string &expectedError) {
873 checkRegisterVotesError(avanodeid, next(resp),
"unexpected-ava-response");
882 resp = {round, 0, {
Vote(0, itemid),
Vote(0, itemid)}};
884 checkRegisterVotesError(avanodeid, resp,
"invalid-ava-response-size");
888 resp = {getRound(), 0, {}};
890 checkRegisterVotesError(avanodeid, resp,
"invalid-ava-response-size");
894 resp = {getRound(), 0, {
Vote()}};
896 checkRegisterVotesError(avanodeid, resp,
"invalid-ava-response-content");
903 invs = getInvsForNextPoll();
906 item = provider.buildVoteItem();
907 itemid = provider.getVoteItemId(item);
910 invs = getInvsForNextPoll();
914 uint64_t queryRound = getRound();
917 resp = {queryRound + 1, 0, {
Vote()}};
918 checkRegisterVotesError(avanodeid, resp,
"unexpected-ava-response");
920 resp = {queryRound - 1, 0, {
Vote()}};
921 checkRegisterVotesError(avanodeid, resp,
"unexpected-ava-response");
925 resp = {queryRound, 0, {
Vote(0, itemid)}};
926 checkRegisterVotesError(avanodeid + 1234, resp,
"unexpected-ava-response");
929 resp = {queryRound, 0, {
Vote(0, itemid)}};
930 BOOST_CHECK(registerVotes(avanodeid, resp, updates));
935 const auto item2 = provider.buildVoteItem();
938 std::vector<Vote> votes = provider.buildVotesForItems(0, {item, item2});
939 resp = {getRound(), 0, {votes[1], votes[0]}};
941 checkRegisterVotesError(avanodeid, resp,
"invalid-ava-response-content");
945 resp = {getRound(), 0, votes};
947 BOOST_CHECK(registerVotes(avanodeid, resp, updates));
954 const uint32_t invType = provider.invType;
956 auto itemA = provider.buildVoteItem();
957 auto itemB = provider.buildVoteItem();
959 auto avanodes = ConnectNodes();
962 std::vector<Vote> votes = provider.buildVotesForItems(0, {itemA, itemB});
968 auto invs = getInvsForNextPoll();
970 for (
size_t i = 0; i < invs.size(); i++) {
976 provider.invalidateItem(itemB);
978 Response goodResp{getRound(), 0, {
Vote(0, provider.getVoteItemId(itemA))}};
979 std::vector<avalanche::VoteItemUpdate> updates;
981 BOOST_CHECK(registerVotes(avanodes[0]->GetId(), goodResp, updates));
985 Response badResp{getRound(), 0, votes};
992 BOOST_TEST_DECORATOR(*boost::unit_test::timeout(60))
997 auto queryTimeDuration = std::chrono::milliseconds(10);
998 setArg(
"-avatimeout",
ToString(queryTimeDuration.count()));
1005 const auto item = provider.buildVoteItem();
1006 const auto itemid = provider.getVoteItemId(item);
1016 for (
int i = 0; i < 10; i++) {
1018 avanodeid = getSuitableNodeToQuery();
1020 auto start = std::chrono::steady_clock::now();
1024 std::this_thread::sleep_for(std::chrono::milliseconds(1));
1027 std::vector<avalanche::VoteItemUpdate> updates;
1028 bool ret = registerVotes(avanodeid, next(resp), updates);
1029 if (std::chrono::steady_clock::now() > start + queryTimeDuration) {
1040 avanodeid = getSuitableNodeToQuery();
1044 std::this_thread::sleep_for(queryTimeDuration);
1046 BOOST_CHECK(!registerVotes(avanodeid, next(resp), updates));
1052 const uint32_t invType = provider.invType;
1055 auto proof = GetProof();
1059 std::array<CNode *, AVALANCHE_MAX_INFLIGHT_POLL + 1> nodes;
1060 for (
auto &n : nodes) {
1066 const auto item = provider.buildVoteItem();
1067 const auto itemid = provider.getVoteItemId(item);
1071 std::map<NodeId, uint64_t> node_round_map;
1073 NodeId nodeid = getSuitableNodeToQuery();
1074 BOOST_CHECK(node_round_map.find(nodeid) == node_round_map.end());
1075 node_round_map.insert(std::pair<NodeId, uint64_t>(nodeid, getRound()));
1076 auto invs = getInvsForNextPoll();
1084 auto suitablenodeid = getSuitableNodeToQuery();
1086 auto invs = getInvsForNextPoll();
1092 auto it = node_round_map.begin();
1094 std::vector<avalanche::VoteItemUpdate> updates;
1095 BOOST_CHECK(registerVotes(it->first, resp, updates));
1096 node_round_map.erase(it);
1098 invs = getInvsForNextPoll();
1105 std::vector<VoteItemUpdate> updates;
1113 Assert(
m_node.chainman)->m_blockman.LookupBlockIndex(blockHash);
1117 auto avanodes = ConnectNodes();
1126 uint64_t round = getRound();
1130 for (
size_t i = 0; i < avanodes.size(); i++) {
1132 BOOST_CHECK(registerVotes(avanodes[i]->GetId(), next(resp), updates));
1136 const NodeId firstNodeId = getSuitableNodeToQuery();
1137 std::map<NodeId, uint64_t> node_round_map;
1139 for (
size_t i = 0; i < avanodes.size(); i++) {
1140 NodeId nodeid = getSuitableNodeToQuery();
1141 BOOST_CHECK(node_round_map.find(nodeid) == node_round_map.end());
1142 node_round_map[nodeid] = getRound();
1148 auto confidence = m_processor->getConfidence(pindex);
1149 BOOST_REQUIRE(confidence > 0);
1151 for (
auto &[nodeid, r] : node_round_map) {
1152 if (nodeid == firstNodeId) {
1159 registerVotes(nodeid, {r, 0, {
Vote(0, blockHash)}}, updates));
1164 registerVotes(firstNodeId, {round, 0, {
Vote(0, blockHash)}}, updates));
1177 Assert(
m_node.chainman)->m_blockman.LookupBlockIndex(blockHash);
1184 std::chrono::steady_clock::time_point start,
stop;
1194 auto avanodes = ConnectNodes();
1197 NodeId nodeid = getSuitableNodeToQuery();
1198 BOOST_CHECK_NE(nodeid,
NO_NODE);
1201 uint64_t queryRound = getRound();
1205 for (
int i = 0; i < 60 * 1000; i++) {
1209 if (getRound() == queryRound + avanodes.size()) {
1218 uint64_t responseRound = getRound();
1220 std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
1222 std::vector<VoteItemUpdate> updates;
1224 BOOST_CHECK(registerVotes(nodeid, {queryRound, 100, {
Vote(0, blockHash)}},
1227 for (
int i = 0; i < 10000; i++) {
1230 if (getRound() != responseRound) {
1231 BOOST_CHECK(std::chrono::steady_clock::now() > queryTime);
1250 schedulerThread.join();
1255 std::chrono::steady_clock::time_point start,
stop;
1257 std::thread schedulerThread;
1267 m_processor.reset();
1274 schedulerThread.join();
1281 auto addProofToReconcile = [&](uint32_t proofScore) {
1291 auto proof = addProofToReconcile(++score);
1293 auto invs = AvalancheTest::getInvsForNextPoll(*m_processor);
1302 for (
size_t i = 0; i < 10; i++) {
1303 auto proof = addProofToReconcile(++score);
1305 auto invs = AvalancheTest::getInvsForNextPoll(*m_processor);
1310 lastProofId = proof->
getId();
1313 for (
size_t i = 0; i < 10; i++) {
1314 auto proof = addProofToReconcile(--score);
1316 auto invs = AvalancheTest::getInvsForNextPoll(*m_processor);
1324 auto proof = addProofToReconcile(--score);
1325 auto invs = AvalancheTest::getInvsForNextPoll(*m_processor);
1326 for (
auto &inv : invs) {
1327 BOOST_CHECK_NE(inv.hash, proof->
getId());
1333 setArg(
"-avaproofstakeutxoconfirmations",
"2");
1334 setArg(
"-avalancheconflictingproofcooldown",
"0");
1348 Assert(
m_node.chainman)->ActiveChainstate().CoinsTip();
1349 coins.
AddCoin(conflictingOutpoint,
1352 coins.
AddCoin(immatureOutpoint,
1357 auto buildProof = [&](
const COutPoint &outpoint, uint64_t sequence,
1358 uint32_t height = 10) {
1365 auto conflictingProof = buildProof(conflictingOutpoint, 1);
1366 auto validProof = buildProof(conflictingOutpoint, 2);
1367 auto immatureProof = buildProof(immatureOutpoint, 3, 100);
1369 BOOST_CHECK(!m_processor->isAccepted(conflictingProof));
1370 BOOST_CHECK(!m_processor->isAccepted(validProof));
1371 BOOST_CHECK(!m_processor->isAccepted(immatureProof));
1377 BOOST_CHECK(!m_processor->addToReconcile(conflictingProof));
1378 BOOST_CHECK(!m_processor->addToReconcile(validProof));
1379 BOOST_CHECK(!m_processor->addToReconcile(immatureProof));
1391 BOOST_CHECK(m_processor->addToReconcile(conflictingProof));
1392 BOOST_CHECK(!m_processor->isAccepted(conflictingProof));
1393 BOOST_CHECK(!m_processor->isAccepted(validProof));
1394 BOOST_CHECK(!m_processor->isAccepted(immatureProof));
1399 BOOST_CHECK(m_processor->addToReconcile(validProof));
1400 BOOST_CHECK(!m_processor->isAccepted(conflictingProof));
1402 BOOST_CHECK(!m_processor->isAccepted(immatureProof));
1407 BOOST_CHECK(!m_processor->addToReconcile(immatureProof));
1408 BOOST_CHECK(!m_processor->isAccepted(conflictingProof));
1410 BOOST_CHECK(!m_processor->isAccepted(immatureProof));
1418 int minStake = 400'000'000;
1419 setArg(
"-avaminquorumstake",
ToString(minStake));
1420 setArg(
"-avaminquorumconnectedstakeratio",
"0.5");
1432 setArg(
"-avaproof", localProof->ToHex());
1441 BOOST_CHECK(m_processor->getLocalProof() !=
nullptr);
1443 localProof->getId());
1446 AvalancheTest::getMinQuorumConnectedScoreRatio(*m_processor), 0.5);
1467 for (
NodeId id = 0;
id < 8;
id++) {
1469 pm.
addNode(
id, m_processor->getLocalProof()->getId());
1487 const Amount amount = (int64_t(minScore / 4) *
COIN) / 100;
1488 const int height = 100;
1489 const bool isCoinbase =
false;
1496 height, isCoinbase),
1501 auto proof2 = pb.
build();
1512 pm.
addNode(8, proof2->getId());
1531 m_processor->withPeerManager(
1537 pm.
addNode(7, m_processor->getLocalProof()->getId());
1542 auto spendProofUtxo = [&](
ProofRef proof) {
1555 for (int64_t i = 0; i < 6; i++) {
1557 CreateAndProcessBlock({},
CScript());
1560 proof2->getExpirationTime());
1571 spendProofUtxo(proof1);
1578 spendProofUtxo(m_processor->getLocalProof());
1590 const std::vector<std::tuple<std::string, std::string, std::string, bool>>
1593 {
"",
"",
"",
false},
1594 {
"-1",
"-1",
"-1",
false},
1597 {
"-1",
"0",
"0",
false},
1598 {
"-0.01",
"0",
"0",
false},
1599 {
"21000000000000.01",
"0",
"0",
false},
1602 {
"0",
"-1",
"0",
false},
1603 {
"0",
"1.1",
"0",
false},
1606 {
"0",
"0",
"-1",
false},
1609 {
"0",
"0",
"0",
true},
1610 {
"0.00",
"0",
"0",
true},
1611 {
"0.01",
"0",
"0",
true},
1612 {
"1",
"0.1",
"0",
true},
1613 {
"10",
"0.5",
"0",
true},
1614 {
"10",
"1",
"0",
true},
1615 {
"21000000000000.00",
"0",
"0",
true},
1616 {
"0",
"0",
"1",
true},
1617 {
"0",
"0",
"100",
true},
1622 for (
const auto &[stake, stakeRatio, numProofsMessages, success] :
1624 setArg(
"-avaminquorumstake", stake);
1625 setArg(
"-avaminquorumconnectedstakeratio", stakeRatio);
1626 setArg(
"-avaminavaproofsnodecount", numProofsMessages);
1649 auto checkMinAvaproofsMessages = [&](int64_t minAvaproofsMessages) {
1650 setArg(
"-avaminavaproofsnodecount",
ToString(minAvaproofsMessages));
1657 auto addNode = [&](
NodeId nodeid) {
1670 for (
NodeId id = 100;
id < 108;
id++) {
1675 minAvaproofsMessages <= 0);
1677 for (int64_t i = 0; i < minAvaproofsMessages - 1; i++) {
1680 processor->avaproofsSent(i);
1684 processor->avaproofsSent(i);
1690 addNode(minAvaproofsMessages);
1691 processor->avaproofsSent(minAvaproofsMessages);
1695 AvalancheTest::clearavaproofsNodeCounter(*processor);
1699 checkMinAvaproofsMessages(0);
1700 checkMinAvaproofsMessages(1);
1701 checkMinAvaproofsMessages(10);
1702 checkMinAvaproofsMessages(100);
1707 setArg(
"-avastalevotethreshold",
1709 setArg(
"-avastalevotefactor",
"2");
1711 const std::vector<std::tuple<int, int>> testCases = {
1727 const uint32_t invType = provider.invType;
1729 const auto item = provider.buildVoteItem();
1730 const auto itemid = provider.getVoteItemId(item);
1733 auto avanodes = ConnectNodes();
1734 int nextNodeIndex = 0;
1736 std::vector<avalanche::VoteItemUpdate> updates;
1737 for (
const auto &[numYesVotes, numNeutralVotes] : testCases) {
1740 auto invs = getInvsForNextPoll();
1747 auto registerNewVote = [&](
const Response &resp) {
1749 auto nodeid = avanodes[nextNodeIndex++ % avanodes.size()]->GetId();
1750 BOOST_CHECK(registerVotes(nodeid, resp, updates));
1754 for (
int i = 0; i < numYesVotes; i++) {
1756 registerNewVote(next(resp));
1759 i >= 6 ? i - 5 : 0);
1764 for (
int i = 0; i < numNeutralVotes; i++) {
1766 registerNewVote(next(resp));
1771 invs = getInvsForNextPoll();
1778 registerNewVote(next(resp));
1780 BOOST_CHECK(provider.fromAnyVoteItem(updates[0].getVoteItem()) == item);
1785 invs = getInvsForNextPoll();
1791 BlockProvider provider(
this);
1793 std::vector<CBlockIndex *> blockIndexes;
1797 blockIndexes.push_back(pindex);
1800 auto invs = getInvsForNextPoll();
1812 std::vector<Vote> votes;
1815 BlockHash blockhash = blockIndexes[i - 1]->GetBlockHash();
1816 votes.emplace_back(blockhash == eleventhBlockHash ? 0 : -1, blockhash);
1819 auto avanodes = ConnectNodes();
1820 int nextNodeIndex = 0;
1822 std::vector<avalanche::VoteItemUpdate> updates;
1823 auto registerNewVote = [&]() {
1824 Response resp = {getRound(), 0, votes};
1826 auto nodeid = avanodes[nextNodeIndex++ % avanodes.size()]->GetId();
1827 BOOST_CHECK(registerVotes(nodeid, resp, updates));
1831 bool eleventhBlockFinalized =
false;
1832 for (
size_t i = 0; i < 10000 && !eleventhBlockFinalized; i++) {
1835 for (
auto &update : updates) {
1837 provider.fromAnyVoteItem(update.getVoteItem())
1838 ->GetBlockHash() == eleventhBlockHash) {
1839 eleventhBlockFinalized =
true;
1846 invs = getInvsForNextPoll();
1848 for (
size_t i = 0; i < 10; i++) {
1863 auto &activeChainstate =
m_node.chainman->ActiveChainstate();
1865 activeChainstate.InvalidateBlock(config, state, tip);
1871 ->m_blockman.LookupBlockIndex(altblock.
GetHash()));
1879 activeChainstate.ResetBlockFailureFlags(tip);
1881 activeChainstate.ActivateBestChain(config, state);
1885 invs = getInvsForNextPoll();
1892 for (
auto &inv : invs) {
1893 votes.emplace_back(inv.hash == tiphash ? 0 : -1, inv.hash);
1896 bool tipFinalized =
false;
1897 for (
size_t i = 0; i < 10000 && !tipFinalized; i++) {
1900 for (
auto &update : updates) {
1902 provider.fromAnyVoteItem(update.getVoteItem())
1903 ->GetBlockHash() == tiphash) {
1904 tipFinalized =
true;
1913 invs = getInvsForNextPoll();
1921 BlockHash alttiphash = alttip->GetBlockHash();
1922 votes = {{1, alttiphash}};
1924 bool alttipInvalidated =
false;
1925 for (
size_t i = 0; i < 10000 && !alttipInvalidated; i++) {
1928 for (
auto &update : updates) {
1930 provider.fromAnyVoteItem(update.getVoteItem())
1931 ->GetBlockHash() == alttiphash) {
1932 alttipInvalidated =
true;
1937 invs = getInvsForNextPoll();
1948 const int numberElementsEachType = 100;
1951 std::vector<ProofRef> proofs;
1952 for (
size_t i = 1; i <= numberElementsEachType; i++) {
1956 proofs.emplace_back(std::move(proof));
1958 Shuffle(proofs.begin(), proofs.end(), rng);
1960 std::vector<CBlockIndex> indexes;
1961 for (
size_t i = 1; i <= numberElementsEachType; i++) {
1964 indexes.emplace_back(std::move(index));
1966 Shuffle(indexes.begin(), indexes.end(), rng);
1968 auto allItems = std::make_tuple(std::move(proofs), std::move(indexes));
1969 static const size_t numTypes = std::tuple_size<decltype(allItems)>::value;
1975 for (
size_t i = 0; i < numberElementsEachType; i++) {
1977 const size_t firstType = rng.
randrange(numTypes);
1979 for (
size_t j = 0; j < numTypes; j++) {
1980 switch ((firstType + j) % numTypes) {
1983 writeView->insert(std::make_pair(
1984 std::get<0>(allItems)[i],
VoteRecord(
true)));
1988 writeView->insert(std::make_pair(
1989 &std::get<1>(allItems)[i],
VoteRecord(
true)));
2001 auto it = readView.
begin();
2004 uint32_t lastScore = std::numeric_limits<uint32_t>::max();
2005 for (
size_t i = 0; i < numberElementsEachType; i++) {
2006 BOOST_CHECK(std::holds_alternative<const ProofRef>(it->first));
2008 uint32_t currentScore =
2009 std::get<const ProofRef>(it->first)->getScore();
2010 BOOST_CHECK_LT(currentScore, lastScore);
2011 lastScore = currentScore;
2019 for (
size_t i = 0; i < numberElementsEachType; i++) {
2020 BOOST_CHECK(std::holds_alternative<const CBlockIndex *>(it->first));
2023 std::get<const CBlockIndex *>(it->first)->nChainWork;
2025 lastWork = currentWork;
2037 Chainstate &chainstate = chainman->ActiveChainstate();
2039 const auto block = std::make_shared<const CBlock>(
2040 this->CreateBlock({},
CScript(), chainstate));
2051 blockindex = chainman->m_blockman.LookupBlockIndex(blockhash);
2059 BOOST_CHECK(AvalancheTest::getInvsForNextPoll(*g_avalanche).empty());
2068 auto invs = AvalancheTest::getInvsForNextPoll(*
g_avalanche);
static constexpr Amount COIN
std::unique_ptr< avalanche::Processor > g_avalanche
Global avalanche instance.
RecursiveMutex cs_main
Global state.
const CChainParams & Params()
Return the currently selected parameters.
#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.
A CService with information about it as peer.
The block chain is a tree shaped structure starting with the genesis block at the root,...
CBlockIndex * pprev
pointer to the index of the predecessor of this block
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
int64_t GetBlockTime() const
int64_t GetMedianTimePast() const
BlockHash GetBlockHash() const
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
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.
CConnman(const Config &configIn, uint64_t seed0, uint64_t seed1, AddrMan &addrmanIn, bool network_active=true)
An encapsulated secp256k1 private key.
static CKey MakeCompressedKey()
Produce a valid compressed key.
CPubKey GetPubKey() const
Compute the public key from a private key.
A mutable version of CTransaction.
std::vector< CTxOut > vout
Information about a peer.
An outpoint - a combination of a transaction hash and an index n into its vout.
Simple class for background tasks that should be run periodically or once "after a while".
void serviceQueue()
Services the queue 'forever'.
size_t getQueueInfo(std::chrono::steady_clock::time_point &first, std::chrono::steady_clock::time_point &last) const
Returns number of tasks waiting to be serviced, and first and last task times.
void StopWhenDrained()
Tell any threads running serviceQueue to stop when there is no work left to be done.
Serialized script, used inside transaction inputs and outputs.
A combination of a network address (CNetAddr) and a (TCP) port.
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
bool exists(const TxId &txid) const
void check(const CCoinsViewCache &active_coins_tip, int64_t spendheight) const EXCLUSIVE_LOCKS_REQUIRED(void addUnchecked(const CTxMemPoolEntry &entry) EXCLUSIVE_LOCKS_REQUIRED(cs
If sanity-checking is turned on, check makes sure the pool is consistent (does not contain two transa...
An output of a transaction.
Chainstate stores and provides an API to update our local knowledge of the current best chain.
bool AcceptBlock(const Config &config, const std::shared_ptr< const CBlock > &pblock, BlockValidationState &state, bool fRequested, const FlatFilePos *dbp, bool *fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Store a block on disk.
CChain m_chain
The current chain of blockheaders we consult and build on.
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
bool ActivateBestChain(const Config &config, BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) LOCKS_EXCLUDED(cs_main)
Find the best known block, and make it the tip of the block chain.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Chainstate & ActiveChainstate() const
The most-work chain.
CBlockIndex * ActiveTip() const
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
static std::unique_ptr< PeerManager > make(const CChainParams &chainparams, CConnman &connman, AddrMan &addrman, BanMan *banman, ChainstateManager &chainman, CTxMemPool &pool, bool ignore_incoming_txs)
ReadView getReadView() const
256-bit unsigned big integer.
bool removeNode(NodeId nodeid)
uint32_t getConnectedPeersScore() const
bool exists(const ProofId &proofid) const
uint32_t getTotalPeersScore() const
bool addNode(NodeId nodeid, const ProofId &proofid)
Node API.
std::unordered_set< ProofRef, SaltedProofHasher > updatedBlockTip()
Update the peer set when a new block is connected.
bool isBoundToPeer(const ProofId &proofid) const
bool isImmature(const ProofId &proofid) const
bool rejectProof(const ProofId &proofid, RejectionMode mode=RejectionMode::DEFAULT)
bool isInConflictingPool(const ProofId &proofid) const
bool registerProof(const ProofRef &proof, ProofRegistrationState ®istrationState, RegistrationMode mode=RegistrationMode::DEFAULT)
std::atomic< uint64_t > round
Keep track of peers and queries sent.
static std::unique_ptr< Processor > MakeProcessor(const ArgsManager &argsman, interfaces::Chain &chain, CConnman *connman, ChainstateManager &chainman, CTxMemPool *mempoolIn, CScheduler &scheduler, bilingual_str &error)
RWCollection< VoteMap > voteRecords
Items to run avalanche on.
uint32_t minQuorumScore
Quorum management.
std::atomic< int64_t > avaproofsNodeCounter
std::vector< CInv > getInvsForNextPoll(bool forPoll=true)
Mutex cs_peerManager
Keep track of the peers and associated infos.
double minQuorumConnectedScoreRatio
bool addUTXO(COutPoint utxo, Amount amount, uint32_t height, bool is_coinbase, CKey key)
const ProofId & getId() const
const std::vector< SignedStake > & getStakes() const
static uint32_t amountToScore(Amount amount)
uint32_t getCooldown() const
uint64_t getRound() const
const std::vector< Vote > & GetVotes() const
const VoteStatus & getStatus() const
const AnyVoteItem & getVoteItem() const
unsigned int size() const
const Config & GetConfig()
std::string EncodeSecret(const CKey &key)
static constexpr Amount PROOF_DUST_THRESHOLD
Minimum amount per utxo.
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
std::variant< const ProofRef, const CBlockIndex *, const CTransactionRef > AnyVoteItem
std::unique_ptr< Chain > MakeChain(node::NodeContext &node, const CChainParams ¶ms)
Return implementation of Chain interface.
@ OUTBOUND_FULL_RELAY
These are the default connections that we use to connect with the network.
static constexpr NodeId NO_NODE
Special NodeId that represent no node.
#define BOOST_AUTO_TEST_SUITE_END()
#define BOOST_FIXTURE_TEST_SUITE(a, b)
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
static CTransactionRef MakeTransactionRef()
std::shared_ptr< const CTransaction > CTransactionRef
static constexpr size_t AVALANCHE_MAX_ELEMENT_POLL
Maximum item that can be polled at once.
static constexpr uint32_t AVALANCHE_FINALIZED_ITEMS_FILTER_NUM_ELEMENTS
The size of the finalized items filter.
BOOST_AUTO_TEST_CASE_TEMPLATE(voteitemupdate, P, VoteItemProviders)
BOOST_AUTO_TEST_CASE(quorum_diversity)
boost::mpl::list< BlockProvider, ProofProvider, TxProvider > VoteItemProviders
ServiceFlags
nServices flags.
uint256 GetRandHash() noexcept
int GetRandInt(int nMax) noexcept
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
reverse_range< T > reverse_iterate(T &x)
static uint16_t GetDefaultPort()
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
A BlockHash is a unqiue identifier for a block.
static const Currency & get()
A TxId is the identifier of a transaction.
Compare proofs by score, then by id in case of equality.
TestVoteRecord(uint16_t conf)
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
bool error(const char *fmt, const Args &...args)
void UninterruptibleSleep(const std::chrono::microseconds &n)
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
@ CONFLICT
Removed for conflict with in-block transaction.
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
static const int PROTOCOL_VERSION
network protocol versioning
static constexpr int AVALANCHE_MAX_INFLIGHT_POLL
How many inflight requests can exist for one item.
static constexpr uint32_t AVALANCHE_VOTE_STALE_MIN_THRESHOLD
Lowest configurable staleness threshold (finalization score + necessary votes to increase confidence ...
static constexpr int AVALANCHE_FINALIZATION_SCORE
Finalization score.