From e636de3e89917e0778195aa40f44c7f95d1c7ed8 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 4 Nov 2024 10:00:59 -0600 Subject: [PATCH 1/2] GH-1003 Advance forkdb root when pending lib greater than head --- libraries/chain/controller.cpp | 9 ++++++--- unittests/fork_db_tests.cpp | 8 ++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index bda29fa837..07c7c2133a 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1497,9 +1497,12 @@ struct controller_impl { assert(!irreversible_mode() || forkdb.head()); const auto& head_id = irreversible_mode() ? forkdb.head()->id() : chain_head.id(); // verifies lib is on head branch, otherwise returns an empty branch - // The new lib needs to be on the head branch because the forkdb.advance_root() below could purge blocks that - // would be needed to be re-applied on a fork switch from the exiting chain_head. - auto branch = forkdb.fetch_branch(head_id, new_lib_id); + // The new lib needs to be on the head branch because the forkdb.advance_root() below could purge blocks that + // would be needed to be re-applied on a fork switch from the exiting chain_head. + // Pending LIB can be greater than chain head, for example when syncing, in that case fetch branch from the + // pending LIB. If the pending LIB not found on the head branch then fetch_branch returns an empty branch. + // Otherwise fetch_branch will return from chain_head to root iff chain_head on pending LIB branch. + auto branch = new_lib_num <= chain_head.block_num() ? forkdb.fetch_branch(head_id, new_lib_id) : forkdb.fetch_branch(new_lib_id, head_id); try { auto should_process = [&](auto& bsp) { // Only make irreversible blocks that have been validated. Blocks in the fork database may not be on our current best head diff --git a/unittests/fork_db_tests.cpp b/unittests/fork_db_tests.cpp index 410fe3c63d..31e9fed7a9 100644 --- a/unittests/fork_db_tests.cpp +++ b/unittests/fork_db_tests.cpp @@ -138,6 +138,14 @@ BOOST_FIXTURE_TEST_CASE(add_remove_test, generate_forkdb_state) try { BOOST_REQUIRE(branch.size() == 2); BOOST_TEST(branch[0] == bsp12a); BOOST_TEST(branch[1] == bsp11a); + + // test fetch branch when lib is greater than head + branch = forkdb.fetch_branch(bsp13b->id(), bsp12a->id()); + BOOST_TEST(branch.empty()); + branch = forkdb.fetch_branch(bsp13b->id(), bsp12b->id()); + BOOST_REQUIRE(branch.size() == 2); + BOOST_TEST(branch[0] == bsp12b); + BOOST_TEST(branch[1] == bsp11b); } FC_LOG_AND_RETHROW(); From cef82331be203a4f4d59e7853f75a9a491b679c0 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 4 Nov 2024 11:45:45 -0600 Subject: [PATCH 2/2] GH-1003 Use forkdb head in irreversible mode --- libraries/chain/controller.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 07c7c2133a..161aac3191 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1496,13 +1496,14 @@ struct controller_impl { auto mark_branch_irreversible = [&, this](auto& forkdb) { assert(!irreversible_mode() || forkdb.head()); const auto& head_id = irreversible_mode() ? forkdb.head()->id() : chain_head.id(); + const auto head_num = block_header::num_from_id(head_id); // verifies lib is on head branch, otherwise returns an empty branch // The new lib needs to be on the head branch because the forkdb.advance_root() below could purge blocks that // would be needed to be re-applied on a fork switch from the exiting chain_head. // Pending LIB can be greater than chain head, for example when syncing, in that case fetch branch from the // pending LIB. If the pending LIB not found on the head branch then fetch_branch returns an empty branch. // Otherwise fetch_branch will return from chain_head to root iff chain_head on pending LIB branch. - auto branch = new_lib_num <= chain_head.block_num() ? forkdb.fetch_branch(head_id, new_lib_id) : forkdb.fetch_branch(new_lib_id, head_id); + auto branch = new_lib_num <= head_num ? forkdb.fetch_branch(head_id, new_lib_id) : forkdb.fetch_branch(new_lib_id, head_id); try { auto should_process = [&](auto& bsp) { // Only make irreversible blocks that have been validated. Blocks in the fork database may not be on our current best head