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: Block header extension -- replace finalizer_policy_extension and proposal_info_extension with instant_finality_extension #2024

Merged
merged 15 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
1 change: 1 addition & 0 deletions CMakeModules/EosioTesterBuild.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ target_include_directories(EosioChain INTERFACE
@CMAKE_BINARY_DIR@/libraries/chain/include
@CMAKE_SOURCE_DIR@/libraries/libfc/include
@CMAKE_SOURCE_DIR@/libraries/libfc/libraries/boringssl/boringssl/src/include
@CMAKE_SOURCE_DIR@/libraries/libfc/libraries/bls12-381/include
@CMAKE_SOURCE_DIR@/libraries/softfloat/source/include
@CMAKE_SOURCE_DIR@/libraries/appbase/include
@CMAKE_SOURCE_DIR@/libraries/chainbase/include
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ set(CHAIN_WEBASSEMBLY_SOURCES

set(CHAIN_HOTSTUFF_SOURCES
hotstuff/chain_pacemaker.cpp
hotstuff/instant_finality_extension.cpp
hotstuff/qc_chain.cpp
hotstuff/finalizer_policy.cpp
hotstuff/hotstuff.cpp
Expand Down
12 changes: 6 additions & 6 deletions libraries/chain/abi_serializer.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/asset.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/hotstuff/finalizer_authority.hpp>
#include <eosio/chain/hotstuff/instant_finality_extension.hpp>
#include <fc/io/raw.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <fc/io/varint.hpp>
Expand Down Expand Up @@ -634,11 +634,11 @@ namespace eosio { namespace chain {
_variant_to_binary(type, var, ds, ctx);
}

void impl::abi_to_variant::add_block_header_finalizer_policy_extension( mutable_variant_object& mvo, const flat_multimap<uint16_t, block_header_extension>& header_exts ) {
if (header_exts.count(finalizer_policy_extension::extension_id())) {
const auto& finalizer_policy =
std::get<finalizer_policy_extension>(header_exts.lower_bound(finalizer_policy_extension::extension_id())->second);
mvo("proposed_finalizer_policy", finalizer_policy);
void impl::abi_to_variant::add_block_header_instant_finality_extension( mutable_variant_object& mvo, const flat_multimap<uint16_t, block_header_extension>& header_exts ) {
if (header_exts.count(instant_finality_extension::extension_id())) {
const auto& if_extension =
std::get<instant_finality_extension>(header_exts.lower_bound(instant_finality_extension::extension_id())->second);
mvo("instant_finality_extension", if_extension);
}
}

Expand Down
16 changes: 12 additions & 4 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1916,10 +1916,14 @@ struct controller_impl {
finalizer_policy& fin_pol = *bb._pending_block_header_state_legacy.proposed_finalizer_policy;
++bb._pending_block_header_state_legacy.last_proposed_finalizer_policy_generation;
fin_pol.generation = bb._pending_block_header_state_legacy.last_proposed_finalizer_policy_generation;
#warning set last_qc_block_num, is_last_qc_strong, and new_proposer_policy correctly
uint32_t last_qc_block_num {0};
bool is_last_qc_strong {false};
std::optional<proposer_policy> new_proposer_policy {std::nullopt};
emplace_extension(
block_ptr->header_extensions,
finalizer_policy_extension::extension_id(),
fc::raw::pack( finalizer_policy_extension{ std::move(fin_pol) } )
instant_finality_extension::extension_id(),
fc::raw::pack( instant_finality_extension{ last_qc_block_num, is_last_qc_strong, std::move(fin_pol), std::move(new_proposer_policy) } )
);
}

Expand Down Expand Up @@ -2213,8 +2217,12 @@ struct controller_impl {
block_state_legacy_ptr create_block_state_i( const block_id_type& id, const signed_block_ptr& b, const block_header_state_legacy& prev ) {
bool hs_active = false;
if (!b->header_extensions.empty()) {
std::optional<block_header_extension> ext = b->extract_header_extension(proposal_info_extension::extension_id());
hs_active = !!ext;
std::optional<block_header_extension> instant_finality_ext = b->extract_header_extension(instant_finality_extension::extension_id());
#warning change to use instant_finality_ext https://github.com/AntelopeIO/leap/issues/1508
if (instant_finality_ext) {
const auto& ext = std::get<instant_finality_extension>(*instant_finality_ext);
hs_active = !!ext.new_proposer_policy;
}
heifner marked this conversation as resolved.
Show resolved Hide resolved
}

auto trx_mroot = calculate_trx_merkle( b->transactions, hs_active );
Expand Down
8 changes: 6 additions & 2 deletions libraries/chain/hotstuff/chain_pacemaker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ namespace eosio::chain {
// called from main thread
void chain_pacemaker::on_irreversible_block( const signed_block_ptr& block ) {
if (!block->header_extensions.empty()) {
std::optional<block_header_extension> ext = block->extract_header_extension(finalizer_policy_extension::extension_id());
std::optional<block_header_extension> ext = block->extract_header_extension(instant_finality_extension::extension_id());
if (ext) {
std::scoped_lock g( _chain_state_mutex );
if (_active_finalizer_policy.generation == 0) {
Expand All @@ -176,7 +176,11 @@ namespace eosio::chain {
// block header extension is set in finalize_block to value set by host function set_finalizers
_chain->set_hs_irreversible_block_num(block->block_num()); // can be any value <= dpos lib
}
_active_finalizer_policy = std::move(std::get<finalizer_policy_extension>(*ext));
auto if_extension = std::get<instant_finality_extension>(*ext);
#warning Revisit after finalizer policy change design is complete as this is not necessarily when we will change active finalizer policy.
if (if_extension.new_finalizer_policy) {
_active_finalizer_policy = std::move(*if_extension.new_finalizer_policy);
}
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions libraries/chain/hotstuff/instant_finality_extension.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <eosio/chain/hotstuff/instant_finality_extension.hpp>
#include <eosio/chain/exceptions.hpp>

namespace eosio::chain {

#warning this file can be removed if no actual validation comes up after all design is complete
void instant_finality_extension::reflector_init() {
static_assert( fc::raw::has_feature_reflector_init_on_unpacked_reflected_types,
"instant_finality_extension expects FC to support reflector_init" );
static_assert( extension_id() == 2, "instant_finality_extension extension id must be 2" );
}

} // eosio::chain
4 changes: 2 additions & 2 deletions libraries/chain/include/eosio/chain/abi_serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ namespace impl {
out(name, std::move(mvo));
}

static void add_block_header_finalizer_policy_extension( mutable_variant_object& mvo, const flat_multimap<uint16_t, block_header_extension>& header_exts );
static void add_block_header_instant_finality_extension( mutable_variant_object& mvo, const flat_multimap<uint16_t, block_header_extension>& header_exts );

/**
* overload of to_variant_object for signed_block
Expand Down Expand Up @@ -678,7 +678,7 @@ namespace impl {
std::get<producer_schedule_change_extension>(header_exts.lower_bound(producer_schedule_change_extension::extension_id())->second);
mvo("new_producer_schedule", new_producer_schedule);
}
add_block_header_finalizer_policy_extension(mvo, header_exts);
add_block_header_instant_finality_extension(mvo, header_exts);

mvo("producer_signature", block.producer_signature);
add(mvo, "transactions", block.transactions, resolver, ctx);
Expand Down
6 changes: 2 additions & 4 deletions libraries/chain/include/eosio/chain/block_header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
#include <eosio/chain/block_timestamp.hpp>
#include <eosio/chain/producer_schedule.hpp>
#include <eosio/chain/protocol_feature_activation.hpp>
#include <eosio/chain/hotstuff/finalizer_policy.hpp>
#include <eosio/chain/hotstuff/proposal_info.hpp>
#include <eosio/chain/hotstuff/instant_finality_extension.hpp>

#include <optional>
#include <type_traits>
Expand All @@ -21,8 +20,7 @@ namespace eosio { namespace chain {
using block_header_extension_types = detail::block_header_extension_types<
protocol_feature_activation,
producer_schedule_change_extension,
finalizer_policy_extension,
proposal_info_extension
instant_finality_extension
>;

using block_header_extension = block_header_extension_types::block_header_extension_t;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#pragma once

#include <eosio/chain/types.hpp>
#include <eosio/chain/hotstuff/finalizer_authority.hpp>

namespace eosio::chain {

struct finalizer_authority;

struct finalizer_policy {
finalizer_policy();
~finalizer_policy();
Expand All @@ -23,15 +22,6 @@ namespace eosio::chain {

using finalizer_policy_ptr = std::shared_ptr<finalizer_policy>;

/**
* Block Header Extension Compatibility
*/
struct finalizer_policy_extension : finalizer_policy {
static constexpr uint16_t extension_id() { return 2; } // TODO 3 instead?
static constexpr bool enforce_unique() { return true; }
};

} /// eosio::chain

FC_REFLECT( eosio::chain::finalizer_policy, (generation)(threshold)(finalizers) )
FC_REFLECT_DERIVED( eosio::chain::finalizer_policy_extension, (eosio::chain::finalizer_policy), )
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <eosio/chain/hotstuff/finalizer_policy.hpp>
#include <eosio/chain/hotstuff/proposer_policy.hpp>

namespace eosio::chain {

struct instant_finality_extension : fc::reflect_init {
static constexpr uint16_t extension_id() { return 2; }
static constexpr bool enforce_unique() { return true; }

instant_finality_extension() = default;
instant_finality_extension( uint32_t last_qc_block_num, bool is_last_qc_strong, std::optional<finalizer_policy> new_finalizer_policy, std::optional<proposer_policy> new_proposer_policy)
:last_qc_block_num( last_qc_block_num ), is_last_qc_strong( is_last_qc_strong ), new_finalizer_policy( std::move(new_finalizer_policy) ), new_proposer_policy( std::move(new_proposer_policy) )
{}

void reflector_init();

uint32_t last_qc_block_num {0}; // The block height of the most recent ancestor block that has a QC justification
bool is_last_qc_strong {false}; // Whether the QC for the block referenced by last_qc_block_height is strong or weak.
std::optional<finalizer_policy> new_finalizer_policy;
std::optional<proposer_policy> new_proposer_policy;
};

} /// eosio::chain

FC_REFLECT( eosio::chain::instant_finality_extension, (last_qc_block_num)(is_last_qc_strong)(new_finalizer_policy)(new_proposer_policy) )
18 changes: 18 additions & 0 deletions libraries/chain/include/eosio/chain/hotstuff/proposer_policy.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <eosio/chain/block_timestamp.hpp>
#include <eosio/chain/producer_schedule.hpp>

namespace eosio::chain {

struct proposer_policy {
constexpr static uint8_t current_schema_version = 1;
uint8_t schema_version {current_schema_version};
// Useful for light clients, not necessary for nodeos
block_timestamp_type active_time; // block when schedule will become active
producer_authority_schedule proposer_schedule;
};

} /// eosio::chain
heifner marked this conversation as resolved.
Show resolved Hide resolved

FC_REFLECT( eosio::chain::proposer_policy, (schema_version)(active_time)(proposer_schedule) )
12 changes: 7 additions & 5 deletions unittests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3876,13 +3876,15 @@ BOOST_AUTO_TEST_CASE(set_finalizer_test) { try {

// activate hotstuff
t.set_finalizers(finalizers);
auto block = t.produce_block(); // this block contains the header extension of the finalizer set
auto block = t.produce_block(); // this block contains the header extension for the instant finality

std::optional<block_header_extension> ext = block->extract_header_extension(finalizer_policy_extension::extension_id());
std::optional<block_header_extension> ext = block->extract_header_extension(instant_finality_extension::extension_id());
BOOST_TEST(!!ext);
BOOST_TEST(std::get<finalizer_policy_extension>(*ext).finalizers.size() == finalizers.size());
BOOST_TEST(std::get<finalizer_policy_extension>(*ext).generation == 1);
BOOST_TEST(std::get<finalizer_policy_extension>(*ext).threshold == finalizers.size() / 3 * 2 + 1);
std::optional<finalizer_policy> fin_policy = std::get<instant_finality_extension>(*ext).new_finalizer_policy;
BOOST_TEST(!!fin_policy);
BOOST_TEST(fin_policy->finalizers.size() == finalizers.size());
BOOST_TEST(fin_policy->generation == 1);
BOOST_TEST(fin_policy->threshold == finalizers.size() / 3 * 2 + 1);

// old dpos still in affect until block is irreversible
BOOST_TEST(block->confirmed == 0);
Expand Down
110 changes: 110 additions & 0 deletions unittests/block_header_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include <eosio/chain/block_header.hpp>

#include <boost/test/unit_test.hpp>

using namespace eosio::chain;

BOOST_AUTO_TEST_SUITE(block_header_tests)

// test for block header without extension
BOOST_AUTO_TEST_CASE(block_header_without_extension_test)
{
block_header header;
std::optional<block_header_extension> ext = header.extract_header_extension(instant_finality_extension::extension_id());
BOOST_REQUIRE(!ext);
}

// test for empty instant_finality_extension
BOOST_AUTO_TEST_CASE(instant_finality_extension_with_empty_values_test)
{
block_header header;
constexpr uint32_t last_qc_block_num {0};
constexpr bool is_last_qc_strong {false};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No big deal, but now indentation looks excessive :-).


greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
emplace_extension(
header.header_extensions,
instant_finality_extension::extension_id(),
fc::raw::pack( instant_finality_extension{last_qc_block_num, is_last_qc_strong, std::optional<finalizer_policy>{}, std::optional<proposer_policy>{}} )
);

std::optional<block_header_extension> ext = header.extract_header_extension(instant_finality_extension::extension_id());
BOOST_REQUIRE( !!ext );

const auto& if_extension = std::get<instant_finality_extension>(*ext);
BOOST_REQUIRE_EQUAL( if_extension.last_qc_block_num, last_qc_block_num );
BOOST_REQUIRE_EQUAL( if_extension.is_last_qc_strong, is_last_qc_strong );
BOOST_REQUIRE( !if_extension.new_finalizer_policy );
BOOST_REQUIRE( !if_extension.new_proposer_policy );
}

// test for instant_finality_extension uniqueness
BOOST_AUTO_TEST_CASE(instant_finality_extension_uniqueness_test)
{
block_header header;

emplace_extension(
header.header_extensions,
instant_finality_extension::extension_id(),
fc::raw::pack( instant_finality_extension{0, false, {std::nullopt}, {std::nullopt}} )
);

std::vector<finalizer_authority> finalizers { {"test description", 50, fc::crypto::blslib::bls_public_key{"PUB_BLS_MPPeebAPxt/ibL2XPuZVGpADjGn+YEVPPoYmTZeBD6Ok2E19M8SnmDGSdZBf2qwSuJim+8H83EsTpEn3OiStWBiFeJYfVRLlEsZuSF0SYYwtVteY48n+KeE1IWzlSAkSyBqiGA==" }} };
finalizer_policy new_finalizer_policy;
new_finalizer_policy.generation = 1;
new_finalizer_policy.threshold = 100;
new_finalizer_policy.finalizers = finalizers;

proposer_policy new_proposer_policy {1, block_timestamp_type{200}, {} };

emplace_extension(
header.header_extensions,
instant_finality_extension::extension_id(),
fc::raw::pack( instant_finality_extension{100, true, new_finalizer_policy, new_proposer_policy} )
);

BOOST_CHECK_THROW(header.validate_and_extract_header_extensions(), invalid_block_header_extension);
}

// test for instant_finality_extension with values
BOOST_AUTO_TEST_CASE(instant_finality_extension_with_values_test)
{
block_header header;
constexpr uint32_t last_qc_block_num {10};
constexpr bool is_last_qc_strong {true};

std::vector<finalizer_authority> finalizers { {"test description", 50, fc::crypto::blslib::bls_public_key{"PUB_BLS_MPPeebAPxt/ibL2XPuZVGpADjGn+YEVPPoYmTZeBD6Ok2E19M8SnmDGSdZBf2qwSuJim+8H83EsTpEn3OiStWBiFeJYfVRLlEsZuSF0SYYwtVteY48n+KeE1IWzlSAkSyBqiGA==" }} };
finalizer_policy new_finalizer_policy;
new_finalizer_policy.generation = 1;
new_finalizer_policy.threshold = 100;
new_finalizer_policy.finalizers = finalizers;

proposer_policy new_proposer_policy {1, block_timestamp_type{200}, {} };

emplace_extension(
header.header_extensions,
instant_finality_extension::extension_id(),
fc::raw::pack( instant_finality_extension{last_qc_block_num, is_last_qc_strong, new_finalizer_policy, new_proposer_policy} )
);

std::optional<block_header_extension> ext = header.extract_header_extension(instant_finality_extension::extension_id());
BOOST_REQUIRE( !!ext );

const auto& if_extension = std::get<instant_finality_extension>(*ext);

BOOST_REQUIRE_EQUAL( if_extension.last_qc_block_num, last_qc_block_num );
BOOST_REQUIRE_EQUAL( if_extension.is_last_qc_strong, is_last_qc_strong );

BOOST_REQUIRE( !!if_extension.new_finalizer_policy );
BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->generation, 1u);
BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->threshold, 100u);
BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->finalizers[0].description, "test description");
BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->finalizers[0].weight, 50u);
BOOST_REQUIRE_EQUAL(if_extension.new_finalizer_policy->finalizers[0].public_key.to_string(), "PUB_BLS_MPPeebAPxt/ibL2XPuZVGpADjGn+YEVPPoYmTZeBD6Ok2E19M8SnmDGSdZBf2qwSuJim+8H83EsTpEn3OiStWBiFeJYfVRLlEsZuSF0SYYwtVteY48n+KeE1IWzlSAkSyBqiGA==");
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved

BOOST_REQUIRE( !!if_extension.new_proposer_policy );
BOOST_REQUIRE_EQUAL(if_extension.new_proposer_policy->schema_version, 1u);
fc::time_point t = (fc::time_point)(if_extension.new_proposer_policy->active_time);
BOOST_REQUIRE_EQUAL(t.time_since_epoch().to_seconds(), 946684900ll);
}

BOOST_AUTO_TEST_SUITE_END()