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: set_finalizers updates #1598

Merged
merged 16 commits into from
Sep 7, 2023
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
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
linh2931 marked this conversation as resolved.
Show resolved Hide resolved
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;
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
};
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