diff --git a/src/avalanche/peermanager.h b/src/avalanche/peermanager.h
--- a/src/avalanche/peermanager.h
+++ b/src/avalanche/peermanager.h
@@ -182,6 +182,8 @@
     std::vector<Peer> getPeers() const;
     std::vector<NodeId> getNodeIdsForPeer(PeerId peerId) const;
 
+    std::shared_ptr<Proof> getProof(const ProofId &proofid) const;
+
 private:
     PeerSet::iterator fetchOrCreatePeer(const std::shared_ptr<Proof> &proof);
     bool addNodeToPeer(const PeerSet::iterator &it);
diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp
--- a/src/avalanche/peermanager.cpp
+++ b/src/avalanche/peermanager.cpp
@@ -185,6 +185,12 @@
     return it == peers.end() ? NO_PEER : it->peerid;
 }
 
+std::shared_ptr<Proof> PeerManager::getProof(const ProofId &proofid) const {
+    auto &pview = peers.get<proof_index>();
+    auto it = pview.find(proofid);
+    return it == pview.end() ? nullptr : it->proof;
+}
+
 PeerManager::PeerSet::iterator
 PeerManager::fetchOrCreatePeer(const std::shared_ptr<Proof> &proof) {
     {
diff --git a/src/avalanche/processor.h b/src/avalanche/processor.h
--- a/src/avalanche/processor.h
+++ b/src/avalanche/processor.h
@@ -302,6 +302,9 @@
      */
     uint256 buildRemoteSighash(CNode *pfrom) const;
 
+    bool addProof(const std::shared_ptr<Proof> &proof);
+    std::shared_ptr<Proof> getProof(const ProofId &proofid) const;
+
     /*
      * Return whether the avalanche service flag should be set.
      */
diff --git a/src/avalanche/processor.cpp b/src/avalanche/processor.cpp
--- a/src/avalanche/processor.cpp
+++ b/src/avalanche/processor.cpp
@@ -502,6 +502,17 @@
     return true;
 }
 
+bool Processor::addProof(const std::shared_ptr<Proof> &proof) {
+    LOCK(cs_peerManager);
+    return !peerManager->getProof(proof->getId()) &&
+           peerManager->getPeerId(proof) != NO_PEER;
+}
+
+std::shared_ptr<Proof> Processor::getProof(const ProofId &proofid) const {
+    LOCK(cs_peerManager);
+    return peerManager->getProof(proofid);
+}
+
 bool Processor::startEventLoop(CScheduler &scheduler) {
     return eventLoop.startEventLoop(
         scheduler, [this]() { this->runEventLoop(); }, AVALANCHE_TIME_STEP);
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
@@ -971,4 +971,40 @@
     schedulerThread.join();
 }
 
+BOOST_AUTO_TEST_CASE(proof_accessors) {
+    constexpr int numProofs = 10;
+
+    std::vector<std::shared_ptr<Proof>> proofs;
+    proofs.reserve(numProofs);
+    for (int i = 0; i < numProofs; i++) {
+        proofs.push_back(GetProof());
+    }
+
+    for (int i = 0; i < numProofs; i++) {
+        BOOST_CHECK(m_processor->addProof(proofs[i]));
+        // Fail to add an existing proof
+        BOOST_CHECK(!m_processor->addProof(proofs[i]));
+
+        for (int added = 0; added <= i; added++) {
+            auto proof = m_processor->getProof(proofs[added]->getId());
+            BOOST_CHECK(proof != nullptr);
+            BOOST_CHECK_EQUAL(proof->getId(), proofs[added]->getId());
+        }
+
+        for (int missing = i + 1; missing < numProofs; missing++) {
+            BOOST_CHECK(!m_processor->getProof(proofs[missing]->getId()));
+        }
+    }
+
+    // No stake, copied from proof_tests.cpp
+    const std::string badProofHex(
+        "96527eae083f1f24625f049d9e54bb9a2102a93d98bf42ab90cfc0bf9e7c634ed76a7"
+        "3e95b02cacfd357b64e4fb6c92e92dd00");
+    bilingual_str error;
+    Proof badProof;
+    BOOST_CHECK(Proof::FromHex(badProof, badProofHex, error));
+    BOOST_CHECK(
+        !m_processor->addProof(std::make_shared<Proof>(std::move(badProof))));
+}
+
 BOOST_AUTO_TEST_SUITE_END()