diff --git a/src/avalanche/avalanche.h b/src/avalanche/avalanche.h --- a/src/avalanche/avalanche.h +++ b/src/avalanche/avalanche.h @@ -24,6 +24,12 @@ */ static constexpr bool AVALANCHE_DEFAULT_PEER_DISCOVERY_ENABLED = false; +/** + * Conflicting proofs cooldown time default value in seconds. + * Minimal delay between two proofs with at least a common UTXO. + */ +static constexpr size_t AVALANCHE_DEFAULT_CONFLICTING_PROOF_COOLDOWN = 60; + /** * Avalanche default cooldown in milliseconds. */ diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp --- a/src/avalanche/peermanager.cpp +++ b/src/avalanche/peermanager.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -194,6 +195,31 @@ switch (validProofPool.addProofIfNoConflict(proof, conflictingProofs)) { case ProofPool::AddProofStatus::REJECTED: { if (mode != FORCE_ACCEPT) { + auto now = GetTime(); + auto nextCooldownTimePoint = + now + std::chrono::seconds(gArgs.GetArg( + "-avalancheconflictingproofcooldown", + AVALANCHE_DEFAULT_CONFLICTING_PROOF_COOLDOWN)); + + auto bestPossibleConflictTime = std::chrono::seconds(); + auto &pview = peers.get(); + for (auto &conflictingProof : conflictingProofs) { + auto it = pview.find(conflictingProof->getId()); + assert(it != pview.end()); + + // Search the most recent time over the peers + bestPossibleConflictTime = std::max( + bestPossibleConflictTime, it->nextPossibleConflictTime); + + updateNextPossibleConflictTime(it->peerid, + nextCooldownTimePoint); + } + + if (bestPossibleConflictTime > now) { + // Cooldown not elapsed, reject the proof. + return false; + } + // The proof has conflicts, move it to the conflicting proof // pool so it can be pulled back if the conflicting ones are // invalidated. 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 @@ -8,6 +8,7 @@ #include #include #include