diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index e44014b39c..7e362a0528 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -122,6 +122,7 @@ add_library( eosio_chain ${CHAIN_WEBASSEMBLY_SOURCES} authority.cpp + finalizer_set.cpp trace.cpp transaction_metadata.cpp protocol_state_object.cpp diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index b9e4042a62..1fa7cbb1aa 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1980,6 +1980,7 @@ struct controller_impl { void set_finalizers_impl(const finalizer_set& fin_set) { // TODO store in chainbase current_finalizer_set = fin_set; + ++current_finalizer_set.generation; } /** diff --git a/libraries/chain/finalizer_set.cpp b/libraries/chain/finalizer_set.cpp new file mode 100644 index 0000000000..6fa56a2b0a --- /dev/null +++ b/libraries/chain/finalizer_set.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +namespace eosio::chain { + + /** + * These definitions are all here to avoid including bls_public_key.hpp which includes + * and pulls in bls12-381 types. This keeps bls12-381 out of libtester. + */ + + finalizer_set::finalizer_set() = default; + finalizer_set::~finalizer_set() = default; + + finalizer_set::finalizer_set(const finalizer_set&) = default; + finalizer_set::finalizer_set(finalizer_set&&) noexcept = default; + + 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 diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index c3f91d9cbe..d46df346e5 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -133,7 +133,8 @@ static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1 /** * Maximum number of finalizers in the finalizer set */ -const static int max_finalizers = max_producers; +const static size_t max_finalizers = 64*1024; +const static size_t max_finalizer_description_size = 256; /** * The number of blocks produced per round is based upon all producers having a chance diff --git a/libraries/chain/include/eosio/chain/finalizer_authority.hpp b/libraries/chain/include/eosio/chain/finalizer_authority.hpp new file mode 100644 index 0000000000..e0a0628e15 --- /dev/null +++ b/libraries/chain/include/eosio/chain/finalizer_authority.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace eosio::chain { + + struct finalizer_authority { + + std::string description; + uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold + fc::crypto::blslib::bls_public_key public_key; + + auto operator<=>(const finalizer_authority&) const = default; + }; + +} /// eosio::chain + +FC_REFLECT( eosio::chain::finalizer_authority, (description)(fweight)(public_key) ) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index ca5630ade1..ced75ca27c 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -1,59 +1,39 @@ #pragma once -#include #include -#include -#include -#include - -#include namespace eosio::chain { - struct finalizer_authority { + struct finalizer_authority; + + struct finalizer_set { + finalizer_set(); + ~finalizer_set(); + + finalizer_set(const finalizer_set&); + finalizer_set(finalizer_set&&) noexcept; - std::string description; - uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold - fc::crypto::blslib::bls_public_key public_key; + finalizer_set& operator=(const finalizer_set&); + finalizer_set& operator=(finalizer_set&&) noexcept; - friend bool operator == ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { - return tie( lhs.description, lhs.fweight, lhs.public_key ) == tie( rhs.description, rhs.fweight, rhs.public_key ); - } - friend bool operator != ( const finalizer_authority& lhs, const finalizer_authority& rhs ) { - return !(lhs == rhs); - } + 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 finalizers; ///< Instant Finality voter set }; - struct finalizer_set { - finalizer_set() = default; - - finalizer_set( uint32_t version, uint64_t fthreshold, std::initializer_list finalizers ) - :version(version) - ,fthreshold(fthreshold) - ,finalizers(finalizers) - {} - - uint32_t version = 0; ///< sequentially incrementing version number - uint64_t fthreshold = 0; // vote fweight threshold to finalize blocks - vector 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); - } + using finalizer_set_ptr = std::shared_ptr; + + /** + * Block Header Extension Compatibility + */ + struct hs_finalizer_set_extension : finalizer_set { + 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_authority, (description)(fweight)(public_key) ) -FC_REFLECT( eosio::chain::finalizer_set, (version)(fthreshold)(finalizers) ) +FC_REFLECT( eosio::chain::finalizer_set, (generation)(fthreshold)(finalizers) ) +FC_REFLECT_DERIVED( eosio::chain::hs_finalizer_set_extension, (eosio::chain::finalizer_set), ) \ No newline at end of file diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index dc3992709f..ec704da324 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -151,29 +152,45 @@ namespace eosio { namespace chain { namespace webassembly { } } + // 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 public_key_g1_jacobian; + }; + struct abi_finalizer_set { + uint64_t fthreshold = 0; + std::vector finalizers; + }; + void interface::set_finalizers(span packed_finalizer_set) { - EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_finalizers not allowed in a readonly transaction"); + EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_finalizers not allowed in a readonly transaction"); fc::datastream ds( packed_finalizer_set.data(), packed_finalizer_set.size() ); - finalizer_set finset; - fc::raw::unpack(ds, finset); - vector & finalizers = finset.finalizers; + abi_finalizer_set abi_finset; + fc::raw::unpack(ds, abi_finset); + + std::vector& finalizers = abi_finset.finalizers; - // TODO: check version and increment it or verify correct 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 unique_finalizer_keys; -#warning REVIEW: Is checking for unique finalizer descriptions at all relevant? - std::set unique_finalizers; + std::set unique_finalizer_keys; uint64_t f_weight_sum = 0; + finalizer_set finset; + finset.fthreshold = abi_finset.fthreshold; for (const auto& f: finalizers) { + 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; - unique_finalizer_keys.insert(f.public_key); - unique_finalizers.insert(f.description); + std::optional pk = bls12_381::g1::fromJacobianBytesLE(f.public_key_g1_jacobian); + 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); } - EOS_ASSERT( finalizers.size() == unique_finalizers.size(), wasm_execution_error, "Duplicate finalizer description 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 threshold cannot be met by finalizer weights" ); @@ -254,3 +271,6 @@ 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_set, (fthreshold)(finalizers)); \ No newline at end of file