Skip to content

Commit

Permalink
GH-46 Do not advance LIB past HEAD. It is possible that HEAD is not o…
Browse files Browse the repository at this point in the history
…n the branch that contains the LIB block. If on a fork, then only advance to our HEAD and only if on the same branch as LIB block.
  • Loading branch information
heifner committed Apr 18, 2024
1 parent 608464d commit f5b58d8
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 6 deletions.
11 changes: 6 additions & 5 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1398,17 +1398,18 @@ struct controller_impl {
("lib_num", lib_num)("bn", fork_db_root_block_num()) );
}

block_id_type irreversible_block_id = if_irreversible_block_id.load();
uint32_t if_lib_num = block_header::num_from_id(irreversible_block_id);
const uint32_t new_lib_num = if_lib_num > 0 ? if_lib_num : fork_db_head_irreversible_blocknum();
const block_id_type irreversible_block_id = if_irreversible_block_id.load();
const uint32_t savanna_lib_num = block_header::num_from_id(irreversible_block_id);
const bool savanna = savanna_lib_num > 0;
const uint32_t new_lib_num = savanna ? savanna_lib_num : fork_db_head_irreversible_blocknum();

if( new_lib_num <= lib_num )
return;

bool savanna_transistion_required = false;
auto mark_branch_irreversible = [&, this](auto& forkdb) {
auto branch = (if_lib_num > 0) ? forkdb.fetch_branch( irreversible_block_id, new_lib_num)
: forkdb.fetch_branch( fork_db_head_or_pending(forkdb)->id(), new_lib_num );
auto branch = savanna ? forkdb.fetch_head_branch( irreversible_block_id, new_lib_num)
: forkdb.fetch_branch( fork_db_head_or_pending(forkdb)->id(), new_lib_num );
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
Expand Down
27 changes: 26 additions & 1 deletion libraries/chain/fork_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ namespace eosio::chain {
void remove_impl( const block_id_type& id );
branch_t fetch_branch_impl( const block_id_type& h, uint32_t trim_after_block_num ) const;
block_branch_t fetch_block_branch_impl( const block_id_type& h, uint32_t trim_after_block_num ) const;
branch_t fetch_head_branch_impl( const block_id_type& b, uint32_t trim_after_block_num ) const;
full_branch_t fetch_full_branch_impl(const block_id_type& h) const;
bsp_t search_on_branch_impl( const block_id_type& h, uint32_t block_num, include_root_t include_root ) const;
bsp_t search_on_head_branch_impl( uint32_t block_num, include_root_t include_root ) const;
Expand Down Expand Up @@ -438,6 +439,30 @@ namespace eosio::chain {
return result;
}

template <class BSP>
fork_database_t<BSP>::branch_t
fork_database_t<BSP>::fetch_head_branch(const block_id_type& b, uint32_t trim_after_block_num) const {
std::lock_guard g(my->mtx);
return my->fetch_head_branch_impl(b, trim_after_block_num);
}

template <class BSP>
fork_database_t<BSP>::branch_t
fork_database_impl<BSP>::fetch_head_branch_impl(const block_id_type& b, uint32_t trim_after_block_num) const {
branch_t result;
if (!head)
return result;
result.reserve(index.size());
bool found_branch = false;
for (auto i = index.find(head->id()); i != index.end(); i = index.find((*i)->previous())) {
if ((*i)->id() == b)
found_branch = true;
if (found_branch && (*i)->block_num() <= trim_after_block_num)
result.push_back(*i);
}
return result;
}

template <class BSP>
block_branch_t
fork_database_t<BSP>::fetch_block_branch(const block_id_type& h, uint32_t trim_after_block_num) const {
Expand Down Expand Up @@ -594,7 +619,7 @@ namespace eosio::chain {

for( uint32_t i = 0; i < remove_queue.size(); ++i ) {
EOS_ASSERT( remove_queue[i] != head_id, fork_database_exception,
"removing the block and its descendants would remove the current head block" );
"removing the block and its descendants would remove the current head block ${id}", ("id", head_id) );

auto previtr = previdx.lower_bound( remove_queue[i] );
while( previtr != previdx.end() && (*previtr)->previous() == remove_queue[i] ) {
Expand Down
5 changes: 5 additions & 0 deletions libraries/chain/include/eosio/chain/fork_database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ namespace eosio::chain {
branch_t fetch_branch( const block_id_type& h, uint32_t trim_after_block_num = std::numeric_limits<uint32_t>::max() ) const;
block_branch_t fetch_block_branch( const block_id_type& h, uint32_t trim_after_block_num = std::numeric_limits<uint32_t>::max() ) const;

/**
* Similar to fetch_branch but only returns up to head or empty if b not on head branch.
*/
branch_t fetch_head_branch( const block_id_type& b, uint32_t trim_after_block_num = std::numeric_limits<uint32_t>::max() ) const;

/**
* Returns full branch of block_header_state pointers including the root.
* The order of the sequence is in descending block number order.
Expand Down
11 changes: 11 additions & 0 deletions unittests/fork_db_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ BOOST_AUTO_TEST_CASE(add_remove_test) try {
BOOST_TEST(branch[1] == bsp12bb);
BOOST_TEST(branch[2] == bsp11b);

// test fetch head branch
BOOST_TEST(forkdb.head()->id() == root->id());
forkdb.mark_valid(bsp13a);
BOOST_TEST(forkdb.head()->id() == bsp13a->id());
branch = forkdb.fetch_head_branch(bsp11c->id());
BOOST_TEST(branch.empty()); // bsp11c not on bsp13a branch
branch = forkdb.fetch_head_branch(bsp12a->id());
BOOST_REQUIRE(branch.size() == 2);
BOOST_TEST(branch[0] == bsp12a);
BOOST_TEST(branch[1] == bsp11a);

} FC_LOG_AND_RETHROW();

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit f5b58d8

Please sign in to comment.