Skip to content

Commit

Permalink
Merge pull request #2273 from AntelopeIO/GH-2125-forkdb-simpler
Browse files Browse the repository at this point in the history
IF: Update fork database fork-choice rule
  • Loading branch information
heifner authored Mar 1, 2024
2 parents d77cca1 + 2a2a5da commit 5a029ee
Show file tree
Hide file tree
Showing 28 changed files with 766 additions and 439 deletions.
14 changes: 5 additions & 9 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ block_state::block_state(const block_header_state& bhs, deque<transaction_metada
, strong_digest(compute_finalizer_digest())
, weak_digest(create_weak_digest(strong_digest))
, pending_qc(bhs.active_finalizer_policy->finalizers.size(), bhs.active_finalizer_policy->threshold, bhs.active_finalizer_policy->max_weak_sum_before_weak_final())
, pub_keys_recovered(true) // probably not needed
, pub_keys_recovered(true) // called by produce_block so signature recovery of trxs must have been done
, cached_trxs(std::move(trx_metas))
{
block->transactions = std::move(trx_receipts);
Expand Down Expand Up @@ -83,7 +83,7 @@ void block_state::set_trxs_metas( deque<transaction_metadata_ptr>&& trxs_metas,
}

// Called from net threads
std::pair<vote_status, std::optional<uint32_t>> block_state::aggregate_vote(const vote_message& vote) {
vote_status block_state::aggregate_vote(const vote_message& vote) {
const auto& finalizers = active_finalizer_policy->finalizers;
auto it = std::find_if(finalizers.begin(),
finalizers.end(),
Expand All @@ -92,20 +92,16 @@ std::pair<vote_status, std::optional<uint32_t>> block_state::aggregate_vote(cons
if (it != finalizers.end()) {
auto index = std::distance(finalizers.begin(), it);
auto digest = vote.strong ? strong_digest.to_uint8_span() : std::span<const uint8_t>(weak_digest);
auto [status, strong] = pending_qc.add_vote(vote.strong,
return pending_qc.add_vote(block_num(),
vote.strong,
digest,
index,
vote.finalizer_key,
vote.sig,
finalizers[index].weight);

std::optional<uint32_t> new_lib{};
if (status == vote_status::success && strong)
new_lib = core.final_on_strong_qc_block_num;
return {status, new_lib};
} else {
wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) );
return {vote_status::unknown_public_key, {}};
return vote_status::unknown_public_key;
}
}

Expand Down
117 changes: 75 additions & 42 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ struct controller_impl {

// --------------- access fork_db root ----------------------------------------------------------------------
bool fork_db_has_root() const {
return fork_db.apply<bool>([&](const auto& forkdb) { return !!forkdb.root(); });
return fork_db.apply<bool>([&](const auto& forkdb) { return !!forkdb.has_root(); });
}

block_id_type fork_db_root_block_id() const {
Expand Down Expand Up @@ -1004,9 +1004,9 @@ struct controller_impl {
return prev->block_num();
}

void fork_db_reset_to_head() {
void fork_db_reset_root_to_chain_head() {
return fork_db.apply<void>([&](auto& forkdb) {
forkdb.reset(*forkdb.chain_head);
forkdb.reset_root(*forkdb.chain_head);
});
}

Expand All @@ -1017,37 +1017,37 @@ struct controller_impl {
});
}

signed_block_ptr fork_db_fetch_block_by_num(uint32_t block_num) const {
signed_block_ptr fetch_block_on_head_branch_by_num(uint32_t block_num) const {
return fork_db.apply<signed_block_ptr>([&](const auto& forkdb) {
auto bsp = forkdb.search_on_branch(forkdb.head()->id(), block_num);
auto bsp = forkdb.search_on_head_branch(block_num);
if (bsp) return bsp->block;
return signed_block_ptr{};
});
}

std::optional<block_id_type> fork_db_fetch_block_id_by_num(uint32_t block_num) const {
std::optional<block_id_type> fetch_block_id_on_head_branch_by_num(uint32_t block_num) const {
return fork_db.apply<std::optional<block_id_type>>([&](const auto& forkdb) -> std::optional<block_id_type> {
auto bsp = forkdb.search_on_branch(forkdb.head()->id(), block_num);
auto bsp = forkdb.search_on_head_branch(block_num);
if (bsp) return bsp->id();
return {};
});
}

// search on the branch of head
block_state_ptr fork_db_fetch_bsp_by_num(uint32_t block_num) const {
block_state_ptr fetch_bsp_on_head_branch_by_num(uint32_t block_num) const {
return fork_db.apply<block_state_ptr>(
overloaded{
[](const fork_database_legacy_t&) -> block_state_ptr { return nullptr; },
[&](const fork_database_if_t&forkdb) -> block_state_ptr {
auto bsp = forkdb.search_on_branch(forkdb.head()->id(), block_num);
auto bsp = forkdb.search_on_head_branch(block_num);
return bsp;
}
}
);
}

// search on the branch of given id
block_state_ptr fork_db_fetch_bsp_by_num(const block_id_type& id, uint32_t block_num) const {
block_state_ptr fetch_bsp_on_branch_by_num(const block_id_type& id, uint32_t block_num) const {
return fork_db.apply<block_state_ptr>(
overloaded{
[](const fork_database_legacy_t&) -> block_state_ptr { return nullptr; },
Expand Down Expand Up @@ -1300,7 +1300,7 @@ struct controller_impl {
void replay(std::function<bool()> check_shutdown) {
auto blog_head = blog.head();
if( !fork_db_has_root() ) {
fork_db_reset_to_head();
fork_db_reset_root_to_chain_head();
if (!blog_head)
return;
}
Expand Down Expand Up @@ -1335,7 +1335,7 @@ struct controller_impl {
ilog( "fork database head ${h}, root ${r}", ("h", pending_head->block_num())( "r", forkdb.root()->block_num() ) );
if( pending_head->block_num() < head->block_num() || head->block_num() < forkdb.root()->block_num() ) {
ilog( "resetting fork database with new last irreversible block as the new root: ${id}", ("id", head->id()) );
forkdb.reset( *head );
forkdb.reset_root( *head );
} else if( head->block_num() != forkdb.root()->block_num() ) {
auto new_root = forkdb.search_on_branch( pending_head->id(), head->block_num() );
EOS_ASSERT( new_root, fork_database_exception,
Expand All @@ -1357,22 +1357,22 @@ struct controller_impl {

if (snapshot_head_block != 0 && !blog_head) {
// loading from snapshot without a block log so fork_db can't be considered valid
forkdb.reset( *head );
forkdb.reset_root( *head );
} else if( !except_ptr && !check_shutdown() && forkdb.head() ) {
auto head_block_num = head->block_num();
auto branch = forkdb.fetch_branch( forkdb.head()->id() );
auto branch = fork_db.fetch_branch_from_head();
int rev = 0;
for( auto i = branch.rbegin(); i != branch.rend(); ++i ) {
if( check_shutdown() ) break;
if( (*i)->block_num() <= head_block_num ) continue;
++rev;
replay_push_block<BSP>( (*i)->block, controller::block_status::validated );
replay_push_block<BSP>( *i, controller::block_status::validated );
}
ilog( "${n} reversible blocks replayed", ("n",rev) );
}

if( !forkdb.head() ) {
forkdb.reset( *head );
forkdb.reset_root( *head );
}

auto end = fc::time_point::now();
Expand Down Expand Up @@ -1440,7 +1440,7 @@ struct controller_impl {
initialize_blockchain_state(genesis); // sets head to genesis state

if( !forkdb.head() ) {
forkdb.reset( *forkdb.chain_head );
forkdb.reset_root( *forkdb.chain_head );
}
};

Expand Down Expand Up @@ -2780,10 +2780,8 @@ struct controller_impl {
const auto& bsp = std::get<std::decay_t<decltype(forkdb.chain_head)>>(cb.bsp);

if( s == controller::block_status::incomplete ) {
forkdb.add( bsp );
forkdb.mark_valid( bsp );
forkdb.add( bsp, mark_valid_t::yes, ignore_duplicate_t::no );
emit( accepted_block_header, std::tie(bsp->block, bsp->id()) );
EOS_ASSERT( bsp == forkdb.head(), fork_database_exception, "committed block did not become the new head in fork database");
} else if (s != controller::block_status::irreversible) {
forkdb.mark_valid( bsp );
}
Expand All @@ -2802,6 +2800,21 @@ struct controller_impl {
}});

if( s == controller::block_status::incomplete ) {
fork_db.apply_if<void>([&](auto& forkdb) {
const auto& bsp = std::get<std::decay_t<decltype(forkdb.chain_head)>>(cb.bsp);

uint16_t if_ext_id = instant_finality_extension::extension_id();
assert(bsp->header_exts.count(if_ext_id) > 0); // in all instant_finality block headers
const auto& if_ext = std::get<instant_finality_extension>(bsp->header_exts.lower_bound(if_ext_id)->second);
if (if_ext.qc_claim.is_strong_qc) {
// claim has already been verified
auto claimed = forkdb.search_on_branch(bsp->id(), if_ext.qc_claim.block_num);
if (claimed) {
set_if_irreversible_block_num(claimed->core.final_on_strong_qc_block_num);
}
}
});

log_irreversible();
}

Expand Down Expand Up @@ -3111,22 +3124,19 @@ struct controller_impl {

// called from net threads and controller's thread pool
vote_status process_vote_message( const vote_message& vote ) {
auto aggregate_vote = [&vote](auto& forkdb) -> std::pair<vote_status, std::optional<uint32_t>> {
auto bsp = forkdb.get_block(vote.proposal_id);
if (bsp)
return bsp->aggregate_vote(vote);
return {vote_status::unknown_block, {}};
auto aggregate_vote = [&vote](auto& forkdb) -> vote_status {
auto bsp = forkdb.get_block(vote.proposal_id);
if (bsp) {
return bsp->aggregate_vote(vote);
}
return vote_status::unknown_block;
};
// TODO: https://github.com/AntelopeIO/leap/issues/2057
// TODO: Do not aggregate votes on block_state if in legacy block fork_db
auto aggregate_vote_legacy = [](auto&) -> std::pair<vote_status, std::optional<uint32_t>> {
return {vote_status::unknown_block, {}};
auto aggregate_vote_legacy = [](auto&) -> vote_status {
return vote_status::unknown_block;
};
auto [status, new_lib] = fork_db.apply<std::pair<vote_status, std::optional<uint32_t>>>(aggregate_vote_legacy, aggregate_vote);
if (new_lib) {
set_if_irreversible_block_num(*new_lib);
}
return status;
return fork_db.apply<vote_status>(aggregate_vote_legacy, aggregate_vote);
}

void create_and_send_vote_msg(const block_state_ptr& bsp, const fork_database_if_t& fork_db) {
Expand Down Expand Up @@ -3162,7 +3172,7 @@ struct controller_impl {
const auto& qc_ext = std::get<quorum_certificate_extension>(block_exts.lower_bound(qc_ext_id)->second);
const auto& received_qc = qc_ext.qc.qc;

const auto bsp = fork_db_fetch_bsp_by_num( bsp_in->previous(), qc_ext.qc.block_num );
const auto bsp = fetch_bsp_on_branch_by_num( bsp_in->previous(), qc_ext.qc.block_num );
if( !bsp ) {
return;
}
Expand Down Expand Up @@ -3292,7 +3302,7 @@ struct controller_impl {
("s1", qc_proof.qc.is_strong())("s2", new_qc_claim.is_strong_qc)("b", block_num) );

// find the claimed block's block state on branch of id
auto bsp = fork_db_fetch_bsp_by_num( prev.id(), new_qc_claim.block_num );
auto bsp = fetch_bsp_on_branch_by_num( prev.id(), new_qc_claim.block_num );
EOS_ASSERT( bsp,
invalid_qc_claim,
"Block state was not found in forkdb for block_num ${q}. Block number: ${b}",
Expand Down Expand Up @@ -3422,8 +3432,9 @@ struct controller_impl {
}

auto do_push = [&](auto& forkdb) {
if constexpr (std::is_same_v<BSP, typename std::decay_t<decltype(forkdb.chain_head)>>)
forkdb.add( bsp );
if constexpr (std::is_same_v<BSP, typename std::decay_t<decltype(forkdb.chain_head)>>) {
forkdb.add( bsp, mark_valid_t::no, ignore_duplicate_t::no );
}

if (is_trusted_producer(b->producer)) {
trusted_producer_light_validation = true;
Expand Down Expand Up @@ -3473,7 +3484,7 @@ struct controller_impl {
*forkdb.chain_head, b, protocol_features.get_protocol_feature_set(), validator, skip_validate_signee);

if (s != controller::block_status::irreversible) {
forkdb.add(bsp, true);
forkdb.add(bsp, mark_valid_t::no, ignore_duplicate_t::yes);
}

emit(accepted_block_header, std::tie(bsp->block, bsp->id()));
Expand Down Expand Up @@ -3502,6 +3513,21 @@ struct controller_impl {
} FC_LOG_AND_RETHROW( )
}

void maybe_switch_forks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup) {
auto maybe_switch = [&](auto& forkdb) {
if (read_mode != db_read_mode::IRREVERSIBLE) {
auto fork_head = forkdb.head();
if (forkdb.chain_head->id() != fork_head->id()) {
controller::block_report br;
maybe_switch_forks(br, fork_head, fork_head->is_valid() ? controller::block_status::validated : controller::block_status::complete,
cb, trx_lookup);
}
}
};

fork_db.apply<void>(maybe_switch);
}

template<class BSP>
void maybe_switch_forks( controller::block_report& br, const BSP& new_head, controller::block_status s,
const forked_callback_t& forked_cb, const trx_meta_cache_lookup& trx_lookup )
Expand All @@ -3517,8 +3543,9 @@ struct controller_impl {
throw;
}
} else if( new_head->id() != head->id() ) {
ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
("current_head_id", head->id())("current_head_num", head_block_num())("new_head_id", new_head->id())("new_head_num", new_head->block_num()) );
ilog("switching forks from ${current_head_id} (block number ${current_head_num}) ${c} to ${new_head_id} (block number ${new_head_num}) ${n}",
("current_head_id", head->id())("current_head_num", head_block_num())("new_head_id", new_head->id())("new_head_num", new_head->block_num())
("c", log_fork_comparison(*head))("n", log_fork_comparison(*new_head)));

// not possible to log transaction specific infor when switching forks
if (auto dm_logger = get_deep_mind_logger(false)) {
Expand Down Expand Up @@ -4267,6 +4294,12 @@ void controller::commit_block() {
my->commit_block(block_status::incomplete);
}

void controller::maybe_switch_forks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup) {
validate_db_available_size();
my->maybe_switch_forks(cb, trx_lookup);
}


deque<transaction_metadata_ptr> controller::abort_block() {
return my->abort_block();
}
Expand Down Expand Up @@ -4478,15 +4511,15 @@ std::optional<signed_block_header> controller::fetch_block_header_by_id( const b
}

signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const { try {
auto b = my->fork_db_fetch_block_by_num( block_num );
auto b = my->fetch_block_on_head_branch_by_num( block_num );
if (b)
return b;

return my->blog.read_block_by_num(block_num);
} FC_CAPTURE_AND_RETHROW( (block_num) ) }

std::optional<signed_block_header> controller::fetch_block_header_by_number( uint32_t block_num )const { try {
auto b = my->fork_db_fetch_block_by_num(block_num);
auto b = my->fetch_block_on_head_branch_by_num(block_num);
if (b)
return *b;

Expand All @@ -4500,7 +4533,7 @@ block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try
bool find_in_blog = (blog_head && block_num <= blog_head->block_num());

if( !find_in_blog ) {
std::optional<block_id_type> id = my->fork_db_fetch_block_id_by_num(block_num);
std::optional<block_id_type> id = my->fetch_block_id_on_head_branch_by_num(block_num);
if (id) return *id;
}

Expand Down
Loading

0 comments on commit 5a029ee

Please sign in to comment.