Skip to content

Commit

Permalink
Merge branch 'hotstuff_integration' into sign_broadcast_votes
Browse files Browse the repository at this point in the history
  • Loading branch information
linh2931 authored Jan 16, 2024
2 parents bb457b7 + cbb6b28 commit efa2cdd
Show file tree
Hide file tree
Showing 38 changed files with 1,184 additions and 865 deletions.
2 changes: 1 addition & 1 deletion docs/block_production/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ flowchart TD
direction TB
start -- "stage = Ø" --> sb
sb("start_block()"):::fun -- "stage = building_block" --> et
et["execute transactions" ] -- "stage = building_block" --> fb("finalize_block()"):::fun
et["execute transactions" ] -- "stage = building_block" --> fb("finish_block()"):::fun
fb -- "stage = assembled block" --> cb["add transaction metadata and create completed block"]
cb -- "stage = completed block" --> commit("commit_block() (where we [maybe] add to fork_db and mark valid)"):::fun
Expand Down
157 changes: 132 additions & 25 deletions libraries/chain/block_header_state.cpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
#include <eosio/chain/block_header_state.hpp>
#include <eosio/chain/block_header_state_utils.hpp>
#include <eosio/chain/hotstuff/instant_finality_extension.hpp>
#include <eosio/chain/hotstuff/proposer_policy.hpp>
#include <eosio/chain/exceptions.hpp>
#include <limits>

