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: make qc_info in instant_finality_extension non-optional #2145

Merged
merged 18 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c3f700a
Always include `qc_info` in IF extension.
greg7mdp Jan 25, 2024
a2e9cc6
Merge branch 'hotstuff_integration' of github.com:AntelopeIO/leap int…
greg7mdp Jan 25, 2024
84aeb00
Make it work by updating the ih header extension in the block_state a…
greg7mdp Jan 26, 2024
0c4deb5
Merge branch 'hotstuff_integration' of github.com:AntelopeIO/leap int…
greg7mdp Jan 26, 2024
7b28ddd
Indentation and typo.
greg7mdp Jan 26, 2024
8b3b02b
change `qc_info` -> `qc_claim` and `block_height` -> `block_num`.
greg7mdp Jan 26, 2024
5779b6d
Remove no longer necessary check in `verify_qc_claim`.
greg7mdp Jan 26, 2024
7368768
Revert "Remove no longer necessary check in `verify_qc_claim`."
greg7mdp Jan 26, 2024
ba9b519
Fix eror text.
greg7mdp Jan 26, 2024
4cbdb1e
Update `verify_qc_claim` as discussed with Areg.
greg7mdp Jan 26, 2024
2e0783a
Fix `verify_qc_claim` according to Areg's feedback, and store correct…
greg7mdp Jan 27, 2024
d47e0c2
Update test accordingly to change for first finalizer generation == 0.
greg7mdp Jan 27, 2024
7fc28e4
Revert "Update test accordingly to change for first finalizer generat…
greg7mdp Jan 27, 2024
ed97bf6
Revert initial finalizer generation to 1, as we don't want to change …
greg7mdp Jan 27, 2024
2b3f787
Simplify redundent error message in `FC_ASSERT`, and other formatting…
greg7mdp Jan 29, 2024
68f3f3e
Remove `.clang-format` which I added by mistake.
greg7mdp Jan 29, 2024
1454a5f
Merge branch 'hotstuff_integration' of github.com:AntelopeIO/leap int…
greg7mdp Jan 29, 2024
297d059
Merge branch 'hotstuff_integration' of github.com:AntelopeIO/leap int…
greg7mdp Jan 29, 2024
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
33 changes: 22 additions & 11 deletions libraries/chain/block_header_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ block_header_state block_header_state::next(block_header_state_input& input) con
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] ??
Expand Down Expand Up @@ -127,17 +123,32 @@ block_header_state block_header_state::next(block_header_state_input& input) con
// ++input.new_finalizer_policy->generation;


// add IF block header extension
// -----------------------------
qc_info_t qc_info;
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,
if (input.qc_info) {
qc_info = *input.qc_info;
dlog("qc_info from input -> final value: ${qci}",("qci", qc_info));
} else {
// copy previous qc_claim if we are not provided with a new one
// ------------------------------------------------------------
auto if_entry = header_exts.lower_bound(if_ext_id);
if (if_entry != header_exts.end()) {
const auto& qci = std::get<instant_finality_extension>(if_entry->second).qc_info;
qc_info = qci;
dlog("qc_info from existing extension -> final value: ${qci}",("qci",qc_info));
} else {
assert(0); // we should always get a previous if extension when in IF mode.
}
}

instant_finality_extension new_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;

