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:Unification: Process received Vote message #2073

Merged
merged 15 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
21 changes: 21 additions & 0 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,26 @@ namespace eosio::chain {
,_cached_trxs( std::move(trx_metas) )
{}
#endif

bool block_state::aggregate_vote(const hs_vote_message& vote) {
heifner marked this conversation as resolved.
Show resolved Hide resolved
const auto& finalizers = finalizer_policy->finalizers;
auto it = std::find_if(finalizers.begin(),
finalizers.end(),
[&](const auto& finalizer) { return finalizer.public_key == vote.finalizer_key; });

if (it != finalizers.end()) {
auto index = std::distance(finalizers.begin(), it);
const digest_type& digest = vote.strong ? strong_finalizer_digest : weak_finalizer_digest;

return pending_qc.add_vote(vote.strong,
std::vector<uint8_t>{digest.data(), digest.data() + digest.data_size()},
heifner marked this conversation as resolved.
Show resolved Hide resolved
index,
vote.finalizer_key,
vote.sig);
} else {
wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) );
return false;
}
}

} /// eosio::chain
21 changes: 19 additions & 2 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,23 @@ struct block_data_t {
}, v);
}

bool aggregate_vote(const hs_vote_message& vote) {
heifner marked this conversation as resolved.
Show resolved Hide resolved
return std::visit(
overloaded{[](const block_data_legacy_t&) {
EOS_ASSERT(false, misc_exception, "attempting to call aggregate_vote in legacy mode");
return false; },
[&](const block_data_new_t& bd) {
auto bsp = bd.fork_db.get_block(vote.proposal_id);
if (bsp) {
return bsp->aggregate_vote(vote);
heifner marked this conversation as resolved.
Show resolved Hide resolved
} else {
wlog("no block exists for the vote (proposal_id: ${id}", ("id", vote.proposal_id));
heifner marked this conversation as resolved.
Show resolved Hide resolved
return false;
}}
},
v);
}
heifner marked this conversation as resolved.
Show resolved Hide resolved

