diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp
index 83bdec97dc..74865cabcc 100644
--- a/libraries/chain/block_state.cpp
+++ b/libraries/chain/block_state.cpp
@@ -13,7 +13,7 @@ block_state::block_state(const block_header_state& prev, signed_block_ptr b, con
    , block(std::move(b))
    , strong_digest(compute_finalizer_digest())
    , weak_digest(compute_finalizer_digest())
-   , pending_qc(prev.active_finalizer_policy->finalizers.size(), prev.active_finalizer_policy->threshold)
+   , pending_qc(prev.active_finalizer_policy->finalizers.size(), prev.active_finalizer_policy->threshold, prev.active_finalizer_policy->max_weak_sum_before_weak_final())
 {}
 
 block_state::block_state(const block_header_state& bhs, deque<transaction_metadata_ptr>&& trx_metas,
@@ -22,7 +22,7 @@ block_state::block_state(const block_header_state& bhs, deque<transaction_metada
    , block(std::make_shared<signed_block>(signed_block_header{bhs.header})) // [greg todo] do we need signatures?
    , strong_digest(compute_finalizer_digest())
    , weak_digest(compute_finalizer_digest())
-   , pending_qc(bhs.active_finalizer_policy->finalizers.size(), bhs.active_finalizer_policy->threshold)
+   , pending_qc(bhs.active_finalizer_policy->finalizers.size(), bhs.active_finalizer_policy->threshold, bhs.active_finalizer_policy->max_weak_sum_before_weak_final())
    , pub_keys_recovered(true) // probably not needed
    , cached_trxs(std::move(trx_metas))
 {
@@ -83,7 +83,8 @@ std::pair<bool, std::optional<uint32_t>> block_state::aggregate_vote(const vote_
                                  std::vector<uint8_t>{digest.data(), digest.data() + digest.data_size()},
                                  index,
                                  vote.finalizer_key,
-                                 vote.sig);
+                                 vote.sig,
+                                 finalizers[index].weight);
       return {valid, strong ? core.final_on_strong_qc_block_num : std::optional<uint32_t>{}};
    } else {
       wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) );
diff --git a/libraries/chain/hotstuff/hotstuff.cpp b/libraries/chain/hotstuff/hotstuff.cpp
index 531f2a33a8..e2f361ff1e 100644
--- a/libraries/chain/hotstuff/hotstuff.cpp
+++ b/libraries/chain/hotstuff/hotstuff.cpp
@@ -45,60 +45,39 @@ pending_quorum_certificate::pending_quorum_certificate()
    : _mtx(std::make_unique<std::mutex>()) {
 }
 
-pending_quorum_certificate::pending_quorum_certificate(size_t num_finalizers, size_t quorum)
-   : _num_finalizers(num_finalizers)
+pending_quorum_certificate::pending_quorum_certificate(size_t num_finalizers, uint64_t quorum, uint64_t max_weak_sum_before_weak_final)
+   : _mtx(std::make_unique<std::mutex>())
    , _quorum(quorum)
-   , _mtx(std::make_unique<std::mutex>()) {
+   , _max_weak_sum_before_weak_final(max_weak_sum_before_weak_final) {
    _weak_votes.resize(num_finalizers);
    _strong_votes.resize(num_finalizers);
 }
 
-pending_quorum_certificate::pending_quorum_certificate(const fc::sha256&  proposal_id,
-                                                       const digest_type& proposal_digest, size_t num_finalizers,
-                                                       size_t quorum)
-   : pending_quorum_certificate(num_finalizers, quorum) {
-   _proposal_id = proposal_id;
-   _proposal_digest.assign(proposal_digest.data(), proposal_digest.data() + 32);
-}
-
 bool pending_quorum_certificate::is_quorum_met() const {
    std::lock_guard g(*_mtx);
    return _state == state_t::weak_achieved || _state == state_t::weak_final || _state == state_t::strong;
 }
 
-void pending_quorum_certificate::reset(const fc::sha256& proposal_id, const digest_type& proposal_digest,
-                                       size_t num_finalizers, size_t quorum) {
-   std::lock_guard g(*_mtx);
-   _proposal_id = proposal_id;
-   _proposal_digest.assign(proposal_digest.data(), proposal_digest.data() + 32);
-   _quorum = quorum;
-   _strong_votes.reset(num_finalizers);
-   _weak_votes.reset(num_finalizers);
-   _num_finalizers = num_finalizers;
-   _state          = state_t::unrestricted;
-}
-
 // called by add_vote, already protected by mutex
 bool pending_quorum_certificate::add_strong_vote(const std::vector<uint8_t>& proposal_digest, size_t index,
-                                                 const bls_public_key& pubkey, const bls_signature& sig) {
-   assert(index < _num_finalizers);
+                                                 const bls_public_key& pubkey, const bls_signature& sig,
+                                                 uint64_t weight) {
    if (!_strong_votes.add_vote(proposal_digest, index, pubkey, sig))
       return false;
-   size_t weak   = num_weak();
-   size_t strong = num_strong();
+   _strong_sum += weight;
 
    switch (_state) {
    case state_t::unrestricted:
    case state_t::restricted:
-      if (strong >= _quorum) {
+      if (_strong_sum >= _quorum) {
          assert(_state != state_t::restricted);
          _state = state_t::strong;
-      } else if (weak + strong >= _quorum)
+      } else if (_weak_sum + _strong_sum >= _quorum)
          _state = (_state == state_t::restricted) ? state_t::weak_final : state_t::weak_achieved;
       break;
 
    case state_t::weak_achieved:
-      if (strong >= _quorum)
+      if (_strong_sum >= _quorum)
          _state = state_t::strong;
       break;
 
@@ -112,20 +91,19 @@ bool pending_quorum_certificate::add_strong_vote(const std::vector<uint8_t>& pro
 
 // called by add_vote, already protected by mutex
 bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& proposal_digest, size_t index,
-                                               const bls_public_key& pubkey, const bls_signature& sig) {
-   assert(index < _num_finalizers);
+                                               const bls_public_key& pubkey, const bls_signature& sig,
+                                               uint64_t weight) {
    if (!_weak_votes.add_vote(proposal_digest, index, pubkey, sig))
       return false;
-   size_t weak   = num_weak();
-   size_t strong = num_strong();
+   _weak_sum += weight;
 
    switch (_state) {
    case state_t::unrestricted:
    case state_t::restricted:
-      if (weak + strong >= _quorum)
+      if (_weak_sum + _strong_sum >= _quorum)
          _state = state_t::weak_achieved;
 
-      if (weak > (_num_finalizers - _quorum)) {
+      if (_weak_sum > _max_weak_sum_before_weak_final) {
          if (_state == state_t::weak_achieved)
             _state = state_t::weak_final;
          else if (_state == state_t::unrestricted)
@@ -134,7 +112,7 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& propo
       break;
 
    case state_t::weak_achieved:
-      if (weak >= (_num_finalizers - _quorum))
+      if (_weak_sum >= _max_weak_sum_before_weak_final)
          _state = state_t::weak_final;
       break;
 
@@ -148,10 +126,11 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& propo
 
 // thread safe, <valid, strong>
 std::pair<bool, bool> pending_quorum_certificate::add_vote(bool strong, const std::vector<uint8_t>& proposal_digest, size_t index,
-                                                           const bls_public_key& pubkey, const bls_signature& sig) {
+                                                           const bls_public_key& pubkey, const bls_signature& sig,
+                                                           uint64_t weight) {
    std::lock_guard g(*_mtx);
-   bool valid = strong ? add_strong_vote(proposal_digest, index, pubkey, sig)
-                       : add_weak_vote(proposal_digest, index, pubkey, sig);
+   bool valid = strong ? add_strong_vote(proposal_digest, index, pubkey, sig, weight)
+                       : add_weak_vote(proposal_digest, index, pubkey, sig, weight);
    return {valid, _state == state_t::strong};
 }
 
diff --git a/libraries/chain/hotstuff/test/finality_misc_tests.cpp b/libraries/chain/hotstuff/test/finality_misc_tests.cpp
index 592f225013..9f1726f07b 100644
--- a/libraries/chain/hotstuff/test/finality_misc_tests.cpp
+++ b/libraries/chain/hotstuff/test/finality_misc_tests.cpp
@@ -50,83 +50,93 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
    for (const auto& k : sk)
       pubkey.push_back(k.get_public_key());
 
-   auto weak_vote = [&](pending_quorum_certificate& qc, const std::vector<uint8_t>& digest, size_t index) {
-      return qc.add_vote(false, digest, index, pubkey[index], sk[index].sign(digest)).first;
+   auto weak_vote = [&](pending_quorum_certificate& qc, const std::vector<uint8_t>& digest, size_t index, uint64_t weight) {
+      return qc.add_vote(false, digest, index, pubkey[index], sk[index].sign(digest), weight).first;
    };
 
-   auto strong_vote = [&](pending_quorum_certificate& qc, const std::vector<uint8_t>& digest, size_t index) {
-      return qc.add_vote(true, digest, index, pubkey[index], sk[index].sign(digest)).first;
+   auto strong_vote = [&](pending_quorum_certificate& qc, const std::vector<uint8_t>& digest, size_t index, uint64_t weight) {
+      return qc.add_vote(true, digest, index, pubkey[index], sk[index].sign(digest), weight).first;
    };
 
+   constexpr uint64_t weight = 1;
+
    {
-      pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1
+      constexpr uint64_t quorum = 1;
+      constexpr uint64_t max_weak_sum_before_weak_final = 1;
+      pending_quorum_certificate qc(2, quorum, max_weak_sum_before_weak_final); // 2 finalizers
       BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
 
       // add one weak vote
       // -----------------
-      weak_vote(qc, digest, 0);
+      weak_vote(qc, digest, 0, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
       BOOST_CHECK(qc.is_quorum_met());
 
       // add duplicate weak vote
       // -----------------------
-      bool ok = weak_vote(qc, digest, 0);
+      bool ok = weak_vote(qc, digest, 0, weight);
       BOOST_CHECK(!ok); // vote was a duplicate
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
       BOOST_CHECK(qc.is_quorum_met());
 
       // add another weak vote
       // ---------------------
-      weak_vote(qc, digest, 1);
+      weak_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final);
    }
 
    {
-      pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1
+      constexpr uint64_t quorum = 1;
+      constexpr uint64_t max_weak_sum_before_weak_final = 1;
+      pending_quorum_certificate qc(2, quorum, max_weak_sum_before_weak_final); // 2 finalizers
       BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
 
       // add a weak vote
       // ---------------
-      weak_vote(qc, digest, 0);
+      weak_vote(qc, digest, 0, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
       BOOST_CHECK(qc.is_quorum_met());
 
       // add a strong vote
       // -----------------
-      strong_vote(qc, digest, 1);
+      strong_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::strong);
       BOOST_CHECK(qc.is_quorum_met());
    }
 
    {
-      pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1
+      constexpr uint64_t quorum = 1;
+      constexpr uint64_t max_weak_sum_before_weak_final = 1;
+      pending_quorum_certificate qc(2, quorum, max_weak_sum_before_weak_final); // 2 finalizers, weight_sum_minus_quorum = 1
       BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
 
       // add a strong vote
       // -----------------
-      strong_vote(qc, digest, 1);
+      strong_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::strong);
       BOOST_CHECK(qc.is_quorum_met());
 
       // add a strong vote
       // -----------------
-      strong_vote(qc, digest, 1);
+      strong_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::strong);
       BOOST_CHECK(qc.is_quorum_met());
    }
 
    {
-      pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2
+      constexpr uint64_t quorum = 2;
+      constexpr uint64_t max_weak_sum_before_weak_final = 1;
+      pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers
 
       // add a weak vote
       // ---------------
-      weak_vote(qc, digest, 0);
+      weak_vote(qc, digest, 0, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
       BOOST_CHECK(!qc.is_quorum_met());
 
       // add a strong vote
       // -----------------
-      strong_vote(qc, digest, 1);
+      strong_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
       BOOST_CHECK(qc.is_quorum_met());
 
@@ -135,24 +145,26 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
 
          // add a weak vote
          // ---------------
-         weak_vote(qc2, digest, 2);
+         weak_vote(qc2, digest, 2, weight);
          BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final);
          BOOST_CHECK(qc2.is_quorum_met());
       }
    }
 
    {
-      pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2
+      constexpr uint64_t quorum = 2;
+      constexpr uint64_t max_weak_sum_before_weak_final = 1;
+      pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers, quorum = 2
 
       // add a weak vote
       // ---------------
-      weak_vote(qc, digest, 0);
+      weak_vote(qc, digest, 0, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
       BOOST_CHECK(!qc.is_quorum_met());
 
       // add a strong vote
       // -----------------
-      strong_vote(qc, digest, 1);
+      strong_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
       BOOST_CHECK(qc.is_quorum_met());
 
@@ -161,24 +173,26 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
 
          // add a strong vote
          // -----------------
-         strong_vote(qc2, digest, 2);
+         strong_vote(qc2, digest, 2, weight);
          BOOST_CHECK_EQUAL(qc2.state(), state_t::strong);
          BOOST_CHECK(qc2.is_quorum_met());
       }
    }
 
    {
-      pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2
+      constexpr uint64_t quorum = 2;
+      constexpr uint64_t max_weak_sum_before_weak_final = 1;
+      pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers, quorum = 2
 
       // add a weak vote
       // ---------------
-      weak_vote(qc, digest, 0);
+      weak_vote(qc, digest, 0, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
       BOOST_CHECK(!qc.is_quorum_met());
 
       // add a weak vote
       // ---------------
-      weak_vote(qc, digest, 1);
+      weak_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final);
       BOOST_CHECK(qc.is_quorum_met());
 
@@ -187,24 +201,26 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
 
          // add a weak vote
          // ---------------
-         weak_vote(qc2, digest, 2);
+         weak_vote(qc2, digest, 2, weight);
          BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final);
          BOOST_CHECK(qc2.is_quorum_met());
       }
    }
 
    {
-      pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2
+      constexpr uint64_t quorum = 2;
+      constexpr uint64_t max_weak_sum_before_weak_final = 1;
+      pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers, quorum = 2
 
       // add a weak vote
       // ---------------
-      weak_vote(qc, digest, 0);
+      weak_vote(qc, digest, 0, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
       BOOST_CHECK(!qc.is_quorum_met());
 
       // add a weak vote
       // ---------------
-      weak_vote(qc, digest, 1);
+      weak_vote(qc, digest, 1, weight);
       BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final);
       BOOST_CHECK(qc.is_quorum_met());
 
@@ -213,7 +229,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
 
          // add a strong vote
          // -----------------
-         strong_vote(qc2, digest, 2);
+         strong_vote(qc2, digest, 2, weight);
          BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final);
          BOOST_CHECK(qc2.is_quorum_met());
       }
diff --git a/libraries/chain/include/eosio/chain/hotstuff/finalizer_policy.hpp b/libraries/chain/include/eosio/chain/hotstuff/finalizer_policy.hpp
index 89c75d1994..60a26a755d 100644
--- a/libraries/chain/include/eosio/chain/hotstuff/finalizer_policy.hpp
+++ b/libraries/chain/include/eosio/chain/hotstuff/finalizer_policy.hpp
@@ -9,6 +9,17 @@ namespace eosio::chain {
       uint32_t                         generation = 0; ///< sequentially incrementing version number
       uint64_t                         threshold = 0;  ///< vote weight threshold to finalize blocks
       std::vector<finalizer_authority> finalizers; ///< Instant Finality voter set
+
+      // max accumulated weak weight before becoming weak_final
+      uint64_t max_weak_sum_before_weak_final() const {
+         uint64_t sum = std::accumulate( finalizers.begin(), finalizers.end(), 0,
+            [](uint64_t acc, const finalizer_authority& f) {
+               return acc + f.weight;
+            }
+         );
+
+         return (sum - threshold);
+      }
    };
 
    using finalizer_policy_ptr = std::shared_ptr<finalizer_policy>;
diff --git a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp
index 1e58b5e5f6..7f3b21e653 100644
--- a/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp
+++ b/libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp
@@ -185,25 +185,18 @@ namespace eosio::chain {
 
       pending_quorum_certificate();
 
-      explicit pending_quorum_certificate(size_t num_finalizers, size_t quorum);
-
-      explicit pending_quorum_certificate(const fc::sha256& proposal_id,
-                                          const digest_type& proposal_digest,
-                                          size_t num_finalizers,
-                                          size_t quorum);
+      explicit pending_quorum_certificate(size_t num_finalizers, uint64_t quorum, uint64_t max_weak_sum_before_weak_final);
 
       // thread safe
       bool   is_quorum_met() const;
 
-      // thread safe
-      void reset(const fc::sha256& proposal_id, const digest_type& proposal_digest, size_t num_finalizers, size_t quorum);
-
       // thread safe
       std::pair<bool, bool> add_vote(bool strong,
                                      const std::vector<uint8_t>&proposal_digest,
                                      size_t index,
                                      const bls_public_key&pubkey,
-                                     const bls_signature&sig);
+                                     const bls_signature&sig,
+                                     uint64_t weight);
 
       state_t state()  const { std::lock_guard g(*_mtx); return _state; };
       valid_quorum_certificate to_valid_quorum_certificate() const;
@@ -221,28 +214,28 @@ namespace eosio::chain {
       friend class qc_chain;
       fc::sha256           _proposal_id;     // only used in to_msg(). Remove eventually
       std::vector<uint8_t> _proposal_digest;
+      std::unique_ptr<std::mutex> _mtx;
+      uint64_t             _quorum {0};
+      uint64_t             _max_weak_sum_before_weak_final {0}; // max weak sum before becoming weak_final
       state_t              _state { state_t::unrestricted };
-      size_t               _num_finalizers {0};
-      size_t               _quorum {0};
-      std::unique_ptr<std::mutex> _mtx;  // protect both _strong_votes and _weak_votes
+      uint64_t             _strong_sum {0}; // accumulated sum of strong votes so far
+      uint64_t             _weak_sum {0}; // accumulated sum of weak votes so far
       votes_t              _weak_votes;
       votes_t              _strong_votes;
 
-      // num_weak and num_strong are protected by mutex by add_vote
-      size_t num_weak()   const { return _weak_votes.count(); }
-      size_t num_strong() const { return _strong_votes.count(); }
-
       // called by add_vote, already protected by mutex
       bool add_strong_vote(const std::vector<uint8_t>& proposal_digest,
                            size_t index,
                            const bls_public_key& pubkey,
-                           const bls_signature& sig);
+                           const bls_signature& sig,
+                           uint64_t weight);
 
       // called by add_vote, already protected by mutex
       bool add_weak_vote(const std::vector<uint8_t>& proposal_digest,
                          size_t index,
                          const bls_public_key& pubkey,
-                         const bls_signature& sig);
+                         const bls_signature& sig,
+                         uint64_t weight);
    };
 } //eosio::chain
 
diff --git a/unittests/block_state_tests.cpp b/unittests/block_state_tests.cpp
index 8d962ffc22..eb1295e41a 100644
--- a/unittests/block_state_tests.cpp
+++ b/unittests/block_state_tests.cpp
@@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try {
       bsp->active_finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
       bsp->strong_digest = strong_digest;
       bsp->weak_digest = weak_digest;
-      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };
+      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1, bsp->active_finalizer_policy->max_weak_sum_before_weak_final() };
 
       for (size_t i = 0; i < num_finalizers; ++i) {
          bool strong = (i % 2 == 0); // alternate strong and weak
@@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try {
       block_state_ptr bsp = std::make_shared<block_state>();
       bsp->active_finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
       bsp->strong_digest = strong_digest;
-      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };
+      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1, bsp->active_finalizer_policy->max_weak_sum_before_weak_final() };
 
       vote_message vote {block_id, true, public_key[0], private_key[1].sign(strong_digest_data) };
       BOOST_REQUIRE(!bsp->aggregate_vote(vote).first);
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try {
       block_state_ptr bsp = std::make_shared<block_state>();
       bsp->active_finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
       bsp->strong_digest = strong_digest;
-      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };
+      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1, bsp->active_finalizer_policy->max_weak_sum_before_weak_final() };
 
       vote_message vote {block_id, true, public_key[0], private_key[0].sign(strong_digest_data) };
       BOOST_REQUIRE(bsp->aggregate_vote(vote).first);
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try {
       block_state_ptr bsp = std::make_shared<block_state>();
       bsp->active_finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
       bsp->strong_digest = strong_digest;
-      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };
+      bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1, bsp->active_finalizer_policy->max_weak_sum_before_weak_final() };
 
       bls_private_key new_private_key{ "PVT_BLS_warwI76e+pPX9wLFZKPFagngeFM8bm6J8D5w0iiHpxW7PiId" };
       bls_public_key new_public_key{ new_private_key.get_public_key() };
