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

set_finalizers host function (#1511) #1561

Merged
merged 19 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1990,6 +1990,10 @@ struct controller_impl {
emit( self.new_hs_new_block_message, msg );
}

void set_finalizers_impl(uint64_t fthreshold, vector<finalizer_authority> finalizers) {
emit( self.notify_set_finalizers, std::tie(fthreshold, finalizers) );
}

/**
* This method is called from other threads. The controller_impl should outlive those threads.
* However, to avoid race conditions, it means that the behavior of this function should not change
Expand Down Expand Up @@ -3313,6 +3317,10 @@ int64_t controller::set_proposed_producers( vector<producer_authority> producers
return version;
}

void controller::set_finalizers( uint64_t fthreshold, vector<finalizer_authority> finalizers ) {
my->set_finalizers_impl(fthreshold, finalizers);
heifner marked this conversation as resolved.
Show resolved Hide resolved
}

const producer_authority_schedule& controller::active_producers()const {
if( !(my->pending) )
return my->head->active_schedule;
Expand Down
4 changes: 4 additions & 0 deletions libraries/chain/include/eosio/chain/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ const static int max_producers = 125;
const static size_t maximum_tracked_dpos_confirmations = 1024; ///<
static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1) * producer_repetitions, "Settings never allow for DPOS irreversibility" );

/**
* Maximum number of finalizers in the finalizer set
*/
const static int max_finalizers = max_producers;

/**
* The number of blocks produced per round is based upon all producers having a chance
Expand Down
5 changes: 5 additions & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <eosio/chain/protocol_feature_manager.hpp>
#include <eosio/chain/webassembly/eos-vm-oc/config.hpp>

#include <eosio/chain/finalizer_set.hpp>
heifner marked this conversation as resolved.
Show resolved Hide resolved

namespace chainbase {
class database;
}
Expand Down Expand Up @@ -306,6 +308,8 @@ namespace eosio { namespace chain {

int64_t set_proposed_producers( vector<producer_authority> producers );

void set_finalizers( uint64_t fthreshold, vector<finalizer_authority> finalizers );

bool light_validation_allowed() const;
bool skip_auth_check()const;
bool skip_trx_checks()const;
Expand Down Expand Up @@ -356,6 +360,7 @@ namespace eosio { namespace chain {
signal<void(const hs_vote_message_ptr&)> new_hs_vote_message;
signal<void(const hs_new_view_message_ptr&)> new_hs_new_view_message;
signal<void(const hs_new_block_message_ptr&)> new_hs_new_block_message;
signal<void(std::tuple<const uint64_t, const vector<finalizer_authority>&>)> notify_set_finalizers;
heifner marked this conversation as resolved.
Show resolved Hide resolved

/*
signal<void()> pre_apply_block;
Expand Down
144 changes: 144 additions & 0 deletions libraries/chain/include/eosio/chain/finalizer_set.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#pragma once

#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>
#include <chainbase/chainbase.hpp>
#include <eosio/chain/authority.hpp>
#include <eosio/chain/snapshot.hpp>

#include <fc/crypto/bls_public_key.hpp>

namespace eosio::chain {

struct shared_finalizer_authority {
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
shared_finalizer_authority() = delete;
shared_finalizer_authority( const shared_finalizer_authority& ) = default;
shared_finalizer_authority( shared_finalizer_authority&& ) = default;
shared_finalizer_authority& operator= ( shared_finalizer_authority && ) = default;
shared_finalizer_authority& operator= ( const shared_finalizer_authority & ) = default;

shared_finalizer_authority( const name& finalizer_name, const uint64_t fweight, const fc::crypto::blslib::bls_public_key& public_key )
:finalizer_name(finalizer_name)
,fweight(fweight)
,public_key(public_key)
{}

name finalizer_name;
uint64_t fweight;
fc::crypto::blslib::bls_public_key public_key;
heifner marked this conversation as resolved.
Show resolved Hide resolved
};

struct shared_finalizer_set {
shared_finalizer_set() = delete;

explicit shared_finalizer_set( chainbase::allocator<char> alloc )
:finalizers(alloc){}

shared_finalizer_set( const shared_finalizer_set& ) = default;
shared_finalizer_set( shared_finalizer_set&& ) = default;
shared_finalizer_set& operator= ( shared_finalizer_set && ) = default;
shared_finalizer_set& operator= ( const shared_finalizer_set & ) = default;

uint32_t version = 0; ///< sequentially incrementing version number
uint64_t fthreshold = 0; // minimum finalizer fweight sum for block finalization
shared_vector<shared_finalizer_authority> finalizers;
};

struct finalizer_authority {

name finalizer_name;
heifner marked this conversation as resolved.
Show resolved Hide resolved
uint64_t fweight; // weight that this finalizer's vote has for meeting fthreshold
fc::crypto::blslib::bls_public_key public_key;

auto to_shared(chainbase::allocator<char> alloc) const {
return shared_finalizer_authority(finalizer_name, fweight, public_key);
}

static auto from_shared( const shared_finalizer_authority& src ) {
finalizer_authority result;
result.finalizer_name = src.finalizer_name;
result.fweight = src.fweight;
result.public_key = src.public_key;
return result;
}

/**
* ABI's for contracts expect variants to be serialized as a 2 entry array of
* [type-name, value].
*
* This is incompatible with standard FC rules for
* static_variants which produce
*
* [ordinal, value]
*
* this method produces an appropriate variant for contracts where the authority field
* is correctly formatted
*/
fc::variant get_abi_variant() const;
heifner marked this conversation as resolved.
Show resolved Hide resolved

friend bool operator == ( const finalizer_authority& lhs, const finalizer_authority& rhs ) {
return tie( lhs.finalizer_name, lhs.fweight, lhs.public_key ) == tie( rhs.finalizer_name, rhs.fweight, rhs.public_key );
}
friend bool operator != ( const finalizer_authority& lhs, const finalizer_authority& rhs ) {
return tie( lhs.finalizer_name, lhs.fweight, lhs.public_key ) != tie( rhs.finalizer_name, rhs.fweight, rhs.public_key );
}
};

struct finalizer_set {
finalizer_set() = default;

finalizer_set( uint32_t version, uint64_t fthreshold, std::initializer_list<finalizer_authority> finalizers )
:version(version)
,fthreshold(fthreshold)
,finalizers(finalizers)
{}

auto to_shared(chainbase::allocator<char> alloc) const {
auto result = shared_finalizer_set(alloc);
result.version = version;
result.fthreshold = fthreshold;
result.finalizers.clear();
result.finalizers.reserve( finalizers.size() );
for( const auto& f : finalizers ) {
result.finalizers.emplace_back(f.to_shared(alloc));
}
return result;
}

static auto from_shared( const shared_finalizer_set& src ) {
finalizer_set result;
result.version = src.version;
result.fthreshold = src.fthreshold;
result.finalizers.reserve( src.finalizers.size() );
for( const auto& f : src.finalizers ) {
result.finalizers.emplace_back(finalizer_authority::from_shared(f));
}
return result;
}

uint32_t version = 0; ///< sequentially incrementing version number
uint64_t fthreshold; // vote fweight threshold to finalize blocks
vector<finalizer_authority> finalizers; // Instant Finality voter set

friend bool operator == ( const finalizer_set& a, const finalizer_set& b )
{
if( a.version != b.version ) return false;
if( a.fthreshold != b.fthreshold ) return false;
if ( a.finalizers.size() != b.finalizers.size() ) return false;
for( uint32_t i = 0; i < a.finalizers.size(); ++i )
if( ! (a.finalizers[i] == b.finalizers[i]) ) return false;
return true;
}

friend bool operator != ( const finalizer_set& a, const finalizer_set& b )
{
return !(a==b);
}
};

} /// eosio::chain

