diff --git a/src/avalanche/peermanager.h b/src/avalanche/peermanager.h --- a/src/avalanche/peermanager.h +++ b/src/avalanche/peermanager.h @@ -164,6 +164,9 @@ */ std::unordered_set m_unbroadcast_proofids; + std::unordered_map + nextPossibleConflictTime; + public: /** * Node API. @@ -195,6 +198,14 @@ /** * Proof and Peer related API. */ + + /** + * Update the time before which a proof conflicting with the one with the + * given proofid will be rejected. + */ + bool updateNextPossibleConflictTime(const ProofId &proofid, + const std::chrono::seconds &nextTime); + bool registerProof(const ProofRef &proof); bool exists(const ProofId &proofid) const { return getProof(proofid) != nullptr; diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp --- a/src/avalanche/peermanager.cpp +++ b/src/avalanche/peermanager.cpp @@ -147,6 +147,20 @@ state.GetResult() == ProofValidationResult::HEIGHT_MISMATCH; } +bool PeerManager::updateNextPossibleConflictTime( + const ProofId &proofid, const std::chrono::seconds &nextTime) { + // If there is no entry for this proofid, it will be created + // with the default value of 0, which is fine because it is + // far in the past. + auto &proofNextConflictTime = nextPossibleConflictTime[proofid]; + + // Update the next possible conflict time for this proof. Make sure we don't + // move the time in the past. + proofNextConflictTime = std::max(proofNextConflictTime, nextTime); + + return proofNextConflictTime == nextTime; +} + bool PeerManager::registerProof(const ProofRef &proof) { assert(proof); 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 @@ -40,6 +40,11 @@ auto it = pview.find(proof->getId()); return it == pview.end() ? NO_PEER : it->peerid; } + + static std::chrono::seconds + getNextPossibleConflictTime(PeerManager &pm, const ProofId &proofid) { + return pm.nextPossibleConflictTime[proofid]; + } }; } // namespace } // namespace avalanche @@ -1062,4 +1067,32 @@ BOOST_CHECK(!pm.exists(proofSeq10->getId())); } +BOOST_AUTO_TEST_CASE(update_next_conflict_time) { + avalanche::PeerManager pm; + + const ProofId proofid{GetRandHash()}; + + auto checkNextPossibleConflictTime = [&](std::chrono::seconds expected) { + // FIXME: we can't use BOOST_CHECK_EQUAL without defining operator<< for + // std::chrono::duration + BOOST_CHECK(TestPeerManager::getNextPossibleConflictTime(pm, proofid) == + expected); + }; + + checkNextPossibleConflictTime(std::chrono::seconds{0}); + + auto now = GetTime(); + BOOST_CHECK(pm.updateNextPossibleConflictTime(proofid, now)); + checkNextPossibleConflictTime(now); + + // Move the time in the past is not possible + BOOST_CHECK(!pm.updateNextPossibleConflictTime( + proofid, now - std::chrono::seconds{1})); + checkNextPossibleConflictTime(now); + + BOOST_CHECK(pm.updateNextPossibleConflictTime( + proofid, now + std::chrono::seconds{1})); + checkNextPossibleConflictTime(now + std::chrono::seconds{1}); +} + BOOST_AUTO_TEST_SUITE_END()