template<class R, class F>
R apply(F &f) {
if constexpr (std::is_same_v<void, R>)
Expand Down Expand Up @@ -4007,8 +4024,8 @@ void controller::get_finalizer_state( finalizer_state& fs ) const {
}

// called from net threads
void controller::notify_hs_message( const uint32_t connection_id, const hs_message& msg ) {
my->pacemaker->on_hs_msg(connection_id, msg);
void controller::process_vote_message( const hs_vote_message& vote ) {
my->block_data.aggregate_vote(vote);
heifner marked this conversation as resolved.
Show resolved Hide resolved
};

const producer_authority_schedule& controller::active_producers()const {
Expand Down
10 changes: 7 additions & 3 deletions libraries/chain/hotstuff/hotstuff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ inline std::vector<uint32_t> bitset_to_vector(const hs_bitset& bs) {

bool pending_quorum_certificate::votes_t::add_vote(const std::vector<uint8_t>& proposal_digest, size_t index,
const bls_public_key& pubkey, const bls_signature& new_sig) {
if (_bitset[index])
if (_bitset[index]) {
wlog( "finalizer ${i} has already voted", ("i", index) );
heifner marked this conversation as resolved.
Show resolved Hide resolved
return false; // shouldn't be already present
if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig))
}
if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig)) {
wlog( "signature from finalizer ${i} cannot be verified", ("i", index) );
return false;
}
_bitset.set(index);
_sig = fc::crypto::blslib::aggregate({_sig, new_sig}); // works even if _sig is default initialized (fp2::zero())
return true;
Expand Down Expand Up @@ -192,4 +196,4 @@ quorum_certificate_message valid_quorum_certificate::to_msg() const {
};
}

} // namespace eosio::chain
} // namespace eosio::chain
5 changes: 4 additions & 1 deletion libraries/chain/include/eosio/chain/block_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace eosio::chain {
// ------ data members -------------------------------------------------------------
signed_block_ptr block;
bool validated; // We have executed the block's trxs and verified that action merkle root (block id) matches.
digest_type finalizer_digest;
digest_type strong_finalizer_digest;
digest_type weak_finalizer_digest;
heifner marked this conversation as resolved.
Show resolved Hide resolved
pending_quorum_certificate pending_qc; // where we accumulate votes we receive
std::optional<valid_quorum_certificate> valid_qc; // qc received from the network

Expand All @@ -32,6 +33,8 @@ namespace eosio::chain {

protocol_feature_activation_set_ptr get_activated_protocol_features() const { return block_header_state::activated_protocol_features; }
deque<transaction_metadata_ptr> extract_trxs_metas() { return {}; }; // [greg todo] see impl in block_state_legacy.hpp

bool aggregate_vote(const hs_vote_message& vote); // aggregate vote into pending_qc
};

using block_state_ptr = std::shared_ptr<block_state>;
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ namespace eosio::chain {
void set_proposed_finalizers( const finalizer_policy& fin_set );
void get_finalizer_state( finalizer_state& fs ) const;
// called from net threads
void notify_hs_message( const uint32_t connection_id, const hs_message& msg );
void process_vote_message( const hs_vote_message& msg );

bool light_validation_allowed() const;
bool skip_auth_check()const;
Expand Down
12 changes: 6 additions & 6 deletions plugins/net_plugin/net_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ namespace eosio {
void handle_message( const block_id_type& id, signed_block_ptr ptr );
void handle_message( const packed_transaction& msg ) = delete; // packed_transaction_ptr overload used instead
void handle_message( packed_transaction_ptr trx );
void handle_message( const chain::hs_message& msg );
void handle_message( const chain::hs_vote_message& msg );
heifner marked this conversation as resolved.
Show resolved Hide resolved

// returns calculated number of blocks combined latency
uint32_t calc_block_latency();
Expand Down Expand Up @@ -1177,9 +1177,9 @@ namespace eosio {
c->handle_message( msg );
}

void operator()( const chain::hs_message& msg ) const {
void operator()( const chain::hs_vote_message& msg ) const {
// continue call to handle_message on connection strand
peer_dlog( c, "handle hs_message" );
peer_dlog( c, "handle hs_vote_message" );
c->handle_message( msg );
}
};
Expand Down Expand Up @@ -3673,10 +3673,10 @@ namespace eosio {
}
}

void connection::handle_message( const chain::hs_message& msg ) {
peer_dlog(this, "received hs: ${msg}", ("msg", msg));
void connection::handle_message( const chain::hs_vote_message& msg ) {
peer_dlog(this, "received vote: ${msg}", ("msg", msg));
controller& cc = my_impl->chain_plug->chain();
cc.notify_hs_message(connection_id, msg);
cc.process_vote_message(msg);
}
heifner marked this conversation as resolved.
Show resolved Hide resolved

size_t calc_trx_size( const packed_transaction_ptr& trx ) {
Expand Down
90 changes: 90 additions & 0 deletions unittests/block_state_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include <eosio/chain/block_state.hpp>

#include <fc/exception/exception.hpp>
#include <fc/crypto/bls_private_key.hpp>
#include <fc/crypto/bls_utils.hpp>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(block_state_tests)

BOOST_AUTO_TEST_CASE(aggregate_vote_test) try {
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());

const size_t num_finalizers = 3;

// 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"),
};

// 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", 1, public_key[i] };
}

{ // all finalizers can aggregate votes
block_state_ptr bsp = std::make_shared<block_state>();
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
bsp->strong_finalizer_digest = strong_digest;
bsp->weak_finalizer_digest = weak_digest;
bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };

for (size_t i = 0; i < num_finalizers; ++i) {
bool strong = (i % 2 == 0); // alternate strong and weak
auto sig = strong ? private_key[i].sign(strong_digest_data) : private_key[i].sign(weak_digest_data);
hs_vote_message vote{ block_id, strong, public_key[i], sig };
BOOST_REQUIRE(bsp->aggregate_vote(vote));
}
}

{ // public and private keys mismatched
block_state_ptr bsp = std::make_shared<block_state>();
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
bsp->strong_finalizer_digest = strong_digest;
bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };

hs_vote_message vote {block_id, true, public_key[0], private_key[1].sign(strong_digest_data) };
BOOST_REQUIRE(!bsp->aggregate_vote(vote));
}

{ // duplicate votes
block_state_ptr bsp = std::make_shared<block_state>();
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
bsp->strong_finalizer_digest = strong_digest;
bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };

hs_vote_message vote {block_id, true, public_key[0], private_key[0].sign(strong_digest_data) };
BOOST_REQUIRE(bsp->aggregate_vote(vote));
BOOST_REQUIRE(!bsp->aggregate_vote(vote));
}

{ // public key does not exit in finalizer set
block_state_ptr bsp = std::make_shared<block_state>();
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers );
bsp->strong_finalizer_digest = strong_digest;
bsp->pending_qc = pending_quorum_certificate{ num_finalizers, 1 };

bls_private_key new_private_key{ "PVT_BLS_warwI76e+pPX9wLFZKPFagngeFM8bm6J8D5w0iiHpxW7PiId" };
bls_public_key new_public_key{ new_private_key.get_public_key() };

hs_vote_message vote {block_id, true, new_public_key, private_key[0].sign(strong_digest_data) };
BOOST_REQUIRE(!bsp->aggregate_vote(vote));
}
} FC_LOG_AND_RETHROW();

BOOST_AUTO_TEST_SUITE_END()