Skip to content

Commit

Permalink
Merge branch 'release/1.0' into force_all_checks_tests
Browse files Browse the repository at this point in the history
  • Loading branch information
linh2931 authored Sep 11, 2024
2 parents a0d06fd + 5326f62 commit cfd1162
Show file tree
Hide file tree
Showing 25 changed files with 492 additions and 145 deletions.
37 changes: 30 additions & 7 deletions libraries/chain/block_handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

namespace eosio::chain {

// -------------------------------------------------------------------------------------------
// prior to writing magic and version numbers, we simply serialized the class (*this) to
// file. Let's call this the implicit version 0, which is not supported anymore in
// Spring 1.0.1 and above.
// However, we need to make sure that `chain_head_magic` can't match the tag of a std::variant
// -------------------------------------------------------------------------------------------
constexpr uint64_t chain_head_magic = 0xf1f2f3f4f4f3f2f1;
constexpr uint64_t chain_head_version = 1;


void block_handle::write(const std::filesystem::path& state_file) {
if (!is_valid())
return;
Expand All @@ -13,24 +23,37 @@ void block_handle::write(const std::filesystem::path& state_file) {
fc::datastream<fc::cfile> f;
f.set_file_path(state_file);
f.open("wb");

fc::raw::pack(f, chain_head_magic);
fc::raw::pack(f, chain_head_version);
fc::raw::pack(f, *this);
}

bool block_handle::read(const std::filesystem::path& state_file) {
if (!std::filesystem::exists(state_file))
return false;

fc::datastream<fc::cfile> f;
f.set_file_path(state_file);
f.open("rb");
EOS_ASSERT(std::filesystem::file_size(state_file) >= 2 * sizeof(chain_head_magic), chain_exception,
"File `chain_head.dat` seems to be corrupted. The best course of action might be to restart from a snapshot" );

fc::raw::unpack(f, *this);
try {
fc::datastream<fc::cfile> f;
f.set_file_path(state_file);
f.open("rb");

ilog("Loading chain_head block ${bn} ${id}", ("bn", block_num())("id", id()));
uint64_t magic, version;
fc::raw::unpack(f, magic);
fc::raw::unpack(f, version);

std::filesystem::remove(state_file);
EOS_ASSERT(magic == chain_head_magic && version == chain_head_version, chain_exception,
"Error reading `chain_head.dat` file. It is likely a Spring 1.0.0 version which is not supported by Spring 1.0.1 and above"
"The best course of action might be to restart from a snapshot" );

fc::raw::unpack(f, *this);
ilog("Loading chain_head block ${bn} ${id}", ("bn", block_num())("id", id()));
} FC_CAPTURE_AND_RETHROW( (state_file) );

// remove the `chain_head.dat` file only if we were able to successfully load it.
std::filesystem::remove(state_file);
return true;
}

Expand Down
79 changes: 78 additions & 1 deletion libraries/chain/block_header_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ digest_type block_header_state::compute_base_digest() const {
digest_type::encoder enc;

fc::raw::pack( enc, header );
fc::raw::pack( enc, core );
core.pack_for_digest( enc );

fc::raw::pack( enc, proposed_finalizer_policies );
fc::raw::pack( enc, pending_finalizer_policy );
Expand Down Expand Up @@ -141,6 +141,67 @@ const finalizer_policy& block_header_state::get_last_pending_finalizer_policy()
return *active_finalizer_policy;
}

// Only defined for core.latest_qc_claim().block_num <= ref.block_num() <= core.current_block_num()
// Retrieves the finalizer policies applicable for the block referenced by `ref`.
// See full explanation in issue #694.
// ------------------------------------------------------------------------------------------------
finalizer_policies_t block_header_state::get_finalizer_policies(const block_ref& ref) const {
assert(core.links.empty() || // called from a bogus block_state constructed in a test
(core.latest_qc_claim().block_num <= ref.block_num() && ref.block_num() <= core.current_block_num()));
finalizer_policies_t res;

res.finality_digest = ref.finality_digest;

auto active_gen = ref.active_policy_generation;
assert(active_gen != 0); // we should always have an active policy

if (active_finalizer_policy->generation == active_gen)
res.active_finalizer_policy = active_finalizer_policy; // the one active at block_num is still active
else {
// cannot be the pending one as it never was active
assert(!pending_finalizer_policy || pending_finalizer_policy->second->generation > active_gen);

// has to be the one in latest_qc_claim_block_active_finalizer_policy
assert(latest_qc_claim_block_active_finalizer_policy != nullptr);
assert(latest_qc_claim_block_active_finalizer_policy->generation == active_gen);
EOS_ASSERT(latest_qc_claim_block_active_finalizer_policy != nullptr &&
latest_qc_claim_block_active_finalizer_policy->generation == active_gen,
chain_exception,
"Logic error in finalizer policy retrieval"); // just in case
res.active_finalizer_policy = latest_qc_claim_block_active_finalizer_policy;
}

auto pending_gen = ref.pending_policy_generation;
if (pending_gen == 0)
res.pending_finalizer_policy = nullptr; // no pending policy at block_num.
else if (pending_gen == active_finalizer_policy->generation)
res.pending_finalizer_policy = active_finalizer_policy; // policy pending at block_num became active
else {
// cannot be the one in latest_qc_claim_block_active_finalizer_policy since it was active at
// core.latest_qc_claim().block_num. So it must be the one still pending.
assert(pending_finalizer_policy && pending_finalizer_policy->second->generation == pending_gen);
EOS_ASSERT(pending_finalizer_policy && pending_finalizer_policy->second->generation == pending_gen, chain_exception,
"Logic error in finalizer policy retrieval"); // just in case
res.pending_finalizer_policy = pending_finalizer_policy->second;
}

return res;
}

// Only defined for core.latest_qc_claim().block_num <= num <= core.current_block_num()
// Retrieves the active finalizer policy generation applicatble for the block `num`, which
// can be the current block or one of its ancestors up to core.latest_qc_claim().block_num (incl).
// -----------------------------------------------------------------------------------------------
uint32_t block_header_state::get_active_finalizer_policy_generation(block_num_type num) const {
assert(core.links.empty() || // called from a bogus block_state constructed in a test
(core.last_final_block_num() <= num && num <= core.current_block_num()));
if (num == block_num())
return active_finalizer_policy->generation;
const block_ref& ref = core.get_block_reference(num);
return ref.active_policy_generation;
}


// 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 (latest_proposed_proposer_policy) {
Expand Down Expand Up @@ -325,6 +386,22 @@ void finish_next(const block_header_state& prev,
next_header_state.finalizer_policy_generation = prev.finalizer_policy_generation;
}

// now populate next_header_state.latest_qc_claim_block_active_finalizer_policy
// this keeps track of the finalizer policy which was active @ latest_qc_claim().block_num, but which
// can be overwritten by a previously pending policy (member `active_finalizer_policy`)
// See full explanation in issue #694.
// --------------------------------------------------------------------------------------------------
const auto& next_core = next_header_state.core;
auto latest_qc_claim_block_num = next_core.latest_qc_claim().block_num;
const auto active_generation_num = next_header_state.active_finalizer_policy->generation;
if (prev.get_active_finalizer_policy_generation(latest_qc_claim_block_num) != active_generation_num) {
const auto& latest_qc_claim_block_ref = next_header_state.core.get_block_reference(latest_qc_claim_block_num);
next_header_state.latest_qc_claim_block_active_finalizer_policy =
prev.get_finalizer_policies(latest_qc_claim_block_ref).active_finalizer_policy;
} else {
next_header_state.latest_qc_claim_block_active_finalizer_policy = nullptr;
}

// Finally update block id from header
// -----------------------------------
next_header_state.block_id = next_header_state.header.calculate_id();
Expand Down
36 changes: 24 additions & 12 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,25 +184,30 @@ block_state_ptr block_state::create_transition_block(
return result_ptr;
}

block_state::block_state(snapshot_detail::snapshot_block_state_v7&& sbs)
// Spring 1.0.1 to ? snapshot v8 format. Updated `finality_core` to include finalizer policies
// generation numbers. Also new member `block_state::latest_qc_claim_block_active_finalizer_policy`
// ------------------------------------------------------------------------------------------------
block_state::block_state(snapshot_detail::snapshot_block_state_v8&& sbs)
: block_header_state {
.block_id = sbs.block_id,
.header = std::move(sbs.header),
.activated_protocol_features = std::move(sbs.activated_protocol_features),
.core = std::move(sbs.core),
.active_finalizer_policy = std::move(sbs.active_finalizer_policy),
.active_proposer_policy = std::move(sbs.active_proposer_policy),
.block_id = sbs.block_id,
.header = std::move(sbs.header),
.activated_protocol_features = std::move(sbs.activated_protocol_features),
.core = std::move(sbs.core),
.active_finalizer_policy = std::move(sbs.active_finalizer_policy),
.active_proposer_policy = std::move(sbs.active_proposer_policy),
.latest_proposed_proposer_policy = std::move(sbs.latest_proposed_proposer_policy),
.latest_pending_proposer_policy = std::move(sbs.latest_pending_proposer_policy),
.proposed_finalizer_policies = std::move(sbs.proposed_finalizer_policies),
.pending_finalizer_policy = std::move(sbs.pending_finalizer_policy),
.finalizer_policy_generation = sbs.finalizer_policy_generation,
.proposed_finalizer_policies = std::move(sbs.proposed_finalizer_policies),
.pending_finalizer_policy = std::move(sbs.pending_finalizer_policy),
.latest_qc_claim_block_active_finalizer_policy = std::move(sbs.latest_qc_claim_block_active_finalizer_policy),
.finalizer_policy_generation = sbs.finalizer_policy_generation,
.last_pending_finalizer_policy_digest = sbs.last_pending_finalizer_policy_digest,
.last_pending_finalizer_policy_start_timestamp = sbs.last_pending_finalizer_policy_start_timestamp
}
, strong_digest(compute_finality_digest())
, weak_digest(create_weak_digest(strong_digest))
, aggregating_qc(active_finalizer_policy, pending_finalizer_policy ? pending_finalizer_policy->second : finalizer_policy_ptr{}) // just in case we receive votes
, aggregating_qc(active_finalizer_policy,
pending_finalizer_policy ? pending_finalizer_policy->second : finalizer_policy_ptr{}) // just in case we receive votes
, valid(std::move(sbs.valid))
{
header_exts = header.validate_and_extract_header_extensions();
Expand Down Expand Up @@ -233,7 +238,14 @@ vote_status_t block_state::has_voted(const bls_public_key& key) const {

// Called from net threads
void block_state::verify_qc(const qc_t& qc) const {
aggregating_qc.verify_qc(qc, strong_digest, weak_digest);
// Do not use `block_state::aggregating_qc` which applies only for `this` block.
// `verify_qc()` can be called on a descendant `block_state` of `qc.block_num`, so we need
// to create a new `aggregating_qc_t` with the finalizer policies of the claimed block.
// ---------------------------------------------------------------------------------------
finalizer_policies_t policies = get_finalizer_policies(qc.block_num);
aggregating_qc_t aggregating_qc(policies.active_finalizer_policy, policies.pending_finalizer_policy);

aggregating_qc.verify_qc(qc, policies.finality_digest, create_weak_digest(policies.finality_digest));
}

qc_claim_t block_state::extract_qc_claim() const {
Expand Down
Loading

0 comments on commit cfd1162

Please sign in to comment.