Skip to content

Commit

Permalink
Merge branch 'hotstuff_integration' into reenable-producer_schedule_i…
Browse files Browse the repository at this point in the history
…f_test
  • Loading branch information
heifner authored Feb 2, 2024
2 parents 03ff2eb + 4f6460e commit 6dc3dad
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 58 deletions.
39 changes: 31 additions & 8 deletions libraries/chain/fork_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <fc/io/fstream.hpp>
#include <fc/io/cfile.hpp>
#include <fstream>
#include <mutex>

namespace eosio::chain {
using boost::multi_index_container;
Expand Down Expand Up @@ -56,6 +57,7 @@ namespace eosio::chain {
BOOST_MULTI_INDEX_CONST_MEM_FUN(bs, const block_id_type&, id)>,
composite_key_compare<std::greater<bool>, std::greater<uint32_t>, std::greater<uint32_t>, sha256_less>>>>;

std::mutex mtx;
fork_multi_index_type index;
bsp root; // Only uses the block_header_state_legacy portion
bsp head;
Expand Down Expand Up @@ -88,6 +90,7 @@ namespace eosio::chain {

template<class bsp>
void fork_database_t<bsp>::open( const std::filesystem::path& fork_db_file, validator_t& validator ) {
std::lock_guard g( my->mtx );
my->open_impl( fork_db_file, validator );
}

Expand Down Expand Up @@ -163,6 +166,7 @@ namespace eosio::chain {

template<class bsp>
void fork_database_t<bsp>::close(const std::filesystem::path& fork_db_file) {
std::lock_guard g( my->mtx );
my->close_impl(fork_db_file);
}

Expand Down Expand Up @@ -234,6 +238,7 @@ namespace eosio::chain {

template<class bsp>
void fork_database_t<bsp>::reset( const bhs& root_bhs ) {
std::lock_guard g( my->mtx );
my->reset_impl(root_bhs);
}

Expand All @@ -248,6 +253,7 @@ namespace eosio::chain {

template<class bsp>
void fork_database_t<bsp>::rollback_head_to_root() {
std::lock_guard g( my->mtx );
my->rollback_head_to_root_impl();
}

Expand All @@ -266,6 +272,7 @@ namespace eosio::chain {

template<class bsp>
void fork_database_t<bsp>::advance_root( const block_id_type& id ) {
std::lock_guard g( my->mtx );
my->advance_root_impl( id );
}

Expand Down Expand Up @@ -306,6 +313,7 @@ namespace eosio::chain {

template<class bsp>
fork_database_t<bsp>::bhsp fork_database_t<bsp>::get_block_header( const block_id_type& id ) const {
std::lock_guard g( my->mtx );
return my->get_block_header_impl( id );
}

Expand Down Expand Up @@ -362,6 +370,7 @@ namespace eosio::chain {

template<class bsp>
void fork_database_t<bsp>::add( const bsp& n, bool ignore_duplicate ) {
std::lock_guard g( my->mtx );
my->add_impl( n, ignore_duplicate, false,
[]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
Expand All @@ -372,16 +381,19 @@ namespace eosio::chain {

template<class bsp>
bsp fork_database_t<bsp>::root() const {
std::lock_guard g( my->mtx );
return my->root;
}

template<class bsp>
bsp fork_database_t<bsp>::head() const {
std::lock_guard g( my->mtx );
return my->head;
}

template<class bsp>
bsp fork_database_t<bsp>::pending_head() const {
std::lock_guard g( my->mtx );
const auto& indx = my->index.template get<by_lib_block_num>();

auto itr = indx.lower_bound( false );
Expand All @@ -395,8 +407,8 @@ namespace eosio::chain {

template <class bsp>
fork_database_t<bsp>::branch_type
fork_database_t<bsp>::fetch_branch(const block_id_type& h,
uint32_t trim_after_block_num) const {
fork_database_t<bsp>::fetch_branch(const block_id_type& h, uint32_t trim_after_block_num) const {
std::lock_guard g(my->mtx);
return my->fetch_branch_impl(h, trim_after_block_num);
}

Expand All @@ -414,6 +426,7 @@ namespace eosio::chain {

template<class bsp>
bsp fork_database_t<bsp>::search_on_branch( const block_id_type& h, uint32_t block_num ) const {
std::lock_guard g( my->mtx );
return my->search_on_branch_impl( h, block_num );
}

Expand All @@ -434,6 +447,7 @@ namespace eosio::chain {
template <class bsp>
fork_database_t<bsp>::branch_type_pair
fork_database_t<bsp>::fetch_branch_from(const block_id_type& first, const block_id_type& second) const {
std::lock_guard g(my->mtx);
return my->fetch_branch_from_impl(first, second);
}

Expand Down Expand Up @@ -500,6 +514,7 @@ namespace eosio::chain {
/// remove all of the invalid forks built off of this id including this id
template<class bsp>
void fork_database_t<bsp>::remove( const block_id_type& id ) {
std::lock_guard g( my->mtx );
return my->remove_impl( id );
}

Expand Down Expand Up @@ -527,6 +542,7 @@ namespace eosio::chain {

template<class bsp>
void fork_database_t<bsp>::mark_valid( const bsp& h ) {
std::lock_guard g( my->mtx );
my->mark_valid_impl( h );
}

Expand All @@ -553,6 +569,7 @@ namespace eosio::chain {

template<class bsp>
bsp fork_database_t<bsp>::get_block(const block_id_type& id) const {
std::lock_guard g( my->mtx );
return my->get_block_impl(id);
}

Expand All @@ -567,7 +584,10 @@ namespace eosio::chain {
// ------------------ fork_database -------------------------

fork_database::fork_database(const std::filesystem::path& data_dir)
: data_dir(data_dir) {
: data_dir(data_dir)
// currently needed because chain_head is accessed before fork database open
, fork_db_legacy{std::make_unique<fork_database_legacy_t>(fork_database_legacy_t::legacy_magic_number)}
{
}

fork_database::~fork_database() {
Expand All @@ -579,7 +599,6 @@ namespace eosio::chain {
}

void fork_database::open( validator_t& validator ) {
std::lock_guard g(m);
if (!std::filesystem::is_directory(data_dir))
std::filesystem::create_directories(data_dir);

Expand All @@ -603,12 +622,14 @@ namespace eosio::chain {
);

if (totem == fork_database_legacy_t::legacy_magic_number) {
// fork_db_legacy created in constructor
apply_legacy<void>([&](auto& forkdb) {
forkdb.open(fork_db_file, validator);
});
} else {
// file is instant-finality data, so switch to fork_database_if_t
vforkdb.emplace<fork_database_if_t>(fork_database_if_t::magic_number);
fork_db_if = std::make_unique<fork_database_if_t>(fork_database_if_t::magic_number);
legacy = false;
apply_if<void>([&](auto& forkdb) {
forkdb.open(fork_db_file, validator);
});
Expand All @@ -618,11 +639,13 @@ namespace eosio::chain {
}

void fork_database::switch_from_legacy() {
std::lock_guard g(m);
// no need to close fork_db because we don't want to write anything out, file is removed on open
block_state_legacy_ptr head = std::get<fork_database_legacy_t>(vforkdb).chain_head; // will throw if called after transistion
// threads may be accessing (or locked on mutex about to access legacy forkdb) so don't delete it until program exit
assert(legacy);
block_state_legacy_ptr head = fork_db_legacy->chain_head; // will throw if called after transistion
auto new_head = std::make_shared<block_state>(*head);
vforkdb.emplace<fork_database_if_t>(fork_database_if_t::magic_number);
fork_db_if = std::make_unique<fork_database_if_t>(fork_database_if_t::magic_number);
legacy = false;
apply_if<void>([&](auto& forkdb) {
forkdb.chain_head = new_head;
forkdb.reset(*new_head);
Expand Down
108 changes: 67 additions & 41 deletions libraries/chain/include/eosio/chain/fork_database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ namespace eosio::chain {
* blocks older than the last irreversible block are freed after emitting the
* irreversible signal.
*
* Not thread safe, thread safety provided by fork_database below.
* An internal mutex is used to provide thread-safety.
*
* fork_database should be used instead of fork_database_t directly as it manages
* the different supported types.
*/
Expand Down Expand Up @@ -108,86 +109,111 @@ namespace eosio::chain {
using fork_database_if_t = fork_database_t<block_state_ptr>;

/**
* Provides thread safety on fork_database_t and provide mechanism for opening the correct type
* Provides mechanism for opening the correct type
* as well as switching from legacy (old dpos) to instant-finality.
*
* All methods assert until open() is closed.
*/
class fork_database {
mutable std::recursive_mutex m;
const std::filesystem::path data_dir;
std::variant<fork_database_t<block_state_legacy_ptr>, fork_database_t<block_state_ptr>> vforkdb;
std::atomic<bool> legacy = true;
std::unique_ptr<fork_database_legacy_t> fork_db_legacy;
std::unique_ptr<fork_database_if_t> fork_db_if;
public:
explicit fork_database(const std::filesystem::path& data_dir);
~fork_database(); // close on destruction

// not thread safe, expected to be called from main thread before allowing concurrent access
void open( validator_t& validator );
void close();

// expected to be called from main thread, accesses chain_head
void switch_from_legacy();

// see fork_database_t::fetch_branch(forkdb->head()->id())
std::vector<signed_block_ptr> fetch_branch_from_head();

template <class R, class F>
R apply(const F& f) {
std::lock_guard g(m);
if constexpr (std::is_same_v<void, R>)
std::visit([&](auto& forkdb) { f(forkdb); }, vforkdb);
else
return std::visit([&](auto& forkdb) -> R { return f(forkdb); }, vforkdb);
if constexpr (std::is_same_v<void, R>) {
if (legacy) {
f(*fork_db_legacy);
} else {
f(*fork_db_if);
}
} else {
if (legacy) {
return f(*fork_db_legacy);
} else {
return f(*fork_db_if);
}
}
}

template <class R, class F>
R apply(const F& f) const {
std::lock_guard g(m);
if constexpr (std::is_same_v<void, R>)
std::visit([&](const auto& forkdb) { f(forkdb); }, vforkdb);
else
return std::visit([&](const auto& forkdb) -> R { return f(forkdb); }, vforkdb);
if constexpr (std::is_same_v<void, R>) {
if (legacy) {
f(*fork_db_legacy);
} else {
f(*fork_db_if);
}
} else {
if (legacy) {
return f(*fork_db_legacy);
} else {
return f(*fork_db_if);
}
}
}

/// Apply for when only need lambda executed when in instant-finality mode
template <class R, class F>
R apply_if(const F& f) {
std::lock_guard g(m);
if constexpr (std::is_same_v<void, R>)
std::visit(overloaded{[&](fork_database_legacy_t&) {},
[&](fork_database_if_t& forkdb) { f(forkdb); }},
vforkdb);
else
return std::visit(overloaded{[&](fork_database_legacy_t&) -> R { return {}; },
[&](fork_database_if_t& forkdb) -> R { return f(forkdb); }},
vforkdb);
if constexpr (std::is_same_v<void, R>) {
if (!legacy) {
f(*fork_db_if);
}
} else {
if (!legacy) {
return f(*fork_db_if);
}
return {};
}
}

/// Apply for when only need lambda executed when in legacy mode
template <class R, class F>
R apply_legacy(const F& f) {
std::lock_guard g(m);
if constexpr (std::is_same_v<void, R>)
std::visit(overloaded{[&](fork_database_legacy_t& forkdb) { f(forkdb); },
[&](fork_database_if_t&) {}},
vforkdb);
else
return std::visit(overloaded{[&](fork_database_legacy_t& forkdb) -> R { return f(forkdb); },
[&](fork_database_if_t&) -> R { return {}; }},
vforkdb);
if constexpr (std::is_same_v<void, R>) {
if (legacy) {
f(*fork_db_legacy);
}
} else {
if (legacy) {
return f(*fork_db_legacy);
}
return {};
}
}

/// @param legacy_f the lambda to execute if in legacy mode
/// @param if_f the lambda to execute if in instant-finality mode
template <class R, class LegacyF, class IfF>
R apply(const LegacyF& legacy_f, const IfF& if_f) {
std::lock_guard g(m);
if constexpr (std::is_same_v<void, R>)
std::visit(overloaded{[&](fork_database_legacy_t& forkdb) { legacy_f(forkdb); },
[&](fork_database_if_t& forkdb) { if_f(forkdb); }},
vforkdb);
else
return std::visit(overloaded{[&](fork_database_legacy_t& forkdb) -> R { return legacy_f(forkdb); },
[&](fork_database_if_t& forkdb) -> R { return if_f(forkdb); }},
vforkdb);
if constexpr (std::is_same_v<void, R>) {
if (legacy) {
legacy_f(*fork_db_legacy);
} else {
if_f(*fork_db_if);
}
} else {
if (legacy) {
return legacy_f(*fork_db_legacy);
} else {
return if_f(*fork_db_if);
}
}
}

// if we ever support more than one version then need to save min/max in fork_database_t
Expand Down
1 change: 1 addition & 0 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,7 @@ void chain_plugin_impl::plugin_shutdown() {
applied_transaction_connection.reset();
block_start_connection.reset();
chain.reset();
dlog("exit shutdown");
}

void chain_plugin::plugin_shutdown() {
Expand Down
12 changes: 7 additions & 5 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@ set_property(TEST trx_finality_status_if_test PROPERTY LABELS nonparallelizable_

add_test(NAME trx_finality_status_forked_test COMMAND tests/trx_finality_status_forked_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST trx_finality_status_forked_test PROPERTY LABELS nonparallelizable_tests)
add_test(NAME trx_finality_status_forked_if_test COMMAND tests/trx_finality_status_forked_test.py -v --activate-if ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST trx_finality_status_forked_if_test PROPERTY LABELS nonparallelizable_tests)
# requires https://github.com/AntelopeIO/leap/issues/2189
#add_test(NAME trx_finality_status_forked_if_test COMMAND tests/trx_finality_status_forked_test.py -v --activate-if ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
#set_property(TEST trx_finality_status_forked_if_test PROPERTY LABELS nonparallelizable_tests)

add_test(NAME db_modes_test COMMAND tests/db_modes_test.sh -v WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_tests_properties(db_modes_test PROPERTIES COST 6000)
Expand Down Expand Up @@ -272,6 +273,8 @@ set_property(TEST nodeos_voting_if_lr_test PROPERTY LABELS long_running_tests)

add_test(NAME nodeos_under_min_avail_ram_lr_test COMMAND tests/nodeos_under_min_avail_ram.py -v --wallet-port 9904 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST nodeos_under_min_avail_ram_lr_test PROPERTY LABELS long_running_tests)
add_test(NAME nodeos_under_min_avail_ram_if_lr_test COMMAND tests/nodeos_under_min_avail_ram.py -v --activate-if ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST nodeos_under_min_avail_ram_if_lr_test PROPERTY LABELS long_running_tests)

add_test(NAME nodeos_irreversible_mode_lr_test COMMAND tests/nodeos_irreversible_mode_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST nodeos_irreversible_mode_lr_test PROPERTY LABELS long_running_tests)
Expand Down Expand Up @@ -359,9 +362,8 @@ set_property(TEST light_validation_sync_if_test PROPERTY LABELS nonparallelizabl

add_test(NAME auto_bp_peering_test COMMAND tests/auto_bp_peering_test.py -v ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST auto_bp_peering_test PROPERTY LABELS long_running_tests)
# requires https://github.com/AntelopeIO/leap/issues/2175 & https://github.com/AntelopeIO/leap/issues/2173
#add_test(NAME auto_bp_peering_if_test COMMAND tests/auto_bp_peering_test.py -v --activate-if ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
#set_property(TEST auto_bp_peering_if_test PROPERTY LABELS long_running_tests)
add_test(NAME auto_bp_peering_if_test COMMAND tests/auto_bp_peering_test.py -v --activate-if ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST auto_bp_peering_if_test PROPERTY LABELS long_running_tests)

add_test(NAME gelf_test COMMAND tests/gelf_test.py ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST gelf_test PROPERTY LABELS nonparallelizable_tests)
Expand Down
Loading

0 comments on commit 6dc3dad

Please sign in to comment.