Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IF: Verify bls signature of vote while not holding a mutex #2359

Merged
merged 5 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,19 @@ vote_status block_state::aggregate_vote(const vote_message& vote) {
}
}

bool block_state::has_voted(const bls_public_key& key) const {
const auto& finalizers = active_finalizer_policy->finalizers;
auto it = std::find_if(finalizers.begin(),
finalizers.end(),
[&](const auto& finalizer) { return finalizer.public_key == key; });

if (it != finalizers.end()) {
auto index = std::distance(finalizers.begin(), it);
return pending_qc.has_voted(index);
}
return false;
}

// Called from net threads
void block_state::verify_qc(const valid_quorum_certificate& qc) const {
const auto& finalizers = active_finalizer_policy->finalizers;
Expand Down
22 changes: 22 additions & 0 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3491,6 +3491,24 @@ struct controller_impl {
return fork_db.apply<vote_status>(aggregate_vote_legacy, aggregate_vote);
}

bool node_has_voted_if_finalizer(const block_id_type& id) const {
if (my_finalizers.finalizers.empty())
return true;

std::optional<bool> voted = fork_db.apply_s<std::optional<bool>>([&](auto& forkdb) -> std::optional<bool> {
auto bsp = forkdb.get_block(id);
if (bsp) {
for (auto& f : my_finalizers.finalizers) {
if (bsp->has_voted(f.first))
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
return {true};
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
}
}
return {false};
});
// empty optional means legacy forkdb
return !voted || *voted;
}

void create_and_send_vote_msg(const block_state_ptr& bsp) {
if (!bsp->block->is_proper_svnn_block())
return;
Expand Down Expand Up @@ -5068,6 +5086,10 @@ vote_status controller::process_vote_message( const vote_message& vote ) {
return my->process_vote_message( vote );
};

bool controller::node_has_voted_if_finalizer(const block_id_type& id) const {
return my->node_has_voted_if_finalizer(id);
}

const producer_authority_schedule& controller::active_producers()const {
return my->active_producers();
}
Expand Down
9 changes: 7 additions & 2 deletions libraries/chain/hotstuff/hotstuff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ inline std::vector<uint32_t> bitset_to_vector(const hs_bitset& bs) {
return r;
}

bool pending_quorum_certificate::is_duplicate_no_lock(bool strong, size_t index) const {
bool pending_quorum_certificate::has_voted(size_t index) const {
std::lock_guard g(*_mtx);
return _strong_votes._bitset.at(index) || _weak_votes._bitset.at(index);
}

bool pending_quorum_certificate::has_voted_no_lock(bool strong, size_t index) const {
if (strong) {
return _strong_votes._bitset[index];
}
Expand Down Expand Up @@ -131,7 +136,7 @@ vote_status pending_quorum_certificate::add_vote(block_num_type block_num, bool
std::unique_lock g(*_mtx);
state_t pre_state = _state;
state_t post_state = pre_state;
if (is_duplicate_no_lock(strong, index)) {
if (has_voted_no_lock(strong, index)) {
s = vote_status::duplicate;
} else {
g.unlock();
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/block_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ struct block_state : public block_header_state { // block_header_state provi

// vote_status
vote_status aggregate_vote(const vote_message& vote); // aggregate vote into pending_qc
bool has_voted(const bls_public_key& key) const;
void verify_qc(const valid_quorum_certificate& qc) const; // verify given qc is valid with respect block_state

using bhs_t = block_header_state;
Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ namespace eosio::chain {
void set_proposed_finalizers( const finalizer_policy& fin_set );
// called from net threads
vote_status process_vote_message( const vote_message& msg );
// thread safe, for testing
bool node_has_voted_if_finalizer(const block_id_type& id) const;

bool light_validation_allowed() const;
bool skip_auth_check()const;
Expand Down
5 changes: 4 additions & 1 deletion libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ namespace eosio::chain {
const bls_signature& sig,
uint64_t weight);

// thread safe
bool has_voted(size_t index) const;

state_t state() const { std::lock_guard g(*_mtx); return _state; };
valid_quorum_certificate to_valid_quorum_certificate() const;

Expand All @@ -135,7 +138,7 @@ namespace eosio::chain {
uint64_t weight);

bool is_quorum_met_no_lock() const;
bool is_duplicate_no_lock(bool strong, size_t index) const;
bool has_voted_no_lock(bool strong, size_t index) const;
};
} //eosio::chain

Expand Down
9 changes: 9 additions & 0 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,15 @@ namespace eosio { namespace testing {
control->commit_block();
last_produced_block[producer_name] = control->head_block_id();

if (control->head_block()->is_proper_svnn_block()) {
// wait for this node's vote to be processed
size_t retrys = 200;
while (!control->node_has_voted_if_finalizer(control->head_block_id()) && --retrys) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
FC_ASSERT(retrys, "Never saw this nodes vote processed before timeout");
}

return control->head_block();
}

Expand Down
Loading