FC_REFLECT( eosio::chain::finalizer_authority, (finalizer_name)(fweight)(public_key) )
FC_REFLECT( eosio::chain::finalizer_set, (version)(fthreshold)(finalizers) )
FC_REFLECT( eosio::chain::shared_finalizer_authority, (finalizer_name)(fweight)(public_key) )
FC_REFLECT( eosio::chain::shared_finalizer_set, (version)(fthreshold)(finalizers) )
9 changes: 9 additions & 0 deletions libraries/chain/include/eosio/chain/webassembly/interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ namespace webassembly {
*/
int64_t set_proposed_producers_ex(uint64_t packed_producer_format, legacy_span<const char> packed_producer_schedule);

/**
* Submits a finalizer set change to Hotstuff.
*
* @ingroup privileged
*
* @param packed_finalizer_set - a serialized finalizer_set object.
*/
void set_finalizers(legacy_span<const char> packed_finalizer_set);
heifner marked this conversation as resolved.
Show resolved Hide resolved

/**
* Retrieve the blockchain config parameters.
*
Expand Down
30 changes: 30 additions & 0 deletions libraries/chain/webassembly/privileged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <eosio/chain/transaction_context.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio/chain/apply_context.hpp>
#include <eosio/chain/finalizer_set.hpp>

#include <fc/io/datastream.hpp>

Expand Down Expand Up @@ -150,6 +151,35 @@ namespace eosio { namespace chain { namespace webassembly {
}
}

void interface::set_finalizers(legacy_span<const char> packed_finalizer_set) {
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_finalizers not allowed in a readonly transaction");
fc::datastream<const char*> ds( packed_finalizer_set.data(), packed_finalizer_set.size() );
finalizer_set finset;
fc::raw::unpack(ds, finset);
vector<finalizer_authority> & finalizers = finset.finalizers;

EOS_ASSERT( finalizers.size() <= config::max_finalizers, wasm_execution_error, "Finalizer set exceeds the maximum finalizer count for this chain" );
EOS_ASSERT( finalizers.size() > 0, wasm_execution_error, "Finalizer set cannot be empty" );

std::set<fc::crypto::blslib::bls_public_key> unique_finalizer_keys;
std::set<account_name> unique_finalizers;
uint64_t f_weight_sum = 0;

for (const auto& f: finalizers) {
EOS_ASSERT( context.is_account(f.finalizer_name), wasm_execution_error, "Finalizer set includes a nonexisting account" );
heifner marked this conversation as resolved.
Show resolved Hide resolved
EOS_ASSERT( f.public_key.valid(), wasm_execution_error, "Finalizer set includes an invalid key" );
f_weight_sum += f.fweight;
unique_finalizer_keys.insert(f.public_key);
unique_finalizers.insert(f.finalizer_name);
}

EOS_ASSERT( finalizers.size() == unique_finalizers.size(), wasm_execution_error, "Duplicate finalizer name in finalizer set" );
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 treshold cannot be met by finalizer weights" );

context.control.set_finalizers( finset.fthreshold, std::move(finalizers) );
}

uint32_t interface::get_blockchain_parameters_packed( legacy_span<char> packed_blockchain_parameters ) const {
auto& gpo = context.control.get_global_properties();

Expand Down
7 changes: 4 additions & 3 deletions libraries/libfc/include/fc/crypto/bls_public_key.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ namespace fc { namespace crypto { namespace blslib {


friend std::ostream& operator<< (std::ostream& s, const bls_public_key& k);
//friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2);
//friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2);
//friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2);
#warning FIXME/TODO: Must implement these operators.
friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey == p2._pkey;*/ }
friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey != p2._pkey;*/ }
friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return false; /*p1._pkey < p2._pkey;*/ }
friend struct reflector<bls_public_key>;
friend class bls_private_key;
}; // bls_public_key
Expand Down
Loading