Skip to content

Commit

Permalink
GH-2125 Rename proposal to block. Add additional logging.
Browse files Browse the repository at this point in the history
  • Loading branch information
heifner committed Mar 9, 2024
1 parent 27f2557 commit ae5d26d
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 58 deletions.
10 changes: 5 additions & 5 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1675,7 +1675,7 @@ struct controller_impl {
my_finalizers.set_default_safety_information(
finalizer_safety_information{ .last_vote_range_start = block_timestamp_type(0),
.last_vote = {},
.lock = proposal_ref(lib->id(), lib->timestamp()) });
.lock = {lib->id(), lib->timestamp()} });
};
fork_db.apply_s<void>(set_finalizer_defaults);
} else {
Expand All @@ -1685,7 +1685,7 @@ struct controller_impl {
my_finalizers.set_default_safety_information(
finalizer_safety_information{ .last_vote_range_start = block_timestamp_type(0),
.last_vote = {},
.lock = proposal_ref(lib->id(), lib->timestamp()) });
.lock = {lib->id(), lib->timestamp()} });
};
fork_db.apply_s<void>(set_finalizer_defaults);
}
Expand Down Expand Up @@ -2937,8 +2937,8 @@ struct controller_impl {
auto lib_block = head;
my_finalizers.set_default_safety_information(
finalizer_safety_information{ .last_vote_range_start = block_timestamp_type(0),
.last_vote = proposal_ref(start_block->id(), start_block->timestamp()),
.lock = proposal_ref(lib_block->id(), lib_block->timestamp()) });
.last_vote = {start_block->id(), start_block->timestamp()},
.lock = {lib_block->id(), lib_block->timestamp()} });
}

if ( (s != controller::block_status::irreversible && read_mode != db_read_mode::IRREVERSIBLE) && s != controller::block_status::ephemeral)
Expand Down Expand Up @@ -3220,7 +3220,7 @@ struct controller_impl {
// called from net threads and controller's thread pool
vote_status process_vote_message( const vote_message& vote ) {
auto aggregate_vote = [&vote](auto& forkdb) -> vote_status {
auto bsp = forkdb.get_block(vote.proposal_id);
auto bsp = forkdb.get_block(vote.block_id);
if (bsp) {
return bsp->aggregate_vote(vote);
}
Expand Down
52 changes: 29 additions & 23 deletions libraries/chain/hotstuff/finalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
namespace eosio::chain {

// ----------------------------------------------------------------------------------------
finalizer::vote_result finalizer::decide_vote(const finality_core& core, const block_id_type& proposal_id,
const block_timestamp_type proposal_timestamp) {
finalizer::vote_result finalizer::decide_vote(const block_state_ptr& bsp) {
vote_result res;

res.monotony_check = fsi.last_vote.empty() || proposal_timestamp > fsi.last_vote.timestamp;
res.monotony_check = fsi.last_vote.empty() || bsp->timestamp() > fsi.last_vote.timestamp;
// fsi.last_vote.empty() means we have never voted on a proposal, so the protocol feature
// just activated and we can proceed

if (!res.monotony_check) {
dlog("monotony check failed for proposal ${bn} ${p}, cannot vote", ("bn", block_header::num_from_id(proposal_id))("p", proposal_id));
if (fsi.last_vote.empty()) {
dlog("monotony check failed, block ${bn} ${p}, cannot vote, fsi.last_vote empty", ("bn", bsp->block_num())("p", bsp->id()));
} else {
dlog("monotony check failed, block ${bn} ${p}, cannot vote, ${t} <= ${lt}, fsi.last_vote ${lbn} ${lid}",
("bn", bsp->block_num())("p", bsp->id())("t", bsp->timestamp())("lt", fsi.last_vote.timestamp)("lbn", fsi.last_vote.block_num())("lid", fsi.last_vote.block_id));
}
return res;
}

Expand All @@ -23,23 +27,24 @@ finalizer::vote_result finalizer::decide_vote(const finality_core& core, const b
// than the height of the proposal I'm locked on.
// This allows restoration of liveness if a replica is locked on a stale proposal
// -------------------------------------------------------------------------------
res.liveness_check = core.latest_qc_block_timestamp() > fsi.lock.timestamp;
res.liveness_check = bsp->core.latest_qc_block_timestamp() > fsi.lock.timestamp;

if (!res.liveness_check) {
ilog("liveness check failed for ${bn}: ${c} <= ${l}, latest_qc_claim: ${qc}",
("bn", core.current_block_num())("c", core.latest_qc_block_timestamp())("l", fsi.lock.timestamp)("qc", core.latest_qc_claim()));
dlog("liveness check failed, block ${bn} ${id}: ${c} <= ${l}, fsi.lock ${lbn} ${lid}, latest_qc_claim: ${qc}",
("bn", bsp->block_num())("id", bsp->id())("c", bsp->core.latest_qc_block_timestamp())("l", fsi.lock.timestamp)
("lbn", fsi.lock.block_num())("lid", fsi.lock.block_id)("qc", bsp->core.latest_qc_claim()));
// Safety check : check if this proposal extends the proposal we're locked on
res.safety_check = core.extends(fsi.lock.block_id);
res.safety_check = bsp->core.extends(fsi.lock.block_id);
if (!res.safety_check) {
ilog("safety check failed, block ${bn} : ${id} did not extend ${core}",
("bn", fsi.lock.block_num())("id", fsi.lock.block_id)("core", core.current_block_num()));
dlog("safety check failed, block ${bn} ${id} did not extend fsi.lock ${lbn} ${lid}",
("bn", bsp->block_num())("id", bsp->id())("lbn", fsi.lock.block_num())("lid", fsi.lock.block_id));
}
}
} else {
// Safety and Liveness both fail if `fsi.lock` is empty. It should not happen.
// `fsi.lock` is initially set to `lib` when switching to IF or starting from a snapshot.
// -------------------------------------------------------------------------------------
wlog("fsi.lock is empty");
wlog("liveness check & safety check failed, block ${bn} ${id}, fsi.lock is empty", ("bn", bsp->block_num())("id", bsp->id()));
res.liveness_check = false;
res.safety_check = false;
}
Expand All @@ -50,36 +55,37 @@ finalizer::vote_result finalizer::decide_vote(const finality_core& core, const b
// If we vote, update `fsi.last_vote` and also `fsi.lock` if we have a newer commit qc
// -----------------------------------------------------------------------------------
if (can_vote) {
auto [p_start, p_end] = std::make_pair(core.latest_qc_block_timestamp(), proposal_timestamp);
auto [p_start, p_end] = std::make_pair(bsp->core.latest_qc_block_timestamp(), bsp->timestamp());

bool time_range_disjoint = fsi.last_vote_range_start >= p_end || fsi.last_vote.timestamp <= p_start;
bool voting_strong = time_range_disjoint;
if (!voting_strong && !fsi.last_vote.empty()) {
// we can vote strong if the proposal is a descendant of (i.e. extends) our last vote id
voting_strong = core.extends(fsi.last_vote.block_id);
voting_strong = bsp->core.extends(fsi.last_vote.block_id);
}

fsi.last_vote = proposal_ref(proposal_id, proposal_timestamp);
fsi.last_vote = { bsp->id(), bsp->timestamp() };
fsi.last_vote_range_start = p_start;

auto& final_on_strong_qc_block_ref = core.get_block_reference(core.final_on_strong_qc_block_num);
if (voting_strong && final_on_strong_qc_block_ref.timestamp > fsi.lock.timestamp)
fsi.lock = proposal_ref(final_on_strong_qc_block_ref.block_id, final_on_strong_qc_block_ref.timestamp);
auto& final_on_strong_qc_block_ref = bsp->core.get_block_reference(bsp->core.final_on_strong_qc_block_num);
if (voting_strong && final_on_strong_qc_block_ref.timestamp > fsi.lock.timestamp) {
fsi.lock = { final_on_strong_qc_block_ref.block_id, final_on_strong_qc_block_ref.timestamp };
}

res.decision = voting_strong ? vote_decision::strong_vote : vote_decision::weak_vote;
}

dlog("block=${bn}, liveness_check=${l}, safety_check=${s}, monotony_check=${m}, can vote=${can_vote}, voting=${v}",
("bn", block_header::num_from_id(proposal_id))("l",res.liveness_check)("s",res.safety_check)("m",res.monotony_check)
("can_vote",can_vote)("v", res.decision));
dlog("block=${bn} ${id}, liveness_check=${l}, safety_check=${s}, monotony_check=${m}, can vote=${can_vote}, voting=${v}, locked=${lbn} ${lid}",
("bn", bsp->block_num())("id", bsp->id())("l",res.liveness_check)("s",res.safety_check)("m",res.monotony_check)
("can_vote",can_vote)("v", res.decision)("lbn", fsi.lock.block_num())("lid", fsi.lock.block_id));
return res;
}

// ----------------------------------------------------------------------------------------
std::optional<vote_message> finalizer::maybe_vote(const bls_public_key& pub_key,
const block_header_state_ptr& p,
const block_state_ptr& bsp,
const digest_type& digest) {
finalizer::vote_decision decision = decide_vote(p->core, p->id(), p->timestamp()).decision;
finalizer::vote_decision decision = decide_vote(bsp).decision;
if (decision == vote_decision::strong_vote || decision == vote_decision::weak_vote) {
bls_signature sig;
if (decision == vote_decision::weak_vote) {
Expand All @@ -89,7 +95,7 @@ std::optional<vote_message> finalizer::maybe_vote(const bls_public_key& pub_key,
} else {
sig = priv_key.sign({(uint8_t*)digest.data(), (uint8_t*)digest.data() + digest.data_size()});
}
return vote_message{ p->id(), decision == vote_decision::strong_vote, pub_key, sig };
return vote_message{ bsp->id(), decision == vote_decision::strong_vote, pub_key, sig };
}
return {};
}
Expand Down
15 changes: 6 additions & 9 deletions libraries/chain/include/eosio/chain/hotstuff/finalizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@
// -------------------------------------------------------------------------------------------

namespace eosio::chain {
// ----------------------------------------------------------------------------------------
using proposal_ref = block_ref;

// ----------------------------------------------------------------------------------------
struct finalizer_safety_information {
block_timestamp_type last_vote_range_start;
proposal_ref last_vote;
proposal_ref lock;
block_ref last_vote;
block_ref lock;

static constexpr uint64_t magic = 0x5AFE11115AFE1111ull;

Expand All @@ -59,10 +57,9 @@ namespace eosio::chain {
bls_private_key priv_key;
finalizer_safety_information fsi;

vote_result decide_vote(const finality_core& core, const block_id_type &id,
const block_timestamp_type timestamp);
vote_result decide_vote(const block_state_ptr& bsp);

std::optional<vote_message> maybe_vote(const bls_public_key& pub_key, const block_header_state_ptr& bhsp,
std::optional<vote_message> maybe_vote(const bls_public_key& pub_key, const block_state_ptr& bsp,
const digest_type& digest);
};

Expand All @@ -81,7 +78,7 @@ namespace eosio::chain {

template<class F>
void maybe_vote(const finalizer_policy& fin_pol,
const block_header_state_ptr& bhsp,
const block_state_ptr& bsp,
const digest_type& digest,
F&& process_vote) {
std::vector<vote_message> votes;
Expand All @@ -90,7 +87,7 @@ namespace eosio::chain {
// first accumulate all the votes
for (const auto& f : fin_pol.finalizers) {
if (auto it = finalizers.find(f.public_key); it != finalizers.end()) {
std::optional<vote_message> vote_msg = it->second.maybe_vote(it->first, bhsp, digest);
std::optional<vote_message> vote_msg = it->second.maybe_vote(it->first, bsp, digest);
if (vote_msg)
votes.push_back(std::move(*vote_msg));
}
Expand Down
4 changes: 2 additions & 2 deletions libraries/chain/include/eosio/chain/hotstuff/hotstuff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace eosio::chain {
using bls_key_map_t = std::map<bls_public_key, bls_private_key>;

struct vote_message {
fc::sha256 proposal_id; //vote on proposal
block_id_type block_id;
bool strong{false};
bls_public_key finalizer_key;
bls_signature sig;
Expand Down Expand Up @@ -145,7 +145,7 @@ namespace eosio::chain {
} //eosio::chain


FC_REFLECT(eosio::chain::vote_message, (proposal_id)(strong)(finalizer_key)(sig));
FC_REFLECT(eosio::chain::vote_message, (block_id)(strong)(finalizer_key)(sig));
FC_REFLECT_ENUM(eosio::chain::vote_status, (success)(duplicate)(unknown_public_key)(invalid_signature)(unknown_block))
FC_REFLECT(eosio::chain::valid_quorum_certificate, (_strong_votes)(_weak_votes)(_sig));
FC_REFLECT(eosio::chain::pending_quorum_certificate, (_quorum)(_max_weak_sum_before_weak_final)(_state)(_strong_sum)(_weak_sum)(_weak_votes)(_strong_votes));
Expand Down
16 changes: 8 additions & 8 deletions plugins/net_plugin/net_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3700,9 +3700,9 @@ namespace eosio {
}

void connection::handle_message( const vote_message& msg ) {
peer_dlog(this, "received vote: block #${bn}:${id}.., ${t}, key ${k}..",
("bn", block_header::num_from_id(msg.proposal_id))("id", msg.proposal_id.str().substr(8,16))
("t", msg.strong ? "strong" : "weak")("k", msg.finalizer_key.to_string().substr(8, 16)));
peer_dlog(this, "received vote: block #${bn}:${id}.., ${v}, key ${k}..",
("bn", block_header::num_from_id(msg.block_id))("id", msg.block_id.str().substr(8,16))
("v", msg.strong ? "strong" : "weak")("k", msg.finalizer_key.to_string().substr(8, 16)));
controller& cc = my_impl->chain_plug->chain();

switch( cc.process_vote_message(msg) ) {
Expand Down Expand Up @@ -3991,8 +3991,8 @@ namespace eosio {

// called from application thread
void net_plugin_impl::on_voted_block(const vote_message& msg) {
fc_dlog(logger, "on voted signal: block #${bn}:${id}.., ${t}, key ${k}..",
("bn", block_header::num_from_id(msg.proposal_id))("id", msg.proposal_id.str().substr(8,16))
fc_dlog(logger, "on voted signal: block #${bn} ${id}.., ${t}, key ${k}..",
("bn", block_header::num_from_id(msg.block_id))("id", msg.block_id.str().substr(8,16))
("t", msg.strong ? "strong" : "weak")("k", msg.finalizer_key.to_string().substr(8, 16)));
bcast_vote_message(std::nullopt, msg);
}
Expand All @@ -4001,9 +4001,9 @@ namespace eosio {
buffer_factory buff_factory;
auto send_buffer = buff_factory.get_send_buffer( msg );

fc_dlog(logger, "bcast vote: block #${bn}:${id}.., ${t}, key ${k}..",
("bn", block_header::num_from_id(msg.proposal_id))("id", msg.proposal_id.str().substr(8,16))
("t", msg.strong ? "strong" : "weak")("k", msg.finalizer_key.to_string().substr(8,16)));
fc_dlog(logger, "bcast ${t} vote: block #${bn} ${id}.., ${v}, key ${k}..",
("t", exclude_peer ? "received" : "our")("bn", block_header::num_from_id(msg.block_id))("id", msg.block_id.str().substr(8,16))
("v", msg.strong ? "strong" : "weak")("k", msg.finalizer_key.to_string().substr(8,16)));

dispatcher->strand.post( [this, exclude_peer, msg{std::move(send_buffer)}]() mutable {
dispatcher->bcast_vote_msg( exclude_peer, std::move(msg) );
Expand Down
8 changes: 4 additions & 4 deletions unittests/finality_test_cluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ bool finality_test_cluster::produce_blocks_and_verify_lib_advancing() {
void finality_test_cluster::node1_corrupt_vote_proposal_id() {
node1_orig_vote = node1.votes[0];

if( node1.votes[0].proposal_id.data()[0] == 'a' ) {
node1.votes[0].proposal_id.data()[0] = 'b';
if( node1.votes[0].block_id.data()[0] == 'a' ) {
node1.votes[0].block_id.data()[0] = 'b';
} else {
node1.votes[0].proposal_id.data()[0] = 'a';
node1.votes[0].block_id.data()[0] = 'a';
}
}

Expand Down Expand Up @@ -185,7 +185,7 @@ eosio::chain::vote_status finality_test_cluster::process_vote(node_info& node, s
vote.strong = false;

// fetch the strong digest
auto strong_digest = node.node.control->get_strong_digest_by_id(vote.proposal_id);
auto strong_digest = node.node.control->get_strong_digest_by_id(vote.block_id);
// convert the strong digest to weak and sign it
vote.sig = node.priv_key.sign(eosio::chain::create_weak_digest(strong_digest));
}
Expand Down
10 changes: 5 additions & 5 deletions unittests/finalizer_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ std::vector<FSI> create_random_fsi(size_t count) {
res.reserve(count);
for (size_t i=0; i<count; ++i) {
res.push_back(FSI{tstamp(i),
proposal_ref{sha256::hash((const char *)"vote"), tstamp(i*100 + 3)},
proposal_ref{sha256::hash((const char *)"lock"), tstamp(i*100)} });
block_ref{sha256::hash((const char *)"vote"), tstamp(i*100 + 3)},
block_ref{sha256::hash((const char *)"lock"), tstamp(i*100)} });
if (i)
assert(res.back() != res[0]);
}
return res;
}

std::vector<proposal_ref> create_proposal_refs(size_t count) {
std::vector<proposal_ref> res;
std::vector<block_ref> create_proposal_refs(size_t count) {
std::vector<block_ref> res;
res.reserve(count);
for (size_t i=0; i<count; ++i) {
std::string id_str {"vote"};
id_str += std::to_string(i);
res.push_back(proposal_ref{sha256::hash(id_str.c_str()), tstamp(i)});
res.push_back(block_ref{sha256::hash(id_str.c_str()), tstamp(i)});
}
return res;
}
Expand Down
4 changes: 2 additions & 2 deletions unittests/finalizer_vote_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ struct simulator_t {
my_finalizer.fsi = fsi_t{block_timestamp_type(0), genesis_ref, genesis_ref};
}

vote_result vote(const bhsp& p) {
auto vote_res = my_finalizer.decide_vote(p->core, p->id(), p->timestamp());
vote_result vote(const bsp& p) {
auto vote_res = my_finalizer.decide_vote(p);
return vote_res;
}

Expand Down

0 comments on commit ae5d26d

Please sign in to comment.