Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IF: SHiP -- Provide finality_data for Transition blocks #2362

Merged
merged 12 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 )
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
{}

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 {
heifner marked this conversation as resolved.
Show resolved Hide resolved
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.

Loading