Skip to content

Commit

Permalink
Merge pull request #1598 from AntelopeIO/GH-1523-finalizer-set-transi…
Browse files Browse the repository at this point in the history
…tion-2

IF: set_finalizers updates
  • Loading branch information
heifner authored Sep 7, 2023
2 parents 61db6ac + b1bead1 commit a24b4b4
Show file tree
Hide file tree
Showing 18 changed files with 203 additions and 44 deletions.
9 changes: 9 additions & 0 deletions libraries/chain/abi_serializer.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/asset.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/finalizer_authority.hpp>
#include <fc/io/raw.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <fc/io/varint.hpp>
Expand Down Expand Up @@ -632,6 +633,14 @@ namespace eosio { namespace chain {
_variant_to_binary(type, var, ds, ctx);
}

void impl::abi_to_variant::add_block_header_finalizer_set_extension( mutable_variant_object& mvo, const flat_multimap<uint16_t, block_header_extension>& header_exts ) {
if (header_exts.count(hs_finalizer_set_extension::extension_id())) {
const auto& finalizer_set_extension =
std::get<hs_finalizer_set_extension>(header_exts.lower_bound(hs_finalizer_set_extension::extension_id())->second);
mvo("proposed_finalizer_set", finalizer_set_extension);
}
}

type_name abi_serializer::get_action_type(name action)const {
auto itr = actions.find(action);
if( itr != actions.end() ) return itr->second;
Expand Down
25 changes: 25 additions & 0 deletions libraries/chain/block_header.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <eosio/chain/block.hpp>
#include <eosio/chain/finalizer_authority.hpp>
#include <eosio/chain/merkle.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
Expand Down Expand Up @@ -64,4 +65,28 @@ namespace eosio { namespace chain {
return results;
}

std::optional<block_header_extension> block_header::extract_header_extension(uint16_t extension_id)const {
using decompose_t = block_header_extension_types::decompose_t;

for( size_t i = 0; i < header_extensions.size(); ++i ) {
const auto& e = header_extensions[i];
auto id = e.first;

if (id != extension_id)
continue;

block_header_extension ext;

auto match = decompose_t::extract<block_header_extension>( id, e.second, ext );
EOS_ASSERT( match, invalid_block_header_extension,
"Block header extension with id type ${id} is not supported",
("id", id)
);

return ext;
}

return {};
}

} }
3 changes: 3 additions & 0 deletions libraries/chain/block_header_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace eosio { namespace chain {

#warning Add last_proposed_finalizer_set_generation to snapshot_block_header_state_v3, see header file TODO

namespace detail {
bool is_builtin_activated( const protocol_feature_activation_set_ptr& pfa,
const protocol_feature_set& pfs,
Expand Down Expand Up @@ -65,6 +67,7 @@ namespace eosio { namespace chain {

result.valid_block_signing_authority = proauth.authority;
result.producer = proauth.producer_name;
result.last_proposed_finalizer_set_generation = last_proposed_finalizer_set_generation;

result.blockroot_merkle = blockroot_merkle;
result.blockroot_merkle.append( id );
Expand Down
30 changes: 20 additions & 10 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <eosio/chain/deep_mind.hpp>
#include <eosio/chain/wasm_interface_collection.hpp>
#include <eosio/chain/finalizer_set.hpp>
#include <eosio/chain/finalizer_authority.hpp>

#include <chainbase/chainbase.hpp>
#include <eosio/vm/allocator.hpp>
Expand Down Expand Up @@ -1904,6 +1905,18 @@ struct controller_impl {

block_ptr->transactions = std::move( bb._pending_trx_receipts );

if (bb._pending_block_header_state.proposed_finalizer_set) {
// proposed_finalizer_set can't be set until builtin_protocol_feature_t::instant_finality activated
finalizer_set& fin_set = *bb._pending_block_header_state.proposed_finalizer_set;
++bb._pending_block_header_state.last_proposed_finalizer_set_generation;
fin_set.generation = bb._pending_block_header_state.last_proposed_finalizer_set_generation;
emplace_extension(
block_ptr->header_extensions,
hs_finalizer_set_extension::extension_id(),
fc::raw::pack( hs_finalizer_set_extension{ std::move(fin_set) } )
);
}

auto id = block_ptr->calculate_id();

// Update TaPoS table:
Expand Down Expand Up @@ -1977,10 +1990,11 @@ struct controller_impl {
pending->push();
}

void set_finalizers_impl(const finalizer_set& fin_set) {
// TODO store in chainbase
current_finalizer_set = fin_set;
++current_finalizer_set.generation;
void set_proposed_finalizers(const finalizer_set& fin_set) {
assert(pending); // has to exist and be building_block since called from host function
auto& bb = std::get<building_block>(pending->_block_stage);

bb._pending_block_header_state.proposed_finalizer_set.emplace(fin_set);
}

/**
Expand Down Expand Up @@ -3290,12 +3304,8 @@ int64_t controller::set_proposed_producers( vector<producer_authority> producers
return version;
}

void controller::set_finalizers( const finalizer_set& fin_set ) {
my->set_finalizers_impl(fin_set);
}

const finalizer_set& controller::get_finalizers() const {
return my->current_finalizer_set;
void controller::set_proposed_finalizers( const finalizer_set& fin_set ) {
my->set_proposed_finalizers(fin_set);
}

const producer_authority_schedule& controller::active_producers()const {
Expand Down
2 changes: 0 additions & 2 deletions libraries/chain/finalizer_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,4 @@ namespace eosio::chain {
finalizer_set& finalizer_set::operator=(const finalizer_set&) = default;
finalizer_set& finalizer_set::operator=(finalizer_set&&) noexcept = default;

auto finalizer_set::operator<=>(const finalizer_set&) const = default;

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

static void add_block_header_finalizer_set_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 @@ -676,6 +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_set_extension(mvo, header_exts);

mvo("producer_signature", block.producer_signature);
add(mvo, "transactions", block.transactions, resolver, ctx);
Expand Down
6 changes: 5 additions & 1 deletion libraries/chain/include/eosio/chain/block_header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#include <eosio/chain/block_timestamp.hpp>
#include <eosio/chain/producer_schedule.hpp>
#include <eosio/chain/protocol_feature_activation.hpp>
#include <eosio/chain/finalizer_set.hpp>

#include <optional>
#include <type_traits>

namespace eosio { namespace chain {
Expand All @@ -17,7 +19,8 @@ namespace eosio { namespace chain {

using block_header_extension_types = detail::block_header_extension_types<
protocol_feature_activation,
producer_schedule_change_extension
producer_schedule_change_extension,
hs_finalizer_set_extension
>;

using block_header_extension = block_header_extension_types::block_header_extension_t;
Expand Down Expand Up @@ -68,6 +71,7 @@ namespace eosio { namespace chain {
static uint32_t num_from_id(const block_id_type& id);

flat_multimap<uint16_t, block_header_extension> validate_and_extract_header_extensions()const;
std::optional<block_header_extension> extract_header_extension(uint16_t extension_id)const;
};


Expand Down
5 changes: 4 additions & 1 deletion libraries/chain/include/eosio/chain/block_header_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <eosio/chain/block_header.hpp>
#include <eosio/chain/incremental_merkle.hpp>
#include <eosio/chain/protocol_feature_manager.hpp>
#include <eosio/chain/finalizer_set.hpp>
#include <eosio/chain/chain_snapshot.hpp>
#include <future>

Expand Down Expand Up @@ -53,6 +54,7 @@ namespace detail {
uint32_t dpos_proposed_irreversible_blocknum = 0;
uint32_t dpos_irreversible_blocknum = 0;
producer_authority_schedule active_schedule;
uint32_t last_proposed_finalizer_set_generation = 0; // TODO: Add to snapshot_block_header_state_v3
incremental_merkle blockroot_merkle;
flat_map<account_name,uint32_t> producer_to_last_produced;
flat_map<account_name,uint32_t> producer_to_last_implied_irb;
Expand All @@ -74,6 +76,7 @@ namespace detail {
struct pending_block_header_state : public detail::block_header_state_common {
protocol_feature_activation_set_ptr prev_activated_protocol_features;
detail::schedule_info prev_pending_schedule;
std::optional<finalizer_set> proposed_finalizer_set; // set by set_finalizer host function
bool was_pending_promoted = false;
block_id_type previous;
account_name producer;
Expand Down Expand Up @@ -143,7 +146,6 @@ struct block_header_state : public detail::block_header_state_common {
const vector<digest_type>& )>& validator,
bool skip_validate_signee = false )const;

bool has_pending_producers()const { return pending_schedule.schedule.producers.size(); }
uint32_t calc_dpos_last_irreversible( account_name producer_of_next_block )const;

producer_authority get_scheduled_producer( block_timestamp_type t )const;
Expand All @@ -164,6 +166,7 @@ FC_REFLECT( eosio::chain::detail::block_header_state_common,
(dpos_proposed_irreversible_blocknum)
(dpos_irreversible_blocknum)
(active_schedule)
(last_proposed_finalizer_set_generation)
(blockroot_merkle)
(producer_to_last_produced)
(producer_to_last_implied_irb)
Expand Down
4 changes: 2 additions & 2 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ namespace eosio { namespace chain {

int64_t set_proposed_producers( vector<producer_authority> producers );

void set_finalizers( const finalizer_set& fin_set );
const finalizer_set& get_finalizers() const;
// called by host function set_finalizers
void set_proposed_finalizers( const finalizer_set& fin_set );

bool light_validation_allowed() const;
bool skip_auth_check()const;
Expand Down
2 changes: 0 additions & 2 deletions libraries/chain/include/eosio/chain/finalizer_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ namespace eosio::chain {
finalizer_set& operator=(const finalizer_set&);
finalizer_set& operator=(finalizer_set&&) noexcept;

auto operator<=>(const finalizer_set&) const;

uint32_t generation = 0; ///< sequentially incrementing version number
uint64_t fthreshold = 0; ///< vote fweight threshold to finalize blocks
std::vector<finalizer_authority> finalizers; ///< Instant Finality voter set
Expand Down
11 changes: 11 additions & 0 deletions libraries/chain/include/eosio/chain/webassembly/interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,17 @@ namespace webassembly {
/**
* Submits a finalizer set change to Hotstuff.
*
* // format for packed finalizer_set
* struct abi_finalizer_authority {
* std::string description;
* uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold
* std::array<uint8_t, 96> public_key_g1_affine_le;
* };
* struct abi_finalizer_set {
* uint64_t fthreshold = 0;
* std::vector<abi_finalizer_authority> finalizers;
* };
*
* @ingroup privileged
*
* @param packed_finalizer_set - a serialized finalizer_set object.
Expand Down
11 changes: 7 additions & 4 deletions libraries/chain/webassembly/privileged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ namespace eosio { namespace chain { namespace webassembly {
struct abi_finalizer_authority {
std::string description;
uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold
std::array<uint8_t, 144> public_key_g1_jacobian;
std::array<uint8_t, 96> public_key_g1_affine_le;
};
struct abi_finalizer_set {
uint64_t fthreshold = 0;
Expand All @@ -183,18 +183,21 @@ namespace eosio { namespace chain { namespace webassembly {
EOS_ASSERT( f.description.size() <= config::max_finalizer_description_size, wasm_execution_error,
"Finalizer description greater than ${s}", ("s", config::max_finalizer_description_size) );
f_weight_sum += f.fweight;
std::optional<bls12_381::g1> pk = bls12_381::g1::fromJacobianBytesLE(f.public_key_g1_jacobian);
constexpr bool check = false; // system contract does proof of possession check which is a stronger check
constexpr bool raw = true;
std::optional<bls12_381::g1> pk = bls12_381::g1::fromAffineBytesLE(f.public_key_g1_affine_le, check, raw);
EOS_ASSERT( pk, wasm_execution_error, "Invalid public key for: ${d}", ("d", f.description) );
finset.finalizers.push_back(finalizer_authority{.description = std::move(f.description),
.fweight = f.fweight,
.public_key{fc::crypto::blslib::bls_public_key{*pk}}});
unique_finalizer_keys.insert(*pk);
}

// system contract should perform a duplicate check and fthreshold check before calling
EOS_ASSERT( finalizers.size() == unique_finalizer_keys.size(), wasm_execution_error, "Duplicate finalizer bls key in finalizer set" );
EOS_ASSERT( finset.fthreshold > f_weight_sum / 2, wasm_execution_error, "Finalizer set threshold cannot be met by finalizer weights" );

context.control.set_finalizers( finset );
context.control.set_proposed_finalizers( finset );
}

uint32_t interface::get_blockchain_parameters_packed( legacy_span<char> packed_blockchain_parameters ) const {
Expand Down Expand Up @@ -272,5 +275,5 @@ namespace eosio { namespace chain { namespace webassembly {
}
}}} // ns eosio::chain::webassembly

FC_REFLECT(eosio::chain::webassembly::abi_finalizer_authority, (description)(fweight)(public_key_g1_jacobian));
FC_REFLECT(eosio::chain::webassembly::abi_finalizer_authority, (description)(fweight)(public_key_g1_affine_le));
FC_REFLECT(eosio::chain::webassembly::abi_finalizer_set, (fthreshold)(finalizers));
34 changes: 18 additions & 16 deletions libraries/hotstuff/chain_pacemaker.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <eosio/hotstuff/chain_pacemaker.hpp>
#include <eosio/chain/finalizer_authority.hpp>
#include <iostream>

// comment this out to remove the core profiler
Expand Down Expand Up @@ -108,6 +109,9 @@ namespace eosio { namespace hotstuff {
_accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) {
on_accepted_block( blk );
} );
_irreversible_block_connection = chain->irreversible_block.connect( [this]( const block_state_ptr& blk ) {
on_irreversible_block( blk );
} );
_head_block_state = chain->head_block_state();
}

Expand Down Expand Up @@ -211,8 +215,17 @@ namespace eosio { namespace hotstuff {
void chain_pacemaker::on_accepted_block( const block_state_ptr& blk ) {
std::scoped_lock g( _chain_state_mutex );
_head_block_state = blk;
// TODO only update local cache if changed, check version or use !=
_finalizer_set = _chain->get_finalizers(); // TODO get from chainbase or from block_state
}

// called from main thread
void chain_pacemaker::on_irreversible_block( const block_state_ptr& blk ) {
if (!blk->block->header_extensions.empty()) {
std::optional<block_header_extension> ext = blk->block->extract_header_extension(hs_finalizer_set_extension::extension_id());
if (ext) {
std::scoped_lock g( _chain_state_mutex );
_active_finalizer_set = std::move(std::get<hs_finalizer_set_extension>(*ext));
}
}
}

name chain_pacemaker::get_proposer() {
Expand Down Expand Up @@ -246,21 +259,10 @@ namespace eosio { namespace hotstuff {

std::vector<name> chain_pacemaker::get_finalizers() {

#warning FIXME: Use new finalizer list in pacemaker/qc_chain.
// Every time qc_chain wants to know what the finalizers are, we get it from the controller, which
// is where it's currently stored.
//
// TODO:
// - solve threading. for this particular case, I don't think using _chain-> is a big deal really;
// set_finalizers is called once in a blue moon, and this could be solved by a simple mutex even
// if it is the main thread that is waiting for a lock. But maybe there's a better way to do this
// overall.
// - use this information in qc_chain and delete the old code below
// - list of string finalizer descriptions instead of eosio name now
// - also return the keys for each finalizer, not just name/description so qc_chain can use them
//
#warning FIXME: Use _active_finalizer_set in pacemaker/qc_chain.
// _active_finalizer_set should be used

std::unique_lock g( _chain_state_mutex );
const auto& fin_set = _chain->get_finalizers(); // TODO use
block_state_ptr hbs = _head_block_state;
g.unlock();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace eosio::hotstuff {

private:
void on_accepted_block( const block_state_ptr& blk );
void on_irreversible_block( const block_state_ptr& blk );

void on_hs_proposal_msg(const hs_proposal_message& msg); //consensus msg event handler
void on_hs_vote_msg(const hs_vote_message& msg); //confirmation msg event handler
Expand Down Expand Up @@ -74,9 +75,10 @@ namespace eosio::hotstuff {

mutable std::mutex _chain_state_mutex;
block_state_ptr _head_block_state;
finalizer_set _finalizer_set;
finalizer_set _active_finalizer_set;

boost::signals2::scoped_connection _accepted_block_connection;
boost::signals2::scoped_connection _irreversible_block_connection;

qc_chain _qc_chain;
std::function<void(const chain::hs_message&)> bcast_hs_message;
Expand Down
Loading

0 comments on commit a24b4b4

Please sign in to comment.