namespace eosio::chain {

producer_authority block_header_state::get_scheduled_producer(block_timestamp_type t) const {
return detail::get_scheduled_producer(proposer_policy->proposer_schedule.producers, t);
return detail::get_scheduled_producer(active_proposer_policy->proposer_schedule.producers, t);
}

const vector<digest_type>& block_header_state::get_new_protocol_feature_activations()const {
return detail::get_new_protocol_feature_activations(header_exts);
}

#warning Add last_proposed_finalizer_policy_generation to snapshot_block_header_state_v3, see header file TODO

block_header_state_core block_header_state_core::next(const uint32_t last_qc_block_num, bool is_last_qc_strong) const {
block_header_state_core block_header_state_core::next(qc_info_t incoming) const {
// no state change if last_qc_block_num is the same
if (last_qc_block_num == this->last_qc_block_num) {
if (incoming.last_qc_block_num == this->last_qc_block_num) {
return {*this};
}

EOS_ASSERT(last_qc_block_num > this->last_qc_block_num, block_validate_exception,
EOS_ASSERT(incoming.last_qc_block_num > this->last_qc_block_num, block_validate_exception,
"new last_qc_block_num must be greater than old last_qc_block_num");

auto old_last_qc_block_num = this->last_qc_block_num;
auto old_final_on_strong_qc_block_num = this->final_on_strong_qc_block_num;

block_header_state_core result{*this};

if (is_last_qc_strong) {
if (incoming.is_last_qc_strong) {
// last QC is strong. We can progress forward.

// block with old final_on_strong_qc_block_num becomes irreversible
Expand All @@ -47,7 +52,7 @@ block_header_state_core block_header_state_core::next(const uint32_t last_qc_blo
}

// new last_qc_block_num is always the input last_qc_block_num.
result.last_qc_block_num = last_qc_block_num;
result.last_qc_block_num = incoming.last_qc_block_num;

return result;
}
Expand All @@ -61,37 +66,139 @@ block_header_state block_header_state::next(block_header_state_input& input) con
result.header = block_header {
.timestamp = input.timestamp, // [greg todo] do we have to do the slot++ stuff from the legacy version?
.producer = input.producer,
.confirmed = hs_block_confirmed, // todo: consider 0 instead
.previous = input.parent_id,
.transaction_mroot = input.transaction_mroot,
.action_mroot = input.action_mroot,
//.schedule_version = ?, [greg todo]
//.new_producers = ? [greg todo]
.schedule_version = header.schedule_version
};

// core
// ----
if (input.qc_info)
result.core = core.next(input.qc_info->last_qc_block_num, input.qc_info->is_last_qc_strong);
else
result.core = core;

// add block header extensions
// activated protocol features
// ---------------------------
if (!input.new_protocol_feature_activations.empty()) {
result.activated_protocol_features = std::make_shared<protocol_feature_activation_set>(
*activated_protocol_features, input.new_protocol_feature_activations);
} else {
result.activated_protocol_features = activated_protocol_features;
}

// block_header_state_core
// -----------------------
result.core = input.qc_info ? core.next(*input.qc_info) : core;

// proposal_mtree and finality_mtree
// ---------------------------------
// [greg todo] ??

// proposer policy
// ---------------
result.active_proposer_policy = active_proposer_policy;

if(!proposer_policies.empty()) {
auto it = proposer_policies.begin();
// -1 since this is called after the block is built, this will be the active schedule for the next block
if (it->first.slot <= input.timestamp.slot - 1) {
result.active_proposer_policy = it->second;
result.header.schedule_version = header.schedule_version + 1;
result.active_proposer_policy->proposer_schedule.version = result.header.schedule_version;
result.proposer_policies = { ++it, proposer_policies.end() };
} else {
result.proposer_policies = proposer_policies;
}
}

if (input.new_proposer_policy) {
// called when assembling the block
result.proposer_policies[input.new_proposer_policy->active_time] = input.new_proposer_policy;
}

// finalizer policy
// ----------------
result.active_finalizer_policy = active_finalizer_policy;

// [greg todo] correct support for new finalizer_policy activation using finalizer_policies map

if (input.new_finalizer_policy)
++input.new_finalizer_policy->generation;

std::optional<qc_info_t> qc_info = input.qc_info;
if (!qc_info) {
// [greg todo]: copy the one from the previous block (look in header.header_extensions)

// add IF block header extension
// -----------------------------
uint16_t if_ext_id = instant_finality_extension::extension_id();
auto if_entry = header_exts.lower_bound(if_ext_id);
auto& if_ext = std::get<instant_finality_extension>(if_entry->second);

instant_finality_extension new_if_ext {if_ext.qc_info,
std::move(input.new_finalizer_policy),
std::move(input.new_proposer_policy)};
if (input.qc_info)
new_if_ext.qc_info = *input.qc_info;

emplace_extension(result.header.header_extensions, if_ext_id, fc::raw::pack(new_if_ext));
result.header_exts.emplace(if_ext_id, std::move(new_if_ext));

// add protocol_feature_activation extension
// -----------------------------------------
if (!input.new_protocol_feature_activations.empty()) {
uint16_t ext_id = protocol_feature_activation::extension_id();
protocol_feature_activation pfa_ext{.protocol_features = std::move(input.new_protocol_feature_activations)};

emplace_extension(result.header.header_extensions, ext_id, fc::raw::pack(pfa_ext));
result.header_exts.emplace(ext_id, std::move(pfa_ext));
}

emplace_extension(result.header.header_extensions, instant_finality_extension::extension_id(),
fc::raw::pack(instant_finality_extension{qc_info,
std::move(input.new_finalizer_policy),
std::move(input.new_proposer_policy)}));


// Finally update block id from header
// -----------------------------------
result.id = result.header.calculate_id();

return result;
}

/**
* Transitions the current header state into the next header state given the supplied signed block header.
*
* Given a signed block header, generate the expected template based upon the header time,
* then validate that the provided header matches the template.
*
* If the header specifies new_producers then apply them accordingly.
*/
block_header_state block_header_state::next(const signed_block_header& h, const protocol_feature_set& pfs,
validator_t& validator) const {
auto producer = detail::get_scheduled_producer(active_proposer_policy->proposer_schedule.producers, h.timestamp).producer_name;

EOS_ASSERT( h.previous == id, unlinkable_block_exception, "previous mismatch" );
EOS_ASSERT( h.producer == producer, wrong_producer, "wrong producer specified" );

auto exts = h.validate_and_extract_header_extensions();

// retrieve protocol_feature_activation from incoming block header extension
// -------------------------------------------------------------------------
vector<digest_type> new_protocol_feature_activations;
if( exts.count(protocol_feature_activation::extension_id() > 0) ) {
auto pfa_entry = exts.lower_bound(protocol_feature_activation::extension_id());
auto& pfa_ext = std::get<protocol_feature_activation>(pfa_entry->second);
new_protocol_feature_activations = std::move(pfa_ext.protocol_features);
}

// retrieve instant_finality_extension data from block header extension
// --------------------------------------------------------------------
EOS_ASSERT(exts.count(instant_finality_extension::extension_id()) > 0, invalid_block_header_extension,
"Instant Finality Extension is expected to be present in all block headers after switch to IF");
auto if_entry = exts.lower_bound(instant_finality_extension::extension_id());
auto& if_ext = std::get<instant_finality_extension>(if_entry->second);

building_block_input bb_input{
.parent_id = id,
.timestamp = h.timestamp,
.producer = producer,
.new_protocol_feature_activations = std::move(new_protocol_feature_activations)
};

block_header_state_input bhs_input{
bb_input, h.transaction_mroot, h.action_mroot, if_ext.new_proposer_policy, if_ext.new_finalizer_policy,
if_ext.qc_info};

return next(bhs_input);
}

} // namespace eosio::chain
22 changes: 8 additions & 14 deletions libraries/chain/block_header_state_legacy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,15 @@ namespace eosio::chain {

if( maybe_new_producer_schedule ) {
result.pending_schedule.schedule = std::move(*maybe_new_producer_schedule);
result.pending_schedule.schedule_hash = std::move(*maybe_new_producer_schedule_hash);
result.pending_schedule.schedule_hash = *maybe_new_producer_schedule_hash;
result.pending_schedule.schedule_lib_num = block_number;
} else {
if( was_pending_promoted ) {
result.pending_schedule.schedule.version = prev_pending_schedule.schedule.version;
} else {
result.pending_schedule.schedule = std::move( prev_pending_schedule.schedule );
}
result.pending_schedule.schedule_hash = std::move( prev_pending_schedule.schedule_hash );
result.pending_schedule.schedule_hash = prev_pending_schedule.schedule_hash ;
result.pending_schedule.schedule_lib_num = prev_pending_schedule.schedule_lib_num;
}

Expand Down Expand Up @@ -369,13 +369,12 @@ namespace eosio::chain {
*/
block_header_state_legacy block_header_state_legacy::next(
const signed_block_header& h,
vector<signature_type>&& _additional_signatures,
vector<signature_type>&& additional_signatures,
const protocol_feature_set& pfs,
bool hotstuff_activated,
validator_t& validator,
bool skip_validate_signee )const
{
return next( h.timestamp, h.confirmed ).finish_next( h, std::move(_additional_signatures), pfs, validator, skip_validate_signee );
return next( h.timestamp, h.confirmed ).finish_next( h, std::move(additional_signatures), pfs, validator, skip_validate_signee );
}

digest_type block_header_state_legacy::sig_digest()const {
Expand Down Expand Up @@ -430,15 +429,10 @@ namespace eosio::chain {
}

/**
* Reference cannot outlive *this. Assumes header_exts is not mutated after instatiation.
* Reference cannot outlive *this. Assumes header_exts is not mutated after instantiation.
*/
const vector<digest_type>& block_header_state_legacy::get_new_protocol_feature_activations()const {
static const vector<digest_type> no_activations{};

if( header_exts.count(protocol_feature_activation::extension_id()) == 0 )
return no_activations;

return std::get<protocol_feature_activation>(header_exts.lower_bound(protocol_feature_activation::extension_id())->second).protocol_features;
return detail::get_new_protocol_feature_activations(header_exts);
}

block_header_state_legacy::block_header_state_legacy( legacy::snapshot_block_header_state_v2&& snapshot )
Expand All @@ -452,10 +446,10 @@ namespace eosio::chain {
producer_to_last_implied_irb = std::move(snapshot.producer_to_last_implied_irb);
valid_block_signing_authority = block_signing_authority_v0{ 1, {{std::move(snapshot.block_signing_key), 1}} };
confirm_count = std::move(snapshot.confirm_count);
id = std::move(snapshot.id);
id = snapshot.id;
header = std::move(snapshot.header);
pending_schedule.schedule_lib_num = snapshot.pending_schedule.schedule_lib_num;
pending_schedule.schedule_hash = std::move(snapshot.pending_schedule.schedule_hash);
pending_schedule.schedule_hash = snapshot.pending_schedule.schedule_hash;
pending_schedule.schedule = producer_authority_schedule( snapshot.pending_schedule.schedule );
activated_protocol_features = std::move(snapshot.activated_protocol_features);
}
Expand Down
Loading

0 comments on commit efa2cdd

Please sign in to comment.