Skip to content

Commit

Permalink
Merge branch 'main' into gh_11
Browse files Browse the repository at this point in the history
  • Loading branch information
linh2931 authored May 14, 2024
2 parents 5f0b736 + 61425c1 commit 8e8e921
Show file tree
Hide file tree
Showing 28 changed files with 951 additions and 284 deletions.
122 changes: 107 additions & 15 deletions libraries/chain/block_header_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,29 @@ const vector<digest_type>& block_header_state::get_new_protocol_feature_activati
return detail::get_new_protocol_feature_activations(header_exts);
}

// The last proposed finalizer policy if none proposed or pending is the active finalizer policy
const finalizer_policy& block_header_state::get_last_proposed_finalizer_policy() const {
if (!finalizer_policies.empty()) {
for (auto ritr = finalizer_policies.rbegin(); ritr != finalizer_policies.rend(); ++ritr) {
if (ritr->second.state == finalizer_policy_tracker::state_t::proposed)
return *ritr->second.policy;
}
return *finalizer_policies.rbegin()->second.policy;
}
return *active_finalizer_policy;
}

// The last proposed proposer policy, if none proposed then the active proposer policy
const proposer_policy& block_header_state::get_last_proposed_proposer_policy() const {
if (proposer_policies.empty()) {
assert(active_proposer_policy);
return *active_proposer_policy;
}
auto it = proposer_policies.rbegin();
assert(it != proposer_policies.rend());
return *it->second;
}

// -------------------------------------------------------------------------------------------------
// `finish_next` updates the next `block_header_state` according to the contents of the
// header extensions (either new protocol_features or instant_finality_extension) applicable to this
Expand Down Expand Up @@ -103,10 +126,14 @@ void finish_next(const block_header_state& prev,
}
}

