Skip to content

Commit

Permalink
GH-2057 Fix race condition on switch_from_legacy. Fix startup in sava…
Browse files Browse the repository at this point in the history
…nna.
  • Loading branch information
heifner committed Mar 19, 2024
1 parent 5722be9 commit b8a772c
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 18 deletions.
19 changes: 4 additions & 15 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,6 @@ struct controller_impl {

void transition_to_savanna() {
assert(chain_head.header().contains_header_extension(instant_finality_extension::extension_id()));
fork_db.switch_from_legacy(); // create savanna forkdb if not already created
// copy head branch branch from legacy forkdb legacy to savanna forkdb
fork_database_legacy_t::branch_t legacy_branch;
block_state_legacy_ptr legacy_root;
Expand All @@ -1266,13 +1265,9 @@ struct controller_impl {
assert(!!legacy_root);
assert(read_mode == db_read_mode::IRREVERSIBLE || !legacy_branch.empty());
ilog("Transitioning to savanna, IF Genesis Block ${gb}, IF Critical Block ${cb}", ("gb", legacy_root->block_num())("cb", chain_head.block_num()));
auto new_root = block_state::create_if_genesis_block(*legacy_root);
fork_db.switch_from_legacy(new_root);
fork_db.apply_s<void>([&](auto& forkdb) {
if (!forkdb.root()) {
auto new_root = block_state::create_if_genesis_block(*legacy_root);
forkdb.reset_root(new_root);
} else {
assert(forkdb.root()->id() == legacy_root->id());
}
block_state_ptr prev = forkdb.root();
for (auto bitr = legacy_branch.rbegin(); bitr != legacy_branch.rend(); ++bitr) {
const bool skip_validate_signee = true; // validated already
Expand Down Expand Up @@ -1545,10 +1540,7 @@ struct controller_impl {
if (fork_db.version_in_use() == fork_database::in_use_t::legacy) {
// switch to savanna if needed
apply_s<void>(chain_head, [&](const auto& head) {
fork_db.switch_from_legacy();
fork_db.apply_s<void>([&](auto& forkdb) {
forkdb.reset_root(head);
});
fork_db.switch_from_legacy(head);
});
}
};
Expand Down Expand Up @@ -1653,10 +1645,7 @@ struct controller_impl {
if (block_states.second && head->header.contains_header_extension(instant_finality_extension::extension_id())) {
// snapshot generated in transition to savanna
if (fork_db.version_in_use() == fork_database::in_use_t::legacy) {
fork_db.switch_from_legacy();
fork_db.apply_s<void>([&](auto& forkdb) {
forkdb.reset_root(block_states.second);
});
fork_db.switch_from_legacy(block_states.second);
}
}
});
Expand Down
13 changes: 11 additions & 2 deletions libraries/chain/fork_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -787,11 +787,20 @@ namespace eosio::chain {
}

// only called from the main thread
void fork_database::switch_from_legacy() {
void fork_database::switch_from_legacy(const block_state_ptr& root) {
// no need to close fork_db because we don't want to write anything out, file is removed on open
// threads may be accessing (or locked on mutex about to access legacy forkdb) so don't delete it until program exit
if (in_use == in_use_t::legacy) {
in_use = in_use_t::both;
fork_db_s.reset_root(root);
if (fork_db_l.has_root()) {
in_use = in_use_t::both;
} else {
in_use = in_use_t::savanna;
}
} else if (in_use == in_use_t::both) {
assert(fork_db_s.root()->id() == root->id()); // should always set the same root
} else {
assert(false);
}
}

Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/fork_database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ namespace eosio::chain {
void close();

// switches to using both legacy and savanna during transition
void switch_from_legacy();
void switch_from_legacy(const block_state_ptr& root);

in_use_t version_in_use() const { return in_use.load(); }

Expand Down

0 comments on commit b8a772c

Please sign in to comment.