-
Notifications
You must be signed in to change notification settings - Fork 11
Net: keep block progress honest and stop producers from being nacked #548
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| #include <boost/test/unit_test.hpp> | ||
| #include <sysio/net_plugin/net_utils.hpp> | ||
|
|
||
| using namespace sysio::net_utils; | ||
|
|
||
| BOOST_AUTO_TEST_SUITE(block_nack_default) | ||
|
|
||
| // A node with no producer configured keeps the bandwidth optimization. | ||
| BOOST_AUTO_TEST_CASE(default_enabled_for_non_producer) { | ||
| constexpr bool explicitly_set = false; | ||
| constexpr bool configured_producer = false; | ||
| BOOST_CHECK_EQUAL(resolve_disable_block_nack(false, explicitly_set, configured_producer), false); | ||
| } | ||
|
|
||
| // A configured producer must never receive a notice in place of a block. | ||
| BOOST_AUTO_TEST_CASE(default_disabled_for_producer) { | ||
| constexpr bool explicitly_set = false; | ||
| constexpr bool configured_producer = true; | ||
| BOOST_CHECK_EQUAL(resolve_disable_block_nack(false, explicitly_set, configured_producer), true); | ||
| } | ||
|
|
||
| // An operator turning it off on a producer must win over the producer default. | ||
| BOOST_AUTO_TEST_CASE(explicit_false_overrides_producer_default) { | ||
| constexpr bool explicitly_set = true; | ||
| constexpr bool configured_producer = true; | ||
| BOOST_CHECK_EQUAL(resolve_disable_block_nack(false, explicitly_set, configured_producer), false); | ||
| } | ||
|
|
||
| // An operator turning it on for a non-producer must win over the non-producer default. | ||
| BOOST_AUTO_TEST_CASE(explicit_true_overrides_non_producer_default) { | ||
| constexpr bool explicitly_set = true; | ||
| constexpr bool configured_producer = false; | ||
| BOOST_CHECK_EQUAL(resolve_disable_block_nack(true, explicitly_set, configured_producer), true); | ||
| } | ||
|
|
||
| // An explicit setting that matches the default is still honoured as explicit. | ||
| BOOST_AUTO_TEST_CASE(explicit_value_is_used_when_it_matches_the_default) { | ||
| constexpr bool explicitly_set = true; | ||
| BOOST_CHECK_EQUAL(resolve_disable_block_nack(true, explicitly_set, true), true); | ||
| BOOST_CHECK_EQUAL(resolve_disable_block_nack(false, explicitly_set, false), false); | ||
| } | ||
|
|
||
| BOOST_AUTO_TEST_SUITE_END() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| #include <boost/test/unit_test.hpp> | ||
| #include <sysio/net_plugin/net_utils.hpp> | ||
|
|
||
| using namespace sysio::net_utils; | ||
|
|
||
| BOOST_AUTO_TEST_SUITE(block_notice_handling) | ||
|
|
||
| // A notice for a block we already hold is the only case that records peer knowledge. | ||
| BOOST_AUTO_TEST_CASE(announced_block_already_held_records_peer) { | ||
| BOOST_CHECK(classify_block_notice(true, true) == block_notice_action::record_peer_has_block); | ||
| BOOST_CHECK(classify_block_notice(true, false) == block_notice_action::record_peer_has_block); | ||
| } | ||
|
|
||
| // Missing both the block and its parent means we are two or more behind, so ask for the branch. | ||
| BOOST_AUTO_TEST_CASE(missing_block_and_parent_requests_blocks) { | ||
| BOOST_CHECK(classify_block_notice(false, false) == block_notice_action::request_blocks); | ||
| } | ||
|
|
||
| // Holding the parent but not the block leaves nothing to do in the handler itself. | ||
| BOOST_AUTO_TEST_CASE(missing_block_with_parent_held_is_ignored) { | ||
| BOOST_CHECK(classify_block_notice(false, true) == block_notice_action::ignore); | ||
| } | ||
|
|
||
| // The liveness property: only a notice naming a block we already hold may refresh latest_blk_time. | ||
| // Marking either missing-block case as progress would defer the check_heartbeat handshake that | ||
| // recovers the block when no further block is produced. | ||
| BOOST_AUTO_TEST_CASE(only_a_held_block_marks_progress) { | ||
| BOOST_CHECK_EQUAL(block_notice_marks_progress(block_notice_action::record_peer_has_block), true); | ||
| BOOST_CHECK_EQUAL(block_notice_marks_progress(block_notice_action::request_blocks), false); | ||
| BOOST_CHECK_EQUAL(block_notice_marks_progress(block_notice_action::ignore), false); | ||
| } | ||
|
|
||
| // Stated over the dispatcher inputs rather than the action, so the guarantee survives a reclassification. | ||
| BOOST_AUTO_TEST_CASE(a_notice_for_a_missing_block_never_marks_progress) { | ||
| BOOST_CHECK_EQUAL(block_notice_marks_progress(classify_block_notice(false, true)), false); | ||
| BOOST_CHECK_EQUAL(block_notice_marks_progress(classify_block_notice(false, false)), false); | ||
| BOOST_CHECK_EQUAL(block_notice_marks_progress(classify_block_notice(true, true)), true); | ||
| } | ||
|
|
||
| BOOST_AUTO_TEST_SUITE_END() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a regression test that delivers a notice for a block absent from the dispatcher and verifies it does not refresh
latest_blk_time—or equivalently that the half-heartbeat handshake recovery still fires. The new tests cover only option-default resolution, so this liveness fix could currently regress without failing CI. PR #547 also avoids the original race by waiting for LIB rather than exercising this recovery path.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch — the tests covered only option-default resolution, so the
latest_blk_timechange could have regressed without CI noticing.handle_message(const block_notice_message&)is aconnectionmethod that reaches throughmy_impl->dispatcher,get_fork_db_root_num(), and the connection list, and there is no harness for that; the existing net_plugin tests all work against header-only components. Rather than build one, I lifted the decision into two pure functions innet_utils:The handler now has a single site that touches
latest_blk_time, gated byblock_notice_marks_progress. The added cases pin the three-way classification and, separately, that neither missing-block case counts as progress — the last one stated over the dispatcher inputs rather than the action, so the guarantee survives a reclassification.I checked that it actually guards rather than just describes: mutating
block_notice_marks_progresstoreturn true, the previous behaviour, fails 4 checks across both new cases.To be clear about the limit, this covers the input to the recovery, not the recovery itself. Asserting that the half-heartbeat handshake fires needs a live
connectionplus the heartbeat timer, which is the harness that does not exist here. And you are right that #547 avoids this path deliberately — it waits for LIB so the test is deterministic rather than depending on a 5 to 15 second recovery — so no test in either PR exercises the end-to-end path.The short-circuit is preserved: the parent lookup is still skipped when the announced block is already held, so the common path costs no extra dispatcher lookup.