if (if_ext.new_proposer_policy) {
std::optional<proposer_policy> new_proposer_policy;
if (if_ext.new_proposer_policy_diff) {
new_proposer_policy = prev.get_last_proposed_proposer_policy().apply_diff(*if_ext.new_proposer_policy_diff);
}
if (new_proposer_policy) {
// called when assembling the block
next_header_state.proposer_policies[if_ext.new_proposer_policy->active_time] =
std::move(if_ext.new_proposer_policy);
next_header_state.proposer_policies[new_proposer_policy->active_time] =
std::make_shared<proposer_policy>(std::move(*new_proposer_policy));
}

// finality_core
Expand All @@ -131,6 +158,8 @@ void finish_next(const block_header_state& prev,
// ---------------------------------------------------------------------------
next_header_state.finalizer_policies = prev.finalizer_policies;
} else {
auto next_block_num = next_header_state.block_num();

while (it != prev.finalizer_policies.end() && it->first <= lib) {
const finalizer_policy_tracker& tracker = it->second;
if (tracker.state == finalizer_policy_tracker::state_t::pending) {
Expand All @@ -139,11 +168,33 @@ void finish_next(const block_header_state& prev,
next_header_state.active_finalizer_policy.reset(new finalizer_policy(*tracker.policy));
} else {
assert(tracker.state == finalizer_policy_tracker::state_t::proposed);
// block where finalizer_policy was proposed became final. The finalizer policy will
// become active when next block becomes final.

// The block where finalizer_policy was proposed has became final. The finalizer
// policy will become active when `next_block_num` becomes final.
//
// So `tracker.policy` should become `pending` at `next_block_num`.
//
// Either insert a new `finalizer_policy_tracker` value, or update the `pending`
// policy if there is already one at `next_block_num` (which can happen when
// finality advances multiple block at a time, and more than one policy move from
// proposed to pending.
//
// Since we iterate finalizer_policies which is a multimap sorted by block number,
// the last one we add will be for the highest block number, which is what we want.
// ---------------------------------------------------------------------------------
finalizer_policy_tracker t { finalizer_policy_tracker::state_t::pending, tracker.policy };
next_header_state.finalizer_policies.emplace(next_header_state.block_num(), std::move(t));
auto range = next_header_state.finalizer_policies.equal_range(next_block_num);
auto itr = range.first;
for (; itr != range.second; ++itr) {
if (itr->second.state == finalizer_policy_tracker::state_t::pending) {
itr->second.policy = tracker.policy;
break;
}
}
if (itr == range.second) {
// there wasn't already a pending one for `next_block_num`, add a new tracker
finalizer_policy_tracker t { finalizer_policy_tracker::state_t::pending, tracker.policy };
next_header_state.finalizer_policies.emplace(next_block_num, std::move(t));
}
}
++it;
}
Expand All @@ -156,20 +207,21 @@ void finish_next(const block_header_state& prev,
}
}

if (if_ext.new_finalizer_policy) {
if (if_ext.new_finalizer_policy_diff) {
finalizer_policy new_finalizer_policy = prev.get_last_proposed_finalizer_policy().apply_diff(*if_ext.new_finalizer_policy_diff);

// a new `finalizer_policy` was proposed in the previous block, and is present in the previous
// block's header extensions.
// Add this new proposal to the `finalizer_policies` multimap which tracks the in-flight proposals,
// increment the generation number, and log that proposal (debug level).
// ------------------------------------------------------------------------------------------------
dlog("New finalizer policy proposed in block ${id}: ${pol}",
("id", prev.block_id)("pol", *if_ext.new_finalizer_policy));
next_header_state.finalizer_policy_generation = if_ext.new_finalizer_policy->generation;
dlog("New finalizer policy proposed in block ${id}..: ${pol}",
("id", prev.block_id.str().substr(8,16))("pol", new_finalizer_policy));
next_header_state.finalizer_policy_generation = new_finalizer_policy.generation;
next_header_state.finalizer_policies.emplace(
next_header_state.block_num(),
finalizer_policy_tracker{finalizer_policy_tracker::state_t::proposed,
std::make_shared<finalizer_policy>(std::move(*if_ext.new_finalizer_policy))});

std::make_shared<finalizer_policy>(std::move(new_finalizer_policy))});
} else {
next_header_state.finalizer_policy_generation = prev.finalizer_policy_generation;
}
Expand Down Expand Up @@ -205,9 +257,17 @@ block_header_state block_header_state::next(block_header_state_input& input) con

// finality extension
// ------------------
std::optional<finalizer_policy_diff> new_finalizer_policy_diff;
if (input.new_finalizer_policy) {
new_finalizer_policy_diff = get_last_proposed_finalizer_policy().create_diff(*input.new_finalizer_policy);
}
std::optional<proposer_policy_diff> new_proposer_policy_diff;
if (input.new_proposer_policy) {
new_proposer_policy_diff = get_last_proposed_proposer_policy().create_diff(*input.new_proposer_policy);
}
instant_finality_extension new_if_ext { input.most_recent_ancestor_with_qc,
std::move(input.new_finalizer_policy),
std::move(input.new_proposer_policy) };
std::move(new_finalizer_policy_diff),
std::move(new_proposer_policy_diff) };

uint16_t if_ext_id = instant_finality_extension::extension_id();
emplace_extension(next_header_state.header.header_extensions, if_ext_id, fc::raw::pack(new_if_ext));
Expand Down Expand Up @@ -285,5 +345,37 @@ block_header_state block_header_state::next(const signed_block_header& h, valida
return next_header_state;
}

// -------------------------------------------------------------------------------
// do some sanity checks on block_header_state
// -------------------------------------------------------------------------------
bool block_header_state::sanity_check() const {
// check that we have at most *one* proposed and *one* pending `finalizer_policy`
// for any block number
// -----------------------------------------------------------------------------
block_num_type block_num(0);
bool pending{false}, proposed{false};

for (auto it = finalizer_policies.begin(); it != finalizer_policies.end(); ++it) {
if (block_num != it->first) {
pending = proposed = false;
block_num = it->first;
}
const auto& tracker = it->second;
if (tracker.state == finalizer_policy_tracker::state_t::proposed) {
if (proposed)
return false;
else
proposed = true;
}
if (tracker.state == finalizer_policy_tracker::state_t::pending) {
if (pending)
return false;
else
pending = true;
}
}
return true;
}

} // namespace eosio::chain

