Skip to content

Commit

Permalink
Merge pull request #2362 from AntelopeIO/add_finality_data_in_transit…
Browse files Browse the repository at this point in the history
…ion_block

IF: SHiP -- Provide finality_data for Transition blocks
  • Loading branch information
linh2931 authored Apr 4, 2024
2 parents f02fa48 + 93163ec commit 08d0c96
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 29 deletions.
10 changes: 3 additions & 7 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ block_state::block_state(const block_header_state& bhs,

// Used for transition from dpos to Savanna.
block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& bsp) {
assert(bsp.action_receipt_digests_savanna);
assert(bsp.action_mroot_savanna);

auto result_ptr = std::make_shared<block_state>();
auto &result = *result_ptr;
Expand Down Expand Up @@ -87,15 +87,11 @@ block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& b
result.pending_qc = pending_quorum_certificate{result.active_finalizer_policy->finalizers.size(), result.active_finalizer_policy->threshold, result.active_finalizer_policy->max_weak_sum_before_weak_final()};
result.valid_qc = {}; // best qc received from the network inside block extension, empty until first savanna proper IF block

// Calculate Merkle tree root in Savanna way so that it is stored in Leaf Node when building block_state.
const auto& digests = *bsp.action_receipt_digests_savanna;
auto action_mroot_svnn = calculate_merkle(digests);

// build leaf_node and validation_tree
valid_t::finality_leaf_node_t leaf_node {
.block_num = bsp.block_num(),
.finality_digest = result.strong_digest,
.action_mroot = action_mroot_svnn
.action_mroot = *bsp.action_mroot_savanna
};
// construct valid structure
incremental_merkle_tree validation_tree;
Expand All @@ -108,7 +104,7 @@ block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& b
result.validated = bsp.is_valid();
result.pub_keys_recovered = bsp._pub_keys_recovered;
result.cached_trxs = bsp._cached_trxs;
result.action_mroot = action_mroot_svnn;
result.action_mroot = *bsp.action_mroot_savanna;
result.base_digest = {}; // calculated on demand in get_finality_data()

return result_ptr;
Expand Down
4 changes: 2 additions & 2 deletions libraries/chain/block_state_legacy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ namespace eosio::chain {
block_state_legacy::block_state_legacy( pending_block_header_state_legacy&& cur,
signed_block_ptr&& b,
deque<transaction_metadata_ptr>&& trx_metas,
std::optional<digests_t>&& action_receipt_digests_savanna,
const std::optional<digests_t>& action_receipt_digests_savanna,
const protocol_feature_set& pfs,
const validator_t& validator,
const signer_callback_type& signer
Expand All @@ -75,7 +75,7 @@ namespace eosio::chain {
,block( std::move(b) )
,_pub_keys_recovered( true ) // called by produce_block so signature recovery of trxs must have been done
,_cached_trxs( std::move(trx_metas) )
,action_receipt_digests_savanna( std::move(action_receipt_digests_savanna) )
,action_mroot_savanna( action_receipt_digests_savanna ? std::optional<digest_type>(calculate_merkle(*action_receipt_digests_savanna)) : std::nullopt )
{}

block_state_legacy::block_state_legacy(snapshot_detail::snapshot_block_state_legacy_v7&& sbs)
Expand Down
95 changes: 82 additions & 13 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ struct assembled_block {
return std::visit(overloaded{[&](assembled_block_legacy& ab) {
auto bsp = std::make_shared<block_state_legacy>(
std::move(ab.pending_block_header_state), std::move(ab.unsigned_block),
std::move(ab.trx_metas), std::move(ab.action_receipt_digests_savanna), pfs, validator, signer);
std::move(ab.trx_metas), ab.action_receipt_digests_savanna, pfs, validator, signer);
return completed_block{block_handle{std::move(bsp)}};
},
[&](assembled_block_if& ab) {
Expand Down Expand Up @@ -1291,7 +1291,7 @@ struct controller_impl {
fc::scoped_exit<std::function<void()>> e([&]{fork_db.switch_to(fork_database::in_use_t::both);});
apply_block(br, legacy, controller::block_status::complete, trx_meta_cache_lookup{});
// irreversible apply was just done, calculate new_valid here instead of in transition_to_savanna()
assert(legacy->action_receipt_digests_savanna);
assert(legacy->action_mroot_savanna);
block_state_ptr prev = forkdb.get_block(legacy->previous(), include_root_t::yes);
assert(prev);
transition_add_to_savanna_fork_db(forkdb, legacy, bsp, prev);
Expand All @@ -1305,12 +1305,10 @@ struct controller_impl {
const block_state_ptr& prev) {
// legacy_branch is from head, all will be validated unless irreversible_mode(),
// IRREVERSIBLE applies (validates) blocks when irreversible, new_valid will be done after apply in log_irreversible
assert(read_mode == db_read_mode::IRREVERSIBLE || legacy->action_receipt_digests_savanna);
if (legacy->action_receipt_digests_savanna) {
const auto& digests = *legacy->action_receipt_digests_savanna;
auto action_mroot = calculate_merkle(digests);
assert(read_mode == db_read_mode::IRREVERSIBLE || legacy->action_mroot_savanna);
if (legacy->action_mroot_savanna) {
// Create the valid structure for producing
new_bsp->valid = prev->new_valid(*new_bsp, action_mroot, new_bsp->strong_digest);
new_bsp->valid = prev->new_valid(*new_bsp, *legacy->action_mroot_savanna, new_bsp->strong_digest);
}
forkdb.add(new_bsp, legacy->is_valid() ? mark_valid_t::yes : mark_valid_t::no, ignore_duplicate_t::yes);
}
Expand Down Expand Up @@ -1520,11 +1518,9 @@ struct controller_impl {
protocol_features.get_protocol_feature_set(),
validator_t{}, skip_validate_signee);
// legacy_branch is from head, all should be validated
assert(bspl->action_receipt_digests_savanna);
const auto& digests = *bspl->action_receipt_digests_savanna;
auto action_mroot = calculate_merkle(digests);
assert(bspl->action_mroot_savanna);
// Create the valid structure for producing
new_bsp->valid = prev->new_valid(*new_bsp, action_mroot, new_bsp->strong_digest);
new_bsp->valid = prev->new_valid(*new_bsp, *bspl->action_mroot_savanna, new_bsp->strong_digest);
prev = new_bsp;
}
}
Expand Down Expand Up @@ -3434,7 +3430,8 @@ struct controller_impl {
auto& ab = std::get<assembled_block>(pending->_block_stage);
ab.apply_legacy<void>([&](assembled_block::assembled_block_legacy& abl) {
assert(abl.action_receipt_digests_savanna);
bsp->action_receipt_digests_savanna = std::move(*abl.action_receipt_digests_savanna);
const auto& digests = *abl.action_receipt_digests_savanna;
bsp->action_mroot_savanna = calculate_merkle(digests);
});
}
auto& ab = std::get<assembled_block>(pending->_block_stage);
Expand Down Expand Up @@ -4316,8 +4313,80 @@ struct controller_impl {
}
}

// This is only used during Savanna transition, which is a one-time occurrence,
// and it is only used by SHiP..
// It is OK to calculate from Savanna Genesis block for each Transition block.
std::optional<finality_data_t> get_transition_block_finality_data(const block_state_legacy_ptr& head) const {
fork_database_legacy_t::branch_t legacy_branch;
block_state_legacy_ptr legacy_root;
fork_db.apply_l<void>([&](const auto& forkdb) {
legacy_root = forkdb.root();
legacy_branch = forkdb.fetch_branch(head->id());
});

block_state_ptr prev;
auto bitr = legacy_branch.rbegin();

// get_transition_block_finality_data is called by SHiP as a result
// of receiving accepted_block signal. That is before
// the call to log_irreversible where root() is updated.
// Search both root and legacy_branch for the first block having
// instant_finality_extension -- the Savanna Genesis Block.
// Then start from the Savanna Genesis Block to create corresponding
// Savanna blocks.
// genesis_block already contains all information for finality_data.
if (legacy_root->header.contains_header_extension(instant_finality_extension::extension_id())) {
prev = block_state::create_if_genesis_block(*legacy_root);
} else {
for (; bitr != legacy_branch.rend(); ++bitr) {
if ((*bitr)->header.contains_header_extension(instant_finality_extension::extension_id())) {
prev = block_state::create_if_genesis_block(*(*bitr));
++bitr;
break;
}
}
}

assert(prev);
const bool skip_validate_signee = true; // validated already

for (; bitr != legacy_branch.rend(); ++bitr) {
auto new_bsp = std::make_shared<block_state>(
*prev,
(*bitr)->block,
protocol_features.get_protocol_feature_set(),
validator_t{}, skip_validate_signee);

// We only need action_mroot of the last block for finality_data
if ((bitr + 1) == legacy_branch.rend()) {
assert((*bitr)->action_mroot_savanna);
new_bsp->action_mroot = *((*bitr)->action_mroot_savanna);
}

prev = new_bsp;
}

assert(prev);
return prev->get_finality_data();
}

std::optional<finality_data_t> head_finality_data() const {
return apply_s<std::optional<finality_data_t>>(chain_head, [](const block_state_ptr& head) { return head->get_finality_data(); });
return apply<std::optional<finality_data_t>>(chain_head, overloaded{
[&](const block_state_legacy_ptr& head) -> std::optional<finality_data_t> {
// When in Legacy, if it is during transition to Savana, we need to
// build finality_data for the corresponding Savanna block
if (head->header.contains_header_extension(instant_finality_extension::extension_id())) {
// during transition
return get_transition_block_finality_data(head);
} else {
// pre transition
return {};
}
},
[](const block_state_ptr& head) {
// Returns finality_data from chain_head because we are in Savanna
return head->get_finality_data();
}});
}

uint32_t earliest_available_block_num() const {
Expand Down
6 changes: 3 additions & 3 deletions libraries/chain/include/eosio/chain/block_state_legacy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace eosio::chain {
block_state_legacy( pending_block_header_state_legacy&& cur,
signed_block_ptr&& b, // unsigned block
deque<transaction_metadata_ptr>&& trx_metas,
std::optional<digests_t>&& action_receipt_digests_savanna,
const std::optional<digests_t>& action_receipt_digests_savanna,
const protocol_feature_set& pfs,
const validator_t& validator,
const signer_callback_type& signer
Expand Down Expand Up @@ -85,11 +85,11 @@ namespace eosio::chain {

// to be used during Legacy to Savanna transistion where action_mroot
// needs to be converted from Legacy merkle to Savanna merkle
std::optional<digests_t> action_receipt_digests_savanna;
std::optional<digest_type> action_mroot_savanna;
};

using block_state_legacy_ptr = std::shared_ptr<block_state_legacy>;

} /// namespace eosio::chain

FC_REFLECT_DERIVED( eosio::chain::block_state_legacy, (eosio::chain::block_header_state_legacy), (block)(validated)(action_receipt_digests_savanna) )
FC_REFLECT_DERIVED( eosio::chain::block_state_legacy, (eosio::chain::block_header_state_legacy), (block)(validated)(action_mroot_savanna) )
8 changes: 4 additions & 4 deletions unittests/deep-mind/deep-mind.log

Large diffs are not rendered by default.

0 comments on commit 08d0c96

Please sign in to comment.