// block_header_state_core
// -----------------------
result.core = core.next(new_if_ext.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));
Expand Down
7 changes: 6 additions & 1 deletion libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ block_state::block_state(const block_state_legacy& bsp) {
header = bsp.header;
core.last_final_block_num = bsp.block_num(); // [if todo] instant transition is not acceptable
activated_protocol_features = bsp.activated_protocol_features;
std::optional<block_header_extension> ext = bsp.block->extract_header_extension(instant_finality_extension::extension_id());

auto if_ext_id = instant_finality_extension::extension_id();
std::optional<block_header_extension> ext = bsp.block->extract_header_extension(if_ext_id);
assert(ext); // required by current transition mechanism
const auto& if_extension = std::get<instant_finality_extension>(*ext);
assert(if_extension.new_finalizer_policy); // required by current transition mechanism
Expand All @@ -48,6 +50,9 @@ block_state::block_state(const block_state_legacy& bsp) {
active_proposer_policy->active_time = bsp.timestamp();
active_proposer_policy->proposer_schedule = bsp.active_schedule;
header_exts = bsp.header_exts;

auto& updated_if_extension = std::get<instant_finality_extension>(header_exts.lower_bound(if_ext_id)->second);
heifner marked this conversation as resolved.
Show resolved Hide resolved
updated_if_extension.qc_info = { bsp.block_num(), false };
block = bsp.block;
validated = bsp.is_valid();
pub_keys_recovered = bsp._pub_keys_recovered;
Expand Down
76 changes: 33 additions & 43 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2854,16 +2854,17 @@ struct controller_impl {

static std::optional<qc_data_t> extract_qc_data(const signed_block_ptr& b) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we should name this validate_and_extract_qc_data as it is calling the validate_and_extract methods of extensions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hum, I think it could be misleading, it does the generic extension validation, but not the actual qc_data validation implemented in verify_qc_claim.

std::optional<qc_data_t> qc_data;
auto exts = b->validate_and_extract_extensions();
if (auto entry = exts.lower_bound(quorum_certificate_extension::extension_id()); entry != exts.end()) {
auto& qc_ext = std::get<quorum_certificate_extension>(entry->second);

// get the matching header extension... should always be present
auto hexts = b->validate_and_extract_header_extensions();
auto if_entry = hexts.lower_bound(instant_finality_extension::extension_id());
assert(if_entry != hexts.end());
auto hexts = b->validate_and_extract_header_extensions();
if (auto if_entry = hexts.lower_bound(instant_finality_extension::extension_id()); if_entry != hexts.end()) {
auto& if_ext = std::get<instant_finality_extension>(if_entry->second);
return qc_data_t{ std::move(qc_ext.qc), *if_ext.qc_info };

// get the matching qc extension if present
auto exts = b->validate_and_extract_extensions();
if (auto entry = exts.lower_bound(quorum_certificate_extension::extension_id()); entry != exts.end()) {
auto& qc_ext = std::get<quorum_certificate_extension>(entry->second);
return qc_data_t{ std::move(qc_ext.qc), if_ext.qc_info };
}
return qc_data_t{ {}, if_ext.qc_info };
}
return {};
}
Expand Down Expand Up @@ -3110,19 +3111,9 @@ struct controller_impl {
}

const auto& if_ext = std::get<instant_finality_extension>(*header_ext);
if( !if_ext.qc_info ) {
EOS_ASSERT( block_exts.count(quorum_certificate_extension::extension_id()) == 0,
block_validate_exception,
"A block must have QC claim if it provides QC block extension. Block number: ${b}",
("b", b->block_num()) );

// If header extension does not have QC claim,
// do not continue.
return;
}

// extract QC claim
qc_info_t qc_claim{ *if_ext.qc_info };
qc_info_t qc_claim{ if_ext.qc_info };

// A block should not be able to claim there was a QC on a block that
// is prior to the transition to IF.
Expand All @@ -3135,32 +3126,31 @@ struct controller_impl {
auto prev_qc_info = prev_if_ext.qc_info;

// validate QC claim against previous block QC info
if( prev_qc_info ) {
// new claimed QC block nubmber cannot be smaller than previous block's
EOS_ASSERT( qc_claim.last_qc_block_num >= prev_qc_info->last_qc_block_num,
block_validate_exception,
"claimed last_qc_block_num (${n1}) must be equal to or greater than previous block's last_qc_block_num (${n2}). Block number: ${b}",
("n1", qc_claim.last_qc_block_num)("n2", prev_qc_info->last_qc_block_num)("b", b->block_num()) );

if( qc_claim.last_qc_block_num == prev_qc_info->last_qc_block_num ) {
if( qc_claim.is_last_qc_strong == prev_qc_info->is_last_qc_strong ) {
// QC block extension is redundant
EOS_ASSERT( block_exts.count(quorum_certificate_extension::extension_id()) == 0,
block_validate_exception,
"A block should not provide QC block extension if QC claim is the same as previous block. Block number: ${b}",
("b", b->block_num()) );

// if previous block's header extension has the same claim, just return
// (previous block already validated the claim)
return;
}

// new claimed QC must be stricter than previous if block number is the same
EOS_ASSERT( qc_claim.is_last_qc_strong || !prev_qc_info->is_last_qc_strong,
// new claimed QC block number cannot be smaller than previous block's
EOS_ASSERT( qc_claim.last_qc_block_num >= prev_qc_info.last_qc_block_num,
block_validate_exception,
"claimed last_qc_block_num (${n1}) must be equal to or greater than previous block's last_qc_block_num (${n2}). Block number: ${b}",
("n1", qc_claim.last_qc_block_num)("n2", prev_qc_info.last_qc_block_num)("b", b->block_num()) );

if( qc_claim.last_qc_block_num == prev_qc_info.last_qc_block_num ) {
if( qc_claim.is_last_qc_strong == prev_qc_info.is_last_qc_strong ) {
// QC block extension is redundant
EOS_ASSERT( block_exts.count(quorum_certificate_extension::extension_id()) == 0,
block_validate_exception,
"claimed QC (${s1}) must be stricter than previous block's (${s2}) if block number is the same. Block number: ${b}",
("s1", qc_claim.is_last_qc_strong)("s2", prev_qc_info->is_last_qc_strong)("b", b->block_num()) );
"A block should not provide QC block extension if QC claim is the same as previous block. Block number: ${b}",
("b", b->block_num()) );

// if previous block's header extension has the same claim, just return
// (previous block already validated the claim)
return;
}

// new claimed QC must be stricter than previous if block number is the same
EOS_ASSERT( qc_claim.is_last_qc_strong || !prev_qc_info.is_last_qc_strong,
block_validate_exception,
"claimed QC (${s1}) must be stricter than previous block's (${s2}) if block number is the same. Block number: ${b}",
("s1", qc_claim.is_last_qc_strong)("s2", prev_qc_info.is_last_qc_strong)("b", b->block_num()) );
}

if( block_exts.count(quorum_certificate_extension::extension_id()) == 0 ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct instant_finality_extension : fc::reflect_init {
static constexpr bool enforce_unique() { return true; }

instant_finality_extension() = default;
instant_finality_extension(std::optional<qc_info_t> qc_info,
instant_finality_extension(qc_info_t qc_info,
std::optional<finalizer_policy> new_finalizer_policy,
std::shared_ptr<proposer_policy> new_proposer_policy) :
qc_info(qc_info),
Expand All @@ -25,7 +25,7 @@ struct instant_finality_extension : fc::reflect_init {

void reflector_init();

std::optional<qc_info_t> qc_info;
qc_info_t qc_info;
std::optional<finalizer_policy> new_finalizer_policy;
std::shared_ptr<proposer_policy> new_proposer_policy;
};
Expand Down
8 changes: 4 additions & 4 deletions unittests/block_header_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_with_empty_values_test)
BOOST_REQUIRE( !!ext );

const auto& if_extension = std::get<instant_finality_extension>(*ext);
BOOST_REQUIRE_EQUAL( if_extension.qc_info->last_qc_block_num, last_qc_block_num );
BOOST_REQUIRE_EQUAL( if_extension.qc_info->is_last_qc_strong, is_last_qc_strong );
BOOST_REQUIRE_EQUAL( if_extension.qc_info.last_qc_block_num, last_qc_block_num );
BOOST_REQUIRE_EQUAL( if_extension.qc_info.is_last_qc_strong, is_last_qc_strong );
BOOST_REQUIRE( !if_extension.new_finalizer_policy );
BOOST_REQUIRE( !if_extension.new_proposer_policy );
}
Expand Down Expand Up @@ -91,8 +91,8 @@ BOOST_AUTO_TEST_CASE(instant_finality_extension_with_values_test)

const auto& if_extension = std::get<instant_finality_extension>(*ext);

BOOST_REQUIRE_EQUAL( if_extension.qc_info->last_qc_block_num, last_qc_block_num );
BOOST_REQUIRE_EQUAL( if_extension.qc_info->is_last_qc_strong, is_last_qc_strong );
BOOST_REQUIRE_EQUAL( if_extension.qc_info.last_qc_block_num, last_qc_block_num );
BOOST_REQUIRE_EQUAL( if_extension.qc_info.is_last_qc_strong, is_last_qc_strong );

BOOST_REQUIRE( !!if_extension.new_finalizer_policy );
BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->generation, 1u);
Expand Down
Loading