4 changes: 3 additions & 1 deletion libraries/chain/block_header_state_legacy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ namespace eosio::chain {
// set current block_num as qc_claim.last_qc_block_num in the IF extension
qc_claim_t initial_if_claim { .block_num = block_num,
.is_strong_qc = false };
finalizer_policy no_policy;
auto new_fin_policy_diff = no_policy.create_diff(*new_finalizer_policy);
emplace_extension(h.header_extensions, instant_finality_extension::extension_id(),
fc::raw::pack(instant_finality_extension{ initial_if_claim, std::move(new_finalizer_policy), {} }));
fc::raw::pack(instant_finality_extension{ initial_if_claim, std::move(new_fin_policy_diff), {} }));
} else if (qc_claim) {
emplace_extension(h.header_extensions, instant_finality_extension::extension_id(),
fc::raw::pack(instant_finality_extension{ *qc_claim, {}, {} }));
Expand Down
25 changes: 21 additions & 4 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& b

assert(bsp.block->contains_header_extension(instant_finality_extension::extension_id())); // required by transition mechanism
instant_finality_extension if_ext = bsp.block->extract_header_extension<instant_finality_extension>();
assert(if_ext.new_finalizer_policy); // required by transition mechanism
result.active_finalizer_policy = std::make_shared<finalizer_policy>(*if_ext.new_finalizer_policy);
assert(if_ext.new_finalizer_policy_diff); // required by transition mechanism
result.active_finalizer_policy = std::make_shared<finalizer_policy>(finalizer_policy{}.apply_diff(std::move(*if_ext.new_finalizer_policy_diff)));
result.active_proposer_policy = std::make_shared<proposer_policy>();
result.active_proposer_policy->active_time = bsp.timestamp();
result.active_proposer_policy->proposer_schedule = bsp.active_schedule;
Expand Down Expand Up @@ -337,11 +337,28 @@ finality_data_t block_state::get_finality_data() {
if (!base_digest) {
base_digest = compute_base_digest(); // cache it
}

// Check if there is any proposed finalizer policy in the block
std::optional<finalizer_policy> proposed_finalizer_policy;
if (is_savanna_genesis_block()) {
// For Genesis Block, use the active finalizer policy which was proposed in the block.
proposed_finalizer_policy = *active_finalizer_policy;
} else {
auto range = finalizer_policies.equal_range(block_num());
for (auto itr = range.first; itr != range.second; ++itr) {
if (itr->second.state == finalizer_policy_tracker::state_t::proposed) {
proposed_finalizer_policy = *itr->second.policy;
break;
}
}
}

return {
// other fields take the default values set by finality_data_t definition
.active_finalizer_policy_generation = active_finalizer_policy->generation,
.action_mroot = action_mroot,
.base_digest = *base_digest
.action_mroot = action_mroot,
.base_digest = *base_digest,
.proposed_finalizer_policy = std::move(proposed_finalizer_policy)
};
}

Expand Down
20 changes: 15 additions & 5 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ struct building_block {
assembled_block assemble_block(boost::asio::io_context& ioc,
const protocol_feature_set& pfs,
fork_database& fork_db,
std::unique_ptr<proposer_policy> new_proposer_policy,
std::optional<proposer_policy> new_proposer_policy,
std::optional<finalizer_policy> new_finalizer_policy,
bool validating,
std::optional<qc_data_t> validating_qc_data,
Expand Down Expand Up @@ -2942,6 +2942,8 @@ struct controller_impl {
handle_exception(wrapper);
}

// this code is hit if an exception was thrown, and handled by `handle_exception`
// ------------------------------------------------------------------------------
if (!trx->is_transient()) {
dmlog_applied_transaction(trace);
emit( applied_transaction, std::tie(trace, trx->packed_trx()), __FILE__, __LINE__ );
Expand Down Expand Up @@ -3162,13 +3164,13 @@ struct controller_impl {
resource_limits.process_block_usage(bb.block_num());

// Any proposer policy?
auto process_new_proposer_policy = [&](auto&) -> std::unique_ptr<proposer_policy> {
std::unique_ptr<proposer_policy> new_proposer_policy;
auto process_new_proposer_policy = [&](auto&) -> std::optional<proposer_policy> {
std::optional<proposer_policy> new_proposer_policy;
const auto& gpo = db.get<global_property_object>();
if (gpo.proposed_schedule_block_num) {
std::optional<uint32_t> version = pending->get_next_proposer_schedule_version(gpo.proposed_schedule.producers);
if (version) {
new_proposer_policy = std::make_unique<proposer_policy>();
new_proposer_policy.emplace();
new_proposer_policy->active_time = detail::get_next_next_round_block_time(bb.timestamp());
new_proposer_policy->proposer_schedule = producer_authority_schedule::from_shared(gpo.proposed_schedule);
new_proposer_policy->proposer_schedule.version = *version;
Expand All @@ -3184,7 +3186,7 @@ struct controller_impl {
}
return new_proposer_policy;
};
auto new_proposer_policy = apply_s<std::unique_ptr<proposer_policy>>(chain_head, process_new_proposer_policy);
auto new_proposer_policy = apply_s<std::optional<proposer_policy>>(chain_head, process_new_proposer_policy);

// Any finalizer policy?
std::optional<finalizer_policy> new_finalizer_policy = std::nullopt;
Expand Down Expand Up @@ -5109,6 +5111,10 @@ block_state_legacy_ptr controller::head_block_state_legacy()const {
});
}

bool controller::head_sanity_check()const {
return apply<bool>(my->chain_head, [](const auto& head) { return head->sanity_check(); });
}

const signed_block_ptr& controller::head_block()const {
return my->chain_head.block();
}
Expand Down Expand Up @@ -5281,6 +5287,8 @@ int64_t controller_impl::set_proposed_producers( vector<producer_authority> prod
if (producers.empty())
return -1; // INSTANT_FINALITY depends on DISALLOW_EMPTY_PRODUCER_SCHEDULE

EOS_ASSERT(producers.size() <= config::max_proposers, wasm_execution_error,
"Producer schedule exceeds the maximum proposer count for this chain");
assert(pending);

producer_authority_schedule sch;
Expand All @@ -5299,6 +5307,8 @@ int64_t controller_impl::set_proposed_producers( vector<producer_authority> prod
}

int64_t controller_impl::set_proposed_producers_legacy( vector<producer_authority> producers ) {
EOS_ASSERT(producers.size() <= config::max_producers, wasm_execution_error,
"Producer schedule exceeds the maximum producer count for this chain");
const auto& gpo = db.get<global_property_object>();
auto cur_block_num = chain_head.block_num() + 1;

Expand Down
15 changes: 12 additions & 3 deletions libraries/chain/include/eosio/chain/block_header_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ struct finality_digest_data_v1 {
// ------------------------------------------------------------------------------------------
struct finalizer_policy_tracker {
enum class state_t { proposed = 0, pending };
state_t state;
finalizer_policy_ptr policy;
state_t state;
finalizer_policy_ptr policy;
};

struct building_block_input {
Expand All @@ -61,7 +61,7 @@ struct building_block_input {
// this struct can be extracted from a building block
struct block_header_state_input : public building_block_input {
digest_type transaction_mroot; // Comes from std::get<checksum256_type>(building_block::trx_mroot_or_receipt_digests)
std::shared_ptr<proposer_policy> new_proposer_policy; // Comes from building_block::new_proposer_policy
std::optional<proposer_policy> new_proposer_policy; // Comes from building_block::new_proposer_policy
std::optional<finalizer_policy> new_finalizer_policy; // Comes from building_block::new_finalizer_policy
qc_claim_t most_recent_ancestor_with_qc; // Comes from traversing branch from parent and calling get_best_qc()
digest_type finality_mroot_claim;
Expand Down Expand Up @@ -119,6 +119,10 @@ struct block_header_state {
digest_type compute_base_digest() const;
digest_type compute_finality_digest() const;

// Returns true if the block is a Savanna Genesis Block.
// This method is applicable to any transition block which is re-classified as a Savanna block.
bool is_savanna_genesis_block() const { return core.is_genesis_block_num(block_num()); }

// Returns true if the block is a Proper Savanna Block
bool is_proper_svnn_block() const { return header.is_proper_svnn_block(); }

Expand All @@ -127,8 +131,13 @@ struct block_header_state {
return qc_claim > core.latest_qc_claim();
}

bool sanity_check() const; // does sanity check of block_header_state, returns true if successful

const vector<digest_type>& get_new_protocol_feature_activations() const;
const producer_authority& get_scheduled_producer(block_timestamp_type t) const;

const finalizer_policy& get_last_proposed_finalizer_policy() const;
const proposer_policy& get_last_proposed_proposer_policy() const;
};

using block_header_state_ptr = std::shared_ptr<block_header_state>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ struct block_header_state_legacy : public detail::block_header_state_legacy_comm
void sign( const signer_callback_type& signer );
void verify_signee()const;

bool sanity_check() const { return true; }

const vector<digest_type>& get_new_protocol_feature_activations()const;
};

Expand Down
Loading

0 comments on commit 8e8e921

Please sign in to comment.