@@ -88,6 +88,101 @@ BOOST_AUTO_TEST_CASE(aggregate_vote_test) try {
    }
 } FC_LOG_AND_RETHROW();
 
+void do_quorum_test(const std::vector<uint64_t>& weights,
+                    uint64_t threshold,
+                    bool strong,
+                    const std::vector<bool>& to_vote,
+                    bool expected_quorum) {
+   using namespace eosio::chain;
+   using namespace fc::crypto::blslib;
+
+   digest_type block_id(fc::sha256("0000000000000000000000000000001"));
+   digest_type strong_digest(fc::sha256("0000000000000000000000000000002"));
+   std::vector<uint8_t> strong_digest_data(strong_digest.data(), strong_digest.data() + strong_digest.data_size());
+   digest_type weak_digest(fc::sha256("0000000000000000000000000000003"));
+   std::vector<uint8_t> weak_digest_data(weak_digest.data(), weak_digest.data() + weak_digest.data_size());
+
+   // initialize a set of private keys
+   std::vector<bls_private_key> private_key {
+      bls_private_key("PVT_BLS_r4ZpChd87ooyzl6MIkw23k7PRX8xptp7TczLJHCIIW88h/hS"),
+      bls_private_key("PVT_BLS_/l7xzXANaB+GrlTsbZEuTiSOiWTtpBoog+TZnirxUUSaAfCo"),
+      bls_private_key("PVT_BLS_3FoY73Q/gED3ejyg8cvnGqHrMmx4cLKwh/e0sbcsCxpCeqn3"),
+   };
+   const size_t num_finalizers = private_key.size();
+
+   // construct finalizers
+   std::vector<bls_public_key> public_key(num_finalizers);
+   std::vector<finalizer_authority> finalizers(num_finalizers);
+   for (size_t i = 0; i < num_finalizers; ++i) {
+      public_key[i] = private_key[i].get_public_key();
+      finalizers[i] = finalizer_authority{ "test", weights[i], public_key[i] };
+   }
+
+   block_state_ptr bsp = std::make_shared<block_state>();
+   constexpr uint32_t generation = 1;
+   bsp->active_finalizer_policy = std::make_shared<finalizer_policy>( generation, threshold, finalizers );
+   bsp->strong_digest = strong_digest;
+   bsp->weak_digest = weak_digest;
+   bsp->pending_qc = pending_quorum_certificate{ num_finalizers, threshold, bsp->active_finalizer_policy->max_weak_sum_before_weak_final() };
+
+   for (size_t i = 0; i < num_finalizers; ++i) {
+      if( to_vote[i] ) {
+         auto sig = strong ? private_key[i].sign(strong_digest_data) : private_key[i].sign(weak_digest_data);
+         vote_message vote{ block_id, strong, public_key[i], sig };
+         BOOST_REQUIRE(bsp->aggregate_vote(vote).first);
+      }
+   }
+
+   BOOST_REQUIRE_EQUAL(bsp->pending_qc.is_quorum_met(), expected_quorum);
+}
+
+BOOST_AUTO_TEST_CASE(quorum_test) try {
+   std::vector<uint64_t> weights{1, 3, 5};
+   constexpr uint64_t threshold = 4;
+
+   { // 1 strong vote, quorum not met
+      constexpr bool strong = true;
+      std::vector<bool> to_vote{true, false, false}; // finalizer 0 voting
+      constexpr bool expected_quorum_met = false;
+      do_quorum_test( weights, threshold, strong, to_vote, expected_quorum_met );
+   }
+
+   { // 2 strong votes, quorum met
+      constexpr bool strong = true;
+      std::vector<bool> to_vote{true, true, false}; // finalizers 0 and 1 voting
+      constexpr bool expected_quorum_met = true;
+      do_quorum_test( weights, threshold, strong, to_vote, expected_quorum_met );
+   }
+
+   { // 1 strong vote, quorum met
+      constexpr bool strong = true;
+      std::vector<bool> to_vote{false, false, true}; // finalizer 2 voting
+      constexpr bool expected_quorum_met = true;
+      do_quorum_test( weights, threshold, strong, to_vote, expected_quorum_met );
+   }
+
+   { // 1 weak vote, quorum not met
+      constexpr bool strong = false;
+      std::vector<bool> to_vote{true, false, false}; // finalizer 0 voting
+      constexpr bool expected_quorum_met = false;
+      do_quorum_test( weights, threshold, strong, to_vote, expected_quorum_met );
+   }
+
+   { // 2 weak votes, quorum met
+      constexpr bool strong = false;
+      std::vector<bool> to_vote{true, true, false}; // finalizers 0 and 1 voting
+      constexpr bool expected_quorum_met = true;
+      do_quorum_test( weights, threshold, strong, to_vote, expected_quorum_met );
+   }
+
+   { // 1 weak vote, quorum met
+      constexpr bool strong = false;
+      std::vector<bool> to_vote{false, false, true}; // finalizer 2 voting
+      constexpr bool expected_quorum_met = true;
+      do_quorum_test( weights, threshold, strong, to_vote, expected_quorum_met );
+   }
+} FC_LOG_AND_RETHROW();
+  
 BOOST_AUTO_TEST_CASE(verify_qc_test) try {
    using namespace eosio::chain;
    using namespace fc::crypto::blslib;
@@ -105,7 +200,7 @@ BOOST_AUTO_TEST_CASE(verify_qc_test) try {
       bls_private_key("PVT_BLS_3FoY73Q/gED3ejyg8cvnGqHrMmx4cLKwh/e0sbcsCxpCeqn3")
    };
    auto num_finalizers = private_key.size();
-
+  
    // construct finalizers, with weight 1, 2, 3 respectively
    std::vector<bls_public_key> public_key(num_finalizers);
    std::vector<finalizer_authority> finalizers(num_finalizers);
@@ -114,7 +209,7 @@ BOOST_AUTO_TEST_CASE(verify_qc_test) try {
       uint64_t weight = i + 1;
       finalizers[i] = finalizer_authority{ "test", weight, public_key[i] };
    }
-
+  
    // consturct a test bsp
    block_state_ptr bsp = std::make_shared<block_state>();
    constexpr uint32_